Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package rpm2docserv for openSUSE:Factory 
checked in at 2026-07-07 21:06:48
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/rpm2docserv (Old)
 and      /work/SRC/openSUSE:Factory/.rpm2docserv.new.1982 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "rpm2docserv"

Tue Jul  7 21:06:48 2026 rev:26 rq:1364320 version:20260707.78c4c29

Changes:
--------
--- /work/SRC/openSUSE:Factory/rpm2docserv/rpm2docserv.changes  2025-10-31 
16:29:29.613544464 +0100
+++ /work/SRC/openSUSE:Factory/.rpm2docserv.new.1982/rpm2docserv.changes        
2026-07-07 21:09:20.715039266 +0200
@@ -1,0 +2,6 @@
+Tue Jul 07 14:04:30 UTC 2026 - Thorsten Kukuk <[email protected]>
+
+- Update to version 20260707.78c4c29:
+  * Update go dependencies
+
+-------------------------------------------------------------------

Old:
----
  rpm2docserv-20251031.483a2f9.tar.xz

New:
----
  rpm2docserv-20260707.78c4c29.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ rpm2docserv.spec ++++++
--- /var/tmp/diff_new_pack.uU2384/_old  2026-07-07 21:09:22.651106087 +0200
+++ /var/tmp/diff_new_pack.uU2384/_new  2026-07-07 21:09:22.683107192 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package rpm2docserv
 #
-# Copyright (c) 2025 SUSE LLC and contributors
+# Copyright (c) 2026 SUSE LLC and contributors
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -21,7 +21,7 @@
 %endif
 
 Name:           rpm2docserv
-Version:        20251031.483a2f9
+Version:        20260707.78c4c29
 Release:        0
 Summary:        Make manpages from RPMs accessible in a web browser
 License:        Apache-2.0

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.uU2384/_old  2026-07-07 21:09:23.167123897 +0200
+++ /var/tmp/diff_new_pack.uU2384/_new  2026-07-07 21:09:23.203125140 +0200
@@ -1,7 +1,7 @@
 <servicedata>
   <service name="tar_scm">
     <param name="url">https://github.com/thkukuk/rpm2docserv.git</param>
-  <param 
name="changesrevision">483a2f925d713e6d57f11465c1ecd1b9a53f2b81</param></service>
+  <param 
name="changesrevision">78c4c290d5986ac6f490c9e0c03ef88888209a9b</param></service>
 </servicedata>
 (No newline at EOF)
 


++++++ rpm2docserv-20251031.483a2f9.tar.xz -> 
rpm2docserv-20260707.78c4c29.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rpm2docserv-20251031.483a2f9/go.mod 
new/rpm2docserv-20260707.78c4c29/go.mod
--- old/rpm2docserv-20251031.483a2f9/go.mod     2025-10-31 09:31:27.000000000 
+0100
+++ new/rpm2docserv-20260707.78c4c29/go.mod     2026-07-07 16:03:17.000000000 
+0200
@@ -1,15 +1,13 @@
 module github.com/thkukuk/rpm2docserv
 
-go 1.24.0
-
-toolchain go1.24.7
+go 1.25.0
 
 require (
        github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f
-       golang.org/x/net v0.46.0
-       golang.org/x/sync v0.17.0
-       golang.org/x/text v0.30.0
+       golang.org/x/net v0.56.0
+       golang.org/x/sync v0.21.0
+       golang.org/x/text v0.39.0
        gopkg.in/yaml.v3 v3.0.1
 )
 
-require google.golang.org/protobuf v1.36.10
+require google.golang.org/protobuf v1.36.11
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/rpm2docserv-20251031.483a2f9/go.sum 
new/rpm2docserv-20260707.78c4c29/go.sum
--- old/rpm2docserv-20251031.483a2f9/go.sum     2025-10-31 09:31:27.000000000 
+0100
+++ new/rpm2docserv-20260707.78c4c29/go.sum     2026-07-07 16:03:17.000000000 
+0200
@@ -2,14 +2,14 @@
 github.com/google/go-cmp v0.7.0/go.mod 
h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
 github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f 
h1:xt29M2T6STgldg+WEP51gGePQCsQvklmP2eIhPIBK3g=
 github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f/go.mod 
h1:i4sF0l1fFnY1aiw08QQSwVAFxHEm311Me3WsU/X7nL0=
-golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
-golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
-golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
-golang.org/x/sync v0.17.0/go.mod 
h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
-golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
-golang.org/x/text v0.30.0/go.mod 
h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
-google.golang.org/protobuf v1.36.10 
h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
-google.golang.org/protobuf v1.36.10/go.mod 
h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
+golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o=
+golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec=
+golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
+golang.org/x/sync v0.21.0/go.mod 
h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
+golang.org/x/text v0.39.0 h1:UbZz4pLOvn600D6Oh6GGEI6VAmndrEBLv8/6BEXzyus=
+golang.org/x/text v0.39.0/go.mod 
h1:3UwRclnC2g0TU9x8PZiyfOajCd1zaUNHF9cvqcQZ+ZM=
+google.golang.org/protobuf v1.36.11 
h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
+google.golang.org/protobuf v1.36.11/go.mod 
h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 
h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod 
h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

++++++ vendor.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vendor/golang.org/x/net/context/context.go 
new/vendor/golang.org/x/net/context/context.go
--- old/vendor/golang.org/x/net/context/context.go      2025-10-31 
09:31:27.000000000 +0100
+++ new/vendor/golang.org/x/net/context/context.go      2026-07-07 
16:03:17.000000000 +0200
@@ -2,42 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Package context defines the Context type, which carries deadlines,
-// cancellation signals, and other request-scoped values across API boundaries
-// and between processes.
-// As of Go 1.7 this package is available in the standard library under the
-// name [context].
+// Package context has been superseded by the standard library [context] 
package.
 //
