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

Resolve #24789

## ⚠️ BREAKING ⚠️

Before this, `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`.

But now, `DEFAULT_ACTIONS_URL` supports only
`github`(`https://github.com`) or `self`(the root url of current Gitea
instance), and the default value is `github`.

If it has configured with a URL, an error log will be displayed and it
will fallback to `github`.

Actually, what we really want to do is always make it
`https://github.com`, however, this may not be acceptable for some
instances of internal use, so there's extra support for `self`, but no
more, even `https://gitea.com`.

Please note that `uses: https://xxx/yyy/zzz` always works and it does
exactly what it is supposed to do.

Although it's breaking, I belive it should be backported to `v1.20` due
to some security issues.

Follow-up on the runner side:

- https://gitea.com/gitea/act_runner/pulls/262
- https://gitea.com/gitea/act/pulls/70
This commit is contained in:
Jason Song 2023-06-30 15:26:36 +08:00 committed by GitHub
parent 254a82842a
commit 67bd9d4f1e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 139 additions and 33 deletions

View file

@ -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
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View file

@ -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
`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`.
```yaml
name: versions
on:
push:
branches:
- main
- releases/*
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: 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.
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.
Of course we should support the form in future PRs like
```yaml
steps:
- uses: gitea.com/actions/checkout@v3
```
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`)

View file

@ -5,6 +5,9 @@ package setting
import (
"fmt"
"strings"
"code.gitea.io/gitea/modules/log"
)
// Actions settings
@ -13,13 +16,36 @@ 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)
@ -27,6 +53,19 @@ func loadActionsFrom(rootCfg ConfigProvider) error {
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)
}
}
// don't support to read configuration from [actions]
Actions.LogStorage, err = getStorage(rootCfg, "actions_log", "", nil)
if err != nil {

View file

@ -8,6 +8,7 @@ import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func Test_getStorageInheritNameSectionTypeForActions(t *testing.T) {
@ -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())
})
}
}

View file

@ -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)