mirror of
https://gitea.com/gitea/act_runner.git
synced 2026-07-01 16:44:43 +00:00
Compare commits
2 Commits
v2.0.0
...
renovate/g
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
99e3e9d1f8 | ||
|
|
745b0ab6e4 |
@@ -305,30 +305,45 @@ func setReusedWorkflowCallerResult(rc *RunContext, runner Runner) common.Executo
|
|||||||
// getGitCloneToken returns GITEA_TOKEN when shouldCloneURLUseToken returns true,
|
// getGitCloneToken returns GITEA_TOKEN when shouldCloneURLUseToken returns true,
|
||||||
// otherwise returns an empty string
|
// otherwise returns an empty string
|
||||||
func getGitCloneToken(conf *Config, cloneURL string) string {
|
func getGitCloneToken(conf *Config, cloneURL string) string {
|
||||||
if !shouldCloneURLUseToken(conf.GitHubInstance, cloneURL) {
|
if !shouldCloneURLUseToken(conf.GitHubInstance, conf.trustedActionInstance(), cloneURL) {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return conf.GetToken()
|
return conf.GetToken()
|
||||||
}
|
}
|
||||||
|
|
||||||
// For Gitea
|
// For Gitea
|
||||||
// shouldCloneURLUseToken returns true when the following conditions are met:
|
// trustedActionInstance returns the self-hosted DEFAULT_ACTIONS_URL host that may carry the
|
||||||
// 1. cloneURL is from the same Gitea instance that the runner is registered to
|
// task token, or "" when actions resolve to github.com / a GithubMirror (never trusted).
|
||||||
// 2. the cloneURL does not have basic auth embedded
|
func (c Config) trustedActionInstance() string {
|
||||||
func shouldCloneURLUseToken(instanceURL, cloneURL string) bool {
|
if c.DefaultActionInstanceIsSelfHosted {
|
||||||
if !strings.HasPrefix(instanceURL, "http://") &&
|
return c.DefaultActionInstance
|
||||||
!strings.HasPrefix(instanceURL, "https://") {
|
|
||||||
instanceURL = "https://" + instanceURL
|
|
||||||
}
|
}
|
||||||
|
return ""
|
||||||
u1, err1 := url.Parse(instanceURL)
|
}
|
||||||
u2, err2 := url.Parse(cloneURL)
|
|
||||||
if err1 != nil || err2 != nil {
|
// For Gitea
|
||||||
return false
|
// shouldCloneURLUseToken returns true when the following conditions are met:
|
||||||
}
|
// 1. cloneURL's host matches this Gitea instance: either the registered instance
|
||||||
if u2.User != nil {
|
// (instanceURL) or, for DEFAULT_ACTIONS_URL=self on a different hostname, the
|
||||||
return false
|
// self-hosted action instance (trustedActionInstance, "" when not trusted)
|
||||||
}
|
// 2. the cloneURL does not have basic auth embedded
|
||||||
|
func shouldCloneURLUseToken(instanceURL, trustedActionInstance, cloneURL string) bool {
|
||||||
return u1.Host == u2.Host
|
u2, err := url.Parse(cloneURL)
|
||||||
|
if err != nil || u2.User != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, candidate := range []string{instanceURL, trustedActionInstance} {
|
||||||
|
if candidate == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !strings.HasPrefix(candidate, "http://") &&
|
||||||
|
!strings.HasPrefix(candidate, "https://") {
|
||||||
|
candidate = "https://" + candidate
|
||||||
|
}
|
||||||
|
if u1, err := url.Parse(candidate); err == nil && u1.Host == u2.Host {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,12 +136,30 @@ func TestGetGitCloneTokenWithSchemalessGiteaInstance(t *testing.T) {
|
|||||||
require.Equal(t, "token-value", token)
|
require.Equal(t, "token-value", token)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetGitCloneTokenSelfHostedActionsDifferentHost(t *testing.T) {
|
||||||
|
// The runner registered with one hostname while DEFAULT_ACTIONS_URL=self resolves
|
||||||
|
// actions against AppURL on a different hostname for the same instance.
|
||||||
|
conf := &Config{
|
||||||
|
GitHubInstance: "gitea.local",
|
||||||
|
DefaultActionInstance: "https://gitea.my-nas.lan",
|
||||||
|
DefaultActionInstanceIsSelfHosted: true,
|
||||||
|
Secrets: map[string]string{
|
||||||
|
"GITEA_TOKEN": "token-value",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
token := getGitCloneToken(conf, "https://gitea.my-nas.lan/owner/action")
|
||||||
|
|
||||||
|
require.Equal(t, "token-value", token)
|
||||||
|
}
|
||||||
|
|
||||||
func TestShouldCloneURLUseToken(t *testing.T) {
|
func TestShouldCloneURLUseToken(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
instanceURL string
|
instanceURL string
|
||||||
cloneURL string
|
trustedActionInstance string
|
||||||
want bool
|
cloneURL string
|
||||||
|
want bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "same host with schemaless instance",
|
name: "same host with schemaless instance",
|
||||||
@@ -173,11 +191,37 @@ func TestShouldCloneURLUseToken(t *testing.T) {
|
|||||||
cloneURL: "://gitea.example.net/actions/tools",
|
cloneURL: "://gitea.example.net/actions/tools",
|
||||||
want: false,
|
want: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// self-hosted DEFAULT_ACTIONS_URL on a different hostname than the
|
||||||
|
// registered instance: the token must still be attached.
|
||||||
|
name: "self-hosted action instance on different host",
|
||||||
|
instanceURL: "gitea.local",
|
||||||
|
trustedActionInstance: "https://gitea.my-nas.lan",
|
||||||
|
cloneURL: "https://gitea.my-nas.lan/owner/action",
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// embedded basic auth must still be rejected even when the host matches
|
||||||
|
// the trusted action instance.
|
||||||
|
name: "self-hosted action instance with embedded basic auth",
|
||||||
|
instanceURL: "gitea.local",
|
||||||
|
trustedActionInstance: "https://gitea.my-nas.lan",
|
||||||
|
cloneURL: "https://user:pass@gitea.my-nas.lan/owner/action",
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// github.com / mirror hosts are never trusted: trustedActionInstance is
|
||||||
|
// empty in github mode, so an off-instance clone URL gets no token.
|
||||||
|
name: "github mode does not trust mirror host",
|
||||||
|
instanceURL: "gitea.local",
|
||||||
|
cloneURL: "https://mirror.example.com/owner/action",
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
require.Equal(t, tt.want, shouldCloneURLUseToken(tt.instanceURL, tt.cloneURL))
|
require.Equal(t, tt.want, shouldCloneURLUseToken(tt.instanceURL, tt.trustedActionInstance, tt.cloneURL))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,18 +73,24 @@ type Config struct {
|
|||||||
ContainerNetworkCreateOptions container.NewDockerNetworkCreateExecutorInput // the default network create options
|
ContainerNetworkCreateOptions container.NewDockerNetworkCreateExecutorInput // the default network create options
|
||||||
ActionCache ActionCache // Use a custom ActionCache Implementation
|
ActionCache ActionCache // Use a custom ActionCache Implementation
|
||||||
|
|
||||||
PresetGitHubContext *model.GithubContext // the preset github context, overrides some fields like DefaultBranch, Env, Secrets etc.
|
PresetGitHubContext *model.GithubContext // the preset github context, overrides some fields like DefaultBranch, Env, Secrets etc.
|
||||||
EventJSON string // the content of JSON file to use for event.json in containers, overrides EventPath
|
EventJSON string // the content of JSON file to use for event.json in containers, overrides EventPath
|
||||||
ContainerNamePrefix string // the prefix of container name
|
ContainerNamePrefix string // the prefix of container name
|
||||||
ContainerMaxLifetime time.Duration // the max lifetime of job containers
|
ContainerMaxLifetime time.Duration // the max lifetime of job containers
|
||||||
CleanWorkdir bool // remove host executor workdir on teardown
|
CleanWorkdir bool // remove host executor workdir on teardown
|
||||||
DefaultActionInstance string // the default actions web site
|
DefaultActionInstance string // the default actions web site
|
||||||
PlatformPicker func(labels []string) string // platform picker, it will take precedence over Platforms if isn't nil
|
// DefaultActionInstanceIsSelfHosted reports whether DefaultActionInstance is this
|
||||||
JobLoggerLevel *log.Level // the level of job logger
|
// self-hosted Gitea (DEFAULT_ACTIONS_URL=self). It gates token trust: only then may the
|
||||||
ValidVolumes []string // only volumes (and bind mounts) in this slice can be mounted on the job container or service containers
|
// task token be attached to action clone URLs on DefaultActionInstance's host, which can
|
||||||
InsecureSkipTLS bool // whether to skip verifying TLS certificate of the Gitea instance
|
// differ from GitHubInstance when the runner registered with a different hostname than
|
||||||
MaxParallel int // max parallel jobs to run across all workflows (0 = no limit, uses CPU count)
|
// AppURL. It is never set for github.com or a GithubMirror, so the token stays on-instance.
|
||||||
AllocatePTY bool // allocate a pseudo-TTY for each step's process
|
DefaultActionInstanceIsSelfHosted bool
|
||||||
|
PlatformPicker func(labels []string) string // platform picker, it will take precedence over Platforms if isn't nil
|
||||||
|
JobLoggerLevel *log.Level // the level of job logger
|
||||||
|
ValidVolumes []string // only volumes (and bind mounts) in this slice can be mounted on the job container or service containers
|
||||||
|
InsecureSkipTLS bool // whether to skip verifying TLS certificate of the Gitea instance
|
||||||
|
MaxParallel int // max parallel jobs to run across all workflows (0 = no limit, uses CPU count)
|
||||||
|
AllocatePTY bool // allocate a pseudo-TTY for each step's process
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetToken: Adapt to Gitea
|
// GetToken: Adapt to Gitea
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ func (sar *stepActionRemote) prepareActionExecutor() common.Executor {
|
|||||||
// top-level token; keep the shouldCloneURLUseToken host gate to avoid leaking it.
|
// top-level token; keep the shouldCloneURLUseToken host gate to avoid leaking it.
|
||||||
cloneURL := sar.remoteAction.CloneURL(defaultActionURL)
|
cloneURL := sar.remoteAction.CloneURL(defaultActionURL)
|
||||||
token := ""
|
token := ""
|
||||||
if shouldCloneURLUseToken(sar.RunContext.Config.GitHubInstance, cloneURL) {
|
if shouldCloneURLUseToken(sar.RunContext.Config.GitHubInstance, sar.RunContext.Config.trustedActionInstance(), cloneURL) {
|
||||||
token = github.Token
|
token = github.Token
|
||||||
}
|
}
|
||||||
gitClone := stepActionRemoteNewCloneExecutor(git.NewGitCloneExecutorInput{
|
gitClone := stepActionRemoteNewCloneExecutor(git.NewGitCloneExecutorInput{
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -11,7 +11,7 @@ require (
|
|||||||
github.com/containerd/errdefs v1.0.0
|
github.com/containerd/errdefs v1.0.0
|
||||||
github.com/creack/pty v1.1.24
|
github.com/creack/pty v1.1.24
|
||||||
github.com/distribution/reference v0.6.0
|
github.com/distribution/reference v0.6.0
|
||||||
github.com/docker/cli v29.6.0+incompatible
|
github.com/docker/cli v29.6.1+incompatible
|
||||||
github.com/docker/go-connections v0.7.0
|
github.com/docker/go-connections v0.7.0
|
||||||
github.com/go-git/go-billy/v5 v5.9.0
|
github.com/go-git/go-billy/v5 v5.9.0
|
||||||
github.com/go-git/go-git/v5 v5.19.1
|
github.com/go-git/go-git/v5 v5.19.1
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -51,6 +51,8 @@ github.com/docker/cli v29.5.3+incompatible h1:nbEFfz774vBwQ5KRYv7c/AghjReqnGISvr
|
|||||||
github.com/docker/cli v29.5.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
github.com/docker/cli v29.5.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||||
github.com/docker/cli v29.6.0+incompatible h1:nw9himxMMZ7eIeherJNlKQq+acnlzGgHd+4uf10QRSc=
|
github.com/docker/cli v29.6.0+incompatible h1:nw9himxMMZ7eIeherJNlKQq+acnlzGgHd+4uf10QRSc=
|
||||||
github.com/docker/cli v29.6.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
github.com/docker/cli v29.6.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||||
|
github.com/docker/cli v29.6.1+incompatible h1:oO7F4nn3Ovr/5TlfTUWFbMwBSS/B7Xs6Epv26gBrUP8=
|
||||||
|
github.com/docker/cli v29.6.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||||
github.com/docker/docker-credential-helpers v0.9.6 h1:cT2PbRPSlnMmNTfT2TDMXRyQ1KMWHG7xoTLBcn1ZNv0=
|
github.com/docker/docker-credential-helpers v0.9.6 h1:cT2PbRPSlnMmNTfT2TDMXRyQ1KMWHG7xoTLBcn1ZNv0=
|
||||||
github.com/docker/docker-credential-helpers v0.9.6/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c=
|
github.com/docker/docker-credential-helpers v0.9.6/go.mod h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c=
|
||||||
github.com/docker/go-connections v0.7.0 h1:6SsRfJddP22WMrCkj19x9WKjEDTB+ahsdiGYf0mN39c=
|
github.com/docker/go-connections v0.7.0 h1:6SsRfJddP22WMrCkj19x9WKjEDTB+ahsdiGYf0mN39c=
|
||||||
|
|||||||
@@ -443,10 +443,11 @@ func runExec(ctx context.Context, execArgs *executeArgs) func(cmd *cobra.Command
|
|||||||
NoSkipCheckout: execArgs.noSkipCheckout,
|
NoSkipCheckout: execArgs.noSkipCheckout,
|
||||||
// PresetGitHubContext: preset,
|
// PresetGitHubContext: preset,
|
||||||
// EventJSON: string(eventJSON),
|
// EventJSON: string(eventJSON),
|
||||||
ContainerNamePrefix: "GITEA-ACTIONS-TASK-" + eventName,
|
ContainerNamePrefix: "GITEA-ACTIONS-TASK-" + eventName,
|
||||||
ContainerMaxLifetime: maxLifetime,
|
ContainerMaxLifetime: maxLifetime,
|
||||||
ContainerNetworkMode: container.NetworkMode(execArgs.network),
|
ContainerNetworkMode: container.NetworkMode(execArgs.network),
|
||||||
DefaultActionInstance: execArgs.defaultActionsURL,
|
DefaultActionInstance: execArgs.defaultActionsURL,
|
||||||
|
DefaultActionInstanceIsSelfHosted: execArgs.defaultActionsURL != "" && execArgs.defaultActionsURL != "https://github.com",
|
||||||
PlatformPicker: func(_ []string) string {
|
PlatformPicker: func(_ []string) string {
|
||||||
return execArgs.image
|
return execArgs.image
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -299,6 +299,15 @@ func (r *Runner) getDefaultActionsURL(task *runnerv1.Task) string {
|
|||||||
return giteaDefaultActionsURL
|
return giteaDefaultActionsURL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isSelfHostedActionsURL reports whether actions resolve to this self-hosted Gitea
|
||||||
|
// (DEFAULT_ACTIONS_URL=self), i.e. gitea_default_actions_url is AppURL rather than
|
||||||
|
// github.com (which may be mirror-substituted by getDefaultActionsURL). Only then may the
|
||||||
|
// task token be attached to action clone URLs on the actions instance host.
|
||||||
|
func (r *Runner) isSelfHostedActionsURL(task *runnerv1.Task) bool {
|
||||||
|
giteaDefaultActionsURL := task.Context.Fields["gitea_default_actions_url"].GetStringValue()
|
||||||
|
return giteaDefaultActionsURL != "" && giteaDefaultActionsURL != "https://github.com"
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Runner) run(ctx context.Context, task *runnerv1.Task, reporter *report.Reporter) (err error) {
|
func (r *Runner) run(ctx context.Context, task *runnerv1.Task, reporter *report.Reporter) (err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
@@ -446,14 +455,15 @@ func (r *Runner) run(ctx context.Context, task *runnerv1.Task, reporter *report.
|
|||||||
EnableIPv4: r.cfg.Container.NetworkCreateOptions.EnableIPv4,
|
EnableIPv4: r.cfg.Container.NetworkCreateOptions.EnableIPv4,
|
||||||
EnableIPv6: r.cfg.Container.NetworkCreateOptions.EnableIPv6,
|
EnableIPv6: r.cfg.Container.NetworkCreateOptions.EnableIPv6,
|
||||||
},
|
},
|
||||||
ContainerOptions: r.cfg.Container.Options,
|
ContainerOptions: r.cfg.Container.Options,
|
||||||
ContainerDaemonSocket: r.cfg.Container.DockerHost,
|
ContainerDaemonSocket: r.cfg.Container.DockerHost,
|
||||||
Privileged: r.cfg.Container.Privileged,
|
Privileged: r.cfg.Container.Privileged,
|
||||||
DefaultActionInstance: r.getDefaultActionsURL(task),
|
DefaultActionInstance: r.getDefaultActionsURL(task),
|
||||||
PlatformPicker: r.labels.PickPlatform,
|
DefaultActionInstanceIsSelfHosted: r.isSelfHostedActionsURL(task),
|
||||||
Vars: task.Vars,
|
PlatformPicker: r.labels.PickPlatform,
|
||||||
ValidVolumes: r.cfg.Container.ValidVolumes,
|
Vars: task.Vars,
|
||||||
InsecureSkipTLS: r.cfg.Runner.Insecure,
|
ValidVolumes: r.cfg.Container.ValidVolumes,
|
||||||
|
InsecureSkipTLS: r.cfg.Runner.Insecure,
|
||||||
}
|
}
|
||||||
|
|
||||||
rr, err := runner.New(runnerConfig)
|
rr, err := runner.New(runnerConfig)
|
||||||
|
|||||||
Reference in New Issue
Block a user