Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package melange for openSUSE:Factory checked 
in at 2026-10-12 22:06:04
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/melange (Old)
 and      /work/SRC/openSUSE:Factory/.melange.new.3698736 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "melange"

Mon Oct 12 22:06:04 2026 rev:184 rq:1384146 version:0.62.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/melange/melange.changes  2026-10-08 
12:00:00.433518526 +0200
+++ /work/SRC/openSUSE:Factory/.melange.new.3698736/melange.changes     
2026-10-12 22:06:22.114184468 +0200
@@ -1,0 +2,14 @@
+Mon Oct 12 04:46:13 UTC 2026 - Johannes Kastl 
<[email protected]>
+
+- Update to version 0.62.1:
+  * sca: use libcrypto.so.4 for go-msft 1.26.9+ via
+    microsoft_toolset_version (#2694)
+  * sca: drop obsolete experiments (#2693)
+  * linter: recognise -docs and versioned -doc-<version> as doc
+    packages (#2686)
+  * fix(renovate): read the yam config from the config file's
+    repository (#2690)
+  * build(deps): bump golang.org/x/sync (#2691)
+  * build(deps): bump github.com/go-git/go-git/v5 (#2687)
+
+-------------------------------------------------------------------

Old:
----
  melange-0.62.0.obscpio

New:
----
  melange-0.62.1.obscpio

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

Other differences:
------------------
++++++ melange.spec ++++++
--- /var/tmp/diff_new_pack.ju0HfL/_old  2026-10-12 22:06:24.547286129 +0200
+++ /var/tmp/diff_new_pack.ju0HfL/_new  2026-10-12 22:06:24.549286212 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           melange
-Version:        0.62.0
+Version:        0.62.1
 Release:        0
 Summary:        Build APKs from source code
 License:        Apache-2.0

++++++ _service ++++++
--- /var/tmp/diff_new_pack.ju0HfL/_old  2026-10-12 22:06:24.595288134 +0200
+++ /var/tmp/diff_new_pack.ju0HfL/_new  2026-10-12 22:06:24.599288301 +0200
@@ -3,7 +3,7 @@
     <param name="url">https://github.com/chainguard-dev/melange.git</param>
     <param name="scm">git</param>
     <param name="exclude">.git</param>
-    <param name="revision">refs/tags/v0.62.0</param>
+    <param name="revision">refs/tags/v0.62.1</param>
     <param name="versionformat">@PARENT_TAG@</param>
     <param name="versionrewrite-pattern">v(.*)</param>
     <param name="changesgenerate">enable</param>

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.ju0HfL/_old  2026-10-12 22:06:24.621289220 +0200
+++ /var/tmp/diff_new_pack.ju0HfL/_new  2026-10-12 22:06:24.626289429 +0200
@@ -3,6 +3,6 @@
                 <param 
name="url">https://github.com/chainguard-dev/melange</param>
               <param 
name="changesrevision">3f6115b820985d70ca3c93cdf8519c1b3b4cfe81</param></service><service
 name="tar_scm">
                 <param 
name="url">https://github.com/chainguard-dev/melange.git</param>
-              <param 
name="changesrevision">0ae0a5c52b587563b72755df1c7520b082712517</param></service></servicedata>
+              <param 
name="changesrevision">88faac23efa1fae08a915518e6782a455d5dfd3f</param></service></servicedata>
 (No newline at EOF)
 

++++++ melange-0.62.0.obscpio -> melange-0.62.1.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/melange-0.62.0/go.mod new/melange-0.62.1/go.mod
--- old/melange-0.62.0/go.mod   2026-10-07 22:14:27.000000000 +0200
+++ new/melange-0.62.1/go.mod   2026-10-11 13:26:29.000000000 +0200
@@ -13,7 +13,7 @@
        github.com/dprotaso/go-yit v0.0.0-20250513224043-18a80f8f6df4
        github.com/dustin/go-humanize v1.1.0
        github.com/github/go-spdx/v2 v2.7.0
-       github.com/go-git/go-git/v5 v5.19.2
+       github.com/go-git/go-git/v5 v5.19.3
        github.com/google/go-cmp v0.7.0
        github.com/google/go-containerregistry v0.22.1
        github.com/google/go-licenses/v2 v2.0.1
@@ -43,7 +43,7 @@
        go.yaml.in/yaml/v2 v2.4.4
        golang.org/x/crypto v0.57.0
        golang.org/x/exp v0.0.0-20260908205506-85c1c2202aba
-       golang.org/x/sync v0.23.0
+       golang.org/x/sync v0.24.0
        golang.org/x/sys v0.48.0
        golang.org/x/term v0.46.0
        golang.org/x/text v0.42.0
@@ -96,7 +96,7 @@
        github.com/erofs/go-erofs v0.3.2-0.20260804074615-52cc42c5291c // 
indirect
        github.com/felixge/httpsnoop v1.1.0 // indirect
        github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
-       github.com/go-git/go-billy/v5 v5.9.1 // indirect
+       github.com/go-git/go-billy/v5 v5.9.2 // indirect
        github.com/go-jose/go-jose/v3 v3.0.5 // indirect
        github.com/go-logfmt/logfmt v0.6.1 // indirect
        github.com/go-logr/logr v1.4.4 // indirect
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/melange-0.62.0/go.sum new/melange-0.62.1/go.sum
--- old/melange-0.62.0/go.sum   2026-10-07 22:14:27.000000000 +0200
+++ new/melange-0.62.1/go.sum   2026-10-11 13:26:29.000000000 +0200
@@ -123,12 +123,12 @@
 github.com/gliderlabs/ssh v0.3.8/go.mod 
h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
 github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 
h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
 github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod 
h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
-github.com/go-git/go-billy/v5 v5.9.1 
h1:8U73XiOTfINdItHVa6z4Gv7ToObcZ6grkqQbLryLCdA=
-github.com/go-git/go-billy/v5 v5.9.1/go.mod 
h1:ExsU+jcGwXTBOnyilvAnEM1wug1IxHr4yP2ZXsNRtV0=
+github.com/go-git/go-billy/v5 v5.9.2 
h1:OXFSRyz4g20upsGDJgQG9Bak1l/ZEv8GHVYB52O71sE=
+github.com/go-git/go-billy/v5 v5.9.2/go.mod 
h1:ExsU+jcGwXTBOnyilvAnEM1wug1IxHr4yP2ZXsNRtV0=
 github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 
h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
 github.com/go-git/go-git-fixtures/v4 
v4.3.2-0.20231010084843-55a94097c399/go.mod 
h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
-github.com/go-git/go-git/v5 v5.19.2 
h1:wkfn7vOlUBu8ivAWKBWisTiwJK4jYHzTF8Ndv1LyGqY=
-github.com/go-git/go-git/v5 v5.19.2/go.mod 
h1:QqCBE1EFN5ddFmrliLQ3/ntRCUjZU3EJuwuB/jWEHjk=
+github.com/go-git/go-git/v5 v5.19.3 
h1:qHttbZ+Am7wEjdTpR1XMQ4rl42FK9SIXzZ4o9x7s6M4=
+github.com/go-git/go-git/v5 v5.19.3/go.mod 
h1:Ye4C8dVigkqrv9UsB4NMdSLV4yAIkLiIhW61gcOyhl4=
 github.com/go-jose/go-jose/v3 v3.0.5 
h1:BLLJWbC4nMZOfuPVxoZIxeYsn6Nl2r1fITaJ78UQlVQ=
 github.com/go-jose/go-jose/v3 v3.0.5/go.mod 
h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ=
 github.com/go-logfmt/logfmt v0.6.1 
h1:4hvbpePJKnIzH1B+8OR/JPbTx37NktoI9LE2QZBBkvE=
@@ -429,8 +429,8 @@
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod 
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod 
h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.23.0 h1:KameEIfc1IkluZyXWLn39Wd4tURc6GbCiISGiZm2bQk=
-golang.org/x/sync v0.23.0/go.mod 
h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0=
+golang.org/x/sync v0.24.0 h1:iqiDrGoDgyuvAKrhLQthUEzU/R378N78gXbBjxed7oA=
+golang.org/x/sync v0.24.0/go.mod 
h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod 
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod 
h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod 
h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/melange-0.62.0/pkg/linter/linter_test.go 
new/melange-0.62.1/pkg/linter/linter_test.go
--- old/melange-0.62.0/pkg/linter/linter_test.go        2026-10-07 
22:14:27.000000000 +0200
+++ new/melange-0.62.1/pkg/linter/linter_test.go        2026-10-11 
13:26:29.000000000 +0200
@@ -309,6 +309,64 @@
                pkgname: "regular-doc",
                pass:    true,
        }, {
+               // Plural. jujutsu-docs and squashfs-tools-docs both ship this 
way.
+               dirFunc: mkfile(t, "usr/share/man/man1/foo.1"),
+               linter:  "maninfo",
+               pkgname: "regular-docs",
+               pass:    true,
+       }, {
+               // Version-streamed doc subpackage, the shape split/manpages
+               // produces for a versioned package: podman-doc-6.1,
+               // pdns-auth-doc-5.0.
+               dirFunc: mkfile(t, "usr/share/man/man1/foo.1"),
+               linter:  "maninfo",
+               pkgname: "podman-doc-6.1",
+               pass:    true,
+       }, {
+               // A date, not a dotted version: dwarf-tools-doc-20210528.
+               dirFunc: mkfile(t, "usr/share/man/man1/foo.1"),
+               linter:  "maninfo",
+               pkgname: "dwarf-tools-doc-20210528",
+               pass:    true,
+       }, {
+               dirFunc: mkfile(t, "usr/share/man/man1/foo.1"),
+               linter:  "maninfo",
+               pkgname: "regular-docs-5.0",
+               pass:    true,
+       }, {
+               // A version before -doc is the common case and already worked:
+               // rust-1.95-doc.
+               dirFunc: mkfile(t, "usr/share/info/test.info"),
+               linter:  "maninfo",
+               pkgname: "rust-1.95-doc",
+               pass:    true,
+       }, {
+               // Must still fail. "-doc" has to be a whole trailing component,
+               // not a prefix of the last word.
+               dirFunc: mkfile(t, "usr/share/man/man1/foo.1"),
+               linter:  "maninfo",
+               pkgname: "foo-document",
+               pass:    false,
+       }, {
+               // Must still fail: no separator before "doc".
+               dirFunc: mkfile(t, "usr/share/man/man1/foo.1"),
+               linter:  "maninfo",
+               pkgname: "docker",
+               pass:    false,
+       }, {
+               // Must still fail: -man is deliberately not treated as a doc
+               // package. caddy-man is the only instance in the tree.
+               dirFunc: mkfile(t, "usr/share/man/man1/foo.1"),
+               linter:  "maninfo",
+               pkgname: "caddy-man",
+               pass:    false,
+       }, {
+               // Must still fail: a trailing version alone is not a doc 
package.
+               dirFunc: mkfile(t, "usr/share/man/man1/foo.1"),
+               linter:  "maninfo",
+               pkgname: "openstack-barbican-2026.1",
+               pass:    false,
+       }, {
                dirFunc: mkfile(t, "usr/share/man/man8/bar.8.gz"),
                linter:  "maninfo",
                pkgname: "regular-package",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/melange-0.62.0/pkg/linter/linters/maninfo.go 
new/melange-0.62.1/pkg/linter/linters/maninfo.go
--- old/melange-0.62.0/pkg/linter/linters/maninfo.go    2026-10-07 
22:14:27.000000000 +0200
+++ new/melange-0.62.1/pkg/linter/linters/maninfo.go    2026-10-11 
13:26:29.000000000 +0200
@@ -18,13 +18,37 @@
        "context"
        "fmt"
        "io/fs"
-       "strings"
+       "regexp"
 
        "chainguard.dev/melange/pkg/config"
 )
 
+// docPackageRegex matches the names of packages whose job is to hold
+// documentation, and which this linter therefore skips.
+//
+// A plain HasSuffix(pkgname, "-doc") test is too narrow for two naming
+// shapes already in wide use, and it fails them while they are doing
+// exactly the right thing:
+//
+//   - the plural, "-docs": jujutsu-docs, squashfs-tools-docs
+//   - a version-streamed doc subpackage, "<name>-doc-<version>", which is
+//     what a versioned package produces when it splits its manual pages:
+//     podman-doc-6.1, pdns-auth-doc-5.0, dwarf-tools-doc-20210528
+//
+// Measured over the 433 packages in one repository that ship manual pages:
+// the suffix test flags 50 of them, and 10 of those 50 -- 962 of the 1,036
+// pages -- are correctly packaged documentation caught by one of the two
+// shapes above. So 93% of what the narrow test reports is noise, which is
+// the main reason this linter has not been promoted out of the warn set.
+//
+// Deliberately not matched: "-man". A package holding only manual pages is
+// arguably a documentation package whatever it is called, but "-doc" is the
+// convention split/manpages produces, and widening the rule to a second
+// word trades a little noise for a weaker check.
+var docPackageRegex = regexp.MustCompile(`-docs?(?:-[0-9][a-zA-Z0-9.]*)?$`)
+
 func ManInfoLinter(ctx context.Context, _ *config.Configuration, pkgname 
string, fsys fs.FS) error {
-       if strings.HasSuffix(pkgname, "-doc") {
+       if docPackageRegex.MatchString(pkgname) {
                return nil
        }
        return AllPaths(ctx, pkgname, fsys,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/melange-0.62.0/pkg/renovate/renovate.go 
new/melange-0.62.1/pkg/renovate/renovate.go
--- old/melange-0.62.0/pkg/renovate/renovate.go 2026-10-07 22:14:27.000000000 
+0200
+++ new/melange-0.62.1/pkg/renovate/renovate.go 2026-10-11 13:26:29.000000000 
+0200
@@ -16,10 +16,16 @@
 
 import (
        "context"
+       "errors"
+       "fmt"
+       "io"
+       "io/fs"
        "os"
+       "path/filepath"
        "runtime"
        "strconv"
 
+       "github.com/chainguard-dev/yam/pkg/util"
        "github.com/chainguard-dev/yam/pkg/yam/formatted"
 
        apko_types "chainguard.dev/apko/pkg/build/types"
@@ -127,7 +133,10 @@
        }
        defer configFile.Close()
 
-       enc := formatted.NewEncoder(configFile).AutomaticConfig()
+       enc, err := rc.encoder(configFile)
+       if err != nil {
+               return err
+       }
 
        if err := enc.Encode(rc.Configuration.Root().Content[0]); err != nil {
                return err
@@ -135,3 +144,45 @@
 
        return nil
 }
+
+// encoder returns a yam encoder configured from the nearest .yam.yaml at or
+// above the config file's directory, so the output follows the formatting
+// rules of the repository the file lives in rather than whatever happens to
+// be in the process working directory. Callers such as bots run with a
+// working directory outside the checkout; without this they wrote with no
+// gap expressions, which drops the blank line before a comment block and
+// makes yaml.v3 re-attach the block to the next item on the next parse.
+// When no .yam.yaml is found, fall back to yam's own lookup in the working
+// directory to preserve the existing CLI behaviour.
+func (rc *RenovationContext) encoder(w io.Writer) (formatted.Encoder, error) {
+       dir, err := filepath.Abs(filepath.Dir(rc.Context.ConfigFile))
+       if err != nil {
+               return formatted.Encoder{}, err
+       }
+
+       for {
+               path := filepath.Join(dir, util.ConfigFileName)
+               f, err := os.Open(path)
+               if err == nil {
+                       defer f.Close()
+                       opts, err := formatted.ReadConfigFrom(f)
+                       if err != nil {
+                               return formatted.Encoder{}, fmt.Errorf("reading 
%s: %w", path, err)
+                       }
+                       if opts.Indent == 0 {
+                               // Match the yam CLI default when the config 
omits indent.
+                               opts.Indent = 2
+                       }
+                       return formatted.NewEncoder(w).UseOptions(*opts)
+               }
+               if !errors.Is(err, fs.ErrNotExist) {
+                       return formatted.Encoder{}, err
+               }
+
+               parent := filepath.Dir(dir)
+               if parent == dir {
+                       return formatted.NewEncoder(w).AutomaticConfig(), nil
+               }
+               dir = parent
+       }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/melange-0.62.0/pkg/renovate/renovate_test.go 
new/melange-0.62.1/pkg/renovate/renovate_test.go
--- old/melange-0.62.0/pkg/renovate/renovate_test.go    1970-01-01 
01:00:00.000000000 +0100
+++ new/melange-0.62.1/pkg/renovate/renovate_test.go    2026-10-11 
13:26:29.000000000 +0200
@@ -0,0 +1,153 @@
+// Copyright 2026 Chainguard, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package renovate
+
+import (
+       "os"
+       "path/filepath"
+       "testing"
+
+       "github.com/google/go-cmp/cmp"
+       "gopkg.in/yaml.v3"
+)
+
+// A config whose pipeline has a comment block with a blank line on each
+// side. yaml.v3 stores the trailing blank line inside the head comment of
+// the next item; with gap expressions yam reproduces the layout, without
+// them it emits "comment, blank line, item", which yaml.v3 parses next time
+// as a foot comment on that item's first key.
+const commentedConfig = `package:
+  name: example
+  version: 1.0.0
+  epoch: 0
+  description: example package
+
+environment:
+  contents:
+    packages:
+      - busybox
+
+pipeline:
+  - runs: |
+      echo first
+
+  # A note about the next step, kept as a standalone block.
+  # It spans two lines.
+
+  - runs: |
+      echo second
+`
+
+const yamConfig = `gap:
+  - "."
+  - ".pipeline"
+indent: 2
+`
+
+func writeFile(t *testing.T, path, content string) {
+       t.Helper()
+       if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
+               t.Fatal(err)
+       }
+       if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
+               t.Fatal(err)
+       }
+}
+
+// renovateNoop runs Renovate with no renovators, which only re-encodes the
+// file, and returns the result.
+func renovateNoop(t *testing.T, configPath string) string {
+       t.Helper()
+       rctx, err := New(WithConfig(configPath))
+       if err != nil {
+               t.Fatal(err)
+       }
+       if err := rctx.Renovate(t.Context()); err != nil {
+               t.Fatal(err)
+       }
+       out, err := os.ReadFile(configPath)
+       if err != nil {
+               t.Fatal(err)
+       }
+       return string(out)
+}
+
+func TestWriteConfig_UsesRepositoryYamConfig(t *testing.T) {
+       // The test binary's working directory is this package directory, which
+       // has no .yam.yaml, so AutomaticConfig would find nothing.
+       if _, err := os.Stat(".yam.yaml"); err == nil {
+               t.Fatal("unexpected .yam.yaml in the test working directory")
+       }
+
+       t.Run("config next to the file", func(t *testing.T) {
+               dir := t.TempDir()
+               configPath := filepath.Join(dir, "example.yaml")
+               writeFile(t, filepath.Join(dir, ".yam.yaml"), yamConfig)
+               writeFile(t, configPath, commentedConfig)
+
+               got := renovateNoop(t, configPath)
+               if diff := cmp.Diff(commentedConfig, got); diff != "" {
+                       t.Errorf("layout changed (-want +got):\n%s", diff)
+               }
+       })
+
+       t.Run("config in a parent directory", func(t *testing.T) {
+               dir := t.TempDir()
+               configPath := filepath.Join(dir, "os", "example.yaml")
+               writeFile(t, filepath.Join(dir, ".yam.yaml"), yamConfig)
+               writeFile(t, configPath, commentedConfig)
+
+               got := renovateNoop(t, configPath)
+               if diff := cmp.Diff(commentedConfig, got); diff != "" {
+                       t.Errorf("layout changed (-want +got):\n%s", diff)
+               }
+       })
+
+       t.Run("second pass keeps the comment above its step", func(t 
*testing.T) {
+               dir := t.TempDir()
+               configPath := filepath.Join(dir, "example.yaml")
+               writeFile(t, filepath.Join(dir, ".yam.yaml"), yamConfig)
+               writeFile(t, configPath, commentedConfig)
+
+               renovateNoop(t, configPath)
+               got := renovateNoop(t, configPath)
+
+               var root yaml.Node
+               if err := yaml.Unmarshal([]byte(got), &root); err != nil {
+                       t.Fatalf("second pass produced invalid YAML: %v\n%s", 
err, got)
+               }
+               if diff := cmp.Diff(commentedConfig, got); diff != "" {
+                       t.Errorf("second pass changed the layout (-want 
+got):\n%s", diff)
+               }
+       })
+
+       t.Run("without any yam config the gaps are lost", func(t *testing.T) {
+               // Control case documenting the behaviour this change avoids: 
with no
+               // .yam.yaml reachable, the encoder has no gap expressions and 
the blank
+               // line before the comment block disappears.
+               dir := t.TempDir()
+               configPath := filepath.Join(dir, "example.yaml")
+               writeFile(t, configPath, commentedConfig)
+
+               got := renovateNoop(t, configPath)
+               if got == commentedConfig {
+                       t.Skip("working directory supplied a yam config; 
control case not applicable")
+               }
+               var root yaml.Node
+               if err := yaml.Unmarshal([]byte(got), &root); err != nil {
+                       t.Fatalf("no-config pass produced invalid YAML: 
%v\n%s", err, got)
+               }
+       })
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/melange-0.62.0/pkg/sca/e2e_test.go 
new/melange-0.62.1/pkg/sca/e2e_test.go
--- old/melange-0.62.0/pkg/sca/e2e_test.go      2026-10-07 22:14:27.000000000 
+0200
+++ new/melange-0.62.1/pkg/sca/e2e_test.go      2026-10-11 13:26:29.000000000 
+0200
@@ -25,29 +25,6 @@
        "chainguard.dev/melange/pkg/config"
 )
 
-func TestGoFipsBinDeps(t *testing.T) {
-       ctx := slogtest.Context(t)
-       th := handleFromApk(ctx, t, 
"generated/x86_64/go-fips-bin-0.0.1-r0.apk", "go-fips-bin/go-fips-bin.yaml")
-       defer th.exp.Close()
-
-       got := config.Dependencies{}
-       if err := Analyze(ctx, th, &got); err != nil {
-               t.Fatal(err)
-       }
-       want := config.Dependencies{
-               Runtime: []string{
-                       "openssl-config-fipshardened",
-                       "so:ld-linux-x86-64.so.2",
-                       "so:libc.so.6",
-                       "so:libcrypto.so.3",
-               },
-               Provides: []string{"cmd:go-fips-bin=0.0.1-r0"},
-       }
-       if diff := cmp.Diff(want, got); diff != "" {
-               t.Errorf("Analyze(): (-want, +got):\n%s", diff)
-       }
-}
-
 func TestAnalyze(t *testing.T) {
        for _, c := range []struct {
                apk     string
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/melange-0.62.0/pkg/sca/sca.go 
new/melange-0.62.1/pkg/sca/sca.go
--- old/melange-0.62.0/pkg/sca/sca.go   2026-10-07 22:14:27.000000000 +0200
+++ new/melange-0.62.1/pkg/sca/sca.go   2026-10-11 13:26:29.000000000 +0200
@@ -707,7 +707,6 @@
                }
                var dlopen, fipscrypto, fipsgeomys, geomysv1, geomysesv bool
                libcrypto := "so:libcrypto.so.3"
-               fipsexperiments := []string{"boringcrypto", "systemcrypto", 
"opensslcrypto"}
                geomysesvs := []string{"openssl+geomys", "geomys"}
                for _, setting := range buildinfo.Settings {
                        // go-msft-1.26 imlements dlopen with cgo
@@ -732,16 +731,15 @@
                        if setting.Key == "GOFIPS140" && setting.Value == 
"v1.0.0-c2097c7c" {
                                geomysv1 = true
                        }
-                       // obsolete and now removed, keep for now
-                       if setting.Key == "GOEXPERIMENT" && 
slices.Contains(fipsexperiments, setting.Value) {
-                               fipscrypto = true
-                       }
                        if setting.Key == "microsoft_systemcrypto" && 
setting.Value == "1" {
                                fipscrypto = true
                        }
                        if setting.Key == "chainguard_go_package" && 
goSupportsLibcrypto4(setting.Value) {
                                libcrypto = "so:libcrypto.so.4"
                        }
+                       if setting.Key == "microsoft_toolset_version" && 
msftToolsetSupportsLibcrypto4(setting.Value) {
+                               libcrypto = "so:libcrypto.so.4"
+                       }
                }
                // strong indication of go with openssl compiled binary, will 
dlopen the below at runtime
                if dlopen && fipscrypto {
@@ -808,6 +806,48 @@
        return apk.CompareVersions(ver, minGoMsftLibcrypto4) >= 0
 }
 
+// 1.26.9 is the first go-msft-1.26 toolset version where every Chainguard
+// build carries the libcrypto.so.4 backport. The backport landed in
+// 1.26.8.1-r2, but microsoft_toolset_version can't tell 1.26.8.1-r1 from -r2
+// (both report go1.26.8-microsoft), so 1.26.8 binaries keep libcrypto.so.3.
+// That's safe at runtime: the backport probes libcrypto.so.4 first and falls
+// back to libcrypto.so.3.
+//
+// microsoft_toolset_version is emitted by upstream microsoft/go too, while the
+// libcrypto.so.4 support in 1.26 is a Chainguard backport. A prebuilt upstream
+// Microsoft Go 1.26.9+ FIPS binary vendored into a package would therefore be
+// tagged libcrypto.so.4 even though it only loads libcrypto.so.3.
+var (
+       goMsft126Stream        = mustParseVersion("1.26")
+       minGoMsft126Libcrypto4 = mustParseVersion("1.26.9")
+)
+
+// msftToolsetSupportsLibcrypto4 reports whether the go toolchain recorded in
+// the microsoft_toolset_version build setting (e.g. go1.26.9-microsoft)
+// supports the libcrypto.so.4 ABI. Only the 1.26 stream is handled here;
+// 1.27 and later are detected via chainguard_go_package instead.
+func msftToolsetSupportsLibcrypto4(toolset string) bool {
+       rest, ok := strings.CutPrefix(toolset, "go")
+       if !ok {
+               return false
+       }
+       version, _, _ := strings.Cut(rest, "-")
+       major, minor, ok := strings.Cut(version, ".")
+       if !ok {
+               return false
+       }
+       minor, _, _ = strings.Cut(minor, ".")
+       streamVer, err := apk.ParseVersion(major + "." + minor)
+       if err != nil || apk.CompareVersions(streamVer, goMsft126Stream) != 0 {
+               return false
+       }
+       ver, err := apk.ParseVersion(version)
+       if err != nil {
+               return false
+       }
+       return apk.CompareVersions(ver, minGoMsft126Libcrypto4) >= 0
+}
+
 // TODO(xnox): Note remove this feature flag, once successful
 // note this can generate depends on pc: files that do not exist in
 // wolfi, however package install tests will catch that in presubmit
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/melange-0.62.0/pkg/sca/sca_test.go 
new/melange-0.62.1/pkg/sca/sca_test.go
--- old/melange-0.62.0/pkg/sca/sca_test.go      2026-10-07 22:14:27.000000000 
+0200
+++ new/melange-0.62.1/pkg/sca/sca_test.go      2026-10-11 13:26:29.000000000 
+0200
@@ -15,7 +15,6 @@
 //go:generate go run ./../../ build --generate-index=false 
--out-dir=./testdata/generated ./testdata/nvidia-driver.yaml --arch=x86_64
 //go:generate go run ./../../ build --generate-index=false 
--out-dir=./testdata/generated ./testdata/ld-so-conf-d-test.yaml --arch=x86_64
 //go:generate go run ./../../ build --generate-index=false 
--out-dir=./testdata/generated ./testdata/shbang-test.yaml --arch=x86_64
-//go:generate go run ./../../ build --generate-index=false 
--source-dir=./testdata/go-fips-bin/ --out-dir=./testdata/generated 
./testdata/go-fips-bin/go-fips-bin.yaml --arch=x86_64
 //go:generate curl -s -o ./testdata/py3-seaborn.yaml 
https://raw.githubusercontent.com/wolfi-dev/os/7a39ac1d0603a3561790ea2201dd8ad7c2b7e51e/py3-seaborn.yaml
 //go:generate curl -s -o ./testdata/systemd.yaml 
https://raw.githubusercontent.com/wolfi-dev/os/7a39ac1d0603a3561790ea2201dd8ad7c2b7e51e/systemd.yaml
 
@@ -335,32 +334,6 @@
        }
 }
 
-func TestGoFipsSca(t *testing.T) {
-       ctx := slogtest.Context(t)
-       th := handleFromApk(ctx, t, 
"generated/x86_64/go-fips-bin-0.0.1-r0.apk", "go-fips-bin/go-fips-bin.yaml")
-       defer th.exp.Close()
-
-       got := config.Dependencies{}
-       if err := Analyze(ctx, th, &got); err != nil {
-               t.Fatal(err)
-       }
-
-       want := config.Dependencies{
-               Runtime: []string{
-                       "openssl-config-fipshardened",
-                       "so:ld-linux-x86-64.so.2",
-                       "so:libc.so.6",
-                       "so:libcrypto.so.3",
-               },
-               Provides: []string{
-                       "cmd:go-fips-bin=0.0.1-r0",
-               },
-       }
-       if diff := cmp.Diff(want, got); diff != "" {
-               t.Errorf("Analyze(): (-want, +got):\n%s", diff)
-       }
-}
-
 func TestGoMsftSca(t *testing.T) {
        ctx := slogtest.Context(t)
        th := handleFromApk(ctx, t, 
"generated/x86_64/go-msft-bin-0.0.1-r0.apk", "go-fips-bin/go-msft-bin.yaml")
@@ -564,3 +537,26 @@
                }
        }
 }
+
+func TestMsftToolsetSupportsLibcrypto4(t *testing.T) {
+       for _, tc := range []struct {
+               toolset string
+               want    bool
+       }{
+               {"", false},
+               {"go1.26.9", true},
+               {"go1.26.8-microsoft", false},
+               {"go1.26.9-microsoft", true},
+               {"go1.26.10-microsoft", true},
+               {"go1.26.9.1-microsoft", true},
+               {"go1.25.20-microsoft", false},
+               {"go1.27.1-microsoft", false},
+               {"go1.260.1-microsoft", false},
+               {"1.26.9-microsoft", false},
+               {"gogarbage", false},
+       } {
+               if got := msftToolsetSupportsLibcrypto4(tc.toolset); got != 
tc.want {
+                       t.Errorf("msftToolsetSupportsLibcrypto4(%q) = %v, want 
%v", tc.toolset, got, tc.want)
+               }
+       }
+}
Binary files 
old/melange-0.62.0/pkg/sca/testdata/generated/x86_64/go-fips-bin-0.0.1-r0.apk 
and 
new/melange-0.62.1/pkg/sca/testdata/generated/x86_64/go-fips-bin-0.0.1-r0.apk 
differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/melange-0.62.0/pkg/sca/testdata/go-fips-bin/go-fips-bin.yaml 
new/melange-0.62.1/pkg/sca/testdata/go-fips-bin/go-fips-bin.yaml
--- old/melange-0.62.0/pkg/sca/testdata/go-fips-bin/go-fips-bin.yaml    
2026-10-07 22:14:27.000000000 +0200
+++ new/melange-0.62.1/pkg/sca/testdata/go-fips-bin/go-fips-bin.yaml    
1970-01-01 01:00:00.000000000 +0100
@@ -1,30 +0,0 @@
-# SPDX-FileCopyrightText: 2022 Chainguard, Inc
-# SPDX-License-Identifier: Apache-2.0
-#
-# This is a sample configuration file to demonstrate how to build a software
-# project using melange's built-in go/install pipeline.
-#
-# For more information about melange's built-in golang support check out:
-#
-#
-# For an equivalent pipeline that uses go/install to build the same project
-# please see go-install.yaml in this directory.
-package:
-  name: go-fips-bin
-  version: 0.0.1
-  epoch: 0
-  description: "A tiny fips-like go binary"
-
-environment:
-  contents:
-    keyring:
-      - https://packages.wolfi.dev/os/wolfi-signing.rsa.pub
-    repositories:
-      - https://packages.wolfi.dev/os
-
-pipeline:
-  - uses: go/install
-    with:
-      package: .
-      # This is an approximation to the real go-fips toolchain
-      experiments: boringcrypto

++++++ melange.obsinfo ++++++
--- /var/tmp/diff_new_pack.ju0HfL/_old  2026-10-12 22:06:25.862341075 +0200
+++ /var/tmp/diff_new_pack.ju0HfL/_new  2026-10-12 22:06:25.865341200 +0200
@@ -1,5 +1,5 @@
 name: melange
-version: 0.62.0
-mtime: 1791404067
-commit: 0ae0a5c52b587563b72755df1c7520b082712517
+version: 0.62.1
+mtime: 1791717989
+commit: 88faac23efa1fae08a915518e6782a455d5dfd3f
 

++++++ vendor.tar.gz ++++++
/work/SRC/openSUSE:Factory/melange/vendor.tar.gz 
/work/SRC/openSUSE:Factory/.melange.new.3698736/vendor.tar.gz differ: char 30, 
line 1

Reply via email to