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-08-28 19:49:50 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/melange (Old) and /work/SRC/openSUSE:Factory/.melange.new.1265 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "melange" Fri Aug 28 19:49:50 2026 rev:177 rq:1374194 version:0.59.2 Changes: -------- --- /work/SRC/openSUSE:Factory/melange/melange.changes 2026-08-14 22:09:04.608518805 +0200 +++ /work/SRC/openSUSE:Factory/.melange.new.1265/melange.changes 2026-08-28 19:50:41.534918113 +0200 @@ -1,0 +2,17 @@ +Fri Aug 28 06:07:15 UTC 2026 - Johannes Kastl <[email protected]> + +- Update to version 0.59.2: + * build(deps): bump the gomod group with 4 updates (#2621) + * build(deps): bump step-security/harden-runner in the actions + group (#2623) + * build(deps): bump google.golang.org/protobuf from + 1.36.12-0.20260120151049-f2248ac996af to 1.36.12 (#2622) + * Remove stale SHA-1 signature references (#2620) + * build(deps): bump chainguard-dev/actions/setup-gitsign from + 1.6.30 to 1.6.31 in the actions group (#2617) + * build(deps): bump the gomod group across 1 directory with 5 + updates (#2618) +- Update to version 0.59.1: + * Fetch license-check sources with native handlers (#2619) + +------------------------------------------------------------------- Old: ---- melange-0.59.0.obscpio New: ---- melange-0.59.2.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ melange.spec ++++++ --- /var/tmp/diff_new_pack.A3ISQw/_old 2026-08-28 19:50:46.609095475 +0200 +++ /var/tmp/diff_new_pack.A3ISQw/_new 2026-08-28 19:50:46.611095545 +0200 @@ -17,7 +17,7 @@ Name: melange -Version: 0.59.0 +Version: 0.59.2 Release: 0 Summary: Build APKs from source code License: Apache-2.0 ++++++ _service ++++++ --- /var/tmp/diff_new_pack.A3ISQw/_old 2026-08-28 19:50:46.704098796 +0200 +++ /var/tmp/diff_new_pack.A3ISQw/_new 2026-08-28 19:50:46.713099110 +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.59.0</param> + <param name="revision">refs/tags/v0.59.2</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> <param name="changesgenerate">enable</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.A3ISQw/_old 2026-08-28 19:50:46.755100578 +0200 +++ /var/tmp/diff_new_pack.A3ISQw/_new 2026-08-28 19:50:46.764100893 +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">4ec09c011312941753169b4089e69b5828d71c8e</param></service></servicedata> + <param name="changesrevision">2043d30b549e6f03c43e90341fb77c3532c4b790</param></service></servicedata> (No newline at EOF) ++++++ melange-0.59.0.obscpio -> melange-0.59.2.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.59.0/go.mod new/melange-0.59.2/go.mod --- old/melange-0.59.0/go.mod 2026-08-13 17:23:43.000000000 +0200 +++ new/melange-0.59.2/go.mod 2026-08-18 14:48:42.000000000 +0200 @@ -3,24 +3,24 @@ go 1.26.2 require ( - chainguard.dev/apko v1.2.33 + chainguard.dev/apko v1.2.37 github.com/chainguard-dev/clog v1.8.1 github.com/chainguard-dev/go-pkgconfig v0.0.0-20240404163941-6351b37b2a10 github.com/chainguard-dev/yam v0.2.65 github.com/charmbracelet/log v1.0.0 - github.com/docker/cli v29.7.1+incompatible + github.com/docker/cli v29.7.2+incompatible github.com/docker/docker v28.5.2+incompatible github.com/dprotaso/go-yit v0.0.0-20250513224043-18a80f8f6df4 github.com/github/go-spdx/v2 v2.7.0 github.com/go-git/go-git/v5 v5.19.2 github.com/google/go-cmp v0.7.0 - github.com/google/go-containerregistry v0.21.8 + github.com/google/go-containerregistry v0.21.9 github.com/google/licenseclassifier/v2 v2.0.0 github.com/in-toto/attestation v1.2.0 github.com/invopop/jsonschema v0.14.0 github.com/joho/godotenv v1.5.1 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 - github.com/klauspost/compress v1.19.1 + github.com/klauspost/compress v1.19.2 github.com/klauspost/pgzip v1.2.6 github.com/opencontainers/image-spec v1.1.1 github.com/package-url/packageurl-go v0.1.6 @@ -28,7 +28,7 @@ github.com/psanford/memfs v0.0.0-20241019191636-4ef911798f9b github.com/spdx/tools-golang v0.5.7 github.com/spf13/cobra v1.10.2 - github.com/stretchr/testify v1.11.1 + github.com/stretchr/testify v1.12.0 github.com/ulikunitz/xz v0.5.16 github.com/yookoala/realpath v1.0.0 github.com/zealic/xignore v0.3.3 @@ -36,12 +36,12 @@ go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.45.0 go.opentelemetry.io/otel/sdk v1.45.0 go.yaml.in/yaml/v2 v2.4.4 - golang.org/x/crypto v0.54.0 - golang.org/x/exp v0.0.0-20260709172345-9ea1abe57597 + golang.org/x/crypto v0.55.0 + golang.org/x/exp v0.0.0-20260727155853-b88d891fe743 golang.org/x/sync v0.22.0 golang.org/x/sys v0.47.0 golang.org/x/term v0.45.0 - golang.org/x/text v0.40.0 + golang.org/x/text v0.41.0 golang.org/x/time v0.15.0 gopkg.in/ini.v1 v1.67.3 gopkg.in/yaml.v3 v3.0.1 @@ -69,7 +69,7 @@ github.com/pb33f/ordered-map/v2 v2.3.1 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 // indirect - go.yaml.in/yaml/v3 v3.0.4 // indirect + go.yaml.in/yaml/v3 v3.0.5 // indirect go.yaml.in/yaml/v4 v4.0.0-rc.6 // indirect golang.org/x/tools v0.48.0 // indirect k8s.io/klog/v2 v2.140.0 // indirect @@ -81,8 +81,8 @@ ) require ( - chainguard.dev/go-grpc-kit v0.17.17 // indirect - chainguard.dev/sdk v0.1.164 // indirect + chainguard.dev/go-grpc-kit v0.18.0 // indirect + chainguard.dev/sdk v0.1.184 // indirect cloud.google.com/go/auth v0.22.0 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect cloud.google.com/go/compute/metadata v0.9.0 // indirect @@ -113,7 +113,7 @@ github.com/emirpasic/gods v1.18.1 // 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.0 // indirect + github.com/go-git/go-billy/v5 v5.9.1 // 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 @@ -142,10 +142,9 @@ github.com/opencontainers/go-digest v1.0.0 // indirect github.com/pierrec/lz4/v4 v4.1.27 // indirect github.com/pjbgf/sha1cd v0.6.0 - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/client_golang v1.23.2 // indirect + github.com/prometheus/client_golang v1.24.1 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.70.0 // indirect + github.com/prometheus/common v0.70.1 // indirect github.com/prometheus/procfs v0.21.1 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect @@ -168,11 +167,11 @@ golang.org/x/mod v0.38.0 // indirect golang.org/x/net v0.57.0 // indirect golang.org/x/oauth2 v0.36.0 // indirect - google.golang.org/api v0.291.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20260706201446-f0a921348800 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260724162435-b2f20204f0df // indirect - google.golang.org/grpc v1.82.1 // indirect - google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af + google.golang.org/api v0.292.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260715232425-e75dac1f907d // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260803160001-6ac0973c030d // indirect + google.golang.org/grpc v1.83.0 // indirect + google.golang.org/protobuf v1.36.12 gopkg.in/warnings.v0 v0.1.2 // indirect k8s.io/apimachinery v0.36.3 // indirect ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.59.0/go.sum new/melange-0.59.2/go.sum --- old/melange-0.59.0/go.sum 2026-08-13 17:23:43.000000000 +0200 +++ new/melange-0.59.2/go.sum 2026-08-18 14:48:42.000000000 +0200 @@ -1,9 +1,9 @@ -chainguard.dev/apko v1.2.33 h1:KdMVBNOeCbq/e1pA/F+kquuBObgXQL9qm32JnKCtyA0= -chainguard.dev/apko v1.2.33/go.mod h1:rZDihDy6oDIV9q+/AJ5ne4/OCS0nDOPOD4xxkNvsTjg= -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.164 h1:k2Ir/l1cuHDS/vg29sLNjJYm2kInnCfR5w0uFD0Y1Hg= -chainguard.dev/sdk v0.1.164/go.mod h1:y5AGo04erWjKtEyGX7fO9zZA4vtj9cLGXZjgIYxeMdo= +chainguard.dev/apko v1.2.37 h1:xiLmeSQKIgrLfVE4YvbFV0FsQoU9x8dpQYoRNsVOVa8= +chainguard.dev/apko v1.2.37/go.mod h1:inQA3zWjDP9dLbnxZzmv0KP6F1NYL+sDOWgvB5gl8oE= +chainguard.dev/go-grpc-kit v0.18.0 h1:kr451ml4eBgNcc0ytqcSSPZ3KGtyfHRrrBcYxW/oZwI= +chainguard.dev/go-grpc-kit v0.18.0/go.mod h1:N1ZZiV3KkNHFlIS6RPhLT9ppfObC7aa1hqWMPmNiTA0= +chainguard.dev/sdk v0.1.184 h1:L9SLup6giGc+qGUDZ7iuMKL5wC0rg6US23L2k5tbg5k= +chainguard.dev/sdk v0.1.184/go.mod h1:EdDABW102LAdDIbUXoTokZlRlyTa6D2ml0tC9Agnpbs= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go/auth v0.22.0 h1:Xp9wAKkLoeaYb5pYZZoQGz4E9sdPxIbzS3gywZE3ciQ= cloud.google.com/go/auth v0.22.0/go.mod h1:M9o2Oz+YI2jAfxewJgb1vyI3vceHF+eohmxyzmrl+9s= @@ -87,8 +87,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/cli v29.7.1+incompatible h1:ILZpP6B7fedIr6ANy824QkDp1WMJuouIq0O2SrBkB2w= -github.com/docker/cli v29.7.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v29.7.2+incompatible h1:dlkwallR8XqfeVnA2ELEhdwvb4lsSwuB4IgsG8Q9cLY= +github.com/docker/cli v29.7.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM= github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.9.8 h1:bIREROb7So6PRlq6KTtdS9MPEjC29OQRkFNlvK2OX8Q= @@ -121,8 +121,8 @@ 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.0 h1:jItGXszUDRtR/AlferWPTMN4j38BQ88XnXKbilmmBPA= -github.com/go-git/go-billy/v5 v5.9.0/go.mod h1:jCnQMLj9eUgGU7+ludSTYoZL/GGmii14RxKFj7ROgHw= +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-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= @@ -165,8 +165,8 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -github.com/google/go-containerregistry v0.21.8 h1:Ig/zIsnztdCUNaiNNczE+MoP5xcyUMfvpvfOr1xyMLE= -github.com/google/go-containerregistry v0.21.8/go.mod h1:dP5XNKcL7kMFF/TB3LfvWmVhAcv7iqkHb3oDK8aauTo= +github.com/google/go-containerregistry v0.21.9 h1:F+D4uZ3iA3DLMJLfhaqMdHJbzeqm/216WGQq2dokuLs= +github.com/google/go-containerregistry v0.21.9/go.mod h1:dP5XNKcL7kMFF/TB3LfvWmVhAcv7iqkHb3oDK8aauTo= github.com/google/go-licenses/v2 v2.0.1 h1:ti+9bi5o7DKbeeg5eBb/uZTgsaPNoJaLCh93cRcXsW8= github.com/google/go-licenses/v2 v2.0.1/go.mod h1:efibo0EDNGkau6AIMOViGW+rTNPudhxX9rCxtfw5zKE= github.com/google/go-replayers/httpreplay v1.2.0 h1:VM1wEyyjaoU53BwrOnaf9VhAyQQEEioJvFYxYcLRKzk= @@ -216,8 +216,8 @@ github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/kevinburke/ssh_config v1.6.0 h1:J1FBfmuVosPHf5GRdltRLhPJtJpTlMdKTBjRgTaQBFY= github.com/kevinburke/ssh_config v1.6.0/go.mod h1:q2RIzfka+BXARoNexmF9gkxEX7DmvbW9P4hIVx2Kg4M= -github.com/klauspost/compress v1.19.1 h1:VsB4HPswih7mmZ8WleSFQ75c/Ui1M4trX5oAsJnhSlk= -github.com/klauspost/compress v1.19.1/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= +github.com/klauspost/compress v1.19.2 h1:hMRETovs/pu/dVWN7zIT1PGG8t509MwT6bO7XSi26R8= +github.com/klauspost/compress v1.19.2/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ= github.com/klauspost/cpuid/v2 v2.4.0 h1:S6Hrbc7+ywsr0r+RLapfGBHfyefhCTwEh3A0tV913Dw= github.com/klauspost/cpuid/v2 v2.4.0/go.mod h1:19jmZ9mjzoF//ddRSUsv0zfBTJWh3QJh9FNxZTMrGxU= github.com/klauspost/pgzip v1.2.6 h1:8RXeL5crjEUFnR2/Sn6GJNWtSQ3Dk8pq4CL3jvdDyjU= @@ -280,15 +280,13 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= -github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= +github.com/prometheus/client_golang v1.24.1 h1:JnJkREXzWxUdCuPFpIWZiPispT9xVV59uiuyR2bPlnU= +github.com/prometheus/client_golang v1.24.1/go.mod h1:F+oSRECHg4sse5ucfYpYDeIv/hu68Zo0uoHKetWnzcE= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= -github.com/prometheus/common v0.70.0 h1:bcpru3tWPVnxGnETLgOV5jbp/JRXgYEyv65CuBLAMMI= -github.com/prometheus/common v0.70.0/go.mod h1:S/SFasQmgGiYH6C81LKCtYa8QACgthGg5zxL2udV7SY= +github.com/prometheus/common v0.70.1 h1:1HvjP4D5oL3t8RsPlwxA9onvvStjtIHYE5XuuwOi/PY= +github.com/prometheus/common v0.70.1/go.mod h1:VdFUQDMZK3VLkurFUVhia6uys/0suUp86TJz5qbJRhc= github.com/prometheus/procfs v0.21.1 h1:GljZCt+zSTS+NZq88cyQ1LjZ+RCHp3uVuabBWA5+OJI= github.com/prometheus/procfs v0.21.1/go.mod h1:aB55Cww9pdSJVHk0hUf0inxWyyjPogFIjmHKYgMKmtY= github.com/psanford/memfs v0.0.0-20241019191636-4ef911798f9b h1:xzjEJAHum+mV5Dd5KyohRlCyP03o4yq6vNpEUtAJQzI= @@ -329,8 +327,9 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/stretchr/testify v1.12.0 h1:K6Mr6jO9JICuend/5xzTM03ydSV3vdNRYAdPSukj8uI= +github.com/stretchr/testify v1.12.0/go.mod h1:bOYBZb5qJ00vPzWfIqBUZPaxK8jWiXc6d3ErP4Ca9Gw= github.com/u-root/u-root v0.16.0 h1:wY40O83MBVks97+Is0WlFlOPSwKQMIrWP9R1IsrExg8= github.com/u-root/u-root v0.16.0/go.mod h1:yL/XdSSW27PdGLgUh4MNRBy54mKM+TBLzpwiB4nwj90= github.com/u-root/uio v0.0.0-20240224005618-d2acac8f3701 h1:pyC9PaHYZFgEKFdlp3G8RaCKgVpHZnecvArXvPXcFkM= @@ -358,8 +357,8 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0/go.mod h1:z9+yiacE0IHRqM4qFfkbt/JYlmYXgss8GY/jXoNuPJI= go.opentelemetry.io/otel v1.45.0 h1:pdrWmLHofpubmArBv1LgFSv1Z0Ie/ppdZzu+kUN5EeU= go.opentelemetry.io/otel v1.45.0/go.mod h1:XZxIqPapzEYnhNSScF5DIqXhm/rYi0FzCe2XddAwZfQ= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 h1:88Y4s2C8oTui1LGM6bTWkw0ICGcOLCAI5l6zsD1j20k= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0/go.mod h1:Vl1/iaggsuRlrHf/hfPJPvVag77kKyvrLeD10kpMl+A= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0 h1:4YsVu3B8+3qtWYYrsUYgn0OG78pN0rnNPRGX4SbokQI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.44.0/go.mod h1:+wnlSn0mD1ADVMe3v9Z/WIaiz6q6gL2J/ejaAmdmv80= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 h1:3iZJKlCZufyRzPzlQhUIWVmfltrXuGyfjREgGP3UUjc= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0/go.mod h1:/G+nUPfhq2e+qiXMGxMwumDrP5jtzU+mWN7/sjT2rak= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.45.0 h1:lsA/S1bxgdbyFGkTj+3meEdJ6ADVU7QoFstV6MXgE68= @@ -380,8 +379,9 @@ go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ= 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/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw= +go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg= go.yaml.in/yaml/v4 v4.0.0-rc.6 h1:1h7H1ohdUh93/FyE4YaDa1Zh64K6VVbjF4K6WUxMtH4= go.yaml.in/yaml/v4 v4.0.0-rc.6/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -389,11 +389,11 @@ 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= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.54.0 h1:YLIA59K4fiNzHzjnZt2tUJQjQtUWfWbeHBqKtk3eScw= -golang.org/x/crypto v0.54.0/go.mod h1:KWL8ny2AZdGR2cWmzeHrp2azQPGogOv+HeQaVEXC2dk= +golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M= +golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20260709172345-9ea1abe57597 h1:qLvzZeaANDgyVOA8pyHCOStGlXn0rseXma+GQjeuv2g= -golang.org/x/exp v0.0.0-20260709172345-9ea1abe57597/go.mod h1:EdfpwwqSu+0Li0mzskwHU6FWDV3t9Q+RZDo3QMUtL3Q= +golang.org/x/exp v0.0.0-20260727155853-b88d891fe743 h1:ex206bKw+v3K0dm3andkrIF+ijyQKJG1pLgwQ2PYdQM= +golang.org/x/exp v0.0.0-20260727155853-b88d891fe743/go.mod h1:EdfpwwqSu+0Li0mzskwHU6FWDV3t9Q+RZDo3QMUtL3Q= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= @@ -457,8 +457,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.40.0 h1:Ub2Z6/xjgF1WrYQz2nuITOEegKFtiIy+rieRJ5lHZKs= -golang.org/x/text v0.40.0/go.mod h1:hpnzDAfGV753zIKo+wk3u1bVKCGPbrnF7+7LBF/UHVY= +golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8= +golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M= 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= @@ -475,8 +475,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= -google.golang.org/api v0.291.0 h1:wfPbbY+mr9c7wZLqqzrHJLft/q8iFKREd6IgTBUene0= -google.golang.org/api v0.291.0/go.mod h1:at7kwWbuonglBFEBoeMDAV1bguHqL3qf0BHFsv3coa0= +google.golang.org/api v0.292.0 h1:Ewiwo/GTtiaPZSNAZQUcWLh8AYDEoPmIXyJfeoTSMHU= +google.golang.org/api v0.292.0/go.mod h1:07kjmMnFGm2RQuCza2EZM/5N68G/fVvFb1xKjWqoFA0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= @@ -484,17 +484,17 @@ google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20260406210006-6f92a3bedf2d h1:N1Ec54vZnIPd7MnxRiYLW+oY4fDR4BOS/LrssdD9+ek= google.golang.org/genproto v0.0.0-20260406210006-6f92a3bedf2d/go.mod h1:c2hJ1grtnH0xUiEKGDGkjGNTJ1Hy2LrblyKOHF0sqRM= -google.golang.org/genproto/googleapis/api v0.0.0-20260706201446-f0a921348800 h1:admdQBe8jR3VWhBsUrAOaF2Qw6K/+p5pSm1GN8+6Fw4= -google.golang.org/genproto/googleapis/api v0.0.0-20260706201446-f0a921348800/go.mod h1:FPk7EXUKMtImne7AmknoYjT4QXqKIzzRbeQIXzLk6fQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260724162435-b2f20204f0df h1:O3ig1i5WDDzsVzRp+cCdgelT9vXnlnOFdlEeFtL4HCc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260724162435-b2f20204f0df/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/genproto/googleapis/api v0.0.0-20260715232425-e75dac1f907d h1:QwnJwPte4XXAkhPu26LTDIahnsMSUV0kK8HkxbC+Pc4= +google.golang.org/genproto/googleapis/api v0.0.0-20260715232425-e75dac1f907d/go.mod h1:WRrQ7/7N19PypuT0fxLOL5Lq0waoiRri4FbtHDEKrGE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260803160001-6ac0973c030d h1:IL4hdHzcUv2l/gcg98/Rj3FbtE6axwqslOW8SW0C+S0= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260803160001-6ac0973c030d/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.82.1 h1:NnAxzGRA0677vCa4BUkOAnO5+FfQqVl9iUXeD0IqcGE= -google.golang.org/grpc v1.82.1/go.mod h1:yzTZ1TB1Z3SG+LIYaI+WiE8D5+PZ3ArnrSp8zF3+/ZA= +google.golang.org/grpc v1.83.0 h1:JeNZEKJFbQxArAMl+hiytHauacDNqJUllNfmIMmpqnQ= +google.golang.org/grpc v1.83.0/go.mod h1:kDyl6SKsiHKt0uylY5gtn5cEjkrIOhQOGDgIc4JGwzQ= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -504,8 +504,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI= -google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc= +google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.59.0/pkg/build/package.go new/melange-0.59.2/pkg/build/package.go --- old/melange-0.59.0/pkg/build/package.go 2026-08-13 17:23:43.000000000 +0200 +++ new/melange-0.59.2/pkg/build/package.go 2026-08-18 14:48:42.000000000 +0200 @@ -296,10 +296,6 @@ return buf.Bytes(), nil } -func (pc *PackageBuild) SignatureName() string { - return fmt.Sprintf(".SIGN.RSA.%s.pub", filepath.Base(pc.Build.SigningKey)) -} - // removeSelfProvidedDeps removes dependencies which are provided by the package itself. func removeSelfProvidedDeps(runtimeDeps, providedDeps []string) []string { providedDepsMap := map[string]bool{} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.59.0/pkg/sign/apk.go new/melange-0.59.2/pkg/sign/apk.go --- old/melange-0.59.0/pkg/sign/apk.go 2026-08-13 17:23:43.000000000 +0200 +++ new/melange-0.59.2/pkg/sign/apk.go 2026-08-18 14:48:42.000000000 +0200 @@ -155,7 +155,7 @@ return sigbuf.Bytes(), nil } -// Key base signature (normal) uses a SHA-1 hash on the control digest. +// Key base signature (normal) uses a SHA-256 hash on the control digest. type KeyApkSigner struct { KeyFile string KeyPassphrase string diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.59.0/pkg/source/fetch.go new/melange-0.59.2/pkg/source/fetch.go --- old/melange-0.59.0/pkg/source/fetch.go 1970-01-01 01:00:00.000000000 +0100 +++ new/melange-0.59.2/pkg/source/fetch.go 2026-08-18 14:48:42.000000000 +0200 @@ -0,0 +1,209 @@ +// 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 source + +import ( + "context" + "crypto/sha256" + "crypto/sha512" + "encoding/hex" + "fmt" + "hash" + "io" + "net/http" + "net/url" + "os" + "os/exec" + "path" + "path/filepath" + "strings" + + "github.com/chainguard-dev/clog" +) + +// FetchOptions describes a native equivalent of the built-in `fetch` pipeline. +// Values come from the melange config and are used only as data: a URL, a +// filename, and argv elements. +type FetchOptions struct { + URI string + Directory string // where to extract; relative to the current working directory + StripComponents int + Extract bool + ExpectedSHA256 string + ExpectedSHA512 string + Delete bool +} + +// Fetch downloads the artifact named by opts.URI into the current working +// directory, optionally verifies its checksum, and optionally extracts it. The +// URI is parsed and used as data (never passed to a shell). +func Fetch(ctx context.Context, opts *FetchOptions) error { + log := clog.FromContext(ctx) + + u, err := url.Parse(opts.URI) + if err != nil { + return fmt.Errorf("invalid fetch uri %q: %w", opts.URI, err) + } + if u.Scheme != "http" && u.Scheme != "https" { + return fmt.Errorf("invalid fetch uri %q: only http and https schemes are supported", opts.URI) + } + if u.Host == "" { + return fmt.Errorf("invalid fetch uri %q: missing host", opts.URI) + } + + // Derive the local filename from the URL path only (not the raw string), so + // query strings or crafted values can't influence the on-disk name. + base := path.Base(u.Path) + if base == "" || base == "." || base == ".." || base == "/" { + return fmt.Errorf("could not determine a filename from uri %q", opts.URI) + } + + log.Infof("Fetching %s", opts.URI) + if err := download(ctx, opts.URI, base); err != nil { + return err + } + + if err := verifyChecksum(base, opts.ExpectedSHA256, opts.ExpectedSHA512); err != nil { + return err + } + + if opts.Extract { + dir := opts.Directory + if dir == "" { + dir = "." + } + // tar is invoked with an explicit argv, so the filename and directory + // are passed as plain arguments. tar auto-detects the compression + // format, matching the built-in pipeline. + // #nosec G204 - argv-only invocation; args are validated data, not shell + cmd := exec.CommandContext(ctx, "tar", "-x", + fmt.Sprintf("--strip-components=%d", opts.StripComponents), + "--no-same-owner", "-C", dir, "-f", base) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return fmt.Errorf("extracting %q: %w", base, err) + } + } + + if opts.Delete { + if err := os.Remove(base); err != nil { + return fmt.Errorf("deleting %q: %w", base, err) + } + } + + return nil +} + +// download streams uri to the file named dest in the current working directory. +func download(ctx context.Context, uri, dest string) error { + req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil) + if err != nil { + return fmt.Errorf("creating request for %s: %w", uri, err) + } + + resp, err := http.DefaultClient.Do(req) // #nosec G107 - uri scheme validated to http(s) by caller + if err != nil { + return fmt.Errorf("fetching %s: %w", uri, err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("fetching %s: unexpected status %d", uri, resp.StatusCode) + } + + // #nosec G304 - dest is a sanitized basename written into the workspace dir + f, err := os.Create(dest) + if err != nil { + return fmt.Errorf("creating %q: %w", dest, err) + } + defer f.Close() + + if _, err := io.Copy(f, resp.Body); err != nil { + return fmt.Errorf("writing %q: %w", dest, err) + } + + return nil +} + +// verifyChecksum checks the downloaded file against the expected digests, when +// provided. A missing checksum is not fatal here, as license-check is +// best-effort. +func verifyChecksum(file, expectedSHA256, expectedSHA512 string) error { + check := func(h hash.Hash, expected, algo string) error { + f, err := os.Open(file) // #nosec G304 - file is a sanitized basename in the workspace dir + if err != nil { + return err + } + defer f.Close() + if _, err := io.Copy(h, f); err != nil { + return err + } + got := hex.EncodeToString(h.Sum(nil)) + if !strings.EqualFold(got, strings.TrimSpace(expected)) { + return fmt.Errorf("%s mismatch for %q: expected %s, got %s", algo, file, expected, got) + } + return nil + } + + if expectedSHA256 != "" { + return check(sha256.New(), expectedSHA256, "sha256") + } + if expectedSHA512 != "" { + return check(sha512.New(), expectedSHA512, "sha512") + } + return nil +} + +// applyPatchStep applies patch files, a native equivalent of the built-in +// `patch` pipeline. Each patch path is resolved relative to workDir, opened in +// Go, and fed to `patch` on stdin. +func applyPatchStep(ctx context.Context, patches string, stripComponents, fuzz int, workDir string) error { + log := clog.FromContext(ctx) + + for patch := range strings.FieldsSeq(patches) { + // Keep patch paths within the workspace directory. + if filepath.IsAbs(patch) { + return fmt.Errorf("absolute patch paths are not allowed: %q", patch) + } + patchPath := filepath.Join(workDir, patch) + if rel, err := filepath.Rel(workDir, patchPath); err != nil || rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator)) { + return fmt.Errorf("patch path %q escapes the workspace directory", patch) + } + + log.Infof("Applying patch %s", patchPath) + + f, err := os.Open(patchPath) // #nosec G304 G703 - patch path validated to stay within the workspace dir + if err != nil { + return fmt.Errorf("opening patch %q: %w", patchPath, err) + } + + // #nosec G204 - argv-only invocation; strip/fuzz are ints, no shell + cmd := exec.CommandContext(ctx, "patch", + fmt.Sprintf("-p%d", stripComponents), + fmt.Sprintf("--fuzz=%d", fuzz)) + cmd.Dir = workDir + cmd.Stdin = f + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + err = cmd.Run() + f.Close() + if err != nil { + return fmt.Errorf("applying patch %q: %w", patchPath, err) + } + } + + return nil +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.59.0/pkg/source/source.go new/melange-0.59.2/pkg/source/source.go --- old/melange-0.59.0/pkg/source/source.go 2026-08-13 17:23:43.000000000 +0200 +++ new/melange-0.59.2/pkg/source/source.go 2026-08-18 14:48:42.000000000 +0200 @@ -16,14 +16,13 @@ import ( "archive/tar" - "bytes" "compress/gzip" "context" "fmt" "io" "os" - "os/exec" "path/filepath" + "strconv" "strings" apkofs "chainguard.dev/apko/pkg/apk/fs" @@ -31,27 +30,180 @@ "chainguard.dev/melange/pkg/build" "chainguard.dev/melange/pkg/config" + "chainguard.dev/melange/pkg/util" ) -// Variable to allow mocking the runCommand function in tests. -var sourceRunPipelineStep = runPipelineStep +// sourceRunStep dispatches a single source-fetching pipeline step to its native +// handler. It is a package variable so tests can stub it out. +var sourceRunStep = runStep + +// runStep executes one supported source-fetching step (fetch, git-checkout, or +// patch) natively in Go. Input values are resolved through the substitution map +// (so `${{package.version}}` and friends still work) and are then used as data: +// a URL, a git remote, and argv elements. +func runStep(ctx context.Context, step config.Pipeline, sm *build.SubstitutionMap, _ bool, destDir string) error { + // resolve returns the substituted value for a `with:` input, or "" if the + // input was not provided. The result is used as data. + resolve := func(key string) (string, error) { + v, ok := step.With[key] + if !ok { + return "", nil + } + return util.MutateStringFromMap(sm.Substitutions, v) + } -// Simple wrapper for executing pipeline steps. -func runPipelineStep(ctx context.Context, step config.Pipeline) error { - var stdout, stderr io.Writer - outputBuf := &bytes.Buffer{} - log := clog.FromContext(ctx) - stdout = outputBuf - stderr = outputBuf + switch step.Uses { + case "fetch": + return runFetchStep(ctx, resolve) + case "git-checkout": + return runGitCheckoutStep(ctx, resolve, destDir) + case "patch": + return runPatchStep(ctx, resolve, destDir) + default: + return fmt.Errorf("unsupported source step %q", step.Uses) + } +} - cmd := []string{"/bin/sh", "-c", step.Pipeline[0].Runs} - // #nosec G204 - Executing pipeline step from trusted melange configuration - proc := exec.Command(cmd[0], cmd[1:]...) - proc.Stdout = stdout - proc.Stderr = stderr - log.Debugf("Command output:\n%s", outputBuf.String()) +func runFetchStep(ctx context.Context, resolve func(string) (string, error)) error { + get := func(dst *string, key string) error { + v, err := resolve(key) + if err != nil { + return err + } + *dst = v + return nil + } - return proc.Run() + opts := &FetchOptions{} + var stripRaw, extractRaw, deleteRaw string + for dst, key := range map[*string]string{ + &opts.URI: "uri", + &opts.Directory: "directory", + &opts.ExpectedSHA256: "expected-sha256", + &opts.ExpectedSHA512: "expected-sha512", + &stripRaw: "strip-components", + &extractRaw: "extract", + &deleteRaw: "delete", + } { + if err := get(dst, key); err != nil { + return err + } + } + + opts.StripComponents = parseIntDefault(stripRaw, 1) + opts.Extract = parseBoolDefault(extractRaw, true) + opts.Delete = parseBoolDefault(deleteRaw, false) + + return Fetch(ctx, opts) +} + +func runGitCheckoutStep(ctx context.Context, resolve func(string) (string, error), destDir string) error { + repo, err := resolve("repository") + if err != nil { + return err + } + dest, err := resolve("destination") + if err != nil { + return err + } + switch { + case dest == "" || dest == ".": + dest = destDir + case !filepath.IsAbs(dest): + dest = filepath.Join(destDir, dest) + } + expectedCommit, err := resolve("expected-commit") + if err != nil { + return err + } + cherryPicks, err := resolve("cherry-picks") + if err != nil { + return err + } + recurse, err := resolve("recurse-submodules") + if err != nil { + return err + } + + return GitCheckout(ctx, &GitCheckoutOptions{ + Repository: repo, + Destination: dest, + ExpectedCommit: expectedCommit, + CherryPicks: cherryPicks, + WorkspaceDir: destDir, + RecurseSubmodules: parseBoolDefault(recurse, false), + }) +} + +func runPatchStep(ctx context.Context, resolve func(string) (string, error), destDir string) error { + patches, err := resolve("patches") + if err != nil { + return err + } + series, err := resolve("series") + if err != nil { + return err + } + stripRaw, err := resolve("strip-components") + if err != nil { + return err + } + fuzzRaw, err := resolve("fuzz") + if err != nil { + return err + } + + // A quilt-style series file lists patch filenames, one per line (with '#' + // comments). Fold it into the patch list when no explicit patches are given. + if strings.TrimSpace(patches) == "" && strings.TrimSpace(series) != "" { + // Keep the series path within the workspace directory. + if filepath.IsAbs(series) { + return fmt.Errorf("absolute series paths are not allowed: %q", series) + } + seriesPath := filepath.Join(destDir, series) + if rel, err := filepath.Rel(destDir, seriesPath); err != nil || rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator)) { + return fmt.Errorf("series path %q escapes the workspace directory", series) + } + data, err := os.ReadFile(seriesPath) // #nosec G304 - series path validated to stay within the workspace dir + if err != nil { + return fmt.Errorf("reading series file %q: %w", seriesPath, err) + } + var names []string + for line := range strings.SplitSeq(string(data), "\n") { + line = strings.TrimSpace(line) + if line == "" || strings.HasPrefix(line, "#") { + continue + } + names = append(names, line) + } + patches = strings.Join(names, " ") + } + + if strings.TrimSpace(patches) == "" { + return fmt.Errorf("patch step: neither 'patches' nor 'series' was set") + } + + return applyPatchStep(ctx, patches, parseIntDefault(stripRaw, 1), parseIntDefault(fuzzRaw, 2), destDir) +} + +func parseIntDefault(s string, def int) int { + s = strings.TrimSpace(s) + if s == "" { + return def + } + n, err := strconv.Atoi(s) + if err != nil { + return def + } + return n +} + +func parseBoolDefault(s string, def bool) bool { + s = strings.TrimSpace(s) + if s == "" { + return def + } + return s == "true" } // Function to extract the .melange.yaml from an apk package. @@ -139,45 +291,14 @@ return nil, fmt.Errorf("failed to parse melange config: %w", err) } - // Temporarily copy out the embedded files and directories from f into a - // temporary directory. We want to pass it later on to the pipeline - // compilation. - err = os.CopyFS(tmpDir, build.PipelinesFS) - if err != nil { - return nil, fmt.Errorf("failed to copy embedded pilelines: %w", err) - } - - // Prepare the substitution map and compile the pipelines, making sure that - // the resulting pipeline run statements are all substituted with the - // correct values and ready for execution. - c := &build.Compiled{ - PipelineDirs: []string{tmpDir}, - } - - // Now also try looking if the base directory of filePath has a pipelines - // directory. Add those to the list of directories to search for pipelines. - absFilePath, err := filepath.Abs(filePath) - if err != nil { - return nil, fmt.Errorf("failed to get absolute path of file: %w", err) - } - baseDir := filepath.Dir(absFilePath) - pipelinesDir := filepath.Join(baseDir, "pipelines") - - if _, err := os.Stat(pipelinesDir); err == nil { - log.Infof("Found pipelines directory in base directory: %s", pipelinesDir) - c.PipelineDirs = append(c.PipelineDirs, pipelinesDir) - } else if !os.IsNotExist(err) { - return nil, fmt.Errorf("error checking pipelines directory: %w", err) - } - + // Prepare the substitution map so that input values referencing built-in + // variables (e.g. ${{package.version}}) resolve correctly. The supported + // source steps are dispatched to native Go handlers below, which treat + // every substituted value as data. sm, err := build.NewSubstitutionMap(cfg, "amd64", "gnu", nil) if err != nil { return nil, fmt.Errorf("failed to create substitution map: %w", err) } - err = c.CompilePipelines(ctx, sm, cfg.Pipeline) - if err != nil { - return nil, fmt.Errorf("failed to compile pipelines: %w", err) - } // During command execution we change the working directory. We need to // make sure we change it back to the original working directory afterwards. @@ -207,12 +328,12 @@ // Iterate over the pipeline steps and look for any source fetching steps. for _, step := range cfg.Pipeline { - if step.Uses == "patch" && isApk { - log.Warnf("Skipping patch step as we do not have patches available inside apk metadata yet.") + if step.Uses != "git-checkout" && step.Uses != "fetch" && step.Uses != "patch" { continue } - if step.Uses != "git-checkout" && step.Uses != "fetch" && step.Uses != "patch" { + if step.Uses == "patch" && isApk { + log.Warnf("Skipping patch step as we do not have patches available inside apk metadata yet.") continue } @@ -226,7 +347,7 @@ if err != nil { return nil, fmt.Errorf("failed to change directory: %w", err) } - err = sourceRunPipelineStep(ctx, step) + err = sourceRunStep(ctx, step, sm, isApk, destDir) if err != nil { return nil, fmt.Errorf("failed to run step: %w", err) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/melange-0.59.0/pkg/source/source_test.go new/melange-0.59.2/pkg/source/source_test.go --- old/melange-0.59.0/pkg/source/source_test.go 2026-08-13 17:23:43.000000000 +0200 +++ new/melange-0.59.2/pkg/source/source_test.go 2026-08-18 14:48:42.000000000 +0200 @@ -23,6 +23,7 @@ "path/filepath" "testing" + "chainguard.dev/melange/pkg/build" "chainguard.dev/melange/pkg/config" ) @@ -105,13 +106,13 @@ } } -// TestFetchSourceFromMelange tests the FetchSourceFromMelange function with mocked sourceRunCommand +// TestFetchSourceFromMelange tests the FetchSourceFromMelange function with a mocked step dispatcher func TestFetchSourceFromMelange(t *testing.T) { - // Mock the sourceRunCommand function + // Mock the step dispatcher so the test stays hermetic (no network/git). stepsRun := []string{} - originalSourceRunPipelineStep := sourceRunPipelineStep - defer func() { sourceRunPipelineStep = originalSourceRunPipelineStep }() - sourceRunPipelineStep = func(ctx context.Context, step config.Pipeline) error { + originalSourceRunStep := sourceRunStep + defer func() { sourceRunStep = originalSourceRunStep }() + sourceRunStep = func(ctx context.Context, step config.Pipeline, sm *build.SubstitutionMap, isApk bool, destDir string) error { fmt.Printf("Running step: %s\n", step.Uses) stepsRun = append(stepsRun, step.Uses) return nil @@ -175,4 +176,63 @@ } }) } +} + +// TestFetchSourceFromMelange_inputsTreatedAsData runs the real (unmocked) +// dispatcher against configs whose inputs contain shell-like syntax, and +// asserts those inputs are treated as literal data: the fetch/checkout fails +// (the value is not a valid URL or git remote) and no side-effect file is +// produced. +func TestFetchSourceFromMelange_inputsTreatedAsData(t *testing.T) { + tmpDir := t.TempDir() + marker := filepath.Join(tmpDir, "marker") + + // If a value were ever evaluated by a shell, it would create the marker + // file. As literal data (a URL / git remote) it cannot. + configs := map[string]string{ + "fetch-uri": `package: + name: example + version: "1.0.0" + epoch: 0 + copyright: + - license: MIT +pipeline: + - uses: fetch + with: + uri: "$(touch ` + marker + `; echo x)" + expected-none: "true" +`, + "git-checkout-repository": `package: + name: example + version: "1.0.0" + epoch: 0 + copyright: + - license: MIT +pipeline: + - uses: git-checkout + with: + repository: "$(touch ` + marker + `; echo x)" +`, + } + + for name, content := range configs { + t.Run(name, func(t *testing.T) { + _ = os.Remove(marker) + + cfgPath := filepath.Join(tmpDir, name+".yaml") + if err := os.WriteFile(cfgPath, []byte(content), 0o600); err != nil { + t.Fatalf("failed to write config: %v", err) + } + + // The value is not a valid URL/remote, so fetching fails. + _, err := FetchSourceFromMelange(context.Background(), cfgPath, filepath.Join(tmpDir, name+"-out")) + if err == nil { + t.Errorf("expected an error fetching from an invalid uri/repository, got nil") + } + + if _, statErr := os.Stat(marker); statErr == nil { + t.Fatalf("input was not treated as literal data (marker file %s was created)", marker) + } + }) + } } ++++++ melange.obsinfo ++++++ --- /var/tmp/diff_new_pack.A3ISQw/_old 2026-08-28 19:50:49.465195307 +0200 +++ /var/tmp/diff_new_pack.A3ISQw/_new 2026-08-28 19:50:49.476195691 +0200 @@ -1,5 +1,5 @@ name: melange -version: 0.59.0 -mtime: 1786634623 -commit: 4ec09c011312941753169b4089e69b5828d71c8e +version: 0.59.2 +mtime: 1787057322 +commit: 2043d30b549e6f03c43e90341fb77c3532c4b790 ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/melange/vendor.tar.gz /work/SRC/openSUSE:Factory/.melange.new.1265/vendor.tar.gz differ: char 15, line 1
