Skip to content

Commit 869efc6

Browse files
committed
Add instance-level secrets
1 parent b36e2ca commit 869efc6

File tree

13 files changed

+326
-26
lines changed

13 files changed

+326
-26
lines changed

models/secret/secret.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ func init() {
6464
}
6565

6666
func (s *Secret) Validate() error {
67-
if s.OwnerID == 0 && s.RepoID == 0 {
68-
return errors.New("the secret is not bound to any scope")
67+
if s.OwnerID != 0 && s.RepoID != 0 {
68+
return errors.New("a secret should not be bound to an owner and a repository at the same time")
6969
}
7070
return nil
7171
}
@@ -80,12 +80,8 @@ type FindSecretsOptions struct {
8080

8181
func (opts *FindSecretsOptions) toConds() builder.Cond {
8282
cond := builder.NewCond()
83-
if opts.OwnerID > 0 {
84-
cond = cond.And(builder.Eq{"owner_id": opts.OwnerID})
85-
}
86-
if opts.RepoID > 0 {
87-
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
88-
}
83+
cond = cond.And(builder.Eq{"owner_id": opts.OwnerID})
84+
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
8985
if opts.SecretID != 0 {
9086
cond = cond.And(builder.Eq{"id": opts.SecretID})
9187
}

routers/api/actions/runner/utils.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ func getSecretsOfTask(ctx context.Context, task *actions_model.ActionTask) map[s
6767
return secrets
6868
}
6969

70+
globalSecrets, err := secret_model.FindSecrets(ctx, secret_model.FindSecretsOptions{})
71+
if err != nil {
72+
log.Error("find global secrets: %v", err)
73+
// go on
74+
}
7075
ownerSecrets, err := secret_model.FindSecrets(ctx, secret_model.FindSecretsOptions{OwnerID: task.Job.Run.Repo.OwnerID})
7176
if err != nil {
7277
log.Error("find secrets of owner %v: %v", task.Job.Run.Repo.OwnerID, err)
@@ -78,7 +83,8 @@ func getSecretsOfTask(ctx context.Context, task *actions_model.ActionTask) map[s
7883
// go on
7984
}
8085

81-
for _, secret := range append(ownerSecrets, repoSecrets...) {
86+
// Level precedence: Repo > Org / User > Global
87+
for _, secret := range append(globalSecrets, append(ownerSecrets, repoSecrets...)...) {
8288
if v, err := secret_module.DecryptSecret(setting.SecretKey, secret.Data); err != nil {
8389
log.Error("decrypt secret %v %q: %v", secret.ID, secret.Name, err)
8490
// go on

routers/api/v1/admin/action.go

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// Copyright 2023 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package admin
5+
6+
import (
7+
"errors"
8+
"net/http"
9+
10+
"code.gitea.io/gitea/modules/context"
11+
api "code.gitea.io/gitea/modules/structs"
12+
"code.gitea.io/gitea/modules/util"
13+
"code.gitea.io/gitea/modules/web"
14+
secret_service "code.gitea.io/gitea/services/secrets"
15+
)
16+
17+
// create or update one secret in the instance scope
18+
func CreateOrUpdateSecret(ctx *context.APIContext) {
19+
// swagger:operation PUT /admin/actions/secrets/{secretname} admin updateAdminSecret
20+
// ---
21+
// summary: Create or Update a secret value in the instance scope
22+
// consumes:
23+
// - application/json
24+
// produces:
25+
// - application/json
26+
// parameters:
27+
// - name: secretname
28+
// in: path
29+
// description: name of the secret
30+
// type: string
31+
// required: true
32+
// - name: body
33+
// in: body
34+
// schema:
35+
// "$ref": "#/definitions/CreateOrUpdateSecretOption"
36+
// responses:
37+
// "201":
38+
// description: response when creating a secret
39+
// "204":
40+
// description: response when updating a secret
41+
// "400":
42+
// "$ref": "#/responses/error"
43+
// "404":
44+
// "$ref": "#/responses/notFound"
45+
46+
opt := web.GetForm(ctx).(*api.CreateOrUpdateSecretOption)
47+
48+
_, created, err := secret_service.CreateOrUpdateSecret(ctx, 0, 0, ctx.Params("secretname"), opt.Data)
49+
if err != nil {
50+
if errors.Is(err, util.ErrInvalidArgument) {
51+
ctx.Error(http.StatusBadRequest, "CreateOrUpdateSecret", err)
52+
} else if errors.Is(err, util.ErrNotExist) {
53+
ctx.Error(http.StatusNotFound, "CreateOrUpdateSecret", err)
54+
} else {
55+
ctx.Error(http.StatusInternalServerError, "CreateOrUpdateSecret", err)
56+
}
57+
return
58+
}
59+
60+
if created {
61+
ctx.Status(http.StatusCreated)
62+
} else {
63+
ctx.Status(http.StatusNoContent)
64+
}
65+
}
66+
67+
// DeleteSecret delete one secret in the instance scope
68+
func DeleteSecret(ctx *context.APIContext) {
69+
// swagger:operation DELETE /admin/actions/secrets/{secretname} admin deleteAdminSecret
70+
// ---
71+
// summary: Delete a secret in the instance scope
72+
// consumes:
73+
// - application/json
74+
// produces:
75+
// - application/json
76+
// parameters:
77+
// - name: secretname
78+
// in: path
79+
// description: name of the secret
80+
// type: string
81+
// required: true
82+
// responses:
83+
// "204":
84+
// description: delete one secret of the admin
85+
// "400":
86+
// "$ref": "#/responses/error"
87+
// "404":
88+
// "$ref": "#/responses/notFound"
89+
90+
err := secret_service.DeleteSecretByName(ctx, 0, 0, ctx.Params("secretname"))
91+
if err != nil {
92+
if errors.Is(err, util.ErrInvalidArgument) {
93+
ctx.Error(http.StatusBadRequest, "DeleteSecret", err)
94+
} else if errors.Is(err, util.ErrNotExist) {
95+
ctx.Error(http.StatusNotFound, "DeleteSecret", err)
96+
} else {
97+
ctx.Error(http.StatusInternalServerError, "DeleteSecret", err)
98+
}
99+
return
100+
}
101+
102+
ctx.Status(http.StatusNoContent)
103+
}

routers/api/v1/api.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -956,14 +956,11 @@ func Routes() *web.Route {
956956
Get(user.ListEmails).
957957
Post(bind(api.CreateEmailOption{}), user.AddEmail).
958958
Delete(bind(api.DeleteEmailOption{}), user.DeleteEmail)
959-
960-
// create or update a user's actions secrets
961959
m.Group("/actions/secrets", func() {
962960
m.Combo("/{secretname}").
963961
Put(bind(api.CreateOrUpdateSecretOption{}), user.CreateOrUpdateSecret).
964962
Delete(user.DeleteSecret)
965963
})
966-
967964
m.Get("/followers", user.ListMyFollowers)
968965
m.Group("/following", func() {
969966
m.Get("", user.ListMyFollowing)
@@ -1490,6 +1487,11 @@ func Routes() *web.Route {
14901487
}, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization), orgAssignment(false, true), reqToken(), reqTeamMembership())
14911488

14921489
m.Group("/admin", func() {
1490+
m.Group("/actions/secrets", func() {
1491+
m.Combo("/{secretname}").
1492+
Put(bind(api.CreateOrUpdateSecretOption{}), admin.CreateOrUpdateSecret).
1493+
Delete(admin.DeleteSecret)
1494+
})
14931495
m.Group("/cron", func() {
14941496
m.Get("", admin.ListCronTasks)
14951497
m.Post("/{task}", admin.PostCronTask)

routers/api/v1/org/action.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ func ListActionsSecrets(ctx *context.APIContext) {
7272
ctx.JSON(http.StatusOK, apiSecrets)
7373
}
7474

75-
// create or update one secret of the organization
75+
// create or update one secret in the organization
7676
func CreateOrUpdateSecret(ctx *context.APIContext) {
7777
// swagger:operation PUT /orgs/{org}/actions/secrets/{secretname} organization updateOrgSecret
7878
// ---
@@ -127,7 +127,7 @@ func CreateOrUpdateSecret(ctx *context.APIContext) {
127127
}
128128
}
129129

130-
// DeleteSecret delete one secret of the organization
130+
// delete one secret in the organization
131131
func DeleteSecret(ctx *context.APIContext) {
132132
// swagger:operation DELETE /orgs/{org}/actions/secrets/{secretname} organization deleteOrgSecret
133133
// ---

routers/api/v1/repo/action.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414
secret_service "code.gitea.io/gitea/services/secrets"
1515
)
1616

17-
// create or update one secret of the repository
17+
// create or update one secret in the repository
1818
func CreateOrUpdateSecret(ctx *context.APIContext) {
1919
// swagger:operation PUT /repos/{owner}/{repo}/actions/secrets/{secretname} repository updateRepoSecret
2020
// ---
@@ -53,12 +53,11 @@ func CreateOrUpdateSecret(ctx *context.APIContext) {
5353
// "404":
5454
// "$ref": "#/responses/notFound"
5555

56-
owner := ctx.Repo.Owner
5756
repo := ctx.Repo.Repository
5857

5958
opt := web.GetForm(ctx).(*api.CreateOrUpdateSecretOption)
6059

61-
_, created, err := secret_service.CreateOrUpdateSecret(ctx, owner.ID, repo.ID, ctx.Params("secretname"), opt.Data)
60+
_, created, err := secret_service.CreateOrUpdateSecret(ctx, 0, repo.ID, ctx.Params("secretname"), opt.Data)
6261
if err != nil {
6362
if errors.Is(err, util.ErrInvalidArgument) {
6463
ctx.Error(http.StatusBadRequest, "CreateOrUpdateSecret", err)
@@ -77,7 +76,7 @@ func CreateOrUpdateSecret(ctx *context.APIContext) {
7776
}
7877
}
7978

80-
// DeleteSecret delete one secret of the repository
79+
// delete one secret in the repository
8180
func DeleteSecret(ctx *context.APIContext) {
8281
// swagger:operation DELETE /repos/{owner}/{repo}/actions/secrets/{secretname} repository deleteRepoSecret
8382
// ---
@@ -110,10 +109,9 @@ func DeleteSecret(ctx *context.APIContext) {
110109
// "404":
111110
// "$ref": "#/responses/notFound"
112111

113-
owner := ctx.Repo.Owner
114112
repo := ctx.Repo.Repository
115113

116-
err := secret_service.DeleteSecretByName(ctx, owner.ID, repo.ID, ctx.Params("secretname"))
114+
err := secret_service.DeleteSecretByName(ctx, 0, repo.ID, ctx.Params("secretname"))
117115
if err != nil {
118116
if errors.Is(err, util.ErrInvalidArgument) {
119117
ctx.Error(http.StatusBadRequest, "DeleteSecret", err)

routers/api/v1/user/action.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414
secret_service "code.gitea.io/gitea/services/secrets"
1515
)
1616

17-
// create or update one secret of the user scope
17+
// create or update one secret in the user scope
1818
func CreateOrUpdateSecret(ctx *context.APIContext) {
1919
// swagger:operation PUT /user/actions/secrets/{secretname} user updateUserSecret
2020
// ---
@@ -64,7 +64,7 @@ func CreateOrUpdateSecret(ctx *context.APIContext) {
6464
}
6565
}
6666

67-
// DeleteSecret delete one secret of the user scope
67+
// delete one secret in the user scope
6868
func DeleteSecret(ctx *context.APIContext) {
6969
// swagger:operation DELETE /user/actions/secrets/{secretname} user deleteUserSecret
7070
// ---

routers/web/repo/setting/secrets.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,10 @@ import (
1616

1717
const (
1818
// TODO: Separate secrets from runners when layout is ready
19-
tplRepoSecrets base.TplName = "repo/settings/actions"
20-
tplOrgSecrets base.TplName = "org/settings/actions"
21-
tplUserSecrets base.TplName = "user/settings/actions"
19+
tplRepoSecrets base.TplName = "repo/settings/actions"
20+
tplOrgSecrets base.TplName = "org/settings/actions"
21+
tplUserSecrets base.TplName = "user/settings/actions"
22+
tplAdminSecrets base.TplName = "admin/actions"
2223
)
2324

2425
type secretsCtx struct {
@@ -27,6 +28,7 @@ type secretsCtx struct {
2728
IsRepo bool
2829
IsOrg bool
2930
IsUser bool
31+
IsGlobal bool
3032
SecretsTemplate base.TplName
3133
RedirectLink string
3234
}
@@ -67,6 +69,16 @@ func getSecretsCtx(ctx *context.Context) (*secretsCtx, error) {
6769
}, nil
6870
}
6971

72+
if ctx.Data["PageIsAdmin"] == true {
73+
return &secretsCtx{
74+
OwnerID: 0,
75+
RepoID: 0,
76+
IsGlobal: true,
77+
SecretsTemplate: tplAdminSecrets,
78+
RedirectLink: setting.AppSubURL + "/admin/actions/secrets",
79+
}, nil
80+
}
81+
7082
return nil, errors.New("unable to set Secrets context")
7183
}
7284

routers/web/web.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,7 @@ func registerRoutes(m *web.Route) {
757757
m.Group("/actions", func() {
758758
m.Get("", admin.RedirectToDefaultSetting)
759759
addSettingsRunnersRoutes()
760+
addSettingsSecretsRoutes()
760761
})
761762
}, adminReq, ctxDataSet("EnableOAuth2", setting.OAuth2.Enable, "EnablePackages", setting.Packages.Enabled))
762763
// ***** END: Admin *****

templates/admin/actions.tmpl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,8 @@
33
{{if eq .PageType "runners"}}
44
{{template "shared/actions/runner_list" .}}
55
{{end}}
6+
{{if eq .PageType "secrets"}}
7+
{{template "shared/secrets/add_list" .}}
8+
{{end}}
69
</div>
710
{{template "admin/layout_footer" .}}

templates/admin/navbar.tmpl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,15 @@
6060
{{end}}
6161
{{end}}
6262
{{if .EnableActions}}
63-
<details class="item toggleable-item" {{if .PageIsSharedSettingsRunners}}open{{end}}>
63+
<details class="item toggleable-item" {{if or .PageIsSharedSettingsRunners .PageIsSharedSettingsSecrets}}open{{end}}>
6464
<summary>{{ctx.Locale.Tr "actions.actions"}}</summary>
6565
<div class="menu">
6666
<a class="{{if .PageIsSharedSettingsRunners}}active {{end}}item" href="{{AppSubUrl}}/admin/actions/runners">
6767
{{ctx.Locale.Tr "actions.runners"}}
6868
</a>
69+
<a class="{{if .PageIsSharedSettingsSecrets}}active {{end}}item" href="{{AppSubUrl}}/admin/actions/secrets">
70+
{{ctx.Locale.Tr "secrets.secrets"}}
71+
</a>
6972
</div>
7073
</details>
7174
{{end}}

0 commit comments

Comments
 (0)