Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package apko for openSUSE:Factory checked in 
at 2025-01-23 18:03:32
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/apko (Old)
 and      /work/SRC/openSUSE:Factory/.apko.new.5589 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "apko"

Thu Jan 23 18:03:32 2025 rev:34 rq:1239726 version:0.23.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/apko/apko.changes        2025-01-22 
16:32:22.572081132 +0100
+++ /work/SRC/openSUSE:Factory/.apko.new.5589/apko.changes      2025-01-23 
18:04:25.965706803 +0100
@@ -1,0 +2,6 @@
+Thu Jan 23 06:07:29 UTC 2025 - opensuse_buildserv...@ojkastl.de
+
+- Update to version 0.23.0:
+  * fix multi key support in APKINDEX verification (#1490)
+
+-------------------------------------------------------------------

Old:
----
  apko-0.22.7.obscpio

New:
----
  apko-0.23.0.obscpio

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

Other differences:
------------------
++++++ apko.spec ++++++
--- /var/tmp/diff_new_pack.zDLyzk/_old  2025-01-23 18:04:31.145920622 +0100
+++ /var/tmp/diff_new_pack.zDLyzk/_new  2025-01-23 18:04:31.145920622 +0100
@@ -17,7 +17,7 @@
 
 
 Name:           apko
-Version:        0.22.7
+Version:        0.23.0
 Release:        0
 Summary:        Build OCI images from APK packages directly without Dockerfile
 License:        Apache-2.0

++++++ _service ++++++
--- /var/tmp/diff_new_pack.zDLyzk/_old  2025-01-23 18:04:31.181922109 +0100
+++ /var/tmp/diff_new_pack.zDLyzk/_new  2025-01-23 18:04:31.185922274 +0100
@@ -3,7 +3,7 @@
     <param name="url">https://github.com/chainguard-dev/apko</param>
     <param name="scm">git</param>
     <param name="exclude">.git</param>
-    <param name="revision">v0.22.7</param>
+    <param name="revision">v0.23.0</param>
     <param name="versionformat">@PARENT_TAG@</param>
     <param name="versionrewrite-pattern">v(.*)</param>
     <param name="changesgenerate">enable</param>

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.zDLyzk/_old  2025-01-23 18:04:31.205923099 +0100
+++ /var/tmp/diff_new_pack.zDLyzk/_new  2025-01-23 18:04:31.209923265 +0100
@@ -1,6 +1,6 @@
 <servicedata>
 <service name="tar_scm">
                 <param 
name="url">https://github.com/chainguard-dev/apko</param>
-              <param 
name="changesrevision">222193882ef17fda2b4763fb3970344c68fe666b</param></service></servicedata>
+              <param 
name="changesrevision">ec48e3070da9b4691b74de219fffd69d31da3f5d</param></service></servicedata>
 (No newline at EOF)
 

++++++ apko-0.22.7.obscpio -> apko-0.23.0.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/apko-0.22.7/pkg/apk/apk/apkindex_test.go 
new/apko-0.23.0/pkg/apk/apk/apkindex_test.go
--- old/apko-0.22.7/pkg/apk/apk/apkindex_test.go        2025-01-22 
01:02:58.000000000 +0100
+++ new/apko-0.23.0/pkg/apk/apk/apkindex_test.go        2025-01-23 
00:02:19.000000000 +0100
@@ -3,6 +3,7 @@
 import (
        "archive/tar"
        "compress/gzip"
+       "context"
        "fmt"
        "io"
        "os"
@@ -238,3 +239,52 @@
        require.Len(t, pkg.Provides, 0, "Expected no provides")
        require.Len(t, pkg.Dependencies, 0, "Expected no dependencies")
 }
+
+func TestMultipleKeys(t *testing.T) {
+       assert := assert.New(t)
+       // read all the keys from testdata/signing/keys
+       folder := "testdata/signing/keys"
+       // get all the files in the folder
+       files, _ := os.ReadDir(folder)
+       keys := make(map[string][]byte)
+       for _, file := range files {
+               if file.IsDir() {
+                       continue
+               }
+               // read the file
+               keyFile, err := os.Open(fmt.Sprintf("%s/%s", folder, 
file.Name()))
+               require.Nil(t, err)
+               // parse the key
+               key, err := os.ReadFile(keyFile.Name())
+               require.Nil(t, err)
+               keys[file.Name()] = key
+       }
+       // read the index file into []byte
+       indexBytes, err := os.ReadFile("testdata/signing/APKINDEX.tar.gz")
+       require.Nil(t, err)
+
+       ctx := context.Background()
+       // There are 2^N-1 combinations of keys, where N is the number of keys
+       // We will test all of them
+       for comb := 1; comb < (1 << len(keys)); comb++ {
+               // get the keys to use
+               usedKeys := make(map[string][]byte)
+               for i := 0; i < len(keys); i++ {
+                       if (comb & (1 << i)) != 0 {
+                               usedKeys[files[i].Name()] = 
keys[files[i].Name()]
+                       }
+               }
+               // parse the index
+               apkIndex, err := parseRepositoryIndex(ctx, 
"testdata/signing/APKINDEX.tar.gz",
+                       usedKeys, "aarch64", indexBytes, &indexOpts{})
+               require.Nil(t, err)
+               assert.Greater(len(apkIndex.Signature), 0, "Signature missing")
+       }
+       // Now, test the case where we have no matching key
+       _, err = parseRepositoryIndex(ctx, "testdata/signing/APKINDEX.tar.gz",
+               map[string][]byte{
+                       "unused-key": []byte("unused-key-data"),
+               },
+               "aarch64", indexBytes, &indexOpts{})
+       require.NotNil(t, err)
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/apko-0.22.7/pkg/apk/apk/index.go 
new/apko-0.23.0/pkg/apk/apk/index.go
--- old/apko-0.22.7/pkg/apk/apk/index.go        2025-01-22 01:02:58.000000000 
+0100
+++ new/apko-0.23.0/pkg/apk/apk/index.go        2025-01-23 00:02:19.000000000 
+0100
@@ -44,6 +44,12 @@
 
 var signatureFileRegex = 
regexp.MustCompile(`^\.SIGN\.(DSA|RSA|RSA256|RSA512)\.(.*\.rsa\.pub)$`)
 
+type Signature struct {
+       KeyID           string
+       Signature       []byte
+       DigestAlgorithm crypto.Hash
+}
+
 // This is terrible but simpler than plumbing around a cache for now.
 // We just hold the parsed index in memory rather than re-parsing it every 
time,
 // which requires gunzipping, which is (somewhat) expensive.
@@ -332,9 +338,11 @@
 func parseRepositoryIndex(ctx context.Context, u string, keys 
map[string][]byte, arch string, b []byte, opts *indexOpts) (*APKIndex, error) { 
//nolint:gocyclo
        _, span := otel.Tracer("go-apk").Start(ctx, "parseRepositoryIndex")
        defer span.End()
-
        // validate the signature
        if shouldCheckSignatureForIndex(u, arch, opts) {
+               if len(keys) == 0 {
+                       return nil, fmt.Errorf("no keys provided to verify 
signature")
+               }
                buf := bytes.NewReader(b)
                gzipReader, err := gzip.NewReader(buf)
                if err != nil {
@@ -348,14 +356,12 @@
 
                tarReader := tar.NewReader(gzipReader)
 
-               var keyfile string
-               var signature []byte
-               var indexDigestType crypto.Hash
+               sigs := make([]Signature, 0, len(keys))
                for {
                        // read the signature(s)
                        signatureFile, err := tarReader.Next()
                        // found everything, end of stream
-                       if len(keyfile) > 0 && errors.Is(err, io.EOF) {
+                       if errors.Is(err, io.EOF) {
                                break
                        }
                        // oops something went wrong
@@ -366,29 +372,40 @@
                        if len(matches) != 3 {
                                return nil, fmt.Errorf("failed to find key name 
in signature file name: %s", signatureFile.Name)
                        }
-                       // It is lucky that golang only iterates over sorted 
file names, and that
-                       // lexically latest is the strongest hash
+                       keyfile := matches[2]
+                       if _, ok := keys[keyfile]; !ok {
+                               // Ignore this signature if we don't have the 
key
+                               continue
+                       }
+                       var digestAlgorithm crypto.Hash
                        switch signatureType := matches[1]; signatureType {
                        case "DSA":
                                // Obsolete
                                continue
                        case "RSA":
                                // Current legacy compat
-                               indexDigestType = crypto.SHA1
+                               digestAlgorithm = crypto.SHA1
                        case "RSA256":
                                // Current best practice
-                               indexDigestType = crypto.SHA256
+                               digestAlgorithm = crypto.SHA256
                        case "RSA512":
                                // Too big, too slow, not compiled in
                                continue
                        default:
                                return nil, fmt.Errorf("unknown signature 
format: %s", signatureType)
                        }
-                       keyfile = matches[2]
-                       signature, err = io.ReadAll(tarReader)
+                       signature, err := io.ReadAll(tarReader)
                        if err != nil {
                                return nil, fmt.Errorf("failed to read 
signature from repository index: %w", err)
                        }
+                       sigs = append(sigs, Signature{
+                               KeyID:           keyfile,
+                               Signature:       signature,
+                               DigestAlgorithm: digestAlgorithm,
+                       })
+               }
+               if len(sigs) == 0 {
+                       return nil, fmt.Errorf("no signature with known key 
found in repository index")
                }
                // we now have the signature bytes and name, get the contents 
of the rest;
                // this should be everything else in the raw gzip file as is.
@@ -396,31 +413,26 @@
                unreadBytes := buf.Len()
                readBytes := allBytes - unreadBytes
                indexData := b[readBytes:]
-               indexDigest, err := sign.HashData(indexData, indexDigestType)
-               if err != nil {
-                       return nil, err
-               }
-               // now we can check the signature
-               if keys == nil {
-                       return nil, fmt.Errorf("no keys provided to verify 
signature")
-               }
-               var verified bool
-               keyData, ok := keys[keyfile]
-               if ok {
-                       if err := sign.RSAVerifyDigest(indexDigest, 
indexDigestType, signature, keyData); err != nil {
-                               verified = false
-                       }
-               }
-               if !verified {
-                       for _, keyData := range keys {
-                               if err := sign.RSAVerifyDigest(indexDigest, 
indexDigestType, signature, keyData); err == nil {
-                                       verified = true
-                                       break
+               indexDigest := make(map[crypto.Hash][]byte, len(keys))
+               verified := false
+               for _, sig := range sigs {
+                       // compute the digest if not already done
+                       if _, hasDigest := indexDigest[sig.DigestAlgorithm]; 
!hasDigest {
+                               digest, err := sign.HashData(indexData, 
sig.DigestAlgorithm)
+                               if err != nil {
+                                       return nil, fmt.Errorf("failed to 
compute digest: %w", err)
                                }
+                               indexDigest[sig.DigestAlgorithm] = digest
+                       }
+                       if err := 
sign.RSAVerifyDigest(indexDigest[sig.DigestAlgorithm], sig.DigestAlgorithm, 
sig.Signature, keys[sig.KeyID]); err == nil {
+                               verified = true
+                               break
+                       } else {
+                               clog.FromContext(ctx).Warnf("failed to verify 
signature for keyfile %s: %v", sig.KeyID, err)
                        }
                }
                if !verified {
-                       return nil, fmt.Errorf("no key found to verify 
signature for keyfile %s; tried all other keys as well", keyfile)
+                       return nil, errors.New("signature verification failed 
for repository index, for all provided keys")
                }
        }
        // with a valid signature, convert it to an ApkIndex
Binary files old/apko-0.22.7/pkg/apk/apk/testdata/signing/APKINDEX.tar.gz and 
new/apko-0.23.0/pkg/apk/apk/testdata/signing/APKINDEX.tar.gz differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/apko-0.22.7/pkg/apk/apk/testdata/signing/keys/chainguard-0106f58bac88057c2ff5c2829850df492717a876ed700443550353c7ab23f5a0.rsa.pub
 
new/apko-0.23.0/pkg/apk/apk/testdata/signing/keys/chainguard-0106f58bac88057c2ff5c2829850df492717a876ed700443550353c7ab23f5a0.rsa.pub
--- 
old/apko-0.22.7/pkg/apk/apk/testdata/signing/keys/chainguard-0106f58bac88057c2ff5c2829850df492717a876ed700443550353c7ab23f5a0.rsa.pub
       1970-01-01 01:00:00.000000000 +0100
+++ 
new/apko-0.23.0/pkg/apk/apk/testdata/signing/keys/chainguard-0106f58bac88057c2ff5c2829850df492717a876ed700443550353c7ab23f5a0.rsa.pub
       2025-01-23 00:02:19.000000000 +0100
@@ -0,0 +1,14 @@
+-----BEGIN PUBLIC KEY-----
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2TxPZPC1Cdb647P0kvi5
+wtwcoaFCOGHspL3RmmD2idG2FNZc/rpwyIp2bnprFvOCWm7bKAEl/9JDfAGm7DAP
+q/EC7UeJ9yx03jY1I7+Oj1/1UUIyuvfDwyiMxEwcABaivAn9WhYZ5YeZKK8pUYoX
+hOPNqgI+N3BY1H+hgg3xgTrzWmfRSsvTEhSqoLHdl4qbsM5EE/T5W7u+96y9J2vn
+M89rUP557K3n1QKGzTIGjlesFQd8y+uH0TdAe6AFmxFpftdXRu4KInjdrDOArfBO
+cKLB0gHOERkd08JVMWYHd6Ne7BfWpwxmge371GgTj8XYOJrkAj3cg8ked/51Maw0
+FLt4aErQR6y02QIluGZ4gwbIZ8y+iBWvoh8egiab3Whr3SwGuX6X8WJbOgKLCyGK
+CmrxgPO/ahS4XUWtuTp3woIZBnnHGOBdHjRARkl9PdBgN2HhZPS9vj8rrIqbTp3c
+dmqhcsjsgmss6Sb3rOcOL3N3V8+dMiD7VZXeIgVocOpRtLJGQFCupjAfmz5ub4t5
+lBI2EgbR9LdSg9mrFoYbG11sU6MLa0iPMA8gU3nG4dzLDpsF9PbXy6sfBXXc8W25
+tfwZnV4wHouWEhiQ9Hfc4NOGcs+01Zwg9CZRS2SBKC9iqUPsz3RaTAKWsS/QNTND
+Zy9znhL5yGrbHaq2BOlnVqMCAwEAAQ==
+-----END PUBLIC KEY-----
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/apko-0.22.7/pkg/apk/apk/testdata/signing/keys/chainguard-60912bbc46bfc8ed6bda0b50db3a8a5f3c4344d6bc8549ec9b84d96140b475d1.rsa.pub
 
new/apko-0.23.0/pkg/apk/apk/testdata/signing/keys/chainguard-60912bbc46bfc8ed6bda0b50db3a8a5f3c4344d6bc8549ec9b84d96140b475d1.rsa.pub
--- 
old/apko-0.22.7/pkg/apk/apk/testdata/signing/keys/chainguard-60912bbc46bfc8ed6bda0b50db3a8a5f3c4344d6bc8549ec9b84d96140b475d1.rsa.pub
       1970-01-01 01:00:00.000000000 +0100
+++ 
new/apko-0.23.0/pkg/apk/apk/testdata/signing/keys/chainguard-60912bbc46bfc8ed6bda0b50db3a8a5f3c4344d6bc8549ec9b84d96140b475d1.rsa.pub
       2025-01-23 00:02:19.000000000 +0100
@@ -0,0 +1,14 @@
+-----BEGIN PUBLIC KEY-----
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAizNP/QKfB5NKlVBba6dX
+Jzz0/icPE++eM3aAtCARwlAKyRm3ivWM5sAz88lwHFjMAQV0QPD3hDgswcAExTXa
+EPN8M0RroxxnWuJLGhz99ONaGOLo66GDkcdBaaZIinXoWmhqg1zcequ6dLDOGArm
+ZR99egaBFKyQHvBYHIl5dQ1yT8us/m1Yfb7DlERcU2lf3lFhLDrJsBgVw5QYa5h+
+aSneA/B2ZB1BwfyE3F5+UUn0qWRy3Yg526oaWpjjwCaPVq4yaJfg4XuMS82wdVm9
+G6awP1PE0EWwgkcc8z8w7BmxFhdCRt0VNjmept14tJwiU0d81j1HPHsIkqWr2TBA
+f7Wwp34+ByfA7iHbKXFPgK1MKmNzyANoyPaPRo+x+MU8D2AqUBslKOKrhckyd4tQ
+ch3SyaMKMa7hc0PWnFrCCtDTmNZQaquNrUWnbbMtdkjCA/is//W+Lqn+O6BjmR9U
+yztR26l2OwGMu6uf3CMUADX/ra4k2BuxSnaPTgm7M19AAzXSnICa+aupgFsIfx1w
+UyGlq8dvCz8bnipXW4EbTWTSPdFrxQl/LQUB5w82kMorML1TQEpSLjoSmnhNg+rh
+rqIsjp7fwEnX/qTbiwUhgcN1fyLkGGv/UV/H62WcclStKiRHp+ND0ePMABefA+cv
+f9tYynbOV78qct+dQKkQ17kCAwEAAQ==
+-----END PUBLIC KEY-----
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/apko-0.22.7/pkg/apk/apk/testdata/signing/keys/chainguard-61cb6bccd1f584b007db7be51ebce2b0530a54cc5a94e7650b570d113d537cf3.rsa.pub
 
new/apko-0.23.0/pkg/apk/apk/testdata/signing/keys/chainguard-61cb6bccd1f584b007db7be51ebce2b0530a54cc5a94e7650b570d113d537cf3.rsa.pub
--- 
old/apko-0.22.7/pkg/apk/apk/testdata/signing/keys/chainguard-61cb6bccd1f584b007db7be51ebce2b0530a54cc5a94e7650b570d113d537cf3.rsa.pub
       1970-01-01 01:00:00.000000000 +0100
+++ 
new/apko-0.23.0/pkg/apk/apk/testdata/signing/keys/chainguard-61cb6bccd1f584b007db7be51ebce2b0530a54cc5a94e7650b570d113d537cf3.rsa.pub
       2025-01-23 00:02:19.000000000 +0100
@@ -0,0 +1,14 @@
+-----BEGIN PUBLIC KEY-----
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAwlV2kG9xGtkVWc/dS9nC
+Qqef/hx0AysYfrMFetY+mZ0MPvELqOaDJgtjlbMM6w/ujqDtScxbnNNf5/vY/wBh
+rHTeKU+oDlkRTsh8ZxKINFfGGSDxR2pKkvPZeVzxdhTNEPK9ZggbFHe5RhXUT9iK
+CNgF+Xa3p5A1Yi8zR6zEFJ5EDBMnTMagV2ueLfJrpFMm/4hBn6zWtjyDhDPVZyTD
+DyQc2/FIDXM1tJONWDT8wO2xuHf7xKGr6lO/CZca5Pnd/QS5jODoNbTo9VvG+oQt
+mRsWsdVFst0vS54s3mchtuAB2NXnWAZZuux9uYPgvO8eqI0RLqCKX7VLJ8tGOTmL
+3dblTzKbKbVcy4uHsyH2mZPvPUTO+ck7c58iSeUrOFV50B6zqynAXgCrDo3XMjpI
+mLC26LRMqF/Q/RWc9R0K+ZgiLQ7ootyOJILPSR69RhgdQJVt7/gz55dM89yoq/B9
+U2V+1mv0rBQmmNgCM1U3QdgUv5WeIm4Ed2avKZBwJLBVR5AxlY9xlwJ7sEU4Ms2t
+cEblWhqDze/sSsjCYOAmD4/M/90OnBelg+/BU2jOD4nqQdEQDOZdo+EUVeCIuPwD
+kz8kTv8pPtLjKI0jRhYLn2dhg/vTIDJf19iXexGQXOyK/rNwi41i+9snypVb8YSe
+cWTnq+m2CFOiXFsDWQh7RsUCAwEAAQ==
+-----END PUBLIC KEY-----

++++++ apko.obsinfo ++++++
--- /var/tmp/diff_new_pack.zDLyzk/_old  2025-01-23 18:04:31.497935153 +0100
+++ /var/tmp/diff_new_pack.zDLyzk/_new  2025-01-23 18:04:31.497935153 +0100
@@ -1,5 +1,5 @@
 name: apko
-version: 0.22.7
-mtime: 1737504178
-commit: 222193882ef17fda2b4763fb3970344c68fe666b
+version: 0.23.0
+mtime: 1737586939
+commit: ec48e3070da9b4691b74de219fffd69d31da3f5d
 

++++++ vendor.tar.gz ++++++
/work/SRC/openSUSE:Factory/apko/vendor.tar.gz 
/work/SRC/openSUSE:Factory/.apko.new.5589/vendor.tar.gz differ: char 5, line 1

Reply via email to