add CLI command to register runner tokens (#23762)

This is a CLI command to generate new tokens for the runners to register
with

Fix https://github.com/go-gitea/gitea/issues/23643

---------

Co-authored-by: delvh <dev.lh@web.de>
This commit is contained in:
techknowlogick 2023-04-17 13:07:13 -04:00 committed by GitHub
parent 1819c4b59b
commit 4014200021
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 201 additions and 0 deletions

56
cmd/actions.go Normal file
View File

@ -0,0 +1,56 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package cmd
import (
"fmt"
"code.gitea.io/gitea/modules/private"
"code.gitea.io/gitea/modules/setting"
"github.com/urfave/cli"
)
var (
// CmdActions represents the available actions sub-commands.
CmdActions = cli.Command{
Name: "actions",
Usage: "",
Description: "Commands for managing Gitea Actions",
Subcommands: []cli.Command{
subcmdActionsGenRunnerToken,
},
}
subcmdActionsGenRunnerToken = cli.Command{
Name: "generate-runner-token",
Usage: "Generate a new token for a runner to use to register with the server",
Action: runGenerateActionsRunnerToken,
Aliases: []string{"grt"},
Flags: []cli.Flag{
cli.StringFlag{
Name: "scope, s",
Value: "",
Usage: "{owner}[/{repo}] - leave empty for a global runner",
},
},
}
)
func runGenerateActionsRunnerToken(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
setting.InitProviderFromExistingFile()
setting.LoadCommonSettings()
scope := c.String("scope")
respText, extra := private.GenerateActionsRunnerToken(ctx, scope)
if extra.HasError() {
return handleCliResponseExtra(extra)
}
_, _ = fmt.Printf("%s\n", respText)
return nil
}

View File

@ -551,3 +551,28 @@ Restore-repo restore repository data from disk dir:
- `--owner_name lunny`: Restore destination owner name - `--owner_name lunny`: Restore destination owner name
- `--repo_name tango`: Restore destination repository name - `--repo_name tango`: Restore destination repository name
- `--units <units>`: Which items will be restored, one or more units should be separated as comma. wiki, issues, labels, releases, release_assets, milestones, pull_requests, comments are allowed. Empty means all units. - `--units <units>`: Which items will be restored, one or more units should be separated as comma. wiki, issues, labels, releases, release_assets, milestones, pull_requests, comments are allowed. Empty means all units.
### actions generate-runner-token
Generate a new token for a runner to use to register with the server
- Options:
- `--scope {owner}[/{repo}]`, `-s {owner}[/{repo}]`: To limit the scope of the runner, no scope means the runner can be used for all repos, but you can also limit it to a specific repo or owner
To register a global runner:
```
gitea actions generate-runner-token
```
To register a runner for a specific organization, in this case `org`:
```
gitea actions generate-runner-token -s org
```
To register a runner for a specific repo, in this case `username/test-repo`:
```
gitea actions generate-runner-token -s username/test-repo
```

View File

@ -75,6 +75,7 @@ arguments - which can alternatively be run by running the subcommand web.`
cmd.CmdDocs, cmd.CmdDocs,
cmd.CmdDumpRepository, cmd.CmdDumpRepository,
cmd.CmdRestoreRepository, cmd.CmdRestoreRepository,
cmd.CmdActions,
} }
// Now adjust these commands to add our global configuration options // Now adjust these commands to add our global configuration options

View File

@ -0,0 +1,27 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package private
import (
"context"
"code.gitea.io/gitea/modules/setting"
)
// Email structure holds a data for sending general emails
type GenerateTokenRequest struct {
Scope string
}
// GenerateActionsRunnerToken calls the internal GenerateActionsRunnerToken function
func GenerateActionsRunnerToken(ctx context.Context, scope string) (string, ResponseExtra) {
reqURL := setting.LocalURL + "api/internal/actions/generate_actions_runner_token"
req := newInternalRequest(ctx, reqURL, "POST", GenerateTokenRequest{
Scope: scope,
})
resp, extra := requestJSONResp(req, &responseText{})
return resp.Text, extra
}

View File

@ -0,0 +1,91 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package private
import (
"errors"
"fmt"
"net/http"
"strings"
actions_model "code.gitea.io/gitea/models/actions"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/private"
"code.gitea.io/gitea/modules/util"
)
// GenerateActionsRunnerToken generates a new runner token for a given scope
func GenerateActionsRunnerToken(ctx *context.PrivateContext) {
var genRequest private.GenerateTokenRequest
rd := ctx.Req.Body
defer rd.Close()
if err := json.NewDecoder(rd).Decode(&genRequest); err != nil {
log.Error("%v", err)
ctx.JSON(http.StatusInternalServerError, private.Response{
Err: err.Error(),
})
return
}
owner, repo, err := parseScope(ctx, genRequest.Scope)
if err != nil {
log.Error("%v", err)
ctx.JSON(http.StatusInternalServerError, private.Response{
Err: err.Error(),
})
}
token, err := actions_model.GetUnactivatedRunnerToken(ctx, owner, repo)
if errors.Is(err, util.ErrNotExist) {
token, err = actions_model.NewRunnerToken(ctx, owner, repo)
if err != nil {
err := fmt.Sprintf("error while creating runner token: %v", err)
log.Error("%v", err)
ctx.JSON(http.StatusInternalServerError, private.Response{
Err: err,
})
return
}
} else if err != nil {
err := fmt.Sprintf("could not get unactivated runner token: %v", err)
log.Error("%v", err)
ctx.JSON(http.StatusInternalServerError, private.Response{
Err: err,
})
return
}
ctx.PlainText(http.StatusOK, token.Token)
}
func parseScope(ctx *context.PrivateContext, scope string) (ownerID, repoID int64, err error) {
ownerID = 0
repoID = 0
if scope == "" {
return ownerID, repoID, nil
}
ownerName, repoName, found := strings.Cut(scope, "/")
u, err := user_model.GetUserByName(ctx, ownerName)
if err != nil {
return ownerID, repoID, err
}
if !found {
return u.ID, repoID, nil
}
r, err := repo_model.GetRepositoryByName(u.ID, repoName)
if err != nil {
return ownerID, repoID, err
}
repoID = r.ID
return ownerID, repoID, nil
}

View File

@ -77,6 +77,7 @@ func Routes() *web.Route {
r.Get("/manager/processes", Processes) r.Get("/manager/processes", Processes)
r.Post("/mail/send", SendEmail) r.Post("/mail/send", SendEmail)
r.Post("/restore_repo", RestoreRepo) r.Post("/restore_repo", RestoreRepo)
r.Post("/actions/generate_actions_runner_token", GenerateActionsRunnerToken)
return r return r
} }