Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package apko for openSUSE:Factory checked in at 2026-04-30 20:28:32 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/apko (Old) and /work/SRC/openSUSE:Factory/.apko.new.30200 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "apko" Thu Apr 30 20:28:32 2026 rev:110 rq:1350135 version:1.2.9 Changes: -------- --- /work/SRC/openSUSE:Factory/apko/apko.changes 2026-04-25 21:37:18.845631893 +0200 +++ /work/SRC/openSUSE:Factory/.apko.new.30200/apko.changes 2026-04-30 20:28:36.574430630 +0200 @@ -1,0 +2,20 @@ +Thu Apr 30 05:08:39 UTC 2026 - Johannes Kastl <[email protected]> + +- Update to version 1.2.9: + * build(deps): bump chainguard.dev/sdk from 0.1.52 to 0.1.54 + (#2199) + * build(deps): bump goreleaser/goreleaser-action from 7.0.0 to + 7.1.0 (#2198) + * build(deps): bump github.com/invopop/jsonschema from 0.13.0 to + 0.14.0 (#2197) + * apk: verify package data hash against .PKGINFO for completeness + (#2206) + * ci: bump golangci-lint to v2.11 and clear new findings (#2205) + * testdata: refresh apko-discover lock for rotated chainguard key + (#2203) + * chore(zizmor): trigger zizmor on updates to dependabot config + [PSEC-871] (#2186) +- Update to version 1.2.8: + * release: fetch full history for goreleaser changelog (#2192) + +------------------------------------------------------------------- Old: ---- apko-1.2.7.obscpio New: ---- apko-1.2.9.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ apko.spec ++++++ --- /var/tmp/diff_new_pack.XROMIC/_old 2026-04-30 20:28:37.998488460 +0200 +++ /var/tmp/diff_new_pack.XROMIC/_new 2026-04-30 20:28:38.002488623 +0200 @@ -17,7 +17,7 @@ Name: apko -Version: 1.2.7 +Version: 1.2.9 Release: 0 Summary: Build OCI images from APK packages directly without Dockerfile License: Apache-2.0 ++++++ _service ++++++ --- /var/tmp/diff_new_pack.XROMIC/_old 2026-04-30 20:28:38.082491872 +0200 +++ /var/tmp/diff_new_pack.XROMIC/_new 2026-04-30 20:28:38.098492522 +0200 @@ -3,7 +3,7 @@ <param name="url">https://github.com/chainguard-dev/apko.git</param> <param name="scm">git</param> <param name="exclude">.git</param> - <param name="revision">refs/tags/v1.2.7</param> + <param name="revision">refs/tags/v1.2.9</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> <param name="changesgenerate">enable</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.XROMIC/_old 2026-04-30 20:28:38.162495121 +0200 +++ /var/tmp/diff_new_pack.XROMIC/_new 2026-04-30 20:28:38.166495283 +0200 @@ -3,6 +3,6 @@ <param name="url">https://github.com/chainguard-dev/apko</param> <param name="changesrevision">861f83f69e6fa9114405a2f7bb5cf6585ad00421</param></service><service name="tar_scm"> <param name="url">https://github.com/chainguard-dev/apko.git</param> - <param name="changesrevision">a118c3d604107532b5525bd4bee2fb369a6228aa</param></service></servicedata> + <param name="changesrevision">312a1507941c846eadc2ff22d1e2e1f7d82bebe7</param></service></servicedata> (No newline at EOF) ++++++ apko-1.2.7.obscpio -> apko-1.2.9.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-1.2.7/go.mod new/apko-1.2.9/go.mod --- old/apko-1.2.7/go.mod 2026-04-23 21:44:30.000000000 +0200 +++ new/apko-1.2.9/go.mod 2026-04-28 21:09:36.000000000 +0200 @@ -3,7 +3,7 @@ go 1.25.7 require ( - chainguard.dev/sdk v0.1.52 + chainguard.dev/sdk v0.1.54 github.com/chainguard-dev/clog v1.8.0 github.com/charmbracelet/log v1.0.0 github.com/go-git/go-git/v5 v5.18.0 @@ -12,7 +12,7 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/hashicorp/go-cleanhttp v0.5.2 github.com/hashicorp/go-retryablehttp v0.7.8 - github.com/invopop/jsonschema v0.13.0 + github.com/invopop/jsonschema v0.14.0 github.com/klauspost/compress v1.18.5 github.com/klauspost/pgzip v1.2.6 github.com/package-url/packageurl-go v0.1.5 @@ -38,7 +38,7 @@ ) require ( - chainguard.dev/go-grpc-kit v0.17.16 // indirect + chainguard.dev/go-grpc-kit v0.17.17 // indirect cloud.google.com/go/auth v0.20.0 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect cloud.google.com/go/compute/metadata v0.9.0 // indirect @@ -91,7 +91,6 @@ github.com/kelseyhightower/envconfig v1.4.0 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.19 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect @@ -102,6 +101,7 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.1 // indirect + github.com/pb33f/ordered-map/v2 v2.3.1 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/pjbgf/sha1cd v0.3.2 // indirect github.com/pkg/errors v0.9.1 // indirect @@ -117,7 +117,6 @@ github.com/spf13/pflag v1.0.10 // indirect github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 // indirect github.com/vbatts/tar-split v0.12.2 // indirect - github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect @@ -125,10 +124,11 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.67.0 // indirect go.opentelemetry.io/otel/metric v1.43.0 // indirect go.yaml.in/yaml/v2 v2.4.4 // indirect + go.yaml.in/yaml/v4 v4.0.0-rc.2 // indirect golang.org/x/crypto v0.49.0 // indirect golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 // indirect golang.org/x/net v0.52.0 // indirect - golang.org/x/text v0.35.0 // indirect + golang.org/x/text v0.36.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260319201613-d00831a3d3e7 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 // indirect google.golang.org/grpc v1.80.0 // indirect diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-1.2.7/go.sum new/apko-1.2.9/go.sum --- old/apko-1.2.7/go.sum 2026-04-23 21:44:30.000000000 +0200 +++ new/apko-1.2.9/go.sum 2026-04-28 21:09:36.000000000 +0200 @@ -1,7 +1,7 @@ -chainguard.dev/go-grpc-kit v0.17.16 h1:Y9RKwZCnrYR3S0K8BiazyOoBrZF+Q7bJWDacfKXz2zg= -chainguard.dev/go-grpc-kit v0.17.16/go.mod h1:0vrfIBJguXNa+EKOUEhx1Fj2aBp8o6A8gAHoidiF8ps= -chainguard.dev/sdk v0.1.52 h1:G1wmZHU8v5E78YlCHuwQH0Hwt4NBBCvCNAFad5FUanQ= -chainguard.dev/sdk v0.1.52/go.mod h1:IZIiUyuNaxTao6mpC/BROsw/dwjl/DmCR/raIT7eK4c= +chainguard.dev/go-grpc-kit v0.17.17 h1:Jwhc0zyUwQbC2hNcsi+YMeUX/JUnM+dXVCkTw6wtPzs= +chainguard.dev/go-grpc-kit v0.17.17/go.mod h1:qn0meP6RtrbLicE1bgBZnnVU9dvX95eLs0x0T6kZ+b4= +chainguard.dev/sdk v0.1.54 h1:xXNB9G0dnMyAjhQ8+vQORa7ns1AlclkhImgCUS7+c7I= +chainguard.dev/sdk v0.1.54/go.mod h1:WeUO5MQTgLtK8ZDcguIymeIO0UuVAyie8aOvM6ulth8= cloud.google.com/go/auth v0.20.0 h1:kXTssoVb4azsVDoUiF8KvxAqrsQcQtB53DcSgta74CA= cloud.google.com/go/auth v0.20.0/go.mod h1:942/yi/itH1SsmpyrbnTMDgGfdy2BUqIKyd0cyYLc5Q= cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= @@ -138,11 +138,10 @@ github.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E= -github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0= +github.com/invopop/jsonschema v0.14.0 h1:MHQqLhvpNUZfw+hM3AZDYK7jxO8FZoQeQM77g8iyZjg= +github.com/invopop/jsonschema v0.14.0/go.mod h1:ygm6C2EaVNMBDPpaPlnOA2pFAxBnxGjFlMZABxm9n2I= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= @@ -162,8 +161,6 @@ github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= @@ -192,6 +189,8 @@ github.com/package-url/packageurl-go v0.1.5/go.mod h1:nKAWB8E6uk1MHqiS/lQb9pYBGH2+mdJ2PJc2s50dQY0= github.com/pavlo-v-chernykh/keystore-go/v4 v4.5.0 h1:2nosf3P75OZv2/ZO/9Px5ZgZ5gbKrzA3joN1QMfOGMQ= github.com/pavlo-v-chernykh/keystore-go/v4 v4.5.0/go.mod h1:lAVhWwbNaveeJmxrxuSTxMgKpF6DjnuVpn6T8WiBwYQ= +github.com/pb33f/ordered-map/v2 v2.3.1 h1:5319HDO0aw4DA4gzi+zv4FXU9UlSs3xGZ40wcP1nBjY= +github.com/pb33f/ordered-map/v2 v2.3.1/go.mod h1:qxFQgd0PkVUtOMCkTapqotNgzRhMPL7VvaHKbd1HnmQ= github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4= @@ -248,8 +247,6 @@ github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701/go.mod h1:P3a5rG4X7tI17Nn3aOIAYr5HbIMukwXG0urG0WuL8OA= github.com/vbatts/tar-split v0.12.2 h1:w/Y6tjxpeiFMR47yzZPlPj/FcPLpXbTUi/9H7d3CPa4= github.com/vbatts/tar-split v0.12.2/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA= -github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc= -github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= @@ -281,6 +278,8 @@ go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= +go.yaml.in/yaml/v4 v4.0.0-rc.2 h1:/FrI8D64VSr4HtGIlUtlFMGsm7H7pWTbj6vOLVZcA6s= +go.yaml.in/yaml/v4 v4.0.0-rc.2/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= @@ -338,8 +337,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= -golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA= +golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= +golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-1.2.7/internal/cli/dot.go new/apko-1.2.9/internal/cli/dot.go --- old/apko-1.2.7/internal/cli/dot.go 2026-04-23 21:44:30.000000000 +0200 +++ new/apko-1.2.9/internal/cli/dot.go 2026-04-28 21:09:36.000000000 +0200 @@ -18,6 +18,7 @@ "context" "errors" "fmt" + "html" "net" "net/http" "os" @@ -515,7 +516,7 @@ cmd.Stdout = &svgBuf if err := cmd.Run(); err != nil { - fmt.Fprintf(w, "error rendering %v: %v", nodes, err) + fmt.Fprintf(w, "error rendering %s: %s", html.EscapeString(strings.Join(nodes, ",")), html.EscapeString(err.Error())) return } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-1.2.7/internal/cli/testdata/apko-discover.lock.json new/apko-1.2.9/internal/cli/testdata/apko-discover.lock.json --- old/apko-1.2.7/internal/cli/testdata/apko-discover.lock.json 2026-04-23 21:44:30.000000000 +0200 +++ new/apko-1.2.9/internal/cli/testdata/apko-discover.lock.json 2026-04-28 21:09:36.000000000 +0200 @@ -23,12 +23,12 @@ "url": "https://apk.cgr.dev/chainguard/chainguard-4be246965c6e2749ccbaeba0582ed0f90c7cb94f4c0397e014b322b8652e3ba4.rsa.pub" }, { - "name": "apk.cgr.dev/chainguard/chainguard-6ea100e7571978828f8455393090cc468e1f22dfc771ad2d26df14e52b73c37f.rsa.pub", - "url": "https://apk.cgr.dev/chainguard/chainguard-6ea100e7571978828f8455393090cc468e1f22dfc771ad2d26df14e52b73c37f.rsa.pub" - }, - { "name": "apk.cgr.dev/chainguard/chainguard-7fb528a64a862d44bbea6069093f1fec29fa864ba7e9754828eeceed3f487239.rsa.pub", "url": "https://apk.cgr.dev/chainguard/chainguard-7fb528a64a862d44bbea6069093f1fec29fa864ba7e9754828eeceed3f487239.rsa.pub" + }, + { + "name": "apk.cgr.dev/chainguard/chainguard-e3fb44d055702ed0dddf0f2acb1a0a07fc6075967092b203c7aac7db801d65f4.rsa.pub", + "url": "https://apk.cgr.dev/chainguard/chainguard-e3fb44d055702ed0dddf0f2acb1a0a07fc6075967092b203c7aac7db801d65f4.rsa.pub" } ], "build_repositories": [], diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-1.2.7/internal/ldso-cache/ldsocache.go new/apko-1.2.9/internal/ldso-cache/ldsocache.go --- old/apko-1.2.7/internal/ldso-cache/ldsocache.go 2026-04-23 21:44:30.000000000 +0200 +++ new/apko-1.2.9/internal/ldso-cache/ldsocache.go 2026-04-28 21:09:36.000000000 +0200 @@ -491,13 +491,8 @@ // extractShlibName extracts a shared library from the string table. func extractShlibName(strtable []byte, startIdx uint32) string { subset := strtable[startIdx:] - terminatorPos := bytes.IndexByte(subset, 0x0) - - if terminatorPos == -1 { - return string(subset) - } - - return string(subset[:terminatorPos]) + name, _, _ := bytes.Cut(subset, []byte{0x0}) + return string(name) } func (cf *LDSOCacheFile) Write(w io.Writer) error { @@ -508,7 +503,7 @@ fileEntryTableSize := int(unsafe.Sizeof(LDSORawCacheHeader{}) + (uintptr(len(cf.Entries)) * unsafe.Sizeof(LDSORawCacheEntry{}))) // Build the string table. - lrcEntries := []LDSORawCacheEntry{} + lrcEntries := make([]LDSORawCacheEntry, 0, len(cf.Entries)) stringTable := []byte{} for _, lib := range cf.Entries { cursor := uint32(fileEntryTableSize) + uint32(len(stringTable)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-1.2.7/pkg/apk/apk/cache.go new/apko-1.2.9/pkg/apk/apk/cache.go --- old/apko-1.2.7/pkg/apk/apk/cache.go 2026-04-23 21:44:30.000000000 +0200 +++ new/apko-1.2.9/pkg/apk/apk/cache.go 2026-04-28 21:09:36.000000000 +0200 @@ -188,7 +188,7 @@ defer span.End() // We don't cache the response for these because they get cached later in cachePackage. - return t.wrapped.Do(request) + return t.wrapped.Do(request) //#nosec G704 -- transport wrapper executes caller-provided request } return &http.Response{ @@ -213,7 +213,7 @@ v, err, _ := t.cache.headFlight.Do(cacheFile, func() (any, error) { req := request.Clone(request.Context()) req.Method = http.MethodHead - resp, err := t.wrapped.Do(req) + resp, err := t.wrapped.Do(req) //#nosec G704 -- transport wrapper executes caller-provided request if err != nil { return nil, err } @@ -278,7 +278,7 @@ etag, ok := etagFromResponse(resp) if !ok { - return t.wrapped.Do(request) + return t.wrapped.Do(request) //#nosec G704 -- transport wrapper executes caller-provided request } initialEtag = etag @@ -295,7 +295,7 @@ return nil, err } - f, err := os.Open(etagFile) + f, err := os.Open(etagFile) //#nosec G304 G703 -- etagFile is sanitized by cacheFileFromEtag to stay within cacheDir if err != nil { return nil, fmt.Errorf("open(%q): %w", etagFile, err) } @@ -421,7 +421,7 @@ if t.wrapped == nil { return "", fmt.Errorf("wrapped client is nil") } - resp, err := t.wrapped.Do(request) + resp, err := t.wrapped.Do(request) //#nosec G704 -- transport wrapper executes caller-provided request if err != nil { return "", err } else if resp.StatusCode != 200 { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-1.2.7/pkg/apk/apk/install_test.go new/apko-1.2.9/pkg/apk/apk/install_test.go --- old/apko-1.2.7/pkg/apk/apk/install_test.go 2026-04-23 21:44:30.000000000 +0200 +++ new/apko-1.2.9/pkg/apk/apk/install_test.go 2026-04-28 21:09:36.000000000 +0200 @@ -22,6 +22,7 @@ "crypto/sha1" //nolint:gosec // this is what apk tools is using "crypto/sha256" "encoding/base64" + "encoding/hex" "fmt" "io" "io/fs" @@ -163,13 +164,13 @@ fp1 := fakePackage(t, pkg, []testDirEntry{ {"etc", 0o755, true, nil, nil}, {overwriteFilename, 0o755, false, originalContent, nil}, - }) + }, "") pkg2 := &Package{Name: "second", Origin: "second"} fp2 := fakePackage(t, pkg2, []testDirEntry{ {"etc", 0o755, true, nil, nil}, {overwriteFilename, 0o755, false, finalContent, nil}, - }) + }, "") _, err = apk.InstallPackages(context.Background(), nil, []InstallablePackage{fp1, fp2}) require.Error(t, err, "some double-write error") @@ -192,13 +193,13 @@ fp1 := fakePackage(t, pkg, []testDirEntry{ {"etc", 0755, true, nil, nil}, {overwriteFilename, 0755, false, originalContent, nil}, - }) + }, "") pkg2 := &Package{Name: "second", Origin: "second", Replaces: []string{"first"}} fp2 := fakePackage(t, pkg2, []testDirEntry{ {"etc", 0755, true, nil, nil}, {overwriteFilename, 0755, false, finalContent, nil}, - }) + }, "") _, err = apk.InstallPackages(context.Background(), nil, []InstallablePackage{fp1, fp2}) require.NoError(t, err) @@ -221,13 +222,13 @@ fp1 := fakePackage(t, pkg, []testDirEntry{ {"etc", 0o755, true, nil, nil}, {overwriteFilename, 0o755, false, originalContent, nil}, - }) + }, "") pkg2 := &Package{Name: "first-compat", Origin: "first"} fp2 := fakePackage(t, pkg2, []testDirEntry{ {"etc", 0o755, true, nil, nil}, {overwriteFilename, 0o755, false, finalContent, nil}, - }) + }, "") _, err = apk.InstallPackages(context.Background(), nil, []InstallablePackage{fp1, fp2}) require.NoError(t, err) @@ -249,13 +250,13 @@ fp1 := fakePackage(t, pkg, []testDirEntry{ {"etc", 0o755, true, nil, nil}, {overwriteFilename, 0o755, false, originalContent, nil}, - }) + }, "") pkg2 := &Package{Name: "second", Origin: "second"} fp2 := fakePackage(t, pkg2, []testDirEntry{ {"etc", 0o755, true, nil, nil}, {overwriteFilename, 0o755, false, originalContent, nil}, - }) + }, "") _, err = apk.InstallPackages(context.Background(), nil, []InstallablePackage{fp1, fp2}) require.NoError(t, err) @@ -278,13 +279,13 @@ fp1 := fakePackage(t, pkg, []testDirEntry{ {"etc", 0755, true, nil, nil}, {overwriteFilename, 0755, false, originalContent, nil}, - }) + }, "") pkg2 := &Package{Name: "second", Origin: "second"} fp2 := fakePackage(t, pkg2, []testDirEntry{ {"etc", 0755, true, nil, nil}, {overwriteFilename, 0755, false, finalContent, nil}, - }) + }, "") _, err = apk.InstallPackages(context.Background(), nil, []InstallablePackage{fp1, fp2}) require.NoError(t, err) @@ -349,73 +350,52 @@ return t.checksum } -func fakePackage(t *testing.T, pkg *Package, entries []testDirEntry) InstallablePackage { +// fakePackage builds a well-formed synthetic APK. If dataHashOverride is +// non-empty it is written into .PKGINFO as the datahash instead of the real +// computed SHA-256 (use "" for a correctly-formed package). +func fakePackage(t *testing.T, pkg *Package, entries []testDirEntry, dataHashOverride string) *testPackage { t.Helper() - dir := t.TempDir() - f, err := os.CreateTemp(dir, pkg.Name) - if err != nil { - t.Fatal(err) - } - - h := sha1.New() //nolint:gosec + // Pass 1: compute data section bytes and SHA-256. + var dataBuf bytes.Buffer dh := sha256.New() + dataZw := gzip.NewWriter(io.MultiWriter(&dataBuf, dh)) + dataTw := tar.NewWriter(dataZw) + require.NoError(t, writeFiles(dataTw, entries)) + require.NoError(t, dataTw.Close()) + require.NoError(t, dataZw.Close()) + dataHash := hex.EncodeToString(dh.Sum(nil)) + if dataHashOverride != "" { + dataHash = dataHashOverride + } + pkg.DataHash = dataHash - mw := io.MultiWriter(f, h) + // Pass 2: write control section (with datahash now set) then data bytes. + f, err := os.CreateTemp(t.TempDir(), pkg.Name+"*.apk") + require.NoError(t, err) - zw := gzip.NewWriter(mw) - tw := tar.NewWriter(zw) + h := sha1.New() //nolint:gosec + ctlZw := gzip.NewWriter(io.MultiWriter(f, h)) + ctlTw := tar.NewWriter(ctlZw) - tmpl := template.New("control") var b bytes.Buffer - if err := template.Must(tmpl.Parse(controlTemplate)).Execute(&b, pkg); err != nil { - t.Fatal(err) - } - - if err := tw.WriteHeader(&tar.Header{ + require.NoError(t, template.Must(template.New("control").Parse(controlTemplate)).Execute(&b, pkg)) + require.NoError(t, ctlTw.WriteHeader(&tar.Header{ Name: ".PKGINFO", Typeflag: tar.TypeReg, Size: int64(b.Len()), - }); err != nil { - t.Fatal(err) - } - - if _, err := tw.Write(b.Bytes()); err != nil { - t.Fatal(err) - } - - if err := tw.Flush(); err != nil { - t.Fatal(err) - } - - if err := zw.Close(); err != nil { - t.Fatal(err) - } - - mw = io.MultiWriter(f, dh) - zw.Reset(mw) - - if err := writeFiles(tw, entries); err != nil { - t.Fatal(err) - } - - if err := tw.Close(); err != nil { - t.Fatal(err) - } - - if err := zw.Close(); err != nil { - t.Fatal(err) - } - - if err := f.Close(); err != nil { - t.Fatal(err) - } - - pkg.DataHash = base64.StdEncoding.EncodeToString(dh.Sum(nil)) + })) + _, err = ctlTw.Write(b.Bytes()) + require.NoError(t, err) + require.NoError(t, ctlTw.Close()) + require.NoError(t, ctlZw.Close()) + _, err = io.Copy(f, &dataBuf) + require.NoError(t, err) + require.NoError(t, f.Close()) return &testPackage{ - pkg: pkg, file: f.Name(), + pkg: pkg, checksum: "Q1" + base64.StdEncoding.EncodeToString(h.Sum(nil)), } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-1.2.7/pkg/apk/apk/installed_test.go new/apko-1.2.9/pkg/apk/apk/installed_test.go --- old/apko-1.2.7/pkg/apk/apk/installed_test.go 2026-04-23 21:44:30.000000000 +0200 +++ new/apko-1.2.9/pkg/apk/apk/installed_test.go 2026-04-28 21:09:36.000000000 +0200 @@ -1098,7 +1098,7 @@ t.Fatalf("package %s not found installed in %s\n", c.pkgName, c.installedFile) } - got := []string{} + got := make([]string, 0, len(installedPkg.Files)) for _, i := range installedPkg.Files { got = append(got, i.Name) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-1.2.7/pkg/apk/apk/package_getter.go new/apko-1.2.9/pkg/apk/apk/package_getter.go --- old/apko-1.2.7/pkg/apk/apk/package_getter.go 2026-04-23 21:44:30.000000000 +0200 +++ new/apko-1.2.9/pkg/apk/apk/package_getter.go 2026-04-28 21:09:36.000000000 +0200 @@ -170,9 +170,34 @@ return nil, fmt.Errorf("expanding %s: %w", pkg.PackageName(), err) } - if err := verifyControlHash(pkg, exp.ControlHash); err != nil { + chk := pkg.ChecksumString() + if !strings.HasPrefix(chk, "Q1") { _ = exp.Close() - return nil, err + return nil, fmt.Errorf("package %q has unexpected checksum format: %q", pkg.PackageName(), chk) + } + expectedControlHash, err := base64.StdEncoding.DecodeString(chk[2:]) + if err != nil { + _ = exp.Close() + return nil, fmt.Errorf("package %q has malformed checksum %q: %w", pkg.PackageName(), chk, err) + } + if !bytes.Equal(expectedControlHash, exp.ControlHash) { + _ = exp.Close() + return nil, fmt.Errorf("package %q control hash mismatch: expected %x, got %x", pkg.PackageName(), expectedControlHash, exp.ControlHash) + } + + pkgInfo, err := exp.PkgInfo() + if err != nil { + _ = exp.Close() + return nil, fmt.Errorf("reading pkginfo for %s: %w", pkg.PackageName(), err) + } + expectedDataHash, err := hex.DecodeString(pkgInfo.DataHash) + if err != nil { + _ = exp.Close() + return nil, fmt.Errorf("package %q has malformed datahash %q: %w", pkg.PackageName(), pkgInfo.DataHash, err) + } + if !bytes.Equal(expectedDataHash, exp.PackageHash) { + _ = exp.Close() + return nil, fmt.Errorf("package %q data hash mismatch: expected %x, got %x", pkg.PackageName(), expectedDataHash, exp.PackageHash) } // If we don't have a cache, we're done. @@ -197,29 +222,6 @@ return h.Sum(nil), nil } -// verifyControlHash compares the SHA-1 of the downloaded package's control -// section against the Q1-prefixed base64 checksum recorded in the signed -// APKINDEX (or lock file). Without this check a compromised mirror or -// poisoned cache could substitute arbitrary package contents even though -// the index itself is signature-verified. -func verifyControlHash(pkg InstallablePackage, controlHash []byte) error { - chk := pkg.ChecksumString() - if !strings.HasPrefix(chk, "Q1") { - return fmt.Errorf("package %q has unexpected checksum format: %q", pkg.PackageName(), chk) - } - expected, err := base64.StdEncoding.DecodeString(chk[2:]) - if err != nil { - return fmt.Errorf("package %q has malformed checksum %q: %w", pkg.PackageName(), chk, err) - } - if len(expected) == 0 { - return fmt.Errorf("package %q has empty checksum", pkg.PackageName()) - } - if !bytes.Equal(expected, controlHash) { - return fmt.Errorf("package %q control hash mismatch: expected %x, got %x", pkg.PackageName(), expected, controlHash) - } - return nil -} - // fetchPackage fetches a package from the network or local filesystem. func (d *defaultPackageGetter) fetchPackage(ctx context.Context, pkg FetchablePackage) (io.ReadCloser, error) { log := clog.FromContext(ctx) @@ -365,16 +367,13 @@ return nil, err } - // Recompute the hash of the on-disk control file rather than trusting - // the content-addressable filename. A missed check here would let a - // tampered or corrupted cache entry be served without the verification - // that getPackageImpl applies on the fetch path. + // Recompute rather than trust the content-addressable filename; a tampered cache entry must not bypass fetch-path verification. ctlHash, err := sha1File(ctl) if err != nil { return nil, fmt.Errorf("hashing cached control %q: %w", ctl, err) } - if err := verifyControlHash(pkg, ctlHash); err != nil { - return nil, fmt.Errorf("cached %q: %w", ctl, err) + if !bytes.Equal(checksum, ctlHash) { + return nil, fmt.Errorf("cached %q: control hash mismatch: expected %x, got %x", ctl, checksum, ctlHash) } exp.ControlFile = ctl diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-1.2.7/pkg/apk/apk/package_getter_test.go new/apko-1.2.9/pkg/apk/apk/package_getter_test.go --- old/apko-1.2.7/pkg/apk/apk/package_getter_test.go 2026-04-23 21:44:30.000000000 +0200 +++ new/apko-1.2.9/pkg/apk/apk/package_getter_test.go 2026-04-28 21:09:36.000000000 +0200 @@ -329,24 +329,40 @@ require.Contains(t, err.Error(), "control hash mismatch") } -func TestVerifyControlHash(t *testing.T) { - want := make([]byte, 20) - for i := range want { - want[i] = byte(i) - } - pkg := &testPackage{ - pkg: &Package{Name: "example"}, - checksum: "Q1" + base64.StdEncoding.EncodeToString(want), +// TestGetPackage_HashVerification confirms that GetPackage checks both the +// control hash and the data hash and that each failure path returns a +// distinguishable error. A synthetic APK is used so the test is fully +// self-contained and will regress if either check is removed. +func TestGetPackage_HashVerification(t *testing.T) { + ctx := context.Background() + getter := newDefaultPackageGetter(http.DefaultClient, nil, auth.DefaultAuthenticators) + + entries := []testDirEntry{ + {path: "usr/", dir: true, perms: 0o755}, + {path: "usr/bin/hello", perms: 0o755, content: []byte("hello")}, } - require.NoError(t, verifyControlHash(pkg, want)) + t.Run("success", func(t *testing.T) { + ip := fakePackage(t, &Package{Name: "testpkg", Version: "1.0.0-r0"}, entries, "") + exp, err := getter.GetPackage(ctx, ip) + require.NoError(t, err) + require.NotNil(t, exp) + _ = exp.Close() + }) - bad := append([]byte(nil), want...) - bad[0] ^= 0xff - require.Error(t, verifyControlHash(pkg, bad)) + t.Run("control hash mismatch", func(t *testing.T) { + ip := fakePackage(t, &Package{Name: "testpkg", Version: "1.0.0-r0"}, entries, "") + ip.checksum = "Q1" + base64.StdEncoding.EncodeToString(make([]byte, 20)) // all-zero SHA-1 + _, err := getter.GetPackage(ctx, ip) + require.Error(t, err) + require.Contains(t, err.Error(), "control hash mismatch") + }) - require.Error(t, verifyControlHash(&testPackage{pkg: &Package{Name: "x"}, checksum: ""}, want)) - require.Error(t, verifyControlHash(&testPackage{pkg: &Package{Name: "x"}, checksum: "Q1"}, want)) - require.Error(t, verifyControlHash(&testPackage{pkg: &Package{Name: "x"}, checksum: "Q1!!!"}, want)) - require.Error(t, verifyControlHash(&testPackage{pkg: &Package{Name: "x"}, checksum: "raw-no-prefix"}, want)) + t.Run("data hash mismatch", func(t *testing.T) { + wrongHash := fmt.Sprintf("%x", make([]byte, 32)) // 32 zero bytes, hex-encoded + ip := fakePackage(t, &Package{Name: "testpkg", Version: "1.0.0-r0"}, entries, wrongHash) + _, err := getter.GetPackage(ctx, ip) + require.Error(t, err) + require.Contains(t, err.Error(), "data hash mismatch") + }) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-1.2.7/pkg/apk/auth/auth.go new/apko-1.2.9/pkg/apk/auth/auth.go --- old/apko-1.2.7/pkg/apk/auth/auth.go 2026-04-23 21:44:30.000000000 +0200 +++ new/apko-1.2.9/pkg/apk/auth/auth.go 2026-04-28 21:09:36.000000000 +0200 @@ -101,8 +101,8 @@ } sometimes.Do(func() { - cmd := exec.CommandContext(ctx, "chainctl", "auth", "token", "--audience", host) - cmd.Stderr = io.Discard // Don't pollute logs when things fail + cmd := exec.CommandContext(ctx, "chainctl", "auth", "token", "--audience", host) //#nosec G702 -- host is from env/default, passed as argv (no shell) + cmd.Stderr = io.Discard // Don't pollute logs when things fail out, err := cmd.Output() if err != nil { // Document that automatic auth failed and how to reproduce. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-1.2.7/pkg/apk/fs/rwosfs_test.go new/apko-1.2.9/pkg/apk/fs/rwosfs_test.go --- old/apko-1.2.7/pkg/apk/fs/rwosfs_test.go 2026-04-23 21:44:30.000000000 +0200 +++ new/apko-1.2.9/pkg/apk/fs/rwosfs_test.go 2026-04-28 21:09:36.000000000 +0200 @@ -426,8 +426,8 @@ require.NoError(t, err, "OpenFile for temp should succeed") // Step 5: Write existing + new content to temp - combinedData := make([]byte, len(existingData)) - copy(existingData, combinedData) + combinedData := make([]byte, 0, len(existingData)+14) + combinedData = append(combinedData, existingData...) combinedData = append(combinedData, []byte(" + new content")...) _, err = tempFile.Write(combinedData) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-1.2.7/pkg/build/apk.go new/apko-1.2.9/pkg/build/apk.go --- old/apko-1.2.7/pkg/build/apk.go 2026-04-23 21:44:30.000000000 +0200 +++ new/apko-1.2.9/pkg/build/apk.go 2026-04-28 21:09:36.000000000 +0200 @@ -87,7 +87,7 @@ // Get all packages from base image and merge them into the desired world. if bc.baseimg != nil { basePkgs := bc.baseimg.InstalledPackages() - var basePkgsNames []string + basePkgsNames := make([]string, 0, len(basePkgs)) for _, basePkg := range basePkgs { basePkgsNames = append(basePkgsNames, fmt.Sprintf("%s=%s", basePkg.Name, basePkg.Version)) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-1.2.7/pkg/build/build_implementation.go new/apko-1.2.9/pkg/build/build_implementation.go --- old/apko-1.2.7/pkg/build/build_implementation.go 2026-04-23 21:44:30.000000000 +0200 +++ new/apko-1.2.9/pkg/build/build_implementation.go 2026-04-28 21:09:36.000000000 +0200 @@ -244,11 +244,12 @@ return nil } - libdirs := []string{"/lib"} dirs, err := ldsocache.ParseLDSOConf(fsys, "etc/ld.so.conf") if err != nil { return fmt.Errorf("parsing /etc/ld.so.conf: %w", err) } + libdirs := make([]string, 0, 1+len(dirs)) + libdirs = append(libdirs, "/lib") libdirs = append(libdirs, dirs...) cacheFile, err := ldsocache.BuildCacheFileForDirs(fsys, libdirs) if err != nil { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-1.2.7/pkg/sbom/generator/spdx/spdx_test.go new/apko-1.2.9/pkg/sbom/generator/spdx/spdx_test.go --- old/apko-1.2.7/pkg/sbom/generator/spdx/spdx_test.go 2026-04-23 21:44:30.000000000 +0200 +++ new/apko-1.2.9/pkg/sbom/generator/spdx/spdx_test.go 2026-04-28 21:09:36.000000000 +0200 @@ -297,7 +297,7 @@ fsys := apkfs.NewMemFS() opts := testOpts(fsys) sx := New() - d := [][]byte{} + d := make([][]byte, 0, 2) for i := range 2 { path := filepath.Join(dir, fmt.Sprintf("sbom%d.%s", i, sx.Ext())) require.NoError(t, sx.Generate(t.Context(), opts, path)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-1.2.7/pkg/sbom/options/options.go new/apko-1.2.9/pkg/sbom/options/options.go --- old/apko-1.2.7/pkg/sbom/options/options.go 2026-04-23 21:44:30.000000000 +0200 +++ new/apko-1.2.9/pkg/sbom/options/options.go 2026-04-28 21:09:36.000000000 +0200 @@ -127,7 +127,7 @@ // This function is here while a fix in the purl library gets merged // ref: https://github.com/package-url/packageurl-go/pull/22 func (pq PurlQualifiers) String() string { - q := []purl.Qualifier{} + q := make([]purl.Qualifier, 0, len(pq)) for k, v := range pq { q = append(q, purl.Qualifier{Key: k, Value: v}) } ++++++ apko.obsinfo ++++++ --- /var/tmp/diff_new_pack.XROMIC/_old 2026-04-30 20:28:39.174536220 +0200 +++ /var/tmp/diff_new_pack.XROMIC/_new 2026-04-30 20:28:39.182536545 +0200 @@ -1,5 +1,5 @@ name: apko -version: 1.2.7 -mtime: 1776973470 -commit: a118c3d604107532b5525bd4bee2fb369a6228aa +version: 1.2.9 +mtime: 1777403376 +commit: 312a1507941c846eadc2ff22d1e2e1f7d82bebe7 ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/apko/vendor.tar.gz /work/SRC/openSUSE:Factory/.apko.new.30200/vendor.tar.gz differ: char 13, line 1
