Skip to content

Commit e07a113

Browse files
committed
Merge branch 'main' into fix-runner-token
2 parents 78b7ac8 + 89f31f7 commit e07a113

File tree

134 files changed

+751
-572
lines changed

Some content is hidden

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

134 files changed

+751
-572
lines changed

Dockerfile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Build stage
2-
FROM docker.io/library/golang:1.23-alpine3.20 AS build-env
2+
FROM docker.io/library/golang:1.23-alpine3.21 AS build-env
33

44
ARG GOPROXY
55
ENV GOPROXY=${GOPROXY:-direct}
@@ -41,7 +41,7 @@ RUN chmod 755 /tmp/local/usr/bin/entrypoint \
4141
/go/src/code.gitea.io/gitea/environment-to-ini
4242
RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete
4343

44-
FROM docker.io/library/alpine:3.20
44+
FROM docker.io/library/alpine:3.21
4545
LABEL maintainer="maintainers@gitea.io"
4646

4747
EXPOSE 22 3000
@@ -78,7 +78,7 @@ ENV GITEA_CUSTOM=/data/gitea
7878
VOLUME ["/data"]
7979

8080
ENTRYPOINT ["/usr/bin/entrypoint"]
81-
CMD ["/bin/s6-svscan", "/etc/s6"]
81+
CMD ["/usr/bin/s6-svscan", "/etc/s6"]
8282

8383
COPY --from=build-env /tmp/local /
8484
COPY --from=build-env /go/src/code.gitea.io/gitea/gitea /app/gitea/gitea

Dockerfile.rootless

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Build stage
2-
FROM docker.io/library/golang:1.23-alpine3.20 AS build-env
2+
FROM docker.io/library/golang:1.23-alpine3.21 AS build-env
33

44
ARG GOPROXY
55
ENV GOPROXY=${GOPROXY:-direct}
@@ -39,7 +39,7 @@ RUN chmod 755 /tmp/local/usr/local/bin/docker-entrypoint.sh \
3939
/go/src/code.gitea.io/gitea/environment-to-ini
4040
RUN chmod 644 /go/src/code.gitea.io/gitea/contrib/autocompletion/bash_autocomplete
4141

42-
FROM docker.io/library/alpine:3.20
42+
FROM docker.io/library/alpine:3.21
4343
LABEL maintainer="maintainers@gitea.io"
4444

4545
EXPOSE 2222 3000

