Skip to content

Commit

Permalink
add CLI command to register runner tokens (#23762)
Browse files Browse the repository at this point in the history
This is a CLI command to generate new tokens for the runners to register
with

Fix #23643

---------

Co-authored-by: delvh <[email protected]>
  • Loading branch information
techknowlogick and delvh authored Apr 17, 2023
1 parent 1819c4b commit 4014200
Show file tree
Hide file tree
Showing 6 changed files with 201 additions and 0 deletions.
56 changes: 56 additions & 0 deletions cmd/actions.go
Original file line number Diff line number Diff line change
@@ -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
}
25 changes: 25 additions & 0 deletions docs/content/doc/administration/command-line.en-us.md
Original file line number Diff line number Diff line change
Expand Up @@ -551,3 +551,28 @@ Restore-repo restore repository data from disk dir:
- `--owner_name lunny`: Restore destination owner 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.

### 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
```
1 change: 1 addition & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ arguments - which can alternatively be run by running the subcommand web.`
cmd.CmdDocs,
cmd.CmdDumpRepository,
cmd.CmdRestoreRepository,
cmd.CmdActions,
}
// Now adjust these commands to add our global configuration options

Expand Down
27 changes: 27 additions & 0 deletions modules/private/actions.go
Original file line number Diff line number Diff line change
@@ -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
}
91 changes: 91 additions & 0 deletions routers/private/actions.go
Original file line number Diff line number Diff line change
@@ -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
}
1 change: 1 addition & 0 deletions routers/private/internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ func Routes() *web.Route {
r.Get("/manager/processes", Processes)
r.Post("/mail/send", SendEmail)
r.Post("/restore_repo", RestoreRepo)
r.Post("/actions/generate_actions_runner_token", GenerateActionsRunnerToken)

return r
}

0 comments on commit 4014200

Please sign in to comment.