-// Incoming requests to a server should create a [Context], and outgoing
-// calls to servers should accept a Context. The chain of function
-// calls between them must propagate the Context, optionally replacing
-// it with a derived Context created using [WithCancel], [WithDeadline],
-// [WithTimeout], or [WithValue].
-//
-// Programs that use Contexts should follow these rules to keep interfaces
-// consistent across packages and enable static analysis tools to check context
-// propagation:
-//
-// Do not store Contexts inside a struct type; instead, pass a Context
-// explicitly to each function that needs it. This is discussed further in
-// https://go.dev/blog/context-and-structs. The Context should be the first
-// parameter, typically named ctx:
-//
-//     func DoSomething(ctx context.Context, arg Arg) error {
-//             // ... use ctx ...
-//     }
-//
-// Do not pass a nil [Context], even if a function permits it. Pass 
[context.TODO]
-// if you are unsure about which Context to use.
-//
-// Use context Values only for request-scoped data that transits processes and
-// APIs, not for passing optional parameters to functions.
-//
-// The same Context may be passed to functions running in different goroutines;
-// Contexts are safe for simultaneous use by multiple goroutines.
-//
-// See https://go.dev/blog/context for example code for a server that uses
-// Contexts.
+// Deprecated: Use the standard library context package instead.
 package context
 
 import (
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vendor/golang.org/x/net/html/entity.go 
new/vendor/golang.org/x/net/html/entity.go
--- old/vendor/golang.org/x/net/html/entity.go  2025-10-31 09:31:27.000000000 
+0100
+++ new/vendor/golang.org/x/net/html/entity.go  2026-07-07 16:03:17.000000000 
+0200
@@ -2156,9 +2156,8 @@
 
 // HTML entities that are two unicode codepoints.
 var entity2 = map[string][2]rune{
-       // TODO(nigeltao): Handle replacements that are wider than their names.
-       // "nLt;":                     {'\u226A', '\u20D2'},
-       // "nGt;":                     {'\u226B', '\u20D2'},
+       "nLt;":                     {'\u226A', '\u20D2'},
+       "nGt;":                     {'\u226B', '\u20D2'},
        "NotEqualTilde;":           {'\u2242', '\u0338'},
        "NotGreaterFullEqual;":     {'\u2267', '\u0338'},
        "NotGreaterGreater;":       {'\u226B', '\u0338'},
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vendor/golang.org/x/net/html/escape.go 
new/vendor/golang.org/x/net/html/escape.go
--- old/vendor/golang.org/x/net/html/escape.go  2025-10-31 09:31:27.000000000 
+0100
+++ new/vendor/golang.org/x/net/html/escape.go  2026-07-07 16:03:17.000000000 
+0200
@@ -6,6 +6,7 @@
 
 import (
        "bytes"
+       "slices"
        "strings"
        "unicode/utf8"
 )
@@ -50,25 +51,24 @@
        // 0x0D->'\u000D' is a no-op.
 }
 
-// unescapeEntity reads an entity like "&lt;" from b[src:] and writes the
-// corresponding "<" to b[dst:], returning the incremented dst and src cursors.
-// Precondition: b[src] == '&' && dst <= src.
-// attribute should be true if parsing an attribute value.
-func unescapeEntity(b []byte, dst, src int, attribute bool) (dst1, src1 int) {
+// unescapeEntity attempts to consume a character reference from s[src:],
+// returning the rune, potential second rune, and number of bytes consumed
+// (which indicates the length of the character reference). It is assumed that
+// the first byte of s is '&'. attribute should be true if parsing an attribute
+// value.
+func unescapeEntity(s []byte, attribute bool) (rune, rune, int) {
        // 
https://html.spec.whatwg.org/multipage/syntax.html#consume-a-character-reference
 
        // i starts at 1 because we already know that s[0] == '&'.
-       i, s := 1, b[src:]
+       i := 1
 
        if len(s) <= 1 {
-               b[dst] = b[src]
-               return dst + 1, src + 1
+               return '&', 0, 1
        }
 
        if s[i] == '#' {
-               if len(s) <= 3 { // We need to have at least "&#.".
-                       b[dst] = b[src]
-                       return dst + 1, src + 1
+               if len(s) <= 2 { // We need to have at least "&#".
+                       return '&', 0, 1
                }
                i++
                c := s[i]
@@ -78,34 +78,43 @@
                        i++
                }
 
+               i0 := i
                x := '\x00'
                for i < len(s) {
                        c = s[i]
-                       i++
+                       var d rune
+                       var mult rune
                        if hex {
+                               mult = 16
                                if '0' <= c && c <= '9' {
-                                       x = 16*x + rune(c) - '0'
-                                       continue
+                                       d = rune(c) - '0'
                                } else if 'a' <= c && c <= 'f' {
-                                       x = 16*x + rune(c) - 'a' + 10
-                                       continue
+                                       d = rune(c) - 'a' + 10
                                } else if 'A' <= c && c <= 'F' {
-                                       x = 16*x + rune(c) - 'A' + 10
-                                       continue
+                                       d = rune(c) - 'A' + 10
+                               } else {
+                                       break
+                               }
+                       } else {
+                               mult = 10
+                               if '0' <= c && c <= '9' {
+                                       d = rune(c) - '0'
+                               } else {
+                                       break
                                }
-                       } else if '0' <= c && c <= '9' {
-                               x = 10*x + rune(c) - '0'
-                               continue
                        }
-                       if c != ';' {
-                               i--
+                       if x <= 0x10FFFF {
+                               x = mult*x + d
                        }
-                       break
+                       i++
                }
 
-               if i <= 3 { // No characters matched.
-                       b[dst] = b[src]
-                       return dst + 1, src + 1
+               if i == i0 { // No characters matched.
+                       return '&', 0, 1
+               }
+
+               if i < len(s) && s[i] == ';' {
+                       i++
                }
 
                if 0x80 <= x && x <= 0x9F {
@@ -116,7 +125,7 @@
                        x = '\uFFFD'
                }
 
-               return dst + utf8.EncodeRune(b[dst:], x), src + i
+               return x, 0, i
        }
 
        // Consume the maximum number of characters possible, with the
@@ -141,10 +150,9 @@
        } else if attribute && entityName[len(entityName)-1] != ';' && len(s) > 
i && s[i] == '=' {
                // No-op.
        } else if x := entity[entityName]; x != 0 {
-               return dst + utf8.EncodeRune(b[dst:], x), src + i
+               return x, 0, i
        } else if x := entity2[entityName]; x[0] != 0 {
-               dst1 := dst + utf8.EncodeRune(b[dst:], x[0])
-               return dst1 + utf8.EncodeRune(b[dst1:], x[1]), src + i
+               return x[0], x[1], i
        } else if !attribute {
                maxLen := len(entityName) - 1
                if maxLen > longestEntityWithoutSemicolon {
@@ -152,35 +160,67 @@
                }
                for j := maxLen; j > 1; j-- {
                        if x := entity[entityName[:j]]; x != 0 {
-                               return dst + utf8.EncodeRune(b[dst:], x), src + 
j + 1
+                               return x, 0, j + 1
                        }
                }
        }
 
-       dst1, src1 = dst+i, src+i
-       copy(b[dst:dst1], b[src:src1])
-       return dst1, src1
+       return '&', 0, 1
 }
 
-// unescape unescapes b's entities in-place, so that "a&lt;b" becomes "a<b".
-// attribute should be true if parsing an attribute value.
+// unescape unescapes b's entites, so that "a&lt;b" becomes "a<b". It attempts
+// to do so in place, but if the unescaped value is longer than the input it
+// allocates a new slice. attribute should be true if parsing an attribute
+// value.
 func unescape(b []byte, attribute bool) []byte {
-       for i, c := range b {
-               if c == '&' {
-                       dst, src := unescapeEntity(b, i, i, attribute)
-                       for src < len(b) {
-                               c := b[src]
-                               if c == '&' {
-                                       dst, src = unescapeEntity(b, dst, src, 
attribute)
-                               } else {
-                                       b[dst] = c
-                                       dst, src = dst+1, src+1
-                               }
+       firstAmp := slices.Index(b, '&')
+       if firstAmp == -1 {
+               return b
+       }
+
+       out := b[:firstAmp]
+       src := firstAmp
+       reusingB := true
+       for src < len(b) {
+               if b[src] != '&' {
+                       out = append(out, b[src])
+                       src++
+                       continue
+               }
+
+               r1, r2, entityNameLen := unescapeEntity(b[src:], attribute)
+               if entityNameLen == 1 && r1 == '&' {
+                       // Not an entity
+                       out = append(out, '&')
+                       src++
+                       continue
+               }
+
+               // Compute replacement length
+               replLen := utf8.RuneLen(r1)
+               if r2 != 0 {
+                       replLen += utf8.RuneLen(r2)
+               }
+
+               // If the name of the entity is shorter than the width of the
+               // replacement runes then we need to expand the output slice to
+               // fit the replacement.
+               if replLen > entityNameLen {
+                       if reusingB {
+                               out = slices.Clone(out)
+                               reusingB = false
                        }
-                       return b[0:dst]
+                       out = slices.Grow(out, replLen)
                }
+               out = utf8.AppendRune(out, r1)
+               if r2 != 0 {
+                       out = utf8.AppendRune(out, r2)
+               }
+
+               src += entityNameLen
        }
-       return b
+
+       return out
 }
 
 // lower lower-cases the A-Z bytes in b in-place, so that "aBc" becomes "abc".
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vendor/golang.org/x/net/html/foreign.go 
new/vendor/golang.org/x/net/html/foreign.go
--- old/vendor/golang.org/x/net/html/foreign.go 2025-10-31 09:31:27.000000000 
+0100
+++ new/vendor/golang.org/x/net/html/foreign.go 2026-07-07 16:03:17.000000000 
+0200
@@ -23,7 +23,7 @@
                }
                switch a.Key {
                case "xlink:actuate", "xlink:arcrole", "xlink:href", 
"xlink:role", "xlink:show",
-                       "xlink:title", "xlink:type", "xml:base", "xml:lang", 
"xml:space", "xmlns:xlink":
+                       "xlink:title", "xlink:type", "xml:lang", "xml:space", 
"xmlns:xlink":
                        j := strings.Index(a.Key, ":")
                        aa[i].Namespace = a.Key[:j]
                        aa[i].Key = a.Key[j+1:]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vendor/golang.org/x/net/html/iter.go 
new/vendor/golang.org/x/net/html/iter.go
--- old/vendor/golang.org/x/net/html/iter.go    2025-10-31 09:31:27.000000000 
+0100
+++ new/vendor/golang.org/x/net/html/iter.go    2026-07-07 16:03:17.000000000 
+0200
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build go1.23
-
 package html
 
 import "iter"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vendor/golang.org/x/net/html/node.go 
new/vendor/golang.org/x/net/html/node.go
--- old/vendor/golang.org/x/net/html/node.go    2025-10-31 09:31:27.000000000 
+0100
+++ new/vendor/golang.org/x/net/html/node.go    2026-07-07 16:03:17.000000000 
+0200
@@ -11,6 +11,7 @@
 // A NodeType is the type of a Node.
 type NodeType uint32
 
+//go:generate stringer -type NodeType
 const (
        ErrorNode NodeType = iota
        TextNode
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vendor/golang.org/x/net/html/nodetype_string.go 
new/vendor/golang.org/x/net/html/nodetype_string.go
--- old/vendor/golang.org/x/net/html/nodetype_string.go 1970-01-01 
01:00:00.000000000 +0100
+++ new/vendor/golang.org/x/net/html/nodetype_string.go 2026-07-07 
16:03:17.000000000 +0200
@@ -0,0 +1,31 @@
+// Code generated by "stringer -type NodeType"; DO NOT EDIT.
+
+package html
+
+import "strconv"
+
+func _() {
+       // An "invalid array index" compiler error signifies that the constant 
values have changed.
+       // Re-run the stringer command to generate them again.
+       var x [1]struct{}
+       _ = x[ErrorNode-0]
+       _ = x[TextNode-1]
+       _ = x[DocumentNode-2]
+       _ = x[ElementNode-3]
+       _ = x[CommentNode-4]
+       _ = x[DoctypeNode-5]
+       _ = x[RawNode-6]
+       _ = x[scopeMarkerNode-7]
+}
+
+const _NodeType_name = 
"ErrorNodeTextNodeDocumentNodeElementNodeCommentNodeDoctypeNodeRawNodescopeMarkerNode"
+
+var _NodeType_index = [...]uint8{0, 9, 17, 29, 40, 51, 62, 69, 84}
+
+func (i NodeType) String() string {
+       idx := int(i) - 0
+       if i < 0 || idx >= len(_NodeType_index)-1 {
+               return "NodeType(" + strconv.FormatInt(int64(i), 10) + ")"
+       }
+       return _NodeType_name[_NodeType_index[idx]:_NodeType_index[idx+1]]
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vendor/golang.org/x/net/html/parse.go 
new/vendor/golang.org/x/net/html/parse.go
--- old/vendor/golang.org/x/net/html/parse.go   2025-10-31 09:31:27.000000000 
+0100
+++ new/vendor/golang.org/x/net/html/parse.go   2026-07-07 16:03:17.000000000 
+0200
@@ -5,9 +5,11 @@
 package html
 
 import (
+       "cmp"
        "errors"
        "fmt"
        "io"
+       "slices"
        "strings"
 
        a "golang.org/x/net/html/atom"
@@ -61,7 +63,7 @@
 // Stop tags for use in popUntil. These come from section 12.2.4.2.
 var (
        defaultScopeStopTags = map[string][]a.Atom{
-               "":     {a.Applet, a.Caption, a.Html, a.Table, a.Td, a.Th, 
a.Marquee, a.Object, a.Template},
+               "":     {a.Applet, a.Caption, a.Html, a.Table, a.Td, a.Th, 
a.Marquee, a.Object, a.Template, a.Select},
                "math": {a.AnnotationXml, a.Mi, a.Mn, a.Mo, a.Ms, a.Mtext},
                "svg":  {a.Desc, a.ForeignObject, a.Title},
        }
@@ -76,7 +78,6 @@
        tableScope
        tableRowScope
        tableBodyScope
-       selectScope
 )
 
 // popUntil pops the stack of open elements at the highest element whose tag
@@ -131,10 +132,6 @@
                                if tagAtom == a.Html || tagAtom == a.Table || 
tagAtom == a.Template {
                                        return -1
                                }
-                       case selectScope:
-                               if tagAtom != a.Optgroup && tagAtom != a.Option 
{
-                                       return -1
-                               }
                        default:
                                panic(fmt.Sprintf("html: internal error: 
indexOfElementInScope unknown scope: %d", s))
                        }
@@ -328,6 +325,14 @@
        })
 }
 
+func attrCompare(a, b Attribute) int {
+       return cmp.Or(
+               cmp.Compare(a.Namespace, b.Namespace),
+               cmp.Compare(a.Key, b.Key),
+               cmp.Compare(a.Val, b.Val),
+       )
+}
+
 // addElement adds a child element based on the current token.
 func (p *parser) addElement() {
        p.addChild(&Node{
@@ -343,6 +348,10 @@
        tagAtom, attr := p.tok.DataAtom, p.tok.Attr
        p.addElement()
 
+       // In order to optimize the search, we need the attributes to be 
sorted, so we
+       // can just use slices.Equal.
+       slices.SortFunc(attr, attrCompare)
+
        // Implement the Noah's Ark clause, but with three per family instead 
of two.
        identicalElements := 0
 findIdenticalElements:
@@ -360,19 +369,7 @@
                if n.DataAtom != tagAtom {
                        continue
                }
-               if len(n.Attr) != len(attr) {
-                       continue
-               }
-       compareAttributes:
-               for _, t0 := range n.Attr {
-                       for _, t1 := range attr {
-                               if t0.Key == t1.Key && t0.Namespace == 
t1.Namespace && t0.Val == t1.Val {
-                                       // Found a match for this attribute, 
continue with the next attribute.
-                                       continue compareAttributes
-                               }
-                       }
-                       // If we get here, there is no attribute that matches a.
-                       // Therefore the element is not identical to the new 
one.
+               if !slices.Equal(n.Attr, attr) {
                        continue findIdenticalElements
                }
 
@@ -382,7 +379,11 @@
                }
        }
 
-       p.afe = append(p.afe, p.top())
+       // Sort the attributes to optimize future identical-element searches.
+       top := p.top()
+       slices.SortFunc(top.Attr, attrCompare)
+
+       p.afe = append(p.afe, top)
 }
 
 // Section 12.2.4.3.
@@ -454,21 +455,6 @@
                }
 
                switch n.DataAtom {
-               case a.Select:
-                       if !last {
-                               for ancestor, first := n, p.oe[0]; ancestor != 
first; {
-                                       ancestor = p.oe[p.oe.index(ancestor)-1]
-                                       switch ancestor.DataAtom {
-                                       case a.Template:
-                                               p.im = inSelectIM
-                                               return
-                                       case a.Table:
-                                               p.im = inSelectInTableIM
-                                               return
-                                       }
-                               }
-                       }
-                       p.im = inSelectIM
                case a.Td, a.Th:
                        // TODO: remove this divergence from the HTML5 spec.
                        //
@@ -996,7 +982,10 @@
                        p.popUntil(buttonScope, a.P)
                        p.addElement()
                case a.Button:
-                       p.popUntil(defaultScope, a.Button)
+                       if p.elementInScope(defaultScope, a.Button) {
+                               p.generateImpliedEndTags()
+                               p.popUntil(defaultScope, a.Button)
+                       }
                        p.reconstructActiveFormattingElements()
                        p.addElement()
                        p.framesetOK = false
@@ -1034,7 +1023,18 @@
                        p.framesetOK = false
                        p.im = inTableIM
                        return true
-               case a.Area, a.Br, a.Embed, a.Img, a.Input, a.Keygen, a.Wbr:
+               case a.Area, a.Br, a.Embed, a.Img, a.Keygen, a.Wbr:
+                       p.reconstructActiveFormattingElements()
+                       p.addElement()
+                       p.oe.pop()
+                       p.acknowledgeSelfClosingTag()
+                       p.framesetOK = false
+               case a.Input:
+                       if p.fragment && p.context.DataAtom == a.Select {
+                               // Ignore the token.
+                               return true
+                       }
+                       p.popUntil(defaultScope, a.Select)
                        p.reconstructActiveFormattingElements()
                        p.addElement()
                        p.oe.pop()
@@ -1055,7 +1055,13 @@
                        p.oe.pop()
                        p.acknowledgeSelfClosingTag()
                case a.Hr:
-                       p.popUntil(buttonScope, a.P)
+                       if p.elementInScope(buttonScope, a.P) {
+                               p.generateImpliedEndTags("p")
+                               p.popUntil(defaultScope, a.P)
+                       }
+                       if p.elementInScope(defaultScope, a.Select) {
+                               p.generateImpliedEndTags()
+                       }
                        p.addElement()
                        p.oe.pop()
                        p.acknowledgeSelfClosingTag()
@@ -1089,13 +1095,30 @@
                        // Don't let the tokenizer go into raw text mode when 
scripting is disabled.
                        p.tokenizer.NextIsNotRawText()
                case a.Select:
+                       if p.fragment && p.context.DataAtom == a.Select {
+                               // Ignore the token.
+                               return true
+                       } else if p.popUntil(defaultScope, a.Select) {
+                               return true
+                       }
                        p.reconstructActiveFormattingElements()
                        p.addElement()
                        p.framesetOK = false
-                       p.im = inSelectIM
                        return true
-               case a.Optgroup, a.Option:
-                       if p.top().DataAtom == a.Option {
+               case a.Option:
+                       if p.elementInScope(defaultScope, a.Select) {
+                               p.generateImpliedEndTags("optgroup")
+                               // If oe has option element in scope, parse 
error?
+                       } else if p.top().DataAtom == a.Option {
+                               p.oe.pop()
+                       }
+                       p.reconstructActiveFormattingElements()
+                       p.addElement()
+               case a.Optgroup:
+                       if p.elementInScope(defaultScope, a.Select) {
+                               p.generateImpliedEndTags()
+                               // If oe has option or optgroup element in 
scope, parse error?
+                       } else if p.top().DataAtom == a.Option {
                                p.oe.pop()
                        }
                        p.reconstructActiveFormattingElements()
@@ -1143,7 +1166,12 @@
                                return false
                        }
                        return true
-               case a.Address, a.Article, a.Aside, a.Blockquote, a.Button, 
a.Center, a.Details, a.Dialog, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, 
a.Figure, a.Footer, a.Header, a.Hgroup, a.Listing, a.Main, a.Menu, a.Nav, a.Ol, 
a.Pre, a.Search, a.Section, a.Summary, a.Ul:
+               case a.Address, a.Article, a.Aside, a.Blockquote, a.Button, 
a.Center, a.Details, a.Dialog, a.Dir, a.Div, a.Dl, a.Fieldset, a.Figcaption, 
a.Figure, a.Footer, a.Header, a.Hgroup, a.Listing, a.Main, a.Menu, a.Nav, a.Ol, 
a.Pre, a.Search, a.Section, a.Select, a.Summary, a.Ul:
+                       if !p.elementInScope(defaultScope, p.tok.DataAtom) {
+                               // Ignore the token.
+                               return true
+                       }
+                       p.generateImpliedEndTags()
                        p.popUntil(defaultScope, p.tok.DataAtom)
                case a.Form:
                        if p.oe.contains(a.Template) {
@@ -1372,8 +1400,6 @@
 }
 
 // inBodyEndTagOther performs the "any other end tag" algorithm for inBodyIM.
-// "Any other end tag" handling from 12.2.6.5 The rules for parsing tokens in 
foreign content
-// https://html.spec.whatwg.org/multipage/syntax.html#parsing-main-inforeign
 func (p *parser) inBodyEndTagOther(tagAtom a.Atom, tagName string) {
        for i := len(p.oe) - 1; i >= 0; i-- {
                // Two element nodes have the same tag if they have the same 
Data (a
@@ -1383,7 +1409,7 @@
                // Uncommon (custom) tags get a zero DataAtom.
                //
                // The if condition here is equivalent to (p.oe[i].Data == 
tagName).
-               if (p.oe[i].DataAtom == tagAtom) &&
+               if p.oe[i].Namespace == "" && (p.oe[i].DataAtom == tagAtom) &&
                        ((tagAtom != 0) || (p.oe[i].Data == tagName)) {
                        p.oe = p.oe[:i]
                        break
@@ -1484,17 +1510,6 @@
                        }
                        p.addElement()
                        p.form = p.oe.pop()
-               case a.Select:
-                       p.reconstructActiveFormattingElements()
-                       switch p.top().DataAtom {
-                       case a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr:
-                               p.fosterParenting = true
-                       }
-                       p.addElement()
-                       p.fosterParenting = false
-                       p.framesetOK = false
-                       p.im = inSelectInTableIM
-                       return true
                }
        case EndTagToken:
                switch p.tok.DataAtom {
@@ -1543,12 +1558,6 @@
                        p.clearActiveFormattingElements()
                        p.im = inTableIM
                        return false
-               case a.Select:
-                       p.reconstructActiveFormattingElements()
-                       p.addElement()
-                       p.framesetOK = false
-                       p.im = inSelectInTableIM
-                       return true
                }
        case EndTagToken:
                switch p.tok.DataAtom {
@@ -1758,12 +1767,6 @@
                        }
                        // Ignore the token.
                        return true
-               case a.Select:
-                       p.reconstructActiveFormattingElements()
-                       p.addElement()
-                       p.framesetOK = false
-                       p.im = inSelectInTableIM
-                       return true
                }
        case EndTagToken:
                switch p.tok.DataAtom {
@@ -1794,118 +1797,6 @@
        return inBodyIM(p)
 }
 
-// Section 12.2.6.4.16.
-func inSelectIM(p *parser) bool {
-       switch p.tok.Type {
-       case TextToken:
-               p.addText(strings.Replace(p.tok.Data, "\x00", "", -1))
-       case StartTagToken:
-               switch p.tok.DataAtom {
-               case a.Html:
-                       return inBodyIM(p)
-               case a.Option:
-                       if p.top().DataAtom == a.Option {
-                               p.oe.pop()
-                       }
-                       p.addElement()
-               case a.Optgroup:
-                       if p.top().DataAtom == a.Option {
-                               p.oe.pop()
-                       }
-                       if p.top().DataAtom == a.Optgroup {
-                               p.oe.pop()
-                       }
-                       p.addElement()
-               case a.Select:
-                       if !p.popUntil(selectScope, a.Select) {
-                               // Ignore the token.
-                               return true
-                       }
-                       p.resetInsertionMode()
-               case a.Input, a.Keygen, a.Textarea:
-                       if p.elementInScope(selectScope, a.Select) {
-                               p.parseImpliedToken(EndTagToken, a.Select, 
a.Select.String())
-                               return false
-                       }
-                       // In order to properly ignore <textarea>, we need to 
change the tokenizer mode.
-                       p.tokenizer.NextIsNotRawText()
-                       // Ignore the token.
-                       return true
-               case a.Script, a.Template:
-                       return inHeadIM(p)
-               case a.Iframe, a.Noembed, a.Noframes, a.Noscript, a.Plaintext, 
a.Style, a.Title, a.Xmp:
-                       // Don't let the tokenizer go into raw text mode when 
there are raw tags
-                       // to be ignored. These tags should be ignored from the 
tokenizer
-                       // properly.
-                       p.tokenizer.NextIsNotRawText()
-                       // Ignore the token.
-                       return true
-               }
-       case EndTagToken:
-               switch p.tok.DataAtom {
-               case a.Option:
-                       if p.top().DataAtom == a.Option {
-                               p.oe.pop()
-                       }
-               case a.Optgroup:
-                       i := len(p.oe) - 1
-                       if p.oe[i].DataAtom == a.Option {
-                               i--
-                       }
-                       if p.oe[i].DataAtom == a.Optgroup {
-                               p.oe = p.oe[:i]
-                       }
-               case a.Select:
-                       if !p.popUntil(selectScope, a.Select) {
-                               // Ignore the token.
-                               return true
-                       }
-                       p.resetInsertionMode()
-               case a.Template:
-                       return inHeadIM(p)
-               }
-       case CommentToken:
-               p.addChild(&Node{
-                       Type: CommentNode,
-                       Data: p.tok.Data,
-               })
-       case DoctypeToken:
-               // Ignore the token.
-               return true
-       case ErrorToken:
-               return inBodyIM(p)
-       }
-
-       return true
-}
-
-// Section 12.2.6.4.17.
-func inSelectInTableIM(p *parser) bool {
-       switch p.tok.Type {
-       case StartTagToken, EndTagToken:
-               switch p.tok.DataAtom {
-               case a.Caption, a.Table, a.Tbody, a.Tfoot, a.Thead, a.Tr, a.Td, 
a.Th:
-                       if p.tok.Type == EndTagToken && 
!p.elementInScope(tableScope, p.tok.DataAtom) {
-                               // Ignore the token.
-                               return true
-                       }
-                       // This is like p.popUntil(selectScope, a.Select), but 
it also
-                       // matches <math select>, not just <select>. Matching 
the MathML
-                       // tag is arguably incorrect (conceptually), but it 
mimics what
-                       // Chromium does.
-                       for i := len(p.oe) - 1; i >= 0; i-- {
-                               if n := p.oe[i]; n.DataAtom == a.Select {
-                                       p.oe = p.oe[:i]
-                                       break
-                               }
-                       }
-                       p.resetInsertionMode()
-                       return false
-               }
-       }
-       return inSelectIM(p)
-}
-
 // Section 12.2.6.4.18.
 func inTemplateIM(p *parser) bool {
        switch p.tok.Type {
@@ -2170,7 +2061,7 @@
 
 const whitespaceOrNUL = whitespace + "\x00"
 
-// Section 12.2.6.5
+// Section 13.2.6.5
 func parseForeignContent(p *parser) bool {
        switch p.tok.Type {
        case TextToken:
@@ -2185,28 +2076,26 @@
                        Data: p.tok.Data,
                })
        case StartTagToken:
-               if !p.fragment {
-                       b := breakout[p.tok.Data]
-                       if p.tok.DataAtom == a.Font {
-                       loop:
-                               for _, attr := range p.tok.Attr {
-                                       switch attr.Key {
-                                       case "color", "face", "size":
-                                               b = true
-                                               break loop
-                                       }
+               b := breakout[p.tok.Data]
+               if p.tok.DataAtom == a.Font {
+               loop:
+                       for _, attr := range p.tok.Attr {
+                               switch attr.Key {
+                               case "color", "face", "size":
+                                       b = true
+                                       break loop
                                }
                        }
-                       if b {
-                               for i := len(p.oe) - 1; i >= 0; i-- {
-                                       n := p.oe[i]
-                                       if n.Namespace == "" || 
htmlIntegrationPoint(n) || mathMLTextIntegrationPoint(n) {
-                                               p.oe = p.oe[:i+1]
-                                               break
-                                       }
+               }
+               if b {
+                       for i := len(p.oe) - 1; i >= 0; i-- {
+                               n := p.oe[i]
+                               if n.Namespace == "" || htmlIntegrationPoint(n) 
|| mathMLTextIntegrationPoint(n) {
+                                       p.oe = p.oe[:i+1]
+                                       break
                                }
-                               return false
                        }
+                       return p.im(p)
                }
                current := p.adjustedCurrentNode()
                switch current.Namespace {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vendor/golang.org/x/net/html/render.go 
new/vendor/golang.org/x/net/html/render.go
--- old/vendor/golang.org/x/net/html/render.go  2025-10-31 09:31:27.000000000 
+0100
+++ new/vendor/golang.org/x/net/html/render.go  2026-07-07 16:03:17.000000000 
+0200
@@ -113,14 +113,14 @@
                                if _, err := w.WriteString(" PUBLIC "); err != 
nil {
                                        return err
                                }
-                               if err := writeQuoted(w, p); err != nil {
+                               if err := writeDoctypeQuoted(w, p); err != nil {
                                        return err
                                }
                                if s != "" {
                                        if err := w.WriteByte(' '); err != nil {
                                                return err
                                        }
-                                       if err := writeQuoted(w, s); err != nil 
{
+                                       if err := writeDoctypeQuoted(w, s); err 
!= nil {
                                                return err
                                        }
                                }
@@ -128,7 +128,7 @@
                                if _, err := w.WriteString(" SYSTEM "); err != 
nil {
                                        return err
                                }
-                               if err := writeQuoted(w, s); err != nil {
+                               if err := writeDoctypeQuoted(w, s); err != nil {
                                        return err
                                }
                        }
@@ -243,27 +243,50 @@
        if n.Namespace != "" {
                return false
        }
+
        switch n.Data {
        case "iframe", "noembed", "noframes", "noscript", "plaintext", 
"script", "style", "xmp":
+               // We need to check if n is a node that was fostered from a 
HTML namespace
+               // into a non-HTML namespace (in which case, different rules 
apply to it).
+               // We do this by walking up the tree until we find a node with 
a non-empty
+               // namespace. If we find such a node, we also have to check if 
it's
+               // an HTML integration point. If it isn't, then the node we're 
currently
+               // looking at is foster-parented and we should return false.
+               for p := n.Parent; p != nil; p = p.Parent {
+                       if p.Namespace != "" {
+                               if !htmlIntegrationPoint(p) {
+                                       return false
+                               }
+                               break
+                       }
+               }
+
                return true
        default:
                return false
        }
 }
 
-// writeQuoted writes s to w surrounded by quotes. Normally it will use double
+// writeDoctypeQuoted writes s to w surrounded by quotes. Normally it will use 
double
 // quotes, but if s contains a double quote, it will use single quotes.
+// If s contains any '>' characters, they are replaced with &gt; in order
+// to prevent triggering an abrupt-doctype-system-identifier parse error.
 // It is used for writing the identifiers in a doctype declaration.
 // In valid HTML, they can't contain both types of quotes.
-func writeQuoted(w writer, s string) error {
+func writeDoctypeQuoted(w writer, s string) error {
        var q byte = '"'
        if strings.Contains(s, `"`) {
+               // parseDoctype will never produce a Node with both quote 
types, but a user
+               // can construct their own Node that violates this assumption.
+               if strings.Contains(s, `'`) {
+                       return errors.New("doctype contains both quote types, 
cannot be safely rendered")
+               }
                q = '\''
        }
        if err := w.WriteByte(q); err != nil {
                return err
        }
-       if _, err := w.WriteString(s); err != nil {
+       if _, err := w.WriteString(strings.ReplaceAll(s, ">", "&gt;")); err != 
nil {
                return err
        }
        if err := w.WriteByte(q); err != nil {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vendor/golang.org/x/net/html/token.go 
new/vendor/golang.org/x/net/html/token.go
--- old/vendor/golang.org/x/net/html/token.go   2025-10-31 09:31:27.000000000 
+0100
+++ new/vendor/golang.org/x/net/html/token.go   2026-07-07 16:03:17.000000000 
+0200
@@ -156,6 +156,7 @@
        // incremented on each call to TagAttr.
        pendingAttr   [2]span
        attr          [][2]span
+       attrNames     map[string]bool
        nAttrReturned int
        // rawTag is the "script" in "</script>" that closes the next token. If
        // non-empty, the subsequent call to Next will return a raw or RCDATA 
text
@@ -703,7 +704,11 @@
        for i := 0; i < 2; i++ {
                c[i] = z.readByte()
                if z.err != nil {
+                       // bogus comment
                        z.data.end = z.raw.end
+                       if i == 1 && c[0] == '>' {
+                               z.data.end--
+                       }
                        return CommentToken
                }
        }
@@ -731,6 +736,13 @@
        for i := 0; i < len(s); i++ {
                c := z.readByte()
                if z.err != nil {
+                       if z.err == io.EOF {
+                               // Back up to read the fragment of "DOCTYPE" 
again, reset
+                               // z.err to signal EOF on the next call
+                               z.raw.end = z.data.start
+                               z.err = nil
+                               return false
+                       }
                        z.data.end = z.raw.end
                        return false
                }
@@ -756,6 +768,13 @@
        for i := 0; i < len(s); i++ {
                c := z.readByte()
                if z.err != nil {
+                       if z.err == io.EOF {
+                               // Back up to read the fragment of "[CDATA[" 
again, reset
+                               // z.err to signal EOF on the next call
+                               z.raw.end = z.data.start
+                               z.err = nil
+                               return false
+                       }
                        z.data.end = z.raw.end
                        return false
                }
@@ -867,6 +886,7 @@
 func (z *Tokenizer) readTag(saveAttr bool) {
        z.attr = z.attr[:0]
        z.nAttrReturned = 0
+       clear(z.attrNames)
        // Read the tag name and attribute key/value pairs.
        z.readTagName()
        if z.skipWhiteSpace(); z.err != nil {
@@ -880,9 +900,11 @@
                z.raw.end--
                z.readTagAttrKey()
                z.readTagAttrVal()
-               // Save pendingAttr if saveAttr and that attribute has a 
non-empty key.
-               if saveAttr && z.pendingAttr[0].start != z.pendingAttr[0].end {
+               // Save pendingAttr if saveAttr and that attribute has a 
non-empty key, and the key hasn't been seen before.
+               key := 
string(lower(bytes.Clone(z.buf[z.pendingAttr[0].start:z.pendingAttr[0].end])))
+               if saveAttr && z.pendingAttr[0].start != z.pendingAttr[0].end 
&& !z.attrNames[key] {
                        z.attr = append(z.attr, z.pendingAttr)
+                       z.attrNames[key] = true
                }
                if z.skipWhiteSpace(); z.err != nil {
                        break
@@ -1202,7 +1224,7 @@
        if z.data.start < z.data.end {
                switch z.tt {
                case StartTagToken, EndTagToken, SelfClosingTagToken:
-                       s := z.buf[z.data.start:z.data.end]
+                       s := bytes.ReplaceAll(z.buf[z.data.start:z.data.end], 
nul, replacement)
                        z.data.start = z.raw.end
                        z.data.end = z.raw.end
                        return lower(s), z.nAttrReturned < len(z.attr)
@@ -1220,8 +1242,8 @@
                case StartTagToken, SelfClosingTagToken:
                        x := z.attr[z.nAttrReturned]
                        z.nAttrReturned++
-                       key = z.buf[x[0].start:x[0].end]
-                       val = z.buf[x[1].start:x[1].end]
+                       key = bytes.ReplaceAll(z.buf[x[0].start:x[0].end], nul, 
replacement)
+                       val = bytes.ReplaceAll(z.buf[x[1].start:x[1].end], nul, 
replacement)
                        return lower(key), unescape(convertNewlines(val), 
true), z.nAttrReturned < len(z.attr)
                }
        }
@@ -1273,13 +1295,27 @@
 // The input is assumed to be UTF-8 encoded.
 func NewTokenizerFragment(r io.Reader, contextTag string) *Tokenizer {
        z := &Tokenizer{
-               r:   r,
-               buf: make([]byte, 0, 4096),
+               r:         r,
+               buf:       make([]byte, 0, 4096),
+               attrNames: make(map[string]bool),
        }
        if contextTag != "" {
+               // Per the "Parsing HTML Fragments" portion of the spec:
+               //    For performance reasons, an implementation that does not 
report errors
+               //    and that uses the actual state machine described in this 
specification
+               //    directly could use the PLAINTEXT state instead of the 
RAWTEXT and script
+               //    data states where those are mentioned in the list above. 
Except for
+               //    rules regarding parse errors, they are equivalent, since 
there is no
+               //    appropriate end tag token in the fragment case, yet they 
involve far
+               //    fewer state transitions.
+               //
+               // As such we just set everything to plaintext, which makes 
some complex parsing
+               // cases somewhat simpler.
                switch s := strings.ToLower(contextTag); s {
-               case "iframe", "noembed", "noframes", "noscript", "plaintext", 
"script", "style", "title", "textarea", "xmp":
+               case "title", "textarea":
                        z.rawTag = s
+               case "style", "xmp", "iframe", "noembed", "noframes", "script", 
"noscript", "plaintext":
+                       z.rawTag = "plaintext"
                }
        }
        return z
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vendor/golang.org/x/sync/errgroup/errgroup.go 
new/vendor/golang.org/x/sync/errgroup/errgroup.go
--- old/vendor/golang.org/x/sync/errgroup/errgroup.go   2025-10-31 
09:31:27.000000000 +0100
+++ new/vendor/golang.org/x/sync/errgroup/errgroup.go   2026-07-07 
16:03:17.000000000 +0200
@@ -3,7 +3,7 @@
 // license that can be found in the LICENSE file.
 
 // Package errgroup provides synchronization, error propagation, and Context
-// cancelation for groups of goroutines working on subtasks of a common task.
+// cancellation for groups of goroutines working on subtasks of a common task.
 //
 // [errgroup.Group] is related to [sync.WaitGroup] but adds handling of tasks
 // returning errors.
@@ -109,7 +109,7 @@
        if g.sem != nil {
                select {
                case g.sem <- token{}:
-                       // Note: this allows barging iff channels in general 
allow barging.
+                       // Note: this allows barging if and only if channels in 
general allow barging.
                default:
                        return false
                }
@@ -144,8 +144,8 @@
                g.sem = nil
                return
        }
-       if len(g.sem) != 0 {
-               panic(fmt.Errorf("errgroup: modify limit while %v goroutines in 
the group are still active", len(g.sem)))
+       if active := len(g.sem); active != 0 {
+               panic(fmt.Errorf("errgroup: modify limit while %v goroutines in 
the group are still active", active))
        }
        g.sem = make(chan token, n)
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/vendor/google.golang.org/protobuf/internal/encoding/tag/tag.go 
new/vendor/google.golang.org/protobuf/internal/encoding/tag/tag.go
--- old/vendor/google.golang.org/protobuf/internal/encoding/tag/tag.go  
2025-10-31 09:31:27.000000000 +0100
+++ new/vendor/google.golang.org/protobuf/internal/encoding/tag/tag.go  
2026-07-07 16:03:17.000000000 +0200
@@ -32,7 +32,7 @@
 func Unmarshal(tag string, goType reflect.Type, evs 
protoreflect.EnumValueDescriptors) protoreflect.FieldDescriptor {
        f := new(filedesc.Field)
        f.L0.ParentFile = filedesc.SurrogateProto2
-       f.L1.EditionFeatures = f.L0.ParentFile.L1.EditionFeatures
+       packed := false
        for len(tag) > 0 {
                i := strings.IndexByte(tag, ',')
                if i < 0 {
@@ -108,7 +108,7 @@
                                f.L1.StringName.InitJSON(jsonName)
                        }
                case s == "packed":
-                       f.L1.EditionFeatures.IsPacked = true
+                       packed = true
                case strings.HasPrefix(s, "def="):
                        // The default tag is special in that everything 
afterwards is the
                        // default regardless of the presence of commas.
@@ -121,6 +121,13 @@
                tag = strings.TrimPrefix(tag[i:], ",")
        }
 
+       // Update EditionFeatures after the loop and after we know whether this 
is
+       // a proto2 or proto3 field.
+       f.L1.EditionFeatures = f.L0.ParentFile.L1.EditionFeatures
+       if packed {
+               f.L1.EditionFeatures.IsPacked = true
+       }
+
        // The generator uses the group message name instead of the field name.
        // We obtain the real field name by lowercasing the group name.
        if f.L1.Kind == protoreflect.GroupKind {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/vendor/google.golang.org/protobuf/internal/encoding/text/decode.go 
new/vendor/google.golang.org/protobuf/internal/encoding/text/decode.go
--- old/vendor/google.golang.org/protobuf/internal/encoding/text/decode.go      
2025-10-31 09:31:27.000000000 +0100
+++ new/vendor/google.golang.org/protobuf/internal/encoding/text/decode.go      
2026-07-07 16:03:17.000000000 +0200
@@ -424,27 +424,34 @@
        return Token{}, d.newSyntaxError("invalid field name: %s", errId(d.in))
 }
 
-// parseTypeName parses Any type URL or extension field name. The name is
-// enclosed in [ and ] characters. The C++ parser does not handle many legal 
URL
-// strings. This implementation is more liberal and allows for the pattern
-// ^[-_a-zA-Z0-9]+([./][-_a-zA-Z0-9]+)*`). Whitespaces and comments are allowed
-// in between [ ], '.', '/' and the sub names.
+// parseTypeName parses an Any type URL or an extension field name. The name is
+// enclosed in [ and ] characters. We allow almost arbitrary type URL prefixes,
+// closely following the text-format spec [1,2]. We implement "ExtensionName |
+// AnyName" as follows (with some exceptions for backwards compatibility):
+//
+// char      = [-_a-zA-Z0-9]
+// url_char  = char | [.~!$&'()*+,;=] | "%", hex, hex
+//
+// Ident         = char, { char }
+// TypeName      = Ident, { ".", Ident } ;
+// UrlPrefix     = url_char, { url_char | "/" } ;
+// ExtensionName = "[", TypeName, "]" ;
+// AnyName       = "[", UrlPrefix, "/", TypeName, "]" ;
+//
+// Additionally, we allow arbitrary whitespace and comments between [ and ].
+//
+// [1] https://protobuf.dev/reference/protobuf/textformat-spec/#characters
+// [2] https://protobuf.dev/reference/protobuf/textformat-spec/#field-names
 func (d *Decoder) parseTypeName() (Token, error) {
-       startPos := len(d.orig) - len(d.in)
        // Use alias s to advance first in order to use d.in for error handling.
-       // Caller already checks for [ as first character.
+       // Caller already checks for [ as first character (d.in[0] == '[').
        s := consume(d.in[1:], 0)
        if len(s) == 0 {
                return Token{}, ErrUnexpectedEOF
        }
 
+       // Collect everything between [ and ] in name.
        var name []byte
-       for len(s) > 0 && isTypeNameChar(s[0]) {
-               name = append(name, s[0])
-               s = s[1:]
-       }
-       s = consume(s, 0)
-
        var closed bool
        for len(s) > 0 && !closed {
                switch {
@@ -452,23 +459,20 @@
                        s = s[1:]
                        closed = true
 
-               case s[0] == '/', s[0] == '.':
-                       if len(name) > 0 && (name[len(name)-1] == '/' || 
name[len(name)-1] == '.') {
-                               return Token{}, d.newSyntaxError("invalid type 
URL/extension field name: %s",
-                                       d.orig[startPos:len(d.orig)-len(s)+1])
-                       }
+               case s[0] == '/' || isTypeNameChar(s[0]) || 
isUrlExtraChar(s[0]):
                        name = append(name, s[0])
-                       s = s[1:]
-                       s = consume(s, 0)
-                       for len(s) > 0 && isTypeNameChar(s[0]) {
-                               name = append(name, s[0])
-                               s = s[1:]
+                       s = consume(s[1:], 0)
+
+               // URL percent-encoded chars
+               case s[0] == '%':
+                       if len(s) < 3 || !isHexChar(s[1]) || !isHexChar(s[2]) {
+                               return Token{}, d.parseTypeNameError(s, 3)
                        }
-                       s = consume(s, 0)
+                       name = append(name, s[0], s[1], s[2])
+                       s = consume(s[3:], 0)
 
                default:
-                       return Token{}, d.newSyntaxError(
-                               "invalid type URL/extension field name: %s", 
d.orig[startPos:len(d.orig)-len(s)+1])
+                       return Token{}, d.parseTypeNameError(s, 1)
                }
        }
 
@@ -476,15 +480,38 @@
                return Token{}, ErrUnexpectedEOF
        }
 
-       // First character cannot be '.'. Last character cannot be '.' or '/'.
-       size := len(name)
-       if size == 0 || name[0] == '.' || name[size-1] == '.' || name[size-1] 
== '/' {
-               return Token{}, d.newSyntaxError("invalid type URL/extension 
field name: %s",
-                       d.orig[startPos:len(d.orig)-len(s)])
+       // Split collected name on last '/' into urlPrefix and typeName (if '/' 
is
+       // present).
+       typeName := name
+       if i := bytes.LastIndexByte(name, '/'); i != -1 {
+               urlPrefix := name[:i]
+               typeName = name[i+1:]
+
+               // urlPrefix may be empty (for backwards compatibility).
+               // If non-empty, it must not start with '/'.
+               if len(urlPrefix) > 0 && urlPrefix[0] == '/' {
+                       return Token{}, d.parseTypeNameError(s, 0)
+               }
+       }
+
+       // typeName must not be empty (note: "" splits to [""]) and all 
identifier
+       // parts must not be empty.
+       for _, ident := range bytes.Split(typeName, []byte{'.'}) {
+               if len(ident) == 0 {
+                       return Token{}, d.parseTypeNameError(s, 0)
+               }
        }
 
+       // typeName must not contain any percent-encoded or special URL chars.
+       for _, b := range typeName {
+               if b == '%' || (b != '.' && isUrlExtraChar(b)) {
+                       return Token{}, d.parseTypeNameError(s, 0)
+               }
+       }
+
+       startPos := len(d.orig) - len(d.in)
+       endPos := len(d.orig) - len(s)
        d.in = s
-       endPos := len(d.orig) - len(d.in)
        d.consume(0)
 
        return Token{
@@ -496,16 +523,32 @@
        }, nil
 }
 
+func (d *Decoder) parseTypeNameError(s []byte, numUnconsumedChars int) error {
+       return d.newSyntaxError(
+               "invalid type URL/extension field name: %s",
+               d.in[:len(d.in)-len(s)+min(numUnconsumedChars, len(s))],
+       )
+}
+
+func isHexChar(b byte) bool {
+       return ('0' <= b && b <= '9') ||
+               ('a' <= b && b <= 'f') ||
+               ('A' <= b && b <= 'F')
+}
+
 func isTypeNameChar(b byte) bool {
-       return (b == '-' || b == '_' ||
+       return b == '-' || b == '_' ||
                ('0' <= b && b <= '9') ||
                ('a' <= b && b <= 'z') ||
-               ('A' <= b && b <= 'Z'))
+               ('A' <= b && b <= 'Z')
 }
 
-func isWhiteSpace(b byte) bool {
+// isUrlExtraChar complements isTypeNameChar with extra characters that we 
allow
+// in URLs but not in type names. Note that '/' is not included so that it can
+// be treated specially.
+func isUrlExtraChar(b byte) bool {
        switch b {
-       case ' ', '\n', '\r', '\t':
+       case '.', '~', '!', '$', '&', '(', ')', '*', '+', ',', ';', '=':
                return true
        default:
                return false
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/vendor/google.golang.org/protobuf/internal/filedesc/desc.go 
new/vendor/google.golang.org/protobuf/internal/filedesc/desc.go
--- old/vendor/google.golang.org/protobuf/internal/filedesc/desc.go     
2025-10-31 09:31:27.000000000 +0100
+++ new/vendor/google.golang.org/protobuf/internal/filedesc/desc.go     
2026-07-07 16:03:17.000000000 +0200
@@ -32,6 +32,7 @@
        EditionProto3      Edition = 999
        Edition2023        Edition = 1000
        Edition2024        Edition = 1001
+       EditionUnstable    Edition = 9999
        EditionUnsupported Edition = 100000
 )
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/vendor/google.golang.org/protobuf/internal/filedesc/desc_lazy.go 
new/vendor/google.golang.org/protobuf/internal/filedesc/desc_lazy.go
--- old/vendor/google.golang.org/protobuf/internal/filedesc/desc_lazy.go        
2025-10-31 09:31:27.000000000 +0100
+++ new/vendor/google.golang.org/protobuf/internal/filedesc/desc_lazy.go        
2026-07-07 16:03:17.000000000 +0200
@@ -330,7 +330,6 @@
                                
md.L1.Extensions.List[extensionIdx].unmarshalFull(v, sb)
                                extensionIdx++
                        case genid.DescriptorProto_Options_field_number:
-                               md.unmarshalOptions(v)
                                rawOptions = appendOptions(rawOptions, v)
                        }
                default:
@@ -356,27 +355,6 @@
        md.L2.Options = 
md.L0.ParentFile.builder.optionsUnmarshaler(&descopts.Message, rawOptions)
 }
 
-func (md *Message) unmarshalOptions(b []byte) {
-       for len(b) > 0 {
-               num, typ, n := protowire.ConsumeTag(b)
-               b = b[n:]
-               switch typ {
-               case protowire.VarintType:
-                       v, m := protowire.ConsumeVarint(b)
-                       b = b[m:]
-                       switch num {
-                       case genid.MessageOptions_MapEntry_field_number:
-                               md.L1.IsMapEntry = protowire.DecodeBool(v)
-                       case 
genid.MessageOptions_MessageSetWireFormat_field_number:
-                               md.L1.IsMessageSet = protowire.DecodeBool(v)
-                       }
-               default:
-                       m := protowire.ConsumeFieldValue(num, typ, b)
-                       b = b[m:]
-               }
-       }
-}
-
 func unmarshalMessageReservedRange(b []byte) (r [2]protoreflect.FieldNumber) {
        for len(b) > 0 {
                num, typ, n := protowire.ConsumeTag(b)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/vendor/google.golang.org/protobuf/internal/genid/descriptor_gen.go 
new/vendor/google.golang.org/protobuf/internal/genid/descriptor_gen.go
--- old/vendor/google.golang.org/protobuf/internal/genid/descriptor_gen.go      
2025-10-31 09:31:27.000000000 +0100
+++ new/vendor/google.golang.org/protobuf/internal/genid/descriptor_gen.go      
2026-07-07 16:03:17.000000000 +0200
@@ -26,6 +26,7 @@
        Edition_EDITION_PROTO3_enum_value          = 999
        Edition_EDITION_2023_enum_value            = 1000
        Edition_EDITION_2024_enum_value            = 1001
+       Edition_EDITION_UNSTABLE_enum_value        = 9999
        Edition_EDITION_1_TEST_ONLY_enum_value     = 1
        Edition_EDITION_2_TEST_ONLY_enum_value     = 2
        Edition_EDITION_99997_TEST_ONLY_enum_value = 99997
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/vendor/google.golang.org/protobuf/internal/impl/codec_map.go 
new/vendor/google.golang.org/protobuf/internal/impl/codec_map.go
--- old/vendor/google.golang.org/protobuf/internal/impl/codec_map.go    
2025-10-31 09:31:27.000000000 +0100
+++ new/vendor/google.golang.org/protobuf/internal/impl/codec_map.go    
2026-07-07 16:03:17.000000000 +0200
@@ -113,6 +113,9 @@
 }
 
 func consumeMap(b []byte, mapv reflect.Value, wtyp protowire.Type, mapi 
*mapInfo, f *coderFieldInfo, opts unmarshalOptions) (out unmarshalOutput, err 
error) {
+       if opts.depth--; opts.depth < 0 {
+               return out, errRecursionDepth
+       }
        if wtyp != protowire.BytesType {
                return out, errUnknown
        }
@@ -170,6 +173,9 @@
 }
 
 func consumeMapOfMessage(b []byte, mapv reflect.Value, wtyp protowire.Type, 
mapi *mapInfo, f *coderFieldInfo, opts unmarshalOptions) (out unmarshalOutput, 
err error) {
+       if opts.depth--; opts.depth < 0 {
+               return out, errRecursionDepth
+       }
        if wtyp != protowire.BytesType {
                return out, errUnknown
        }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/vendor/google.golang.org/protobuf/internal/impl/decode.go 
new/vendor/google.golang.org/protobuf/internal/impl/decode.go
--- old/vendor/google.golang.org/protobuf/internal/impl/decode.go       
2025-10-31 09:31:27.000000000 +0100
+++ new/vendor/google.golang.org/protobuf/internal/impl/decode.go       
2026-07-07 16:03:17.000000000 +0200
@@ -102,8 +102,7 @@
 
 func (mi *MessageInfo) unmarshalPointer(b []byte, p pointer, groupTag 
protowire.Number, opts unmarshalOptions) (out unmarshalOutput, err error) {
        mi.init()
-       opts.depth--
-       if opts.depth < 0 {
+       if opts.depth--; opts.depth < 0 {
                return out, errRecursionDepth
        }
        if flags.ProtoLegacy && mi.isMessageSet {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/vendor/google.golang.org/protobuf/internal/impl/validate.go 
new/vendor/google.golang.org/protobuf/internal/impl/validate.go
--- old/vendor/google.golang.org/protobuf/internal/impl/validate.go     
2025-10-31 09:31:27.000000000 +0100
+++ new/vendor/google.golang.org/protobuf/internal/impl/validate.go     
2026-07-07 16:03:17.000000000 +0200
@@ -68,9 +68,13 @@
        if in.Resolver == nil {
                in.Resolver = protoregistry.GlobalTypes
        }
+       if in.Depth == 0 {
+               in.Depth = protowire.DefaultRecursionLimit
+       }
        o, st := mi.validate(in.Buf, 0, unmarshalOptions{
                flags:    in.Flags,
                resolver: in.Resolver,
+               depth:    in.Depth,
        })
        if o.initialized {
                out.Flags |= protoiface.UnmarshalInitialized
@@ -257,6 +261,9 @@
                states[0].typ = validationTypeGroup
                states[0].endGroup = groupTag
        }
+       if opts.depth--; opts.depth < 0 {
+               return out, ValidationInvalid
+       }
        initialized := true
        start := len(b)
 State:
@@ -451,6 +458,13 @@
                                                mi:      vi.mi,
                                                tail:    b,
                                        })
+                                       if vi.typ == validationTypeMessage ||
+                                               vi.typ == validationTypeGroup ||
+                                               vi.typ == validationTypeMap {
+                                               if opts.depth--; opts.depth < 0 
{
+                                                       return out, 
ValidationInvalid
+                                               }
+                                       }
                                        b = v
                                        continue State
                                case validationTypeRepeatedVarint:
@@ -499,6 +513,9 @@
                                                mi:       vi.mi,
                                                endGroup: num,
                                        })
+                                       if opts.depth--; opts.depth < 0 {
+                                               return out, ValidationInvalid
+                                       }
                                        continue State
                                case flags.ProtoLegacy && vi.typ == 
validationTypeMessageSetItem:
                                        typeid, v, n, err := 
messageset.ConsumeFieldValue(b, false)
@@ -521,6 +538,13 @@
                                                        mi:   xvi.mi,
                                                        tail: b[n:],
                                                })
+                                               if xvi.typ == 
validationTypeMessage ||
+                                                       xvi.typ == 
validationTypeGroup ||
+                                                       xvi.typ == 
validationTypeMap {
+                                                       if opts.depth--; 
opts.depth < 0 {
+                                                               return out, 
ValidationInvalid
+                                                       }
+                                               }
                                                b = v
                                                continue State
                                        }
@@ -547,12 +571,14 @@
                switch st.typ {
                case validationTypeMessage, validationTypeGroup:
                        numRequiredFields = int(st.mi.numRequiredFields)
+                       opts.depth++
                case validationTypeMap:
                        // If this is a map field with a message value that 
contains
                        // required fields, require that the value be present.
                        if st.mi != nil && st.mi.numRequiredFields > 0 {
                                numRequiredFields = 1
                        }
+                       opts.depth++
                }
                // If there are more than 64 required fields, this check will
                // always fail and we will report that the message is 
potentially
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/vendor/google.golang.org/protobuf/internal/version/version.go 
new/vendor/google.golang.org/protobuf/internal/version/version.go
--- old/vendor/google.golang.org/protobuf/internal/version/version.go   
2025-10-31 09:31:27.000000000 +0100
+++ new/vendor/google.golang.org/protobuf/internal/version/version.go   
2026-07-07 16:03:17.000000000 +0200
@@ -52,7 +52,7 @@
 const (
        Major      = 1
        Minor      = 36
-       Patch      = 10
+       Patch      = 11
        PreRelease = ""
 )
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vendor/google.golang.org/protobuf/proto/decode.go 
new/vendor/google.golang.org/protobuf/proto/decode.go
--- old/vendor/google.golang.org/protobuf/proto/decode.go       2025-10-31 
09:31:27.000000000 +0100
+++ new/vendor/google.golang.org/protobuf/proto/decode.go       2026-07-07 
16:03:17.000000000 +0200
@@ -121,9 +121,8 @@
 
                out, err = methods.Unmarshal(in)
        } else {
-               o.RecursionLimit--
-               if o.RecursionLimit < 0 {
-                       return out, errors.New("exceeded max recursion depth")
+               if o.RecursionLimit--; o.RecursionLimit < 0 {
+                       return out, errRecursionDepth
                }
                err = o.unmarshalMessageSlow(b, m)
        }
@@ -220,6 +219,9 @@
 }
 
 func (o UnmarshalOptions) unmarshalMap(b []byte, wtyp protowire.Type, mapv 
protoreflect.Map, fd protoreflect.FieldDescriptor) (n int, err error) {
+       if o.RecursionLimit--; o.RecursionLimit < 0 {
+               return 0, errRecursionDepth
+       }
        if wtyp != protowire.BytesType {
                return 0, errUnknown
        }
@@ -305,3 +307,5 @@
 var errUnknown = errors.New("BUG: internal error (unknown)")
 
 var errDecode = errors.New("cannot parse invalid wire-format data")
+
+var errRecursionDepth = errors.New("exceeded maximum recursion depth")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/vendor/modules.txt new/vendor/modules.txt
--- old/vendor/modules.txt      2025-10-31 09:31:27.000000000 +0100
+++ new/vendor/modules.txt      2026-07-07 16:03:17.000000000 +0200
@@ -1,23 +1,23 @@
 # github.com/knqyf263/go-rpm-version v0.0.0-20240918084003-2afd7dc6a38f
 ## explicit
 github.com/knqyf263/go-rpm-version
-# golang.org/x/net v0.46.0
-## explicit; go 1.24.0
+# golang.org/x/net v0.56.0
+## explicit; go 1.25.0
 golang.org/x/net/context
 golang.org/x/net/html
 golang.org/x/net/html/atom
-# golang.org/x/sync v0.17.0
-## explicit; go 1.24.0
+# golang.org/x/sync v0.21.0
+## explicit; go 1.25.0
 golang.org/x/sync/errgroup
-# golang.org/x/text v0.30.0
-## explicit; go 1.24.0
+# golang.org/x/text v0.39.0
+## explicit; go 1.25.0
 golang.org/x/text/internal/format
 golang.org/x/text/internal/language
 golang.org/x/text/internal/language/compact
 golang.org/x/text/internal/tag
 golang.org/x/text/language
 golang.org/x/text/language/display
-# google.golang.org/protobuf v1.36.10
+# google.golang.org/protobuf v1.36.11
 ## explicit; go 1.23
 google.golang.org/protobuf/encoding/prototext
 google.golang.org/protobuf/encoding/protowire

Reply via email to