Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package gitea-runner for openSUSE:Factory checked in at 2026-10-09 21:46:28 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/gitea-runner (Old) and /work/SRC/openSUSE:Factory/.gitea-runner.new.3698736 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "gitea-runner" Fri Oct 9 21:46:28 2026 rev:3 rq:1383808 version:5.0.0 Changes: -------- --- /work/SRC/openSUSE:Factory/gitea-runner/gitea-runner.changes 2026-10-07 19:36:34.396617690 +0200 +++ /work/SRC/openSUSE:Factory/.gitea-runner.new.3698736/gitea-runner.changes 2026-10-09 21:47:45.721318700 +0200 @@ -1,0 +2,18 @@ +Fri Oct 09 12:23:53 UTC 2026 - Elisei Roca <[email protected]> + +- Update to version 5.0.0: + * enhance!: send OTLP metrics under OpenTelemetry semantic conventions, add runner state (#1282) + * enhance(config): add `container.sweep` option (#1275) + * enhance: support client certificates for mutual TLS (#1273) + * fix: apply the daemon's mtu to job networks (#1270) + * enhance(config): expand environment values (#1274) + * enhance(runner): add extra HTTP headers (#1269) + * fix: enforce read-only volume restrictions (#1272) + * fix!: use the git CLI for action clones and make builtin:checkout match actions/checkout (#1277) + * fix: reject workflows with jobs lacking `runs-on` (#1271) + * fix: strip log-driver and OOM options when privileged is off (#1283) + * fix: allow tmpfs mounts in container options (#1289) + * fix: extract copied directories at their destination in Kubernetes pods (#1286) + * fix: recognize Gitea's 401 reply for an unregistered runner (#1287) + +------------------------------------------------------------------- Old: ---- runner-4.1.0.tar.gz New: ---- runner-5.0.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ gitea-runner.spec ++++++ --- /var/tmp/diff_new_pack.HL0Rxm/_old 2026-10-09 21:47:46.916368818 +0200 +++ /var/tmp/diff_new_pack.HL0Rxm/_new 2026-10-09 21:47:46.918368902 +0200 @@ -17,7 +17,7 @@ Name: gitea-runner -Version: 4.1.0 +Version: 5.0.0 Release: 0 Summary: Gitea Runner for Gitea Actions License: MIT ++++++ _service ++++++ --- /var/tmp/diff_new_pack.HL0Rxm/_old 2026-10-09 21:47:46.959370622 +0200 +++ /var/tmp/diff_new_pack.HL0Rxm/_new 2026-10-09 21:47:46.963370789 +0200 @@ -5,7 +5,7 @@ <param name="exclude">.git</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> - <param name="revision">v4.1.0</param> + <param name="revision">v5.0.0</param> <param name="changesgenerate">enable</param> </service> <service name="recompress" mode="manual"> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.HL0Rxm/_old 2026-10-09 21:47:46.987371796 +0200 +++ /var/tmp/diff_new_pack.HL0Rxm/_new 2026-10-09 21:47:46.991371964 +0200 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://gitea.com/gitea/runner.git</param> - <param name="changesrevision">ddee2e054ae5b590b01b557807b8a53403cc50f3</param></service></servicedata> + <param name="changesrevision">8b14a38d4ad6a1cb40dabb953a8a65656de70301</param></service></servicedata> (No newline at EOF) ++++++ runner-4.1.0.tar.gz -> runner-5.0.0.tar.gz ++++++ ++++ 4958 lines of diff (skipped) ++++++ vendor.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/gitea.dev/actionslib/pkg/expreval/subexpr.go new/vendor/gitea.dev/actionslib/pkg/expreval/subexpr.go --- old/vendor/gitea.dev/actionslib/pkg/expreval/subexpr.go 2026-10-01 21:45:13.000000000 +0200 +++ new/vendor/gitea.dev/actionslib/pkg/expreval/subexpr.go 2026-10-08 20:01:36.000000000 +0200 @@ -61,6 +61,19 @@ return partsMatch(parts, match) } +// Literal returns the text of a value that is plain text or a lone string literal expression. +func Literal(value string) (string, bool) { + parts, err := splitSubExpressions(value) + switch { + case err != nil || len(parts) != 1: + return "", false + case parts[0].isLiteral: + return parts[0].literal, true + default: + return parts[0].text, !parts[0].isExpr + } +} + // ReadsContext reports whether value reads the named context, without exposing the AST. func ReadsContext(value, contextName string) bool { return Match(value, func(node exprparser.ExprNode) bool { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/gitea.dev/actionslib/pkg/model/matrix.go new/vendor/gitea.dev/actionslib/pkg/model/matrix.go --- old/vendor/gitea.dev/actionslib/pkg/model/matrix.go 2026-10-01 21:45:13.000000000 +0200 +++ new/vendor/gitea.dev/actionslib/pkg/model/matrix.go 2026-10-08 20:01:36.000000000 +0200 @@ -8,8 +8,10 @@ "errors" "fmt" "maps" - "reflect" + "math" "slices" + "strconv" + "strings" "go.yaml.in/yaml/v4" ) @@ -21,13 +23,21 @@ type matrixAxis struct { name string values []any + node *yaml.Node } // matrix keeps axes in YAML declaration order for GitHub's first-axis-slowest expansion. type matrix struct { - axes []matrixAxis - include []map[string]any - exclude []map[string]any + axes []matrixAxis + include []map[string]any + includeNodes []*yaml.Node + exclude []map[string]any +} + +// MatrixCombination is an expanded combination with the scalars its default job name lists, in order. +type MatrixCombination struct { + Values map[string]any + NameValues []any } func (j *Job) matrixOf() (*matrix, error) { @@ -60,14 +70,12 @@ return nil, err } if name == "include" { - parsed.include = entries + parsed.include, parsed.includeNodes = entries, value.Content } else { parsed.exclude = entries } default: - if value.Kind == yaml.AliasNode { - value = value.Alias - } + value = resolveAlias(value) if value.Kind != yaml.SequenceNode { return nil, fmt.Errorf("the workflow is not valid. Matrix vector %q is not a list of values", name) } @@ -75,7 +83,7 @@ if err := value.Decode(&values); err != nil { return nil, fmt.Errorf("the workflow is not valid. Matrix key %q: %w", name, err) } - parsed.axes = append(parsed.axes, matrixAxis{name: name, values: values}) + parsed.axes = append(parsed.axes, matrixAxis{name: name, values: values, node: value}) } } if len(parsed.axes) == 0 && len(parsed.include) == 0 { @@ -128,12 +136,25 @@ // GetMatrixes expands evaluated matrix sequences in declaration order, rejecting excludes with undeclared keys. func (j *Job) GetMatrixes() ([]map[string]any, error) { + combinations, err := j.MatrixCombinations() + if err != nil { + return nil, err + } + matrixes := make([]map[string]any, len(combinations)) + for i, combination := range combinations { + matrixes[i] = combination.Values + } + return matrixes, nil +} + +// MatrixCombinations is GetMatrixes with each combination's NameValues. +func (j *Job) MatrixCombinations() ([]MatrixCombination, error) { parsed, err := j.matrixOf() if err != nil { return nil, err } if parsed == nil { - return []map[string]any{{}}, nil + return []MatrixCombination{{Values: map[string]any{}}}, nil } product := 1 @@ -142,7 +163,7 @@ if len(axis.values) == 0 { return nil, fmt.Errorf("the workflow is not valid. Matrix vector %q does not contain any values", axis.name) } - declaredKeys[axis.name] = true + declaredKeys[strings.ToLower(axis.name)] = true product *= len(axis.values) if product > MaxMatrixCombinations { return nil, errTooManyCombinations(product) @@ -151,43 +172,106 @@ for _, exclude := range parsed.exclude { for key := range exclude { - if !declaredKeys[key] { + if !declaredKeys[strings.ToLower(key)] { return nil, fmt.Errorf("the workflow is not valid. Matrix exclude key %q does not match any key within the matrix", key) } } } - matrixes := make([]map[string]any, 0, product) + combinations := make([]MatrixCombination, 0, product) for _, combination := range cartesianProduct(parsed.axes, product) { if !slices.ContainsFunc(parsed.exclude, func(exclude map[string]any) bool { - return matchesMatrixKeys(combination, exclude, declaredKeys) + return matchesMatrixKeys(combination.Values, exclude, declaredKeys) }) { - matrixes = append(matrixes, combination) + combinations = append(combinations, combination) } } - var extra []map[string]any - for _, include := range parsed.include { + var extra []MatrixCombination + for i, include := range parsed.include { matched := false - for _, combination := range matrixes { - if matchesMatrixKeys(combination, include, declaredKeys) { - maps.Copy(combination, include) + for _, combination := range combinations { + if matchesMatrixKeys(combination.Values, include, declaredKeys) { + for key, value := range include { + if !declaredKeys[strings.ToLower(key)] { + combination.Values[key] = value + } + } matched = true } } if !matched { - extra = append(extra, include) + extra = append(extra, MatrixCombination{Values: include, NameValues: includeNameValues(include, parsed.includeNodes[i], declaredKeys)}) } } - matrixes = append(matrixes, extra...) + combinations = append(combinations, extra...) - if len(matrixes) == 0 { - return []map[string]any{{}}, nil + if len(combinations) == 0 { + return []MatrixCombination{{Values: map[string]any{}}}, nil } - if len(matrixes) > MaxMatrixCombinations { - return nil, errTooManyCombinations(len(matrixes)) + if len(combinations) > MaxMatrixCombinations { + return nil, errTooManyCombinations(len(combinations)) } - return matrixes, nil + return combinations, nil +} + +func includeNameValues(include map[string]any, node *yaml.Node, declaredKeys map[string]bool) []any { + axes, others := map[string]any{}, map[string]any{} + for key, value := range include { + if declaredKeys[strings.ToLower(key)] { + axes[key] = value + } else { + others[key] = value + } + } + return appendScalars(appendScalars(nil, axes, node), others, node) +} + +// appendScalars appends the scalars of value, ordering mapping keys like node, which value was decoded from. +func appendScalars(scalars []any, value any, node *yaml.Node) []any { + node = resolveAlias(node) + switch value := value.(type) { + case map[string]any: + remaining := maps.Clone(value) + for i := 0; node != nil && node.Kind == yaml.MappingNode && i+1 < len(node.Content); i += 2 { + key := resolveAlias(node.Content[i]).Value + if item, ok := remaining[key]; ok { + delete(remaining, key) + scalars = appendScalars(scalars, item, node.Content[i+1]) + } + } + for _, key := range slices.Sorted(maps.Keys(remaining)) { + scalars = appendScalars(scalars, remaining[key], nil) + } + case map[any]any: + keyed := make(map[string]any, len(value)) + for key, item := range value { + keyed[fmt.Sprint(key)] = item + } + scalars = appendScalars(scalars, keyed, node) + case []any: + for i, item := range value { + scalars = appendScalars(scalars, item, itemNode(node, i, len(value))) + } + default: + scalars = append(scalars, value) + } + return scalars +} + +// itemNode returns the i-th item of the sequence node, or nil when the decoder dropped items like `<<`. +func itemNode(node *yaml.Node, i, count int) *yaml.Node { + if node == nil || node.Kind != yaml.SequenceNode || len(node.Content) != count { + return nil + } + return node.Content[i] +} + +func resolveAlias(node *yaml.Node) *yaml.Node { + if node != nil && node.Kind == yaml.AliasNode { + return node.Alias + } + return node } func errTooManyCombinations(count int) error { @@ -195,26 +279,105 @@ } func matchesMatrixKeys(combination, entry map[string]any, declaredKeys map[string]bool) bool { - for key, value := range entry { - if declaredKeys[key] && !reflect.DeepEqual(combination[key], value) { + for key, filter := range entry { + if declaredKeys[strings.ToLower(key)] && !matchesFilter(propertyFold(combination, key), filter) { return false } } return true } +// matchesFilter compares each scalar of filter with the value at its path using expression equality. +func matchesFilter(value, filter any) bool { + switch filter := filter.(type) { + case map[string]any: + object, _ := value.(map[string]any) + for key, item := range filter { + if !matchesFilter(propertyFold(object, key), item) { + return false + } + } + return true + case []any: + array, _ := value.([]any) + for i, item := range filter { + var element any + if i < len(array) { + element = array[i] + } + if !matchesFilter(element, item) { + return false + } + } + return true + } + return looseEqual(value, filter) +} + +func propertyFold(object map[string]any, key string) any { + if value, ok := object[key]; ok { + return value + } + for name, value := range object { + if strings.EqualFold(name, key) { + return value + } + } + return nil +} + +// looseEqual is the expression `==` of exprparser, which model cannot import, for a matrix value and a filter scalar. +func looseEqual(value, scalar any) bool { + if valueText, ok := value.(string); ok { + if scalarText, ok := scalar.(string); ok { + return strings.EqualFold(valueText, scalarText) + } + } + return toNumber(value) == toNumber(scalar) +} + +func toNumber(value any) float64 { + switch value := value.(type) { + case nil: + return 0 + case bool: + if value { + return 1 + } + return 0 + case int: + return float64(value) + case uint64: + return float64(value) + case float64: + return value + case string: + text := strings.TrimSpace(value) + if text == "" { + return 0 + } + if number, err := strconv.ParseFloat(text, 64); err == nil { + return number + } + } + return math.NaN() +} + // cartesianProduct expands the axes into combinations with the first axis varying slowest, which // is the order GitHub documents and lists the resulting jobs in. -func cartesianProduct(axes []matrixAxis, product int) []map[string]any { +func cartesianProduct(axes []matrixAxis, product int) []MatrixCombination { if len(axes) == 0 { return nil } - combinations := make([]map[string]any, 0, product) + combinations := make([]MatrixCombination, 0, product) for ordinal := range product { - combination := make(map[string]any, len(axes)) - for _, axis := range slices.Backward(axes) { - combination[axis.name] = axis.values[ordinal%len(axis.values)] - ordinal /= len(axis.values) + combination := MatrixCombination{Values: make(map[string]any, len(axes))} + stride := product + for _, axis := range axes { + stride /= len(axis.values) + index := ordinal / stride % len(axis.values) + combination.Values[axis.name] = axis.values[index] + combination.NameValues = appendScalars(combination.NameValues, axis.values[index], itemNode(axis.node, index, len(axis.values))) } combinations = append(combinations, combination) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/golang.org/x/net/http/httpguts/guts.go new/vendor/golang.org/x/net/http/httpguts/guts.go --- old/vendor/golang.org/x/net/http/httpguts/guts.go 1970-01-01 01:00:00.000000000 +0100 +++ new/vendor/golang.org/x/net/http/httpguts/guts.go 2026-10-08 20:01:36.000000000 +0200 @@ -0,0 +1,50 @@ +// Copyright 2018 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package httpguts provides functions implementing various details +// of the HTTP specification. +// +// This package is shared by the standard library (which vendors it) +// and x/net/http2. It comes with no API stability promise. +package httpguts + +import ( + "net/textproto" + "strings" +) + +// ValidTrailerHeader reports whether name is a valid header field name to appear +// in trailers. +// See RFC 7230, Section 4.1.2 +func ValidTrailerHeader(name string) bool { + name = textproto.CanonicalMIMEHeaderKey(name) + if strings.HasPrefix(name, "If-") || badTrailer[name] { + return false + } + return true +} + +var badTrailer = map[string]bool{ + "Authorization": true, + "Cache-Control": true, + "Connection": true, + "Content-Encoding": true, + "Content-Length": true, + "Content-Range": true, + "Content-Type": true, + "Expect": true, + "Host": true, + "Keep-Alive": true, + "Max-Forwards": true, + "Pragma": true, + "Proxy-Authenticate": true, + "Proxy-Authorization": true, + "Proxy-Connection": true, + "Range": true, + "Realm": true, + "Te": true, + "Trailer": true, + "Transfer-Encoding": true, + "Www-Authenticate": true, +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/golang.org/x/net/http/httpguts/httplex.go new/vendor/golang.org/x/net/http/httpguts/httplex.go --- old/vendor/golang.org/x/net/http/httpguts/httplex.go 1970-01-01 01:00:00.000000000 +0100 +++ new/vendor/golang.org/x/net/http/httpguts/httplex.go 2026-10-08 20:01:36.000000000 +0200 @@ -0,0 +1,347 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package httpguts + +import ( + "net" + "strings" + "unicode/utf8" + + "golang.org/x/net/idna" +) + +var isTokenTable = [256]bool{ + '!': true, + '#': true, + '$': true, + '%': true, + '&': true, + '\'': true, + '*': true, + '+': true, + '-': true, + '.': true, + '0': true, + '1': true, + '2': true, + '3': true, + '4': true, + '5': true, + '6': true, + '7': true, + '8': true, + '9': true, + 'A': true, + 'B': true, + 'C': true, + 'D': true, + 'E': true, + 'F': true, + 'G': true, + 'H': true, + 'I': true, + 'J': true, + 'K': true, + 'L': true, + 'M': true, + 'N': true, + 'O': true, + 'P': true, + 'Q': true, + 'R': true, + 'S': true, + 'T': true, + 'U': true, + 'W': true, + 'V': true, + 'X': true, + 'Y': true, + 'Z': true, + '^': true, + '_': true, + '`': true, + 'a': true, + 'b': true, + 'c': true, + 'd': true, + 'e': true, + 'f': true, + 'g': true, + 'h': true, + 'i': true, + 'j': true, + 'k': true, + 'l': true, + 'm': true, + 'n': true, + 'o': true, + 'p': true, + 'q': true, + 'r': true, + 's': true, + 't': true, + 'u': true, + 'v': true, + 'w': true, + 'x': true, + 'y': true, + 'z': true, + '|': true, + '~': true, +} + +func IsTokenRune(r rune) bool { + return r < utf8.RuneSelf && isTokenTable[byte(r)] +} + +// HeaderValuesContainsToken reports whether any string in values +// contains the provided token, ASCII case-insensitively. +func HeaderValuesContainsToken(values []string, token string) bool { + for _, v := range values { + if headerValueContainsToken(v, token) { + return true + } + } + return false +} + +// isOWS reports whether b is an optional whitespace byte, as defined +// by RFC 7230 section 3.2.3. +func isOWS(b byte) bool { return b == ' ' || b == '\t' } + +// trimOWS returns x with all optional whitespace removes from the +// beginning and end. +func trimOWS(x string) string { + // TODO: consider using strings.Trim(x, " \t") instead, + // if and when it's fast enough. See issue 10292. + // But this ASCII-only code will probably always beat UTF-8 + // aware code. + for len(x) > 0 && isOWS(x[0]) { + x = x[1:] + } + for len(x) > 0 && isOWS(x[len(x)-1]) { + x = x[:len(x)-1] + } + return x +} + +// headerValueContainsToken reports whether v (assumed to be a +// 0#element, in the ABNF extension described in RFC 7230 section 7) +// contains token amongst its comma-separated tokens, ASCII +// case-insensitively. +func headerValueContainsToken(v string, token string) bool { + for comma := strings.IndexByte(v, ','); comma != -1; comma = strings.IndexByte(v, ',') { + if tokenEqual(trimOWS(v[:comma]), token) { + return true + } + v = v[comma+1:] + } + return tokenEqual(trimOWS(v), token) +} + +// lowerASCII returns the ASCII lowercase version of b. +func lowerASCII(b byte) byte { + if 'A' <= b && b <= 'Z' { + return b + ('a' - 'A') + } + return b +} + +// tokenEqual reports whether t1 and t2 are equal, ASCII case-insensitively. +func tokenEqual(t1, t2 string) bool { + if len(t1) != len(t2) { + return false + } + for i, b := range t1 { + if b >= utf8.RuneSelf { + // No UTF-8 or non-ASCII allowed in tokens. + return false + } + if lowerASCII(byte(b)) != lowerASCII(t2[i]) { + return false + } + } + return true +} + +// isLWS reports whether b is linear white space, according +// to http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2 +// +// LWS = [CRLF] 1*( SP | HT ) +func isLWS(b byte) bool { return b == ' ' || b == '\t' } + +// isCTL reports whether b is a control byte, according +// to http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2 +// +// CTL = <any US-ASCII control character +// (octets 0 - 31) and DEL (127)> +func isCTL(b byte) bool { + const del = 0x7f // a CTL + return b < ' ' || b == del +} + +// ValidHeaderFieldName reports whether v is a valid HTTP/1.x header name. +// HTTP/2 imposes the additional restriction that uppercase ASCII +// letters are not allowed. +// +// RFC 7230 says: +// +// header-field = field-name ":" OWS field-value OWS +// field-name = token +// token = 1*tchar +// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." / +// "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA +func ValidHeaderFieldName(v string) bool { + if len(v) == 0 { + return false + } + for i := 0; i < len(v); i++ { + if !isTokenTable[v[i]] { + return false + } + } + return true +} + +// ValidHostHeader reports whether h is a valid host header. +func ValidHostHeader(h string) bool { + // The latest spec is actually this: + // + // http://tools.ietf.org/html/rfc7230#section-5.4 + // Host = uri-host [ ":" port ] + // + // Where uri-host is: + // http://tools.ietf.org/html/rfc3986#section-3.2.2 + // + // But we're going to be much more lenient for now and just + // search for any byte that's not a valid byte in any of those + // expressions. + for i := 0; i < len(h); i++ { + if !validHostByte[h[i]] { + return false + } + } + return true +} + +// See the validHostHeader comment. +var validHostByte = [256]bool{ + '0': true, '1': true, '2': true, '3': true, '4': true, '5': true, '6': true, '7': true, + '8': true, '9': true, + + 'a': true, 'b': true, 'c': true, 'd': true, 'e': true, 'f': true, 'g': true, 'h': true, + 'i': true, 'j': true, 'k': true, 'l': true, 'm': true, 'n': true, 'o': true, 'p': true, + 'q': true, 'r': true, 's': true, 't': true, 'u': true, 'v': true, 'w': true, 'x': true, + 'y': true, 'z': true, + + 'A': true, 'B': true, 'C': true, 'D': true, 'E': true, 'F': true, 'G': true, 'H': true, + 'I': true, 'J': true, 'K': true, 'L': true, 'M': true, 'N': true, 'O': true, 'P': true, + 'Q': true, 'R': true, 'S': true, 'T': true, 'U': true, 'V': true, 'W': true, 'X': true, + 'Y': true, 'Z': true, + + '!': true, // sub-delims + '$': true, // sub-delims + '%': true, // pct-encoded (and used in IPv6 zones) + '&': true, // sub-delims + '(': true, // sub-delims + ')': true, // sub-delims + '*': true, // sub-delims + '+': true, // sub-delims + ',': true, // sub-delims + '-': true, // unreserved + '.': true, // unreserved + ':': true, // IPv6address + Host expression's optional port + ';': true, // sub-delims + '=': true, // sub-delims + '[': true, + '\'': true, // sub-delims + ']': true, + '_': true, // unreserved + '~': true, // unreserved +} + +// ValidHeaderFieldValue reports whether v is a valid "field-value" according to +// http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 : +// +// message-header = field-name ":" [ field-value ] +// field-value = *( field-content | LWS ) +// field-content = <the OCTETs making up the field-value +// and consisting of either *TEXT or combinations +// of token, separators, and quoted-string> +// +// http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2 : +// +// TEXT = <any OCTET except CTLs, +// but including LWS> +// LWS = [CRLF] 1*( SP | HT ) +// CTL = <any US-ASCII control character +// (octets 0 - 31) and DEL (127)> +// +// RFC 7230 says: +// +// field-value = *( field-content / obs-fold ) +// obj-fold = N/A to http2, and deprecated +// field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] +// field-vchar = VCHAR / obs-text +// obs-text = %x80-FF +// VCHAR = "any visible [USASCII] character" +// +// http2 further says: "Similarly, HTTP/2 allows header field values +// that are not valid. While most of the values that can be encoded +// will not alter header field parsing, carriage return (CR, ASCII +// 0xd), line feed (LF, ASCII 0xa), and the zero character (NUL, ASCII +// 0x0) might be exploited by an attacker if they are translated +// verbatim. Any request or response that contains a character not +// permitted in a header field value MUST be treated as malformed +// (Section 8.1.2.6). Valid characters are defined by the +// field-content ABNF rule in Section 3.2 of [RFC7230]." +// +// This function does not (yet?) properly handle the rejection of +// strings that begin or end with SP or HTAB. +func ValidHeaderFieldValue(v string) bool { + for i := 0; i < len(v); i++ { + b := v[i] + if isCTL(b) && !isLWS(b) { + return false + } + } + return true +} + +func isASCII(s string) bool { + for i := 0; i < len(s); i++ { + if s[i] >= utf8.RuneSelf { + return false + } + } + return true +} + +// PunycodeHostPort returns the IDNA Punycode version +// of the provided "host" or "host:port" string. +func PunycodeHostPort(v string) (string, error) { + if isASCII(v) { + return v, nil + } + + host, port, err := net.SplitHostPort(v) + if err != nil { + // The input 'v' argument was just a "host" argument, + // without a port. This error should not be returned + // to the caller. + host = v + port = "" + } + host, err = idna.ToASCII(host) + if err != nil { + // Non-UTF-8? Not representable in Punycode, in any + // case. + return "", err + } + if port == "" { + return host, nil + } + return net.JoinHostPort(host, port), nil +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/vendor/modules.txt new/vendor/modules.txt --- old/vendor/modules.txt 2026-10-01 21:45:13.000000000 +0200 +++ new/vendor/modules.txt 2026-10-08 20:01:36.000000000 +0200 @@ -11,7 +11,7 @@ # dario.cat/mergo v1.0.2 ## explicit; go 1.13 dario.cat/mergo -# gitea.dev/actionslib v1.2.1 +# gitea.dev/actionslib v1.3.0 ## explicit; go 1.26.0 gitea.dev/actionslib/ping/v1 gitea.dev/actionslib/ping/v1/pingv1connect @@ -116,7 +116,7 @@ # github.com/distribution/reference v0.6.0 ## explicit; go 1.20 github.com/distribution/reference -# github.com/docker/cli v29.8.1+incompatible +# github.com/docker/cli v29.8.2+incompatible ## explicit github.com/docker/cli/cli/compose/interpolation github.com/docker/cli/cli/compose/loader @@ -166,7 +166,7 @@ github.com/go-git/gcfg/scanner github.com/go-git/gcfg/token github.com/go-git/gcfg/types -# github.com/go-git/go-billy/v5 v5.9.1 +# github.com/go-git/go-billy/v5 v5.9.2 ## explicit; go 1.25.0 github.com/go-git/go-billy/v5 github.com/go-git/go-billy/v5/helper/chroot @@ -517,6 +517,7 @@ # golang.org/x/net v0.59.0 ## explicit; go 1.26.0 golang.org/x/net/context +golang.org/x/net/http/httpguts golang.org/x/net/http/httpproxy golang.org/x/net/idna golang.org/x/net/internal/socks
