Skip to content

Commit 4b7f007

Browse files
committed
Merge branch 'main' into zzc/dev/merge-pull-manually-quick
2 parents 0b3ef59 + 6590551 commit 4b7f007

File tree

37 files changed

+826
-43
lines changed

37 files changed

+826
-43
lines changed

custom/conf/app.example.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,6 +1036,9 @@ ROUTER = console
10361036
;;
10371037
;; Add co-authored-by and co-committed-by trailers if committer does not match author
10381038
;ADD_CO_COMMITTER_TRAILERS = true
1039+
;;
1040+
;; In addition to testing patches using the three-way merge method, re-test conflicting patches with git apply
1041+
;TEST_CONFLICTING_PATCHES_WITH_GIT_APPLY = false
10391042

10401043
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
10411044
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

docs/content/doc/advanced/config-cheat-sheet.en-us.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ In addition there is _`StaticRootPath`_ which can be set as a built-in at build
134134
- `DEFAULT_MERGE_MESSAGE_OFFICIAL_APPROVERS_ONLY`: **true**: In default merge messages only include approvers who are officially allowed to review.
135135
- `POPULATE_SQUASH_COMMENT_WITH_COMMIT_MESSAGES`: **false**: In default squash-merge messages include the commit message of all commits comprising the pull request.
136136
- `ADD_CO_COMMITTER_TRAILERS`: **true**: Add co-authored-by and co-committed-by trailers to merge commit messages if committer does not match author.
137+
- `TEST_CONFLICTING_PATCHES_WITH_GIT_APPLY`: **false**: PR patches are tested using a three-way merge method to discover if there are conflicts. If this setting is set to **true**, conflicting patches will be retested using `git apply` - This was the previous behaviour in 1.18 (and earlier) but is somewhat inefficient. Please report if you find that this setting is required.
137138

