From b1ae30dda8292b255ba8e6d230817e4ca949090d Mon Sep 17 00:00:00 2001 From: Christopher Homberger Date: Thu, 13 Mar 2025 21:57:44 +0000 Subject: [PATCH] ephemeral act runner (#649) Works for both interactive and non-interactive registration mode. A further enhancement would be jitconfig support of the daemon command, because after some changes in Gitea Actions the registration token became reusable. removing runner and fail seems not possible at the current api level Part of https://github.com/go-gitea/gitea/pull/33570 Co-authored-by: Lunny Xiao Reviewed-on: https://gitea.com/gitea/act_runner/pulls/649 Reviewed-by: Zettat123 Reviewed-by: Lunny Xiao Co-authored-by: Christopher Homberger Co-committed-by: Christopher Homberger --- internal/app/cmd/cmd.go | 1 + internal/app/cmd/daemon.go | 2 +- internal/app/cmd/register.go | 18 ++++++++++++++---- internal/pkg/config/registration.go | 13 +++++++------ 4 files changed, 23 insertions(+), 11 deletions(-) diff --git a/internal/app/cmd/cmd.go b/internal/app/cmd/cmd.go index bd1f474..7c8e9a4 100644 --- a/internal/app/cmd/cmd.go +++ b/internal/app/cmd/cmd.go @@ -39,6 +39,7 @@ func Execute(ctx context.Context) { registerCmd.Flags().StringVar(®Args.Token, "token", "", "Runner token") registerCmd.Flags().StringVar(®Args.RunnerName, "name", "", "Runner name") registerCmd.Flags().StringVar(®Args.Labels, "labels", "", "Runner tags, comma separated") + registerCmd.Flags().BoolVar(®Args.Ephemeral, "ephemeral", false, "Configure the runner to be ephemeral and only ever be able to pick a single job (stricter than --once)") rootCmd.AddCommand(registerCmd) // ./act_runner daemon diff --git a/internal/app/cmd/daemon.go b/internal/app/cmd/daemon.go index 57d289c..9134526 100644 --- a/internal/app/cmd/daemon.go +++ b/internal/app/cmd/daemon.go @@ -122,7 +122,7 @@ func runDaemon(ctx context.Context, daemArgs *daemonArgs, configFile *string) fu poller := poll.New(cfg, cli, runner) - if daemArgs.Once { + if daemArgs.Once || reg.Ephemeral { done := make(chan struct{}) go func() { defer close(done) diff --git a/internal/app/cmd/register.go b/internal/app/cmd/register.go index ddd7c29..969529f 100644 --- a/internal/app/cmd/register.go +++ b/internal/app/cmd/register.go @@ -75,6 +75,7 @@ type registerArgs struct { Token string RunnerName string Labels string + Ephemeral bool } type registerStage int8 @@ -101,6 +102,7 @@ type registerInputs struct { Token string RunnerName string Labels []string + Ephemeral bool } func (r *registerInputs) validate() error { @@ -258,6 +260,7 @@ func registerNoInteractive(ctx context.Context, configFile string, regArgs *regi Token: regArgs.Token, RunnerName: regArgs.RunnerName, Labels: defaultLabels, + Ephemeral: regArgs.Ephemeral, } regArgs.Labels = strings.TrimSpace(regArgs.Labels) // command line flag. @@ -321,10 +324,11 @@ func doRegister(ctx context.Context, cfg *config.Config, inputs *registerInputs) } reg := &config.Registration{ - Name: inputs.RunnerName, - Token: inputs.Token, - Address: inputs.InstanceAddr, - Labels: inputs.Labels, + Name: inputs.RunnerName, + Token: inputs.Token, + Address: inputs.InstanceAddr, + Labels: inputs.Labels, + Ephemeral: inputs.Ephemeral, } ls := make([]string, len(reg.Labels)) @@ -339,6 +343,7 @@ func doRegister(ctx context.Context, cfg *config.Config, inputs *registerInputs) Version: ver.Version(), AgentLabels: ls, // Could be removed after Gitea 1.20 Labels: ls, + Ephemeral: reg.Ephemeral, })) if err != nil { log.WithError(err).Error("poller: cannot register new runner") @@ -350,6 +355,11 @@ func doRegister(ctx context.Context, cfg *config.Config, inputs *registerInputs) reg.Name = resp.Msg.Runner.Name reg.Token = resp.Msg.Runner.Token + if inputs.Ephemeral != resp.Msg.Runner.Ephemeral { + // TODO we cannot remove the configuration via runner api, if we return an error here we just fill the database + log.Error("poller: cannot register new runner as ephemeral upgrade Gitea to gain security, run-once will be used automatically") + } + if err := config.SaveRegistration(cfg.Runner.File, reg); err != nil { return fmt.Errorf("failed to save runner config: %w", err) } diff --git a/internal/pkg/config/registration.go b/internal/pkg/config/registration.go index be66b4f..414f44f 100644 --- a/internal/pkg/config/registration.go +++ b/internal/pkg/config/registration.go @@ -14,12 +14,13 @@ const registrationWarning = "This file is automatically generated by act-runner. type Registration struct { Warning string `json:"WARNING"` // Warning message to display, it's always the registrationWarning constant - ID int64 `json:"id"` - UUID string `json:"uuid"` - Name string `json:"name"` - Token string `json:"token"` - Address string `json:"address"` - Labels []string `json:"labels"` + ID int64 `json:"id"` + UUID string `json:"uuid"` + Name string `json:"name"` + Token string `json:"token"` + Address string `json:"address"` + Labels []string `json:"labels"` + Ephemeral bool `json:"ephemeral"` } func LoadRegistration(file string) (*Registration, error) {