Skip to content

Commit afce5d2

Browse files
committed
Merge remote-tracking branch 'giteaofficial/main'
* giteaofficial/main: [skip ci] Updated translations via Crowdin Optimize Layout Styles of Filelist (go-gitea#33920) [skip ci] Updated translations via Crowdin update go version for devcontainers (go-gitea#33923) Added Description Field for Secrets and Variables (go-gitea#33526) Try to figure out attribute checker problem (go-gitea#33901) Defer captcha script loading (go-gitea#33919) Fix file tree issues (go-gitea#33916) Remove unused or abused styles (go-gitea#33918)
2 parents a1c01b2 + 39fc2e7 commit afce5d2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+413
-160
lines changed

.devcontainer/devcontainer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "Gitea DevContainer",
3-
"image": "mcr.microsoft.com/devcontainers/go:1.23-bookworm",
3+
"image": "mcr.microsoft.com/devcontainers/go:1.24-bookworm",
44
"features": {
55
// installs nodejs into container
66
"ghcr.io/devcontainers/features/node:1": {

models/actions/variable.go

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@ package actions
66
import (
77
"context"
88
"strings"
9+
"unicode/utf8"
910

1011
"code.gitea.io/gitea/models/db"
1112
"code.gitea.io/gitea/modules/log"
1213
"code.gitea.io/gitea/modules/timeutil"
14+
"code.gitea.io/gitea/modules/util"
1315

1416
"xorm.io/builder"
1517
)
@@ -32,26 +34,39 @@ type ActionVariable struct {
3234
RepoID int64 `xorm:"INDEX UNIQUE(owner_repo_name)"`
3335
Name string `xorm:"UNIQUE(owner_repo_name) NOT NULL"`
3436
Data string `xorm:"LONGTEXT NOT NULL"`
37+
Description string `xorm:"TEXT"`
3538
CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"`
3639
UpdatedUnix timeutil.TimeStamp `xorm:"updated"`
3740
}
3841

42+
const (
43+
VariableDataMaxLength = 65536
44+
VariableDescriptionMaxLength = 4096
45+
)
46+
3947
func init() {
4048
db.RegisterModel(new(ActionVariable))
4149
}
4250

43-
func InsertVariable(ctx context.Context, ownerID, repoID int64, name, data string) (*ActionVariable, error) {
51+
func InsertVariable(ctx context.Context, ownerID, repoID int64, name, data, description string) (*ActionVariable, error) {
4452
if ownerID != 0 && repoID != 0 {
4553
// It's trying to create a variable that belongs to a repository, but OwnerID has been set accidentally.
4654
// Remove OwnerID to avoid confusion; it's not worth returning an error here.
4755
ownerID = 0
4856
}
4957

58+
if utf8.RuneCountInString(data) > VariableDataMaxLength {
59+
return nil, util.NewInvalidArgumentErrorf("data too long")
60+
}
61+
62+
description = util.TruncateRunes(description, VariableDescriptionMaxLength)
63+
5064
variable := &ActionVariable{
51-
OwnerID: ownerID,
52-
RepoID: repoID,
53-
Name: strings.ToUpper(name),
54-
Data: data,
65+
OwnerID: ownerID,
66+
RepoID: repoID,
67+
Name: strings.ToUpper(name),
68+
Data: data,
69+
Description: description,
5570
}
5671
return variable, db.Insert(ctx, variable)
5772
}
@@ -96,6 +111,12 @@ func FindVariables(ctx context.Context, opts FindVariablesOpts) ([]*ActionVariab
96111
}
97112

98113
func UpdateVariableCols(ctx context.Context, variable *ActionVariable, cols ...string) (bool, error) {
114+
if utf8.RuneCountInString(variable.Data) > VariableDataMaxLength {
115+
return false, util.NewInvalidArgumentErrorf("data too long")
116+
}
117+
118+
variable.Description = util.TruncateRunes(variable.Description, VariableDescriptionMaxLength)
119+
99120
variable.Name = strings.ToUpper(variable.Name)
100121
count, err := db.GetEngine(ctx).
101122
ID(variable.ID).

models/migrations/migrations.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,7 @@ func prepareMigrationTasks() []*migration {
376376
newMigration(313, "Move PinOrder from issue table to a new table issue_pin", v1_24.MovePinOrderToTableIssuePin),
377377
newMigration(314, "Update OwnerID as zero for repository level action tables", v1_24.UpdateOwnerIDOfRepoLevelActionsTables),
378378
newMigration(315, "Add Ephemeral to ActionRunner", v1_24.AddEphemeralToActionRunner),
379+
newMigration(316, "Add description for secrets and variables", v1_24.AddDescriptionForSecretsAndVariables),
379380
}
380381
return preparedMigrations
381382
}

models/migrations/v1_24/v316.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2025 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package v1_24 //nolint
5+
6+
import (
7+
"xorm.io/xorm"
8+
)
9+
10+
func AddDescriptionForSecretsAndVariables(x *xorm.Engine) error {
11+
type Secret struct {
12+
Description string `xorm:"TEXT"`
13+
}
14+
15+
type ActionVariable struct {
16+
Description string `xorm:"TEXT"`
17+
}
18+
19+
return x.Sync(new(Secret), new(ActionVariable))
20+
}

models/secret/secret.go

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,15 @@ type Secret struct {
4040
RepoID int64 `xorm:"INDEX UNIQUE(owner_repo_name) NOT NULL DEFAULT 0"`
4141
Name string `xorm:"UNIQUE(owner_repo_name) NOT NULL"`
4242
Data string `xorm:"LONGTEXT"` // encrypted data
43+
Description string `xorm:"TEXT"`
4344
CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"`
4445
}
4546

47+
const (
48+
SecretDataMaxLength = 65536
49+
SecretDescriptionMaxLength = 4096
50+
)
51+
4652
// ErrSecretNotFound represents a "secret not found" error.
4753
type ErrSecretNotFound struct {
4854
Name string
@@ -57,7 +63,7 @@ func (err ErrSecretNotFound) Unwrap() error {
5763
}
5864

5965
// InsertEncryptedSecret Creates, encrypts, and validates a new secret with yet unencrypted data and insert into database
60-
func InsertEncryptedSecret(ctx context.Context, ownerID, repoID int64, name, data string) (*Secret, error) {
66+
func InsertEncryptedSecret(ctx context.Context, ownerID, repoID int64, name, data, description string) (*Secret, error) {
6167
if ownerID != 0 && repoID != 0 {
6268
// It's trying to create a secret that belongs to a repository, but OwnerID has been set accidentally.
6369
// Remove OwnerID to avoid confusion; it's not worth returning an error here.
@@ -67,15 +73,23 @@ func InsertEncryptedSecret(ctx context.Context, ownerID, repoID int64, name, dat
6773
return nil, fmt.Errorf("%w: ownerID and repoID cannot be both zero, global secrets are not supported", util.ErrInvalidArgument)
6874
}
6975

76+
if len(data) > SecretDataMaxLength {
77+
return nil, util.NewInvalidArgumentErrorf("data too long")
78+
}
79+
80+
description = util.TruncateRunes(description, SecretDescriptionMaxLength)
81+
7082
encrypted, err := secret_module.EncryptSecret(setting.SecretKey, data)
7183
if err != nil {
7284
return nil, err
7385
}
86+
7487
secret := &Secret{
75-
OwnerID: ownerID,
76-
RepoID: repoID,
77-
Name: strings.ToUpper(name),
78-
Data: encrypted,
88+
OwnerID: ownerID,
89+
RepoID: repoID,
90+
Name: strings.ToUpper(name),
91+
Data: encrypted,
92+
Description: description,
7993
}
8094
return secret, db.Insert(ctx, secret)
8195
}
@@ -114,16 +128,23 @@ func (opts FindSecretsOptions) ToConds() builder.Cond {
114128
}
115129

116130
// UpdateSecret changes org or user reop secret.
117-
func UpdateSecret(ctx context.Context, secretID int64, data string) error {
131+
func UpdateSecret(ctx context.Context, secretID int64, data, description string) error {
132+
if len(data) > SecretDataMaxLength {
133+
return util.NewInvalidArgumentErrorf("data too long")
134+
}
135+
136+
description = util.TruncateRunes(description, SecretDescriptionMaxLength)
137+
118138
encrypted, err := secret_module.EncryptSecret(setting.SecretKey, data)
119139
if err != nil {
120140
return err
121141
}
122142

123143
s := &Secret{
124-
Data: encrypted,
144+
Data: encrypted,
145+
Description: description,
125146
}
126-
affected, err := db.GetEngine(ctx).ID(secretID).Cols("data").Update(s)
147+
affected, err := db.GetEngine(ctx).ID(secretID).Cols("data", "description").Update(s)
127148
if affected != 1 {
128149
return ErrSecretNotFound{}
129150
}

modules/git/command.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ type Command struct {
4646
args []string
4747
globalArgsLength int
4848
brokenArgs []string
49+
cmd *exec.Cmd // for debug purpose only
4950
}
5051

5152
func logArgSanitize(arg string) string {
@@ -314,6 +315,7 @@ func (c *Command) run(ctx context.Context, skip int, opts *RunOpts) error {
314315
startTime := time.Now()
315316

316317
cmd := exec.CommandContext(ctx, c.prog, c.args...)
318+
c.cmd = cmd // for debug purpose only
317319
if opts.Env == nil {
318320
cmd.Env = os.Environ()
319321
} else {

modules/git/repo_attribute.go

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import (
99
"fmt"
1010
"io"
1111
"os"
12+
"path/filepath"
13+
"time"
1214

1315
"code.gitea.io/gitea/modules/log"
1416
)
@@ -102,7 +104,7 @@ type CheckAttributeReader struct {
102104

103105
stdinReader io.ReadCloser
104106
stdinWriter *os.File
105-
stdOut attributeWriter
107+
stdOut *nulSeparatedAttributeWriter
106108
cmd *Command
107109
env []string
108110
ctx context.Context
@@ -152,7 +154,6 @@ func (c *CheckAttributeReader) Init(ctx context.Context) error {
152154
return nil
153155
}
154156

155-
// Run run cmd
156157
func (c *CheckAttributeReader) Run() error {
157158
defer func() {
158159
_ = c.stdinReader.Close()
@@ -176,7 +177,7 @@ func (c *CheckAttributeReader) Run() error {
176177
func (c *CheckAttributeReader) CheckPath(path string) (rs map[string]string, err error) {
177178
defer func() {
178179
if err != nil && err != c.ctx.Err() {
179-
log.Error("Unexpected error when checking path %s in %s. Error: %v", path, c.Repo.Path, err)
180+
log.Error("Unexpected error when checking path %s in %s, error: %v", path, filepath.Base(c.Repo.Path), err)
180181
}
181182
}()
182183

@@ -191,9 +192,31 @@ func (c *CheckAttributeReader) CheckPath(path string) (rs map[string]string, err
191192
return nil, err
192193
}
193194

195+
reportTimeout := func() error {
196+
stdOutClosed := false
197+
select {
198+
case <-c.stdOut.closed:
199+
stdOutClosed = true
200+
default:
201+
}
202+
debugMsg := fmt.Sprintf("check path %q in repo %q", path, filepath.Base(c.Repo.Path))
203+
debugMsg += fmt.Sprintf(", stdOut: tmp=%q, pos=%d, closed=%v", string(c.stdOut.tmp), c.stdOut.pos, stdOutClosed)
204+
if c.cmd.cmd != nil {
205+
debugMsg += fmt.Sprintf(", process state: %q", c.cmd.cmd.ProcessState.String())
206+
}
207+
_ = c.Close()
208+
return fmt.Errorf("CheckPath timeout: %s", debugMsg)
209+
}
210+
194211
rs = make(map[string]string)
195212
for range c.Attributes {
196213
select {
214+
case <-time.After(5 * time.Second):
215+
// There is a strange "hang" problem in gitdiff.GetDiff -> CheckPath
216+
// So add a timeout here to mitigate the problem, and output more logs for debug purpose
217+
// In real world, if CheckPath runs long than seconds, it blocks the end user's operation,
218+
// and at the moment the CheckPath result is not so important, so we can just ignore it.
219+
return nil, reportTimeout()
197220
case attr, ok := <-c.stdOut.ReadAttribute():
198221
if !ok {
199222
return nil, c.ctx.Err()
@@ -206,18 +229,12 @@ func (c *CheckAttributeReader) CheckPath(path string) (rs map[string]string, err
206229
return rs, nil
207230
}
208231

209-
// Close close pip after use
210232
func (c *CheckAttributeReader) Close() error {
211233
c.cancel()
212234
err := c.stdinWriter.Close()
213235
return err
214236
}
215237

216-
type attributeWriter interface {
217-
io.WriteCloser
218-
ReadAttribute() <-chan attributeTriple
219-
}
220-
221238
type attributeTriple struct {
222239
Filename string
223240
Attribute string
@@ -281,7 +298,7 @@ func (wr *nulSeparatedAttributeWriter) Close() error {
281298
return nil
282299
}
283300

284-
// Create a check attribute reader for the current repository and provided commit ID
301+
// CheckAttributeReader creates a check attribute reader for the current repository and provided commit ID
285302
func (repo *Repository) CheckAttributeReader(commitID string) (*CheckAttributeReader, context.CancelFunc) {
286303
indexFilename, worktree, deleteTemporaryFile, err := repo.ReadTreeToTemporaryIndex(commitID)
287304
if err != nil {
@@ -303,21 +320,21 @@ func (repo *Repository) CheckAttributeReader(commitID string) (*CheckAttributeRe
303320
}
304321
ctx, cancel := context.WithCancel(repo.Ctx)
305322
if err := checker.Init(ctx); err != nil {
306-
log.Error("Unable to open checker for %s. Error: %v", commitID, err)
323+
log.Error("Unable to open attribute checker for commit %s, error: %v", commitID, err)
307324
} else {
308325
go func() {
309326
err := checker.Run()
310-
if err != nil && err != ctx.Err() {
311-
log.Error("Unable to open checker for %s. Error: %v", commitID, err)
327+
if err != nil && !IsErrCanceledOrKilled(err) {
328+
log.Error("Attribute checker for commit %s exits with error: %v", commitID, err)
312329
}
313330
cancel()
314331
}()
315332
}
316-
deferable := func() {
333+
deferrable := func() {
317334
_ = checker.Close()
318335
cancel()
319336
deleteTemporaryFile()
320337
}
321338

322-
return checker, deferable
339+
return checker, deferrable
323340
}

0 commit comments

Comments
 (0)