models/migrations/base/tests.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ import (
1313
"testing"
1414

1515
"code.gitea.io/gitea/models/unittest"
16-
"code.gitea.io/gitea/modules/base"
1716
"code.gitea.io/gitea/modules/git"
1817
"code.gitea.io/gitea/modules/setting"
18+
"code.gitea.io/gitea/modules/test"
1919
"code.gitea.io/gitea/modules/testlogger"
2020

2121
"github.com/stretchr/testify/require"
@@ -92,10 +92,7 @@ func PrepareTestEnv(t *testing.T, skip int, syncModels ...any) (*xorm.Engine, fu
9292
func MainTest(m *testing.M) {
9393
testlogger.Init()
9494

95-
giteaRoot := base.SetupGiteaRoot()
96-
if giteaRoot == "" {
97-
testlogger.Fatalf("Environment variable $GITEA_ROOT not set\n")
98-
}
95+
giteaRoot := test.SetupGiteaRoot()
9996
giteaBinary := "gitea"
10097
if runtime.GOOS == "windows" {
10198
giteaBinary += ".exe"

models/unittest/testdb.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@ import (
1414
"code.gitea.io/gitea/models/db"
1515
"code.gitea.io/gitea/models/system"
1616
"code.gitea.io/gitea/modules/auth/password/hash"
17-
"code.gitea.io/gitea/modules/base"
1817
"code.gitea.io/gitea/modules/cache"
1918
"code.gitea.io/gitea/modules/git"
2019
"code.gitea.io/gitea/modules/log"
2120
"code.gitea.io/gitea/modules/setting"
2221
"code.gitea.io/gitea/modules/setting/config"
2322
"code.gitea.io/gitea/modules/storage"
23+
"code.gitea.io/gitea/modules/test"
2424
"code.gitea.io/gitea/modules/util"
2525

2626
"github.com/stretchr/testify/assert"
@@ -235,5 +235,5 @@ func PrepareTestEnv(t testing.TB) {
235235
assert.NoError(t, PrepareTestDatabase())
236236
metaPath := filepath.Join(giteaRoot, "tests", "gitea-repositories-meta")
237237
assert.NoError(t, SyncDirs(metaPath, setting.RepoRootPath))
238-
base.SetupGiteaRoot() // Makes sure GITEA_ROOT is set
238+
test.SetupGiteaRoot() // Makes sure GITEA_ROOT is set
239239
}

modules/base/base.go

Lines changed: 0 additions & 9 deletions
This file was deleted.

modules/base/tool.go

Lines changed: 0 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,6 @@ import (
1313
"errors"
1414
"fmt"
1515
"hash"
16-
"os"
17-
"path/filepath"
18-
"runtime"
1916
"strconv"
2017
"strings"
2118
"time"
@@ -189,49 +186,3 @@ func EntryIcon(entry *git.TreeEntry) string {
189186

190187
return "file"
191188
}
192-
193-
// SetupGiteaRoot Sets GITEA_ROOT if it is not already set and returns the value
194-
func SetupGiteaRoot() string {
195-
giteaRoot := os.Getenv("GITEA_ROOT")
196-
if giteaRoot == "" {
197-
_, filename, _, _ := runtime.Caller(0)
198-
giteaRoot = strings.TrimSuffix(filename, "modules/base/tool.go")
199-
wd, err := os.Getwd()
200-
if err != nil {
201-
rel, err := filepath.Rel(giteaRoot, wd)
202-
if err != nil && strings.HasPrefix(filepath.ToSlash(rel), "../") {
203-
giteaRoot = wd
204-
}
205-
}
206-
if _, err := os.Stat(filepath.Join(giteaRoot, "gitea")); os.IsNotExist(err) {
207-
giteaRoot = ""
208-
} else if err := os.Setenv("GITEA_ROOT", giteaRoot); err != nil {
209-
giteaRoot = ""
210-
}
211-
}
212-
return giteaRoot
213-
}
214-
215-
// FormatNumberSI format a number
216-
func FormatNumberSI(data any) string {
217-
var num int64
218-
if num1, ok := data.(int64); ok {
219-
num = num1
220-
} else if num1, ok := data.(int); ok {
221-
num = int64(num1)
222-
} else {
223-
return ""
224-
}
225-
226-
if num < 1000 {
227-
return fmt.Sprintf("%d", num)
228-
} else if num < 1000000 {
229-
num2 := float32(num) / float32(1000.0)
230-
return fmt.Sprintf("%.1fk", num2)
231-
} else if num < 1000000000 {
232-
num2 := float32(num) / float32(1000000.0)
233-
return fmt.Sprintf("%.1fM", num2)
234-
}
235-
num2 := float32(num) / float32(1000000000.0)
236-
return fmt.Sprintf("%.1fG", num2)
237-
}

modules/base/tool_test.go

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -169,18 +169,3 @@ func TestInt64sToStrings(t *testing.T) {
169169
}
170170

171171
// TODO: Test EntryIcon
172-
173-
func TestSetupGiteaRoot(t *testing.T) {
174-
t.Setenv("GITEA_ROOT", "test")
175-
assert.Equal(t, "test", SetupGiteaRoot())
176-
t.Setenv("GITEA_ROOT", "")
177-
assert.NotEqual(t, "test", SetupGiteaRoot())
178-
}
179-
180-
func TestFormatNumberSI(t *testing.T) {
181-
assert.Equal(t, "125", FormatNumberSI(int(125)))
182-
assert.Equal(t, "1.3k", FormatNumberSI(int64(1317)))
183-
assert.Equal(t, "21.3M", FormatNumberSI(21317675))
184-
assert.Equal(t, "45.7G", FormatNumberSI(45721317675))
185-
assert.Equal(t, "", FormatNumberSI("test"))
186-
}

modules/references/references.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ var (
3232
// issueNumericPattern matches string that references to a numeric issue, e.g. #1287
3333
issueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[|\'|\")([#!][0-9]+)(?:\s|$|\)|\]|\'|\"|[:;,.?!]\s|[:;,.?!]$)`)
3434
// issueAlphanumericPattern matches string that references to an alphanumeric issue, e.g. ABC-1234
35-
issueAlphanumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[|\"|\')([A-Z]{1,10}-[1-9][0-9]*)(?:\s|$|\)|\]|:|\.(\s|$)|\"|\')`)
35+
issueAlphanumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[|\"|\')([A-Z]{1,10}-[1-9][0-9]*)(?:\s|$|\)|\]|:|\.(\s|$)|\"|\'|,)`)
3636
// crossReferenceIssueNumericPattern matches string that references a numeric issue in a different repository
3737
// e.g. org/repo#12345
3838
crossReferenceIssueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[)([0-9a-zA-Z-_\.]+/[0-9a-zA-Z-_\.]+[#!][0-9]+)(?:\s|$|\)|\]|[:;,.?!]\s|[:;,.?!]$)`)

modules/references/references_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,6 +463,7 @@ func TestRegExp_issueAlphanumericPattern(t *testing.T) {
463463
"ABC-123:",
464464
"\"ABC-123\"",
465465
"'ABC-123'",
466+
"ABC-123, unknown PR",
466467
}
467468
falseTestCases := []string{
468469
"RC-08",

modules/repository/license_test.go

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,7 @@ func Test_getLicense(t *testing.T) {
3131
3232
Copyright (c) 2023 Gitea
3333
34-
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
35-
36-
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
37-
38-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
39-
`,
34+
Permission is hereby granted`,
4035
wantErr: assert.NoError,
4136
},
4237
{
@@ -53,7 +48,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
5348
if !tt.wantErr(t, err, fmt.Sprintf("GetLicense(%v, %v)", tt.args.name, tt.args.values)) {
5449
return
5550
}
56-
assert.Equalf(t, tt.want, string(got), "GetLicense(%v, %v)", tt.args.name, tt.args.values)
51+
assert.Contains(t, string(got), tt.want, "GetLicense(%v, %v)", tt.args.name, tt.args.values)
5752
})
5853
}
5954
}

modules/templates/helper.go

Lines changed: 3 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
"html"
1010
"html/template"
1111
"net/url"
12-
"reflect"
1312
"strings"
1413
"time"
1514

@@ -69,7 +68,7 @@ func NewFuncMap() template.FuncMap {
6968
// -----------------------------------------------------------------
7069
// time / number / format
7170
"FileSize": base.FileSize,
72-
"CountFmt": base.FormatNumberSI,
71+
"CountFmt": countFmt,
7372
"Sec2Time": util.SecToTime,
7473

7574
"TimeEstimateString": timeEstimateString,
@@ -239,29 +238,8 @@ func iif(condition any, vals ...any) any {
239238
}
240239

241240
func isTemplateTruthy(v any) bool {
242-
if v == nil {
243-
return false
244-
}
245-
246-
rv := reflect.ValueOf(v)
247-
switch rv.Kind() {
248-
case reflect.Bool:
249-
return rv.Bool()
250-
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
251-
return rv.Int() != 0
252-
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
253-
return rv.Uint() != 0
254-
case reflect.Float32, reflect.Float64:
255-
return rv.Float() != 0
256-
case reflect.Complex64, reflect.Complex128:
257-
return rv.Complex() != 0
258-
case reflect.String, reflect.Slice, reflect.Array, reflect.Map:
259-
return rv.Len() > 0
260-
case reflect.Struct:
261-
return true
262-
default:
263-
return !rv.IsNil()
264-
}
241+
truth, _ := template.IsTrue(v)
242+
return truth
265243
}
266244

267245
// evalTokens evaluates the expression by tokens and returns the result, see the comment of eval.Expr for details.
@@ -286,14 +264,6 @@ func userThemeName(user *user_model.User) string {
286264
return setting.UI.DefaultTheme
287265
}
288266

289-
func timeEstimateString(timeSec any) string {
290-
v, _ := util.ToInt64(timeSec)
291-
if v == 0 {
292-
return ""
293-
}
294-
return util.TimeEstimateString(v)
295-
}
296-
297267
// QueryBuild builds a query string from a list of key-value pairs.
298268
// It omits the nil and empty strings, but it doesn't omit other zero values,
299269
// because the zero value of number types may have a meaning.

modules/templates/helper_test.go

Lines changed: 37 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"strings"
99
"testing"
1010

11+
"code.gitea.io/gitea/modules/htmlutil"
1112
"code.gitea.io/gitea/modules/util"
1213

1314
"github.com/stretchr/testify/assert"
@@ -65,31 +66,12 @@ func TestSanitizeHTML(t *testing.T) {
6566
assert.Equal(t, template.HTML(`<a href="/" rel="nofollow">link</a> xss <div>inline</div>`), SanitizeHTML(`<a href="/">link</a> <a href="javascript:">xss</a> <div style="dangerous">inline</div>`))
6667
}
6768

68-
func TestTemplateTruthy(t *testing.T) {
69+
func TestTemplateIif(t *testing.T) {
6970
tmpl := template.New("test")
7071
tmpl.Funcs(template.FuncMap{"Iif": iif})
7172
template.Must(tmpl.Parse(`{{if .Value}}true{{else}}false{{end}}:{{Iif .Value "true" "false"}}`))
7273

73-
cases := []any{
74-
nil, false, true, "", "string", 0, 1,
75-
byte(0), byte(1), int64(0), int64(1), float64(0), float64(1),
76-
complex(0, 0), complex(1, 0),
77-
(chan int)(nil), make(chan int),
78-
(func())(nil), func() {},
79-
util.ToPointer(0), util.ToPointer(util.ToPointer(0)),
80-
util.ToPointer(1), util.ToPointer(util.ToPointer(1)),
81-
[0]int{},
82-
[1]int{0},
83-
[]int(nil),
84-
[]int{},
85-
[]int{0},
86-
map[any]any(nil),
87-
map[any]any{},
88-
map[any]any{"k": "v"},
89-
(*struct{})(nil),
90-
struct{}{},
91-
util.ToPointer(struct{}{}),
92-
}
74+
cases := []any{nil, false, true, "", "string", 0, 1}
9375
w := &strings.Builder{}
9476
truthyCount := 0
9577
for i, v := range cases {
@@ -102,3 +84,37 @@ func TestTemplateTruthy(t *testing.T) {
10284
}
10385
assert.True(t, truthyCount != 0 && truthyCount != len(cases))
10486
}
87+
88+
func TestTemplateEscape(t *testing.T) {
89+
execTmpl := func(code string) string {
90+
tmpl := template.New("test")
91+
tmpl.Funcs(template.FuncMap{"QueryBuild": QueryBuild, "HTMLFormat": htmlutil.HTMLFormat})
92+
template.Must(tmpl.Parse(code))
93+
w := &strings.Builder{}
94+
assert.NoError(t, tmpl.Execute(w, nil))
95+
return w.String()
96+
}
97+
98+
t.Run("Golang URL Escape", func(t *testing.T) {
99+
// Golang template considers "href", "*src*", "*uri*", "*url*" (and more) ... attributes as contentTypeURL and does auto-escaping
100+
actual := execTmpl(`<a href="?a={{"%"}}"></a>`)
101+
assert.Equal(t, `<a href="?a=%25"></a>`, actual)
102+
actual = execTmpl(`<a data-xxx-url="?a={{"%"}}"></a>`)
103+
assert.Equal(t, `<a data-xxx-url="?a=%25"></a>`, actual)
104+
})
105+
t.Run("Golang URL No-escape", func(t *testing.T) {
106+
// non-URL content isn't auto-escaped
107+
actual := execTmpl(`<a data-link="?a={{"%"}}"></a>`)
108+
assert.Equal(t, `<a data-link="?a=%"></a>`, actual)
109+
})
110+
t.Run("QueryBuild", func(t *testing.T) {
111+
actual := execTmpl(`<a href="{{QueryBuild "?" "a" "%"}}"></a>`)
112+
assert.Equal(t, `<a href="?a=%25"></a>`, actual)
113+
actual = execTmpl(`<a href="?{{QueryBuild "a" "%"}}"></a>`)
114+
assert.Equal(t, `<a href="?a=%25"></a>`, actual)
115+
})
116+
t.Run("HTMLFormat", func(t *testing.T) {
117+
actual := execTmpl("{{HTMLFormat `<a k=\"%s\">%s</a>` `\"` `<>`}}")
118+
assert.Equal(t, `<a k="&#34;">&lt;&gt;</a>`, actual)
119+
})
120+
}

modules/templates/htmlrenderer.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ import (
2929

3030
type TemplateExecutor scopedtmpl.TemplateExecutor
3131

32+
type TplName string
33+
3234
type HTMLRender struct {
3335
templates atomic.Pointer[scopedtmpl.ScopedTemplate]
3436
}
@@ -40,7 +42,8 @@ var (
4042

4143
var ErrTemplateNotInitialized = errors.New("template system is not initialized, check your log for errors")
4244

43-
func (h *HTMLRender) HTML(w io.Writer, status int, name string, data any, ctx context.Context) error { //nolint:revive
45+
func (h *HTMLRender) HTML(w io.Writer, status int, tplName TplName, data any, ctx context.Context) error { //nolint:revive
46+
name := string(tplName)
4447
if respWriter, ok := w.(http.ResponseWriter); ok {
4548
if respWriter.Header().Get("Content-Type") == "" {
4649
respWriter.Header().Set("Content-Type", "text/html; charset=utf-8")

0 commit comments

Comments
 (0)