138139
### Repository - Issue (`repository.issue`)
139140

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
---
2+
date: "2022-12-19T21:26:00+08:00"
3+
title: "Encrypted secrets"
4+
slug: "secrets/overview"
5+
draft: false
6+
toc: false
7+
menu:
8+
sidebar:
9+
parent: "secrets"
10+
name: "Overview"
11+
weight: 1
12+
identifier: "overview"
13+
---
14+
15+
# Encrypted secrets
16+
17+
Encrypted secrets allow you to store sensitive information in your organization or repository.
18+
Secrets are available on Gitea 1.19+.
19+
20+
# Naming your secrets
21+
22+
The following rules apply to secret names:
23+
24+
Secret names can only contain alphanumeric characters (`[a-z]`, `[A-Z]`, `[0-9]`) or underscores (`_`). Spaces are not allowed.
25+
26+
Secret names must not start with the `GITHUB_` and `GITEA_` prefix.
27+
28+
Secret names must not start with a number.
29+
30+
Secret names are not case-sensitive.
31+
32+
Secret names must be unique at the level they are created at.
33+
34+
For example, a secret created at the repository level must have a unique name in that repository, and a secret created at the organization level must have a unique name at that level.
35+
36+
If a secret with the same name exists at multiple levels, the secret at the lowest level takes precedence. For example, if an organization-level secret has the same name as a repository-level secret, then the repository-level secret takes precedence.

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ require (
8888
github.com/unrolled/render v1.5.0
8989
github.com/urfave/cli v1.22.10
9090
github.com/xanzy/go-gitlab v0.73.1
91+
github.com/xeipuuv/gojsonschema v1.2.0
9192
github.com/yohcop/openid-go v1.0.0
9293
github.com/yuin/goldmark v1.5.2
9394
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20220924101305-151362477c87
@@ -266,6 +267,8 @@ require (
266267
github.com/valyala/fastjson v1.6.3 // indirect
267268
github.com/x448/float16 v0.8.4 // indirect
268269
github.com/xanzy/ssh-agent v0.3.2 // indirect
270+
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
271+
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
269272
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
270273
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect
271274
go.etcd.io/bbolt v1.3.6 // indirect

go.sum

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1468,6 +1468,12 @@ github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+
14681468
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
14691469
github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
14701470
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
1471+
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
1472+
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
1473+
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
1474+
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
1475+
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
1476+
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
14711477
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
14721478
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
14731479
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=

models/migrations/migrations.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,8 @@ var migrations = []Migration{
443443
// v235 -> v236
444444
NewMigration("Add index for access_token", v1_19.AddIndexForAccessToken),
445445
// v236 -> v237
446+
NewMigration("Create secrets table", v1_19.CreateSecretsTable),
447+
// v237 -> v238
446448
NewMigration("Add manually_merge_pull_confirmed to pull_request table", v1_19.AddManuallyMergePullConfirmedToPullRequest),
447449
}
448450

models/migrations/v1_19/v236.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,20 @@
44
package v1_19 //nolint
55

66
import (
7+
"code.gitea.io/gitea/modules/timeutil"
8+
79
"xorm.io/xorm"
810
)
911

10-
func AddManuallyMergePullConfirmedToPullRequest(x *xorm.Engine) error {
11-
type PullRequest struct {
12-
ID int64 `xorm:"pk autoincr"`
13-
14-
ManuallyMergePullConfirmed bool `xorm:"NOT NULL DEFAULT false"`
12+
func CreateSecretsTable(x *xorm.Engine) error {
13+
type Secret struct {
14+
ID int64
15+
OwnerID int64 `xorm:"INDEX UNIQUE(owner_repo_name) NOT NULL"`
16+
RepoID int64 `xorm:"INDEX UNIQUE(owner_repo_name) NOT NULL DEFAULT 0"`
17+
Name string `xorm:"UNIQUE(owner_repo_name) NOT NULL"`
18+
Data string `xorm:"LONGTEXT"`
19+
CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"`
1520
}
1621

17-
return x.Sync(new(PullRequest))
22+
return x.Sync(new(Secret))
1823
}

models/migrations/v1_19/v237.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright 2022 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package v1_19 //nolint
5+
6+
import (
7+
"xorm.io/xorm"
8+
)
9+
10+
func AddManuallyMergePullConfirmedToPullRequest(x *xorm.Engine) error {
11+
type PullRequest struct {
12+
ID int64 `xorm:"pk autoincr"`
13+
14+
ManuallyMergePullConfirmed bool `xorm:"NOT NULL DEFAULT false"`
15+
}
16+
17+
return x.Sync(new(PullRequest))
18+
}

models/organization/org.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"code.gitea.io/gitea/models/db"
1313
"code.gitea.io/gitea/models/perm"
1414
repo_model "code.gitea.io/gitea/models/repo"
15+
secret_model "code.gitea.io/gitea/models/secret"
1516
"code.gitea.io/gitea/models/unit"
1617
user_model "code.gitea.io/gitea/models/user"
1718
"code.gitea.io/gitea/modules/log"
@@ -370,6 +371,7 @@ func DeleteOrganization(ctx context.Context, org *Organization) error {
370371
&TeamUser{OrgID: org.ID},
371372
&TeamUnit{OrgID: org.ID},
372373
&TeamInvite{OrgID: org.ID},
374+
&secret_model.Secret{OwnerID: org.ID},
373375
); err != nil {
374376
return fmt.Errorf("DeleteBeans: %w", err)
375377
}

models/repo.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
access_model "code.gitea.io/gitea/models/perm/access"
2222
project_model "code.gitea.io/gitea/models/project"
2323
repo_model "code.gitea.io/gitea/models/repo"
24+
secret_model "code.gitea.io/gitea/models/secret"
2425
system_model "code.gitea.io/gitea/models/system"
2526
"code.gitea.io/gitea/models/unit"
2627
user_model "code.gitea.io/gitea/models/user"
@@ -150,6 +151,7 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error {
150151
&admin_model.Task{RepoID: repoID},
151152
&repo_model.Watch{RepoID: repoID},
152153
&webhook.Webhook{RepoID: repoID},
154+
&secret_model.Secret{RepoID: repoID},
153155
); err != nil {
154156
return fmt.Errorf("deleteBeans: %w", err)
155157
}

models/secret/secret.go

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// Copyright 2022 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package secret
5+
6+
import (
7+
"context"
8+
"fmt"
9+
"regexp"
10+
"strings"
11+
12+
"code.gitea.io/gitea/models/db"
13+
secret_module "code.gitea.io/gitea/modules/secret"
14+
"code.gitea.io/gitea/modules/setting"
15+
"code.gitea.io/gitea/modules/timeutil"
16+
"code.gitea.io/gitea/modules/util"
17+
18+
"xorm.io/builder"
19+
)
20+
21+
type ErrSecretInvalidValue struct {
22+
Name *string
23+
Data *string
24+
}
25+
26+
func (err ErrSecretInvalidValue) Error() string {
27+
if err.Name != nil {
28+
return fmt.Sprintf("secret name %q is invalid", *err.Name)
29+
}
30+
if err.Data != nil {
31+
return fmt.Sprintf("secret data %q is invalid", *err.Data)
32+
}
33+
return util.ErrInvalidArgument.Error()
34+
}
35+
36+
func (err ErrSecretInvalidValue) Unwrap() error {
37+
return util.ErrInvalidArgument
38+
}
39+
40+
// Secret represents a secret
41+
type Secret struct {
42+
ID int64
43+
OwnerID int64 `xorm:"INDEX UNIQUE(owner_repo_name) NOT NULL"`
44+
RepoID int64 `xorm:"INDEX UNIQUE(owner_repo_name) NOT NULL DEFAULT 0"`
45+
Name string `xorm:"UNIQUE(owner_repo_name) NOT NULL"`
46+
Data string `xorm:"LONGTEXT"` // encrypted data
47+
CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"`
48+
}
49+
50+
// newSecret Creates a new already encrypted secret
51+
func newSecret(ownerID, repoID int64, name, data string) *Secret {
52+
return &Secret{
53+
OwnerID: ownerID,
54+
RepoID: repoID,
55+
Name: strings.ToUpper(name),
56+
Data: data,
57+
}
58+
}
59+
60+
// InsertEncryptedSecret Creates, encrypts, and validates a new secret with yet unencrypted data and insert into database
61+
func InsertEncryptedSecret(ctx context.Context, ownerID, repoID int64, name, data string) (*Secret, error) {
62+
encrypted, err := secret_module.EncryptSecret(setting.SecretKey, strings.TrimSpace(data))
63+
if err != nil {
64+
return nil, err
65+
}
66+
secret := newSecret(ownerID, repoID, name, encrypted)
67+
if err := secret.Validate(); err != nil {
68+
return secret, err
69+
}
70+
return secret, db.Insert(ctx, secret)
71+
}
72+
73+
func init() {
74+
db.RegisterModel(new(Secret))
75+
}
76+
77+
var (
78+
secretNameReg = regexp.MustCompile("^[A-Z_][A-Z0-9_]*$")
79+
forbiddenSecretPrefixReg = regexp.MustCompile("^GIT(EA|HUB)_")
80+
)
81+
82+
// Validate validates the required fields and formats.
83+
func (s *Secret) Validate() error {
84+
switch {
85+
case len(s.Name) == 0 || len(s.Name) > 50:
86+
return ErrSecretInvalidValue{Name: &s.Name}
87+
case len(s.Data) == 0:
88+
return ErrSecretInvalidValue{Data: &s.Data}
89+
case !secretNameReg.MatchString(s.Name) ||
90+
forbiddenSecretPrefixReg.MatchString(s.Name):
91+
return ErrSecretInvalidValue{Name: &s.Name}
92+
default:
93+
return nil
94+
}
95+
}
96+
97+
type FindSecretsOptions struct {
98+
db.ListOptions
99+
OwnerID int64
100+
RepoID int64
101+
}
102+
103+
func (opts *FindSecretsOptions) toConds() builder.Cond {
104+
cond := builder.NewCond()
105+
if opts.OwnerID > 0 {
106+
cond = cond.And(builder.Eq{"owner_id": opts.OwnerID})
107+
}
108+
if opts.RepoID > 0 {
109+
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
110+
}
111+
112+
return cond
113+
}
114+
115+
func FindSecrets(ctx context.Context, opts FindSecretsOptions) ([]*Secret, error) {
116+
var secrets []*Secret
117+
sess := db.GetEngine(ctx)
118+
if opts.PageSize != 0 {
119+
sess = db.SetSessionPagination(sess, &opts.ListOptions)
120+
}
121+
return secrets, sess.
122+
Where(opts.toConds()).
123+
Find(&secrets)
124+
}

modules/charset/escape.go

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
package charset
99

1010
import (
11+
"bufio"
1112
"io"
1213
"strings"
1314

@@ -31,7 +32,7 @@ func EscapeControlHTML(text string, locale translation.Locale, allowed ...rune)
3132
return streamer.escaped, sb.String()
3233
}
3334

34-
// EscapeControlReaders escapes the unicode control sequences in a provider reader and writer in a locale and returns the findings as an EscapeStatus and the escaped []byte
35+
// EscapeControlReaders escapes the unicode control sequences in a provided reader of HTML content and writer in a locale and returns the findings as an EscapeStatus and the escaped []byte
3536
func EscapeControlReader(reader io.Reader, writer io.Writer, locale translation.Locale, allowed ...rune) (escaped *EscapeStatus, err error) {
3637
outputStream := &HTMLStreamerWriter{Writer: writer}
3738
streamer := NewEscapeStreamer(locale, outputStream, allowed...).(*escapeStreamer)
@@ -43,6 +44,35 @@ func EscapeControlReader(reader io.Reader, writer io.Writer, locale translation.
4344
return streamer.escaped, err
4445
}
4546

47+
// EscapeControlStringReader escapes the unicode control sequences in a provided reader of string content and writer in a locale and returns the findings as an EscapeStatus and the escaped []byte
48+
func EscapeControlStringReader(reader io.Reader, writer io.Writer, locale translation.Locale, allowed ...rune) (escaped *EscapeStatus, err error) {
49+
bufRd := bufio.NewReader(reader)
50+
outputStream := &HTMLStreamerWriter{Writer: writer}
51+
streamer := NewEscapeStreamer(locale, outputStream, allowed...).(*escapeStreamer)
52+
53+
for {
54+
line, rdErr := bufRd.ReadString('\n')
55+
if len(line) > 0 {
56+
if err := streamer.Text(line); err != nil {
57+
streamer.escaped.HasError = true
58+
log.Error("Error whilst escaping: %v", err)
59+
return streamer.escaped, err
60+
}
61+
}
62+
if rdErr != nil {
63+
if rdErr != io.EOF {
64+
err = rdErr
65+
}
66+
break
67+
}
68+
if err := streamer.SelfClosingTag("br"); err != nil {
69+
streamer.escaped.HasError = true
70+
return streamer.escaped, err
71+
}
72+
}
73+
return streamer.escaped, err
74+
}
75+
4676
// EscapeControlString escapes the unicode control sequences in a provided string and returns the findings as an EscapeStatus and the escaped string
4777
func EscapeControlString(text string, locale translation.Locale, allowed ...rune) (escaped *EscapeStatus, output string) {
4878
sb := &strings.Builder{}

modules/setting/repository.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ var (
8282
DefaultMergeMessageOfficialApproversOnly bool
8383
PopulateSquashCommentWithCommitMessages bool
8484
AddCoCommitterTrailers bool
85+
TestConflictingPatchesWithGitApply bool
8586
} `ini:"repository.pull-request"`
8687

8788
// Issue Setting
@@ -204,6 +205,7 @@ var (
204205
DefaultMergeMessageOfficialApproversOnly bool
205206
PopulateSquashCommentWithCommitMessages bool
206207
AddCoCommitterTrailers bool
208+
TestConflictingPatchesWithGitApply bool
207209
}{
208210
WorkInProgressPrefixes: []string{"WIP:", "[WIP]"},
209211
// Same as GitHub. See

modules/storage/local.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@ func (l *LocalStorage) Save(path string, r io.Reader, size int64) (int64, error)
102102
return 0, err
103103
}
104104
// Golang's tmp file (os.CreateTemp) always have 0o600 mode, so we need to change the file to follow the umask (as what Create/MkDir does)
105-
if err := util.ApplyUmask(p, os.ModePerm); err != nil {
105+
// but we don't want to make these files executable - so ensure that we mask out the executable bits
106+
if err := util.ApplyUmask(p, os.ModePerm&0o666); err != nil {
106107
return 0, err
107108
}
108109

modules/timeutil/timestamp.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,13 @@ import (
1212
// TimeStamp defines a timestamp
1313
type TimeStamp int64
1414

15-
// mock is NOT concurrency-safe!!
16-
var mock time.Time
15+
var (
16+
// mock is NOT concurrency-safe!!
17+
mock time.Time
18+
19+
// Used for IsZero, to check if timestamp is the zero time instant.
20+
timeZeroUnix = time.Time{}.Unix()
21+
)
1722

1823
// Set sets the time to a mocked time.Time
1924
func Set(now time.Time) {
@@ -102,5 +107,5 @@ func (ts TimeStamp) FormatDate() string {
102107

103108
// IsZero is zero time
104109
func (ts TimeStamp) IsZero() bool {
105-
return int64(ts) == 0
110+
return int64(ts) == 0 || int64(ts) == timeZeroUnix
106111
}

0 commit comments

Comments
 (0)