Skip to content

Commit 48e07bb

Browse files
committed
fix(actions): address review comments on deployment environments
- MatchesBranch: return false on invalid glob pattern instead of skipping - secret.go: log real DB errors when fetching environment, silence only ErrNotExist - variable.go: propagate real DB errors instead of nolint:nilerr suppression - UpdateEnvironment: return 409 when renaming to an already-existing name - web router: wrap environment name with url.PathEscape in all redirects
1 parent f10c32e commit 48e07bb

6 files changed

Lines changed: 32 additions & 15 deletions

File tree

models/actions/environment.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2024 The Gitea Authors. All rights reserved.
1+
// Copyright 2026 The Gitea Authors. All rights reserved.
22
// SPDX-License-Identifier: MIT
33

44
package actions
@@ -155,7 +155,7 @@ func (env *ActionEnvironment) MatchesBranch(ref string) bool {
155155
}
156156
g, err := glob.Compile(pattern)
157157
if err != nil {
158-
continue
158+
return false
159159
}
160160
ok := g.Match(branch)
161161
if ok {

models/actions/variable.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ package actions
55

66
import (
77
"context"
8+
"errors"
9+
"fmt"
810
"strings"
911
"unicode/utf8"
1012

@@ -187,8 +189,10 @@ func GetVariablesOfJob(ctx context.Context, job *ActionRunJob) (map[string]strin
187189

188190
env, err := GetEnvironmentByRepoAndName(ctx, job.RepoID, job.EnvironmentName)
189191
if err != nil {
190-
// environment may not exist (was deleted after job creation); fall back to base vars
191-
return variables, nil //nolint:nilerr // environment may have been deleted after job creation; fall back to base vars
192+
if !errors.Is(err, util.ErrNotExist) {
193+
return nil, fmt.Errorf("get environment %q for job %d: %w", job.EnvironmentName, job.ID, err)
194+
}
195+
return variables, nil
192196
}
193197
if !env.MatchesBranch(job.Run.Ref) {
194198
return variables, nil

models/secret/secret.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package secret
55

66
import (
77
"context"
8+
"errors"
89
"fmt"
910
"strings"
1011

@@ -189,7 +190,11 @@ func GetSecretsOfTask(ctx context.Context, task *actions_model.ActionTask) (map[
189190
// Environment-scoped secrets override repo/org secrets when the job targets a deployment environment.
190191
if task.Job.EnvironmentName != "" {
191192
env, err := actions_model.GetEnvironmentByRepoAndName(ctx, task.Job.Run.RepoID, task.Job.EnvironmentName)
192-
if err == nil && env.MatchesBranch(task.Job.Run.Ref) {
193+
if err != nil {
194+
if !errors.Is(err, util.ErrNotExist) {
195+
log.Error("get environment %q for task %d: %v", task.Job.EnvironmentName, task.ID, err)
196+
}
197+
} else if env.MatchesBranch(task.Job.Run.Ref) {
193198
envSecrets, err := db.Find[actions_model.ActionEnvironmentSecret](ctx, actions_model.FindEnvSecretsOptions{
194199
RepoID: task.Job.Run.RepoID,
195200
EnvironmentID: env.ID,

routers/api/v1/repo/environment.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,11 @@ func UpdateEnvironment(ctx *context.APIContext) {
179179
opt := web.GetForm(ctx).(*api.UpdateEnvironmentOption)
180180
updated, err := actions_service.UpdateEnvironment(ctx, ctx.Repo.Repository.ID, env.ID, opt.Name, opt.ProtectedBranches)
181181
if err != nil {
182-
ctx.APIErrorInternal(err)
182+
if errors.Is(err, util.ErrAlreadyExist) {
183+
ctx.APIError(http.StatusConflict, err.Error())
184+
} else {
185+
ctx.APIErrorInternal(err)
186+
}
183187
return
184188
}
185189
ctx.JSON(http.StatusOK, toAPIEnvironment(updated))

routers/web/repo/setting/environment.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package setting
66
import (
77
"errors"
88
"net/http"
9+
"net/url"
910
"strings"
1011

1112
actions_model "gitea.dev/models/actions"
@@ -64,7 +65,7 @@ func EnvironmentCreate(ctx *context.Context) {
6465
}
6566

6667
ctx.Flash.Success(ctx.Tr("environments.creation.success", name))
67-
ctx.Redirect(ctx.Repo.RepoLink + "/settings/environments/" + name)
68+
ctx.Redirect(ctx.Repo.RepoLink + "/settings/environments/" + url.PathEscape(name))
6869
}
6970

7071
// EnvironmentEdit renders the environment edit page (secrets + variables)
@@ -101,7 +102,7 @@ func EnvironmentEdit(ctx *context.Context) {
101102
ctx.Data["Variables"] = variables
102103
ctx.Data["DataMaxLength"] = secret_model.SecretDataMaxLength
103104
ctx.Data["DescriptionMaxLength"] = secret_model.SecretDescriptionMaxLength
104-
ctx.Data["Link"] = ctx.Repo.RepoLink + "/settings/environments/" + envName
105+
ctx.Data["Link"] = ctx.Repo.RepoLink + "/settings/environments/" + url.PathEscape(envName)
105106
ctx.HTML(http.StatusOK, tplEnvironmentEdit)
106107
}
107108

@@ -121,7 +122,7 @@ func EnvironmentUpdate(ctx *context.Context) {
121122
} else {
122123
ctx.Flash.Success(ctx.Tr("environments.update.success"))
123124
}
124-
ctx.Redirect(ctx.Repo.RepoLink + "/settings/environments/" + envName)
125+
ctx.Redirect(ctx.Repo.RepoLink + "/settings/environments/" + url.PathEscape(envName))
125126
}
126127

127128
// EnvironmentDelete handles POST to delete an environment
@@ -151,7 +152,7 @@ func EnvironmentSecretPost(ctx *context.Context) {
151152
return
152153
}
153154

154-
redirectURL := ctx.Repo.RepoLink + "/settings/environments/" + envName
155+
redirectURL := ctx.Repo.RepoLink + "/settings/environments/" + url.PathEscape(envName)
155156
form := web.GetForm(ctx).(*forms.AddSecretForm)
156157

157158
if err := secret_service.ValidateName(form.Name); err != nil {
@@ -195,7 +196,7 @@ func EnvironmentSecretDelete(ctx *context.Context) {
195196
}
196197

197198
ctx.Flash.Success(ctx.Tr("secrets.deletion.success"))
198-
ctx.JSONRedirect(ctx.Repo.RepoLink + "/settings/environments/" + envName)
199+
ctx.JSONRedirect(ctx.Repo.RepoLink + "/settings/environments/" + url.PathEscape(envName))
199200
}
200201

201202
// EnvironmentVariableCreate handles POST for creating an environment variable
@@ -207,7 +208,7 @@ func EnvironmentVariableCreate(ctx *context.Context) {
207208
return
208209
}
209210

210-
redirectURL := ctx.Repo.RepoLink + "/settings/environments/" + envName
211+
redirectURL := ctx.Repo.RepoLink + "/settings/environments/" + url.PathEscape(envName)
211212
form := web.GetForm(ctx).(*forms.EditVariableForm)
212213

213214
_, err = actions_service.CreateEnvVariable(ctx, ctx.Repo.Repository.ID, env.ID, form.Name, form.Data, form.Description)
@@ -228,7 +229,7 @@ func EnvironmentVariableUpdate(ctx *context.Context) {
228229
return
229230
}
230231

231-
redirectURL := ctx.Repo.RepoLink + "/settings/environments/" + envName
232+
redirectURL := ctx.Repo.RepoLink + "/settings/environments/" + url.PathEscape(envName)
232233
variableID := ctx.PathParamInt64("variable_id")
233234
form := web.GetForm(ctx).(*forms.EditVariableForm)
234235

@@ -257,5 +258,5 @@ func EnvironmentVariableDelete(ctx *context.Context) {
257258
}
258259

259260
ctx.Flash.Success(ctx.Tr("actions.variables.deletion.success"))
260-
ctx.JSONRedirect(ctx.Repo.RepoLink + "/settings/environments/" + envName)
261+
ctx.JSONRedirect(ctx.Repo.RepoLink + "/settings/environments/" + url.PathEscape(envName))
261262
}

services/actions/environment.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ func UpdateEnvironment(ctx context.Context, repoID, envID int64, name, protected
3535
if env.RepoID != repoID {
3636
return nil, util.ErrNotExist
3737
}
38-
if name != "" {
38+
if name != "" && name != env.Name {
39+
if existing, err := actions_model.GetEnvironmentByRepoAndName(ctx, repoID, name); err == nil && existing != nil {
40+
return nil, actions_model.ErrEnvironmentAlreadyExists{Name: name}
41+
}
3942
env.Name = name
4043
}
4144
env.ProtectedBranches = protectedBranches

0 commit comments

Comments
 (0)