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-08-01 18:32:02 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/apko (Old) and /work/SRC/openSUSE:Factory/.apko.new.16738 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "apko" Sat Aug 1 18:32:02 2026 rev:130 rq:1368742 version:1.2.30 Changes: -------- --- /work/SRC/openSUSE:Factory/apko/apko.changes 2026-07-28 17:54:39.157639564 +0200 +++ /work/SRC/openSUSE:Factory/.apko.new.16738/apko.changes 2026-08-01 18:35:11.135924587 +0200 @@ -1,0 +2,33 @@ +Fri Jul 31 05:53:20 UTC 2026 - Johannes Kastl <[email protected]> + +- Update to version 1.2.30: + * build(deps): bump chainguard.dev/sdk from 0.1.156 to 0.1.158 + (#2359) + * build(deps): bump chainguard-dev/actions/setup-registry from + 1.6.28 to 1.6.29 (#2358) + * chore(harden-runner): allow apple endpoints to OSX builds + (#2361) + * Use slices.Concat in TestWriteCABundleChecksumsNoBundles + (#2349) + * build(deps): bump github/codeql-action/init from 4.37.2 to + 4.37.3 (#2354) + * build(deps): bump google.golang.org/api from 0.289.0 to 0.290.0 + (#2353) + * build(deps): bump github/codeql-action/analyze from 4.37.2 to + 4.37.3 (#2355) + * build(deps): bump k8s.io/apimachinery from 0.36.2 to 0.36.3 + (#2352) + * build(deps): bump chainguard.dev/sdk from 0.1.145 to 0.1.156 + (#2351) + * build(deps): bump zizmorcore/zizmor-action from 0.6.0 to 0.6.1 + (#2356) + * Regenerate apko-discover.lock.json golden file (#2350) + * build(deps): bump github/codeql-action/analyze from 4.37.1 to + 4.37.2 (#2348) + * build(deps): bump github/codeql-action/init from 4.37.1 to + 4.37.2 (#2347) + * build(deps): bump chainguard.dev/sdk from 0.1.140 to 0.1.145 + (#2346) + * Write sha256 checksum sidecar next to CA bundles (#2331) + +------------------------------------------------------------------- Old: ---- apko-1.2.29.obscpio New: ---- apko-1.2.30.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ apko.spec ++++++ --- /var/tmp/diff_new_pack.PnEp56/_old 2026-08-01 18:35:13.472005028 +0200 +++ /var/tmp/diff_new_pack.PnEp56/_new 2026-08-01 18:35:13.476005165 +0200 @@ -17,7 +17,7 @@ Name: apko -Version: 1.2.29 +Version: 1.2.30 Release: 0 Summary: Build OCI images from APK packages directly without Dockerfile License: Apache-2.0 ++++++ _service ++++++ --- /var/tmp/diff_new_pack.PnEp56/_old 2026-08-01 18:35:13.520006681 +0200 +++ /var/tmp/diff_new_pack.PnEp56/_new 2026-08-01 18:35:13.524006818 +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.29</param> + <param name="revision">refs/tags/v1.2.30</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> <param name="changesgenerate">enable</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.PnEp56/_old 2026-08-01 18:35:13.548007645 +0200 +++ /var/tmp/diff_new_pack.PnEp56/_new 2026-08-01 18:35:13.552007783 +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">e3915900849d95b35f1f5b7c7401922505332152</param></service></servicedata> + <param name="changesrevision">502643080cb38d339c5804fe7e62c9a5bd46b6d5</param></service></servicedata> (No newline at EOF) ++++++ apko-1.2.29.obscpio -> apko-1.2.30.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-1.2.29/go.mod new/apko-1.2.30/go.mod --- old/apko-1.2.29/go.mod 2026-07-24 15:46:38.000000000 +0200 +++ new/apko-1.2.30/go.mod 2026-07-30 20:33:18.000000000 +0200 @@ -3,7 +3,7 @@ go 1.26.0 require ( - chainguard.dev/sdk v0.1.140 + chainguard.dev/sdk v0.1.158 github.com/chainguard-dev/clog v1.8.1 github.com/charmbracelet/log v1.0.0 github.com/go-git/go-git/v5 v5.19.1 @@ -31,10 +31,10 @@ golang.org/x/sys v0.47.0 golang.org/x/term v0.45.0 golang.org/x/time v0.15.0 - google.golang.org/api v0.289.0 + google.golang.org/api v0.290.0 gopkg.in/ini.v1 v1.67.3 gopkg.in/yaml.v3 v3.0.1 - k8s.io/apimachinery v0.36.2 + k8s.io/apimachinery v0.36.3 sigs.k8s.io/release-utils v0.12.4 ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-1.2.29/go.sum new/apko-1.2.30/go.sum --- old/apko-1.2.29/go.sum 2026-07-24 15:46:38.000000000 +0200 +++ new/apko-1.2.30/go.sum 2026-07-30 20:33:18.000000000 +0200 @@ -1,7 +1,7 @@ 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.140 h1:9rV+7BG70uP+yqFC5IvU/f/fAleJ6kRdALXYMu29xZ0= -chainguard.dev/sdk v0.1.140/go.mod h1:hwsZl3o558o1R4d8hXrIYHZ6E9lCAXJgeVXQMnV5bRM= +chainguard.dev/sdk v0.1.158 h1:aOWATQ4zxYKQ8D+CCUj+hOU18wNQkbHw6tmj+/+GDAk= +chainguard.dev/sdk v0.1.158/go.mod h1:WIaM60bR6qU84RvE45u4QkOh+BN2uc1nfHuZYLnRfvU= cloud.google.com/go/auth v0.21.0 h1:g/QwYfYb2Ai6HH8oomAOyBaIHLbscZ4+T/F/f5JZHkE= cloud.google.com/go/auth v0.21.0/go.mod h1:M9o2Oz+YI2jAfxewJgb1vyI3vceHF+eohmxyzmrl+9s= cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= @@ -345,8 +345,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/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.289.0 h1:DmH0c6NigNFmsvsohM9bxv+MzVhag3aGHnojA5fFQjc= -google.golang.org/api v0.289.0/go.mod h1:weJZ3lldHFYI0DBFNKpJelUDNnusTt5YaOEgxvt8ci8= +google.golang.org/api v0.290.0 h1:eMw0Xo+IfbbMlKmW7aHvpyQRv9RCXuWx/vs8AD+0x9A= +google.golang.org/api v0.290.0/go.mod h1:weJZ3lldHFYI0DBFNKpJelUDNnusTt5YaOEgxvt8ci8= 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= @@ -372,8 +372,8 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= -k8s.io/apimachinery v0.36.2 h1:0PE/W/WNy1UX61NLbXY5TMbJ6UwLL6E6lAPkYrKFxbQ= -k8s.io/apimachinery v0.36.2/go.mod h1:fvf/HOLXq9RId0rnDIbN1OEBvHXdQbLMM8nu0LcBUf4= +k8s.io/apimachinery v0.36.3 h1:PkzMRBRG8joFD8EhCuQAtNPvJlxb82FwplP26HIzvAM= +k8s.io/apimachinery v0.36.3/go.mod h1:cTSjBWgPe/6CQyBKzY/hDIRWCQQQeK0mfLbml0UYFHE= pgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk= pgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= sigs.k8s.io/release-utils v0.12.4 h1:kuG6WTWGCKx5uUrJwl2uFErOKOw+4Ba8WrPmOQh5J3g= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-1.2.29/internal/cli/testdata/apko-discover.lock.json new/apko-1.2.30/internal/cli/testdata/apko-discover.lock.json --- old/apko-1.2.29/internal/cli/testdata/apko-discover.lock.json 2026-07-24 15:46:38.000000000 +0200 +++ new/apko-1.2.30/internal/cli/testdata/apko-discover.lock.json 2026-07-30 20:33:18.000000000 +0200 @@ -22,16 +22,16 @@ "content": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAyduVzi1mWm+lYo2Tqt/0\nXkCIWrDNP1QBMVPrE0/ZlU2bCGSoo2Z9FHQKz/mTyMRlhNqTfhJ5qU3U9XlyGOPJ\npiM+b91g26pnpXJ2Q2kOypSgOMOPA4cQ42PkHBEqhuzssfj9t7x47ppS94bboh46\nxLSDRff/NAbtwTpvhStV3URYkxFG++cKGGa5MPXBrxIp+iZf9GnuxVdST5PGiVGP\nODL/b69sPJQNbJHVquqUTOh5Ry8uuD2WZuXfKf7/C0jC/ie9m2+0CttNu9tMciGM\nEyKG1/Xhk5iIWO43m4SrrT2WkFlcZ1z2JSf9Pjm4C2+HovYpihwwdM/OdP8Xmsnr\nDzVB4YvQiW+IHBjStHVuyiZWc+JsgEPJzisNY0Wyc/kNyNtqVKpX6dRhMLanLmy+\nf53cCSI05KPQAcGj6tdL+D60uKDkt+FsDa0BTAobZ31OsFVid0vCXtsbplNhW1IF\nHwsGXBTVcfXg44RLyL8Lk/2dQxDHNHzAUslJXzPxaHBLmt++2COa2EI1iWlvtznk\nOk9WP8SOAIj+xdqoiHcC4j72BOVVgiITIJNHrbppZCq6qPR+fgXmXa+sDcGh30m6\n9Wpbr28kLMSHiENCWTdsFij+NQTd5S47H7XTROHnalYDuF1RpS+DpQidT5tUimaT\nJZDr++FjKrnnijbyNF8b98UCAwEAAQ==\n-----END PUBLIC KEY-----\n" }, { - "name": "apk.cgr.dev/chainguard/chainguard-4be246965c6e2749ccbaeba0582ed0f90c7cb94f4c0397e014b322b8652e3ba4.rsa.pub", - "url": "https://apk.cgr.dev/chainguard/chainguard-4be246965c6e2749ccbaeba0582ed0f90c7cb94f4c0397e014b322b8652e3ba4.rsa.pub", - "content": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvasoSqEq9IKa4E+vcx7H\nijkwVuKbgG9vjds2+IJaQQoL/5EucLtYQ2dKSiizAnQmdb4EZIcj/M9DHFu8YlCW\nnTzrPinyj+pq8pRrAO3zj8GqZ5IjhC/pv2YdbwjRJHTijiT8miYiZflc2JyEuZb7\newuhEaB/VLcwaS8BIKG+QTjj7QDllhhqyiaeFJxs5ljSNl4EA6m+uSUCir7F+Jb5\nlM9n5b4SGB04p1w36a3eZMIT98jUqvWadxnGt+AeNDad3wT42d95xf4U303q+uwp\nwGqyIvltDR2OMfVqU5tvW7s3PytHuP25N+vUxjquwTj8GqQbaa/w5wl7+Mu8yZhT\nvlFVytrHTZSFqpPVbVgzprpb+HAu4tHohI9Z5G1NzKpKb4HmJe3QSOK1i7dPk8RU\nR2z2hPNfJ1fVn7rT6L3iyShqPxNLst9MT44StzEtrO6vL7mc4Fs0QD/nJJ/30Nyn\nTNsKywONj39cEnIyq6Df/RAfFWL1HbWNDl8w2xe2eqI3VSFGFIjoqNCUvy43jrZc\nzE/K7gqY3eKX6jNfKu1kCHU6YqXCf6S7p7PhcNYX+BaXT5rEuU2e0SDR1gT1gI8K\nNXELTNI4opfQ9JR7KhAwIOyQbUu/q22SDSNbrXp+9h85SGd7gfhqgzR9ivN03k4X\n7H5Er4P2M9cqgT66vN//8rECAwEAAQ==\n-----END PUBLIC KEY-----\n" - }, - { "name": "apk.cgr.dev/chainguard/chainguard-7fb528a64a862d44bbea6069093f1fec29fa864ba7e9754828eeceed3f487239.rsa.pub", "url": "https://apk.cgr.dev/chainguard/chainguard-7fb528a64a862d44bbea6069093f1fec29fa864ba7e9754828eeceed3f487239.rsa.pub", "content": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAnuH20LnWxNl54a7mjSb5\nPmJssMelKeFQUDfzWZSTwCfFpBHRFq4KLWcUByqtmKphXLRMLjy0xR4xux7oh8n2\nCLP1NBt6d5skqaqHNFW24BO0ThrXUbwZ6jCAI0s2xSBaEPMea4Ipn2hmqZLwox6C\nqLGbEsbtRrkKXHva4jqFCX8h8ThwdQuKCEfr/nSk5IV+fn1Uoo8WK89cMUxlj1NB\nB5rdeJCcVaNlZTt2/Zw917BY+tjodWovbIGtqvnflOa5R28R+Q6bBh9oCDvkR6IU\n38NyT7szld5QgD9ebl5sNOFwk4mJdCNdi1wK9kSrBM7D8YEsStmawezpfvhwV55S\nQJpjuo6zJab25RAzcZoj+YhpBSl91QNRaKK3x5RlqW93tBCtpDjfpNqEHgyzHjc1\n4N46SQBU1NamkYBStTwMluc56lwmmWdKfnZXU0vULxQjCyBBeNSpsz8joyO60htD\nG52ieJ+NIqCEX7ikabWGCUfvAtEXDDDmo17JTyNSarziEfBImEtTOt8P93V6nRr7\nDz1fWKQC1pv9eFn1aS2TK50hWEgKpB+lmTf/j8UGawAWHQFND1ndDqNaJnVP/DqR\n6dt7krjlrDVEGq4s3GJabYADKxh0vXt1J4gef07dfEtEa6Aj9hikVyv3bQMeqtMK\nk/o1spotQWzE9+rffQfaUl8CAwEAAQ==\n-----END PUBLIC KEY-----\n" }, { + "name": "apk.cgr.dev/chainguard/chainguard-a758e63f677c21398431017ba63a5f1676378db460c8ee05bacf92d9227b1ba4.rsa.pub", + "url": "https://apk.cgr.dev/chainguard/chainguard-a758e63f677c21398431017ba63a5f1676378db460c8ee05bacf92d9227b1ba4.rsa.pub", + "content": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA75Fs9GZ+vxneIiuqUHgw\n32I2iGn9W+piZCYqO/kIs76fkh+/v4pESLL5jecqXMWi8LCYVkOh6y/zPPaEWrPp\ns2Ue4MKQ6AvItNmYK3g4zLY+Fy14jgIvmTflivRlKkKD/6Bm+SHdwk9ZicHjMwNA\n8JyUXGlCPbRmNrnMFKd+jMPSg2cUfyXCWVYyJcpVy82HUNNKmaX3FGWre/EYCFC+\nzXnwh2toogdcoLt4Q/UBHwsFPGLMj+hOWebQFaOKmUSH0jwwBhIMWbY07wz8Nsus\nUssCf/5NxabvQYGWPBgEHgXlgQKIapQ7BEgeC7gfYnl7wlDDczEgILaBNV7pgPAy\nZTgSewVbLzyeY/FOqLVzR+UU8PGiheXuib3MTtu08Shp3YAQ7mhtpdbH5TWbIo9R\nSOLr+KQHKxkR3vr5wREOFEh6uLeMRKXDS2HluFujcHcyEc2S7xMCoLY03Gj1u8/C\n1HiOrd2F7bdb9/W8DGm0DZ3sJNt4mzl01bCGAd/KVwN12rxSvg6xC6UI7gudNmGu\nv0t1oJ3J3LepvX4/1oZD7TEKT60dylowtwtmjPTUTWC1IKaoX12JPKcUy+dKHTzv\nK61WASFmD6lA6FvniJ6cNEHlsNTnfYxqq6hDTlQJ5N9ngXc3JRffkkI5CcYvKex3\nXkE6VrkMMBfL8HOyVM5VjDcCAwEAAQ==\n-----END PUBLIC KEY-----\n" + }, + { "name": "apk.cgr.dev/chainguard/chainguard-e3fb44d055702ed0dddf0f2acb1a0a07fc6075967092b203c7aac7db801d65f4.rsa.pub", "url": "https://apk.cgr.dev/chainguard/chainguard-e3fb44d055702ed0dddf0f2acb1a0a07fc6075967092b203c7aac7db801d65f4.rsa.pub", "content": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAs+GdB46rERN+mqR3jdGH\nAhrLuu4xxzcyIHQFDXXhFY4Cvzox2AI1/1Kv1UCZetce0w9QMgq35qGEWe61dykC\nLoShLZ1Wgr4OGbZW1J73UGdmYzYOWWJMeXSQ3cFSAFLS23ox72HEZQG7QwDApkjl\nIp9cjt4xpSu/A+25b7t8ZtJAdZgKd+yY8MLnOqxIOqgO2kHUTR+1F8QGBAQUC7AW\nu+1UkcsJbYz3wT61ybuYREGXadEUmJmef5cfCQ66eZ2q0tioSVSWiK9SQGKZwl3w\nb7XInD6UJGQxoj/f2NFzvS9gxG7Dzql4mx9boPHNbEU9X8sdVtoCBIA52Lv9dCLO\nQCVPvm9e+/l5WXlYvoEsAcRdTGlexOQkdAs0R2RjH/teqnU2D7WgjLmtor2Nk52R\nASzESzCyXiSfDH7yBpSuKPNpI4TXXnKnxgAawlz9V7TLLP54qwPpgJ8pxGHz5GaN\n5tikOt95O3If4MMoRbfjbNH0VQ0bAnMeQlE+qbWbLlLWlK3yQq9tbmApG4vVvdpc\nWKe0NPuoxnUkw1n7JQs70RxsJf3SJoC59Fio1mkl3QIsTMl+75IPfwBy3tmdYKQS\nbV5Cb0nnjuB9esVVnEmXUuAS27TQlQJcu2kpV/Uccwv0+4Df3F61MWlTLvjfkXZm\n6uEiubGXOuhXv+QtsNwYGlECAwEAAQ==\n-----END PUBLIC KEY-----\n" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-1.2.29/pkg/build/build_implementation.go new/apko-1.2.30/pkg/build/build_implementation.go --- old/apko-1.2.29/pkg/build/build_implementation.go 2026-07-24 15:46:38.000000000 +0200 +++ new/apko-1.2.30/pkg/build/build_implementation.go 2026-07-30 20:33:18.000000000 +0200 @@ -198,6 +198,12 @@ return nil, fmt.Errorf("failed to install certificates: %w", err) } + // Record checksums of the (possibly updated) CA bundles so downstream + // tooling (e.g. OpenSCAP) can verify they were not modified post-build. + if err := bc.writeCABundleChecksums(ctx); err != nil { + return nil, fmt.Errorf("failed to write CA bundle checksums: %w", err) + } + if err := bc.installRuntimeKeyring(ctx); err != nil { return nil, fmt.Errorf("failed to install runtime keyring: %w", err) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-1.2.29/pkg/build/build_test.go new/apko-1.2.30/pkg/build/build_test.go --- old/apko-1.2.29/pkg/build/build_test.go 2026-07-24 15:46:38.000000000 +0200 +++ new/apko-1.2.30/pkg/build/build_test.go 2026-07-30 20:33:18.000000000 +0200 @@ -16,6 +16,9 @@ import ( "context" + "crypto/sha256" + "encoding/hex" + "fmt" "net/http" "net/http/httptest" "path/filepath" @@ -179,6 +182,18 @@ _, err := fsys.Stat(p) require.NoError(t, err, "cert file %s should exist", p) } + + // A sha256 sidecar should be written next to the bundle, in sha256sum -c + // format, matching the final (post-append) contents of the bundle. + sidecarPath := "etc/ssl/certs/.ca-certificates.crt.sha256" + sidecarData, err := fsys.ReadFile(sidecarPath) + require.NoError(t, err, "CA bundle checksum sidecar should exist at %s", sidecarPath) + + sum := sha256.Sum256(bundleData) + require.Equal(t, + fmt.Sprintf("%s ca-certificates.crt\n", hex.EncodeToString(sum[:])), + string(sidecarData), + "sidecar must record the sha256 of the updated bundle") } func TestBuildImageFromLockFile(t *testing.T) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-1.2.29/pkg/build/certificates.go new/apko-1.2.30/pkg/build/certificates.go --- old/apko-1.2.29/pkg/build/certificates.go 2026-07-24 15:46:38.000000000 +0200 +++ new/apko-1.2.30/pkg/build/certificates.go 2026-07-30 20:33:18.000000000 +0200 @@ -260,6 +260,59 @@ return nil } +// caBundleChecksumSidecar returns the sidecar checksum path for a given CA +// bundle path, e.g. "etc/ssl/certs/ca-certificates.crt" becomes +// "etc/ssl/certs/.ca-certificates.crt.sha256". +func caBundleChecksumSidecar(bundlePath string) string { + return filepath.Join(filepath.Dir(bundlePath), "."+filepath.Base(bundlePath)+".sha256") +} + +// writeCABundleChecksums writes a sha256sum-compatible sidecar file next to each +// existing CA bundle and Java truststore so that downstream integrity tooling +// (e.g. OpenSCAP) can later verify they have not been modified since build time. +// It runs unconditionally after certificate installation, so every image that +// ships a CA bundle or truststore gets a baseline, whether or not additional +// certificates were configured. +func (bc *Context) writeCABundleChecksums(ctx context.Context) error { + _, span := otel.Tracer("apko").Start(ctx, "writeCABundleChecksums") + defer span.End() + + builtTime, err := bc.GetBuildDateEpoch() + if err != nil { + return fmt.Errorf("failed to get build date epoch: %w", err) + } + + // PEM CA bundles plus the binary Java truststore(s). For the truststore the + // checksum is a plain file-level hash of the JKS keystore as written. + for _, bundlePath := range slices.Concat(caBundlePaths, javaTruststorePaths) { + data, err := bc.fs.ReadFile(bundlePath) + if err != nil { + if errors.Is(err, fs.ErrNotExist) { + // No file at this path, nothing to checksum. + continue + } + return fmt.Errorf("failed to read certificate store %s: %w", bundlePath, err) + } + + sum := sha256.Sum256(data) + // sha256sum-compatible line ("<hex> <basename>\n"). Using the basename + // keeps the sidecar verifiable with `sha256sum -c` from the file's dir. + line := fmt.Sprintf("%s %s\n", hex.EncodeToString(sum[:]), filepath.Base(bundlePath)) + + sidecar := caBundleChecksumSidecar(bundlePath) + // Read-only (r--r--r--): a baseline that shouldn't be casually + // overwritten, matching the mode used for /etc/apko.json. + if err := bc.fs.WriteFile(sidecar, []byte(line), 0o444); err != nil { + return fmt.Errorf("failed to write certificate store checksum %s: %w", sidecar, err) + } + if err := bc.fs.Chtimes(sidecar, builtTime, builtTime); err != nil { + return fmt.Errorf("failed to change times on certificate store checksum %s: %w", sidecar, err) + } + } + + return nil +} + // loadJavaTruststores loads all existing Java truststores from the configured paths. // It is ok if no truststores exist; in that case, an empty slice is returned. func (bc *Context) loadJavaTruststores() ([]loadedTruststore, error) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-1.2.29/pkg/build/certificates_test.go new/apko-1.2.30/pkg/build/certificates_test.go --- old/apko-1.2.29/pkg/build/certificates_test.go 2026-07-24 15:46:38.000000000 +0200 +++ new/apko-1.2.30/pkg/build/certificates_test.go 2026-07-30 20:33:18.000000000 +0200 @@ -18,9 +18,12 @@ "archive/tar" "bytes" "context" + "crypto/sha256" + "encoding/hex" "fmt" "io/fs" "path/filepath" + "slices" "strings" "testing" "time" @@ -648,3 +651,86 @@ }) } } + +func TestWriteCABundleChecksums(t *testing.T) { + epoch := time.Unix(1337, 0) + t.Setenv("SOURCE_DATE_EPOCH", fmt.Sprintf("%d", epoch.Unix())) + + // sha256sum -c compatible line for the given content and basename. + sumLine := func(content []byte, name string) []byte { + sum := sha256.Sum256(content) + return fmt.Appendf(nil, "%s %s\n", hex.EncodeToString(sum[:]), name) + } + + bundle := []byte("-----BEGIN CERTIFICATE-----\nbundle\n-----END CERTIFICATE-----\n") + awsBundle := []byte("-----BEGIN CERTIFICATE-----\naws\n-----END CERTIFICATE-----\n") + truststore := []byte("not-really-jks-but-bytes-are-hashed-as-is") + + fsys := apkfs.NewMemFS() + existing := map[string][]byte{ + caBundlePaths[0]: bundle, // etc/ssl/certs/ca-certificates.crt + caBundlePaths[1]: awsBundle, // AWS ECS bundle + javaTruststorePaths[0]: truststore, // Java cacerts + } + for path, content := range existing { + if err := fsys.MkdirAll(filepath.Dir(path), 0o755); err != nil { + t.Fatalf("failed to create dir for %s: %v", path, err) + } + if err := fsys.WriteFile(path, content, 0o644); err != nil { + t.Fatalf("failed to write %s: %v", path, err) + } + } + + bc := &Context{ + o: options.Options{SourceDateEpoch: epoch}, + fs: fsys, + } + if err := bc.writeCABundleChecksums(context.Background()); err != nil { + t.Fatalf("writeCABundleChecksums() error = %v", err) + } + + wantSidecars := map[string][]byte{ + caBundleChecksumSidecar(caBundlePaths[0]): sumLine(bundle, "ca-certificates.crt"), + caBundleChecksumSidecar(caBundlePaths[1]): sumLine(awsBundle, "tls-ca-bundle.pem"), + caBundleChecksumSidecar(javaTruststorePaths[0]): sumLine(truststore, "cacerts"), + } + for path, want := range wantSidecars { + got, err := fsys.ReadFile(path) + if err != nil { + t.Fatalf("expected sidecar %s: %v", path, err) + } + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("sidecar content mismatch for %s (-want +got):\n%s", path, diff) + } + stat, err := fsys.Stat(path) + if err != nil { + t.Fatalf("failed to stat sidecar %s: %v", path, err) + } + if stat.Mode().Perm() != 0o444 { + t.Errorf("sidecar %s has mode %v, want 0444", path, stat.Mode().Perm()) + } + if !stat.ModTime().Equal(epoch) { + t.Errorf("sidecar %s has mod time %v, want %v", path, stat.ModTime(), epoch) + } + } +} + +func TestWriteCABundleChecksumsNoBundles(t *testing.T) { + epoch := time.Unix(1337, 0) + t.Setenv("SOURCE_DATE_EPOCH", fmt.Sprintf("%d", epoch.Unix())) + + fsys := apkfs.NewMemFS() + bc := &Context{ + o: options.Options{SourceDateEpoch: epoch}, + fs: fsys, + } + // No bundles present: should be a no-op, not an error. + if err := bc.writeCABundleChecksums(context.Background()); err != nil { + t.Fatalf("writeCABundleChecksums() error = %v", err) + } + for _, p := range slices.Concat(caBundlePaths, javaTruststorePaths) { + if _, err := fsys.Stat(caBundleChecksumSidecar(p)); err == nil { + t.Errorf("unexpected sidecar created for missing bundle %s", p) + } + } +} ++++++ apko.obsinfo ++++++ --- /var/tmp/diff_new_pack.PnEp56/_old 2026-08-01 18:35:16.136096764 +0200 +++ /var/tmp/diff_new_pack.PnEp56/_new 2026-08-01 18:35:16.168097865 +0200 @@ -1,5 +1,5 @@ name: apko -version: 1.2.29 -mtime: 1784900798 -commit: e3915900849d95b35f1f5b7c7401922505332152 +version: 1.2.30 +mtime: 1785436398 +commit: 502643080cb38d339c5804fe7e62c9a5bd46b6d5 ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/apko/vendor.tar.gz /work/SRC/openSUSE:Factory/.apko.new.16738/vendor.tar.gz differ: char 31, line 1
