Skip to content

Restrict [actions].DEFAULT_ACTIONS_URL to only github or self #25581

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jun 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions custom/conf/app.example.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2541,8 +2541,8 @@ LEVEL = Info
;; Enable/Disable actions capabilities
;ENABLED = false
;;
;; Default address to get action plugins, e.g. the default value means downloading from "https://gitea.com/actions/checkout" for "uses: actions/checkout@v3"
;DEFAULT_ACTIONS_URL = https://gitea.com
;; Default platform to get action plugins, `github` for `https://github.com`, `self` for the current Gitea instance.
;DEFAULT_ACTIONS_URL = github

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Expand Down
39 changes: 11 additions & 28 deletions docs/content/doc/administration/config-cheat-sheet.en-us.md
Original file line number Diff line number Diff line change
Expand Up @@ -1376,39 +1376,22 @@ PROXY_HOSTS = *.github.com
## Actions (`actions`)

- `ENABLED`: **false**: Enable/Disable actions capabilities
- `DEFAULT_ACTIONS_URL`: **https://gitea.com**: Default address to get action plugins, e.g. the default value means downloading from "<https://gitea.com/actions/checkout>" for "uses: actions/checkout@v3"
- `DEFAULT_ACTIONS_URL`: **github**: Default platform to get action plugins, `github` for `https://github.com`, `self` for the current Gitea instance.
- `STORAGE_TYPE`: **local**: Storage type for actions logs, `local` for local disk or `minio` for s3 compatible object storage service, default is `local` or other name defined with `[storage.xxx]`
- `MINIO_BASE_PATH`: **actions_log/**: Minio base path on the bucket only available when STORAGE_TYPE is `minio`

`DEFAULT_ACTIONS_URL` indicates where should we find the relative path action plugin. i.e. when use an action in a workflow file like

```yaml
name: versions
on:
push:
branches:
- main
- releases/*
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
```

Now we need to know how to get actions/checkout, this configuration is the default git server to get it. That means we will get the repository via git clone ${DEFAULT_ACTIONS_URL}/actions/checkout and fetch tag v3.

To help people who don't want to mirror these actions in their git instances, the default value is https://gitea.com
To help people run actions totally in their network, they can change the value and copy all necessary action repositories into their git server.
`DEFAULT_ACTIONS_URL` indicates where the Gitea Actions runners should find the actions with relative path.
For example, `uses: actions/checkout@v3` means `https://github.com/actions/checkout@v3` since the value of `DEFAULT_ACTIONS_URL` is `github`.
And it can be changed to `self` to make it `root_url_of_your_gitea/actions/checkout@v3`.

Of course we should support the form in future PRs like

```yaml
steps:
- uses: gitea.com/actions/checkout@v3
```
Please note that using `self` is not recommended for most cases, as it could make names globally ambiguous.
Additionally, it requires you to mirror all the actions you need to your Gitea instance, which may not be worth it.
Therefore, please use `self` only if you understand what you are doing.

although Github don't support this form.
In earlier versions (<= 1.19), `DEFAULT_ACTIONS_URL` cound be set to any custom URLs like `https://gitea.com` or `http://your-git-server,https://gitea.com`, and the default value was `https://gitea.com`.
However, later updates removed those options, and now the only options are `github` and `self`, with the default value being `github`.
However, if you want to use actions from other git server, you can use a complete URL in `uses` field, it's supported by Gitea (but not GitHub).
Like `uses: https://gitea.com/actions/checkout@v3` or `uses: http://your-git-server/actions/checkout@v3`.

## Other (`other`)

Expand Down
43 changes: 41 additions & 2 deletions modules/setting/actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ package setting

import (
"fmt"
"strings"

"code.gitea.io/gitea/modules/log"
)

// Actions settings
Expand All @@ -13,20 +16,56 @@ var (
LogStorage *Storage // how the created logs should be stored
ArtifactStorage *Storage // how the created artifacts should be stored
Enabled bool
DefaultActionsURL string `ini:"DEFAULT_ACTIONS_URL"`
DefaultActionsURL defaultActionsURL `ini:"DEFAULT_ACTIONS_URL"`
}{
Enabled: false,
DefaultActionsURL: "https://gitea.com",
DefaultActionsURL: defaultActionsURLGitHub,
}
)

type defaultActionsURL string

func (url defaultActionsURL) URL() string {
switch url {
case defaultActionsURLGitHub:
return "https://github.com"
case defaultActionsURLSelf:
return strings.TrimSuffix(AppURL, "/")
default:
// This should never happen, but just in case, use GitHub as fallback
return "https://github.com"
}
}

const (
defaultActionsURLGitHub = "github" // https://github.com
defaultActionsURLSelf = "self" // the root URL of the self-hosted Gitea instance
// DefaultActionsURL only supports GitHub and the self-hosted Gitea.
// It's intentionally not supported more, so please be cautious before adding more like "gitea" or "gitlab".
// If you get some trouble with `uses: username/action_name@version` in your workflow,
// please consider to use `uses: https://the_url_you_want_to_use/username/action_name@version` instead.
)

func loadActionsFrom(rootCfg ConfigProvider) error {
sec := rootCfg.Section("actions")
err := sec.MapTo(&Actions)
if err != nil {
return fmt.Errorf("failed to map Actions settings: %v", err)
}

if urls := string(Actions.DefaultActionsURL); urls != defaultActionsURLGitHub && urls != defaultActionsURLSelf {
url := strings.Split(urls, ",")[0]
if strings.HasPrefix(url, "https://") || strings.HasPrefix(url, "http://") {
log.Error("[actions] DEFAULT_ACTIONS_URL does not support %q as custom URL any longer, fallback to %q",
urls,
defaultActionsURLGitHub,
)
Actions.DefaultActionsURL = defaultActionsURLGitHub
} else {
return fmt.Errorf("unsupported [actions] DEFAULT_ACTIONS_URL: %q", urls)
}
}
Comment on lines +56 to +67
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively, we could also extract these checks into the URL method above, and then simply set Actions.DefaultActionsURL = urls.URL().
That way, we only have all this checks once.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not ideal, URL() depends on AppURL, we cannot assume that AppURL is ready here. That's why I call URL() after Gitea has initialized.


// don't support to read configuration from [actions]
Actions.LogStorage, err = getStorage(rootCfg, "actions_log", "", nil)
if err != nil {
Expand Down
84 changes: 84 additions & 0 deletions modules/setting/actions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func Test_getStorageInheritNameSectionTypeForActions(t *testing.T) {
Expand Down Expand Up @@ -95,3 +96,86 @@ STORAGE_TYPE = minio
assert.EqualValues(t, "local", Actions.ArtifactStorage.Type)
assert.EqualValues(t, "actions_artifacts", filepath.Base(Actions.ArtifactStorage.Path))
}

func Test_getDefaultActionsURLForActions(t *testing.T) {
oldActions := Actions
oldAppURL := AppURL
defer func() {
Actions = oldActions
AppURL = oldAppURL
}()

AppURL = "http://test_get_default_actions_url_for_actions:3000/"

tests := []struct {
name string
iniStr string
wantErr assert.ErrorAssertionFunc
wantURL string
}{
{
name: "default",
iniStr: `
[actions]
`,
wantErr: assert.NoError,
wantURL: "https://github.com",
},
{
name: "github",
iniStr: `
[actions]
DEFAULT_ACTIONS_URL = github
`,
wantErr: assert.NoError,
wantURL: "https://github.com",
},
{
name: "self",
iniStr: `
[actions]
DEFAULT_ACTIONS_URL = self
`,
wantErr: assert.NoError,
wantURL: "http://test_get_default_actions_url_for_actions:3000",
},
{
name: "custom url",
iniStr: `
[actions]
DEFAULT_ACTIONS_URL = https://gitea.com
`,
wantErr: assert.NoError,
wantURL: "https://github.com",
},
{
name: "custom urls",
iniStr: `
[actions]
DEFAULT_ACTIONS_URL = https://gitea.com,https://github.com
`,
wantErr: assert.NoError,
wantURL: "https://github.com",
},
{
name: "invalid",
iniStr: `
[actions]
DEFAULT_ACTIONS_URL = gitea
`,
wantErr: assert.Error,
wantURL: "https://github.com",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cfg, err := NewConfigProviderFromData(tt.iniStr)
require.NoError(t, err)
if !tt.wantErr(t, loadActionsFrom(cfg)) {
return
}
assert.EqualValues(t, tt.wantURL, Actions.DefaultActionsURL.URL())
})
}
}
2 changes: 1 addition & 1 deletion routers/api/actions/runner/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ func generateTaskContext(t *actions_model.ActionTask) *structpb.Struct {
"workspace": "", // string, The default working directory on the runner for steps, and the default location of your repository when using the checkout action.

// additional contexts
"gitea_default_actions_url": setting.Actions.DefaultActionsURL,
"gitea_default_actions_url": setting.Actions.DefaultActionsURL.URL(),
})
if err != nil {
log.Error("structpb.NewStruct failed: %v", err)
Expand Down