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-02-03 21:32:14 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/apko (Old) and /work/SRC/openSUSE:Factory/.apko.new.1995 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "apko" Tue Feb 3 21:32:14 2026 rev:92 rq:1330667 version:1.1.3 Changes: -------- --- /work/SRC/openSUSE:Factory/apko/apko.changes 2026-02-02 14:56:22.965532216 +0100 +++ /work/SRC/openSUSE:Factory/.apko.new.1995/apko.changes 2026-02-03 21:33:57.230803207 +0100 @@ -1,0 +2,6 @@ +Tue Feb 03 06:08:05 UTC 2026 - Johannes Kastl <[email protected]> + +- Update to version 1.1.3: + * Bring back the FetchPackage function on APK (#2049) + +------------------------------------------------------------------- Old: ---- apko-1.1.2.obscpio New: ---- apko-1.1.3.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ apko.spec ++++++ --- /var/tmp/diff_new_pack.Kg5nuP/_old 2026-02-03 21:33:59.462896880 +0100 +++ /var/tmp/diff_new_pack.Kg5nuP/_new 2026-02-03 21:33:59.462896880 +0100 @@ -17,7 +17,7 @@ Name: apko -Version: 1.1.2 +Version: 1.1.3 Release: 0 Summary: Build OCI images from APK packages directly without Dockerfile License: Apache-2.0 ++++++ _service ++++++ --- /var/tmp/diff_new_pack.Kg5nuP/_old 2026-02-03 21:33:59.502898558 +0100 +++ /var/tmp/diff_new_pack.Kg5nuP/_new 2026-02-03 21:33:59.506898726 +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">v1.1.2</param> + <param name="revision">v1.1.3</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> <param name="changesgenerate">enable</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.Kg5nuP/_old 2026-02-03 21:33:59.542900237 +0100 +++ /var/tmp/diff_new_pack.Kg5nuP/_new 2026-02-03 21:33:59.558900908 +0100 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/chainguard-dev/apko</param> - <param name="changesrevision">aee88fb0b3633ca59825330fb5f97b13f08736e5</param></service></servicedata> + <param name="changesrevision">300620ee8c7cf2d51e152ac68c3e8bd60d3c323e</param></service></servicedata> (No newline at EOF) ++++++ apko-1.1.2.obscpio -> apko-1.1.3.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-1.1.2/pkg/apk/apk/implementation.go new/apko-1.1.3/pkg/apk/apk/implementation.go --- old/apko-1.1.2/pkg/apk/apk/implementation.go 2026-01-31 11:59:27.000000000 +0100 +++ new/apko-1.1.3/pkg/apk/apk/implementation.go 2026-02-02 19:15:33.000000000 +0100 @@ -1146,6 +1146,23 @@ return url.Parse(string(asURI)) } +// FetchPackage fetches the given package and returns a ReadCloser for its contents. +// This is only kept for backwards compatibility, prefer using packageGetter.GetPackage instead. +func (a *APK) FetchPackage(ctx context.Context, pkg FetchablePackage) (io.ReadCloser, error) { + // To keep existing behavior, this always uses the default package getter. + var getterOpts []packageGetterOption + if a.sizeLimits != nil { + if a.sizeLimits.APKControlMaxSize != 0 { + getterOpts = append(getterOpts, withAPKControlMaxSize(a.sizeLimits.APKControlMaxSize)) + } + if a.sizeLimits.APKDataMaxSize != 0 { + getterOpts = append(getterOpts, withAPKDataMaxSize(a.sizeLimits.APKDataMaxSize)) + } + } + getter := newDefaultPackageGetter(a.client, a.cache, a.auth, getterOpts...) + return getter.fetchPackage(ctx, pkg) +} + type WriteHeaderer interface { WriteHeader(hdr tar.Header, tfs fs.FS, pkg *Package) (bool, error) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-1.1.2/pkg/apk/apk/implementation_test.go new/apko-1.1.3/pkg/apk/apk/implementation_test.go --- old/apko-1.1.2/pkg/apk/apk/implementation_test.go 2026-01-31 11:59:27.000000000 +0100 +++ new/apko-1.1.3/pkg/apk/apk/implementation_test.go 2026-02-02 19:15:33.000000000 +0100 @@ -20,6 +20,7 @@ "io/fs" "net/http" "net/http/httptest" + "net/url" "os" "path/filepath" "runtime" @@ -656,3 +657,276 @@ }) } } + +// TestFetchPackage_original is the original TestFetchPackage added back to support FetchPackage method +func TestFetchPackage_original(t *testing.T) { + var ( + repo = Repository{URI: fmt.Sprintf("%s/%s", testAlpineRepos, testArch)} + packages = []*Package{&testPkg} + repoWithIndex = repo.WithIndex(&APKIndex{ + Packages: packages, + }) + testEtag = "testetag" + pkg = NewRepositoryPackage(&testPkg, repoWithIndex) + ctx = context.Background() + ) + prepLayout := func(t *testing.T, tr http.RoundTripper, cache string) *APK { + src := apkfs.NewMemFS() + err := src.MkdirAll("usr/lib/apk/db", 0o755) + require.NoError(t, err, "unable to mkdir /usr/lib/apk/db") + + opts := []Option{WithFS(src), WithIgnoreMknodErrors(ignoreMknodErrors), WithTransport(tr)} + if cache != "" { + opts = append(opts, WithCache(cache, false, NewCache(false))) + } + a, err := New(ctx, opts...) + require.NoError(t, err, "unable to create APK") + err = a.InitDB(ctx) + require.NoError(t, err) + + // set a client so we use local testdata instead of heading out to the Internet each time + return a + } + t.Run("no cache", func(t *testing.T) { + a := prepLayout(t, &testLocalTransport{root: testPrimaryPkgDir, basenameOnly: true}, "") + _, err := a.FetchPackage(ctx, pkg) + require.NoErrorf(t, err, "unable to install package") + }) + t.Run("cache miss no network", func(t *testing.T) { + // we use a transport that always returns a 404 so we know we're not hitting the network + // it should fail for a cache hit + tmpDir := t.TempDir() + a := prepLayout(t, &testLocalTransport{fail: true}, tmpDir) + _, err := a.FetchPackage(ctx, pkg) + require.Error(t, err, "should fail when no cache and no network") + }) + /* + These tests commented out since a.expandPackage is no longer available + t.Run("cache miss network should fill cache", func(t *testing.T) { + tmpDir := t.TempDir() + a := prepLayout(t, &testLocalTransport{root: testPrimaryPkgDir, basenameOnly: true}, tmpDir) + // fill the cache + repoDir := filepath.Join(tmpDir, url.QueryEscape(testAlpineRepos), testArch) + err := os.MkdirAll(repoDir, 0o755) + require.NoError(t, err, "unable to mkdir cache") + + cacheApkFile := filepath.Join(repoDir, testPkgFilename) + cacheApkDir := strings.TrimSuffix(cacheApkFile, ".apk") + + _, err = a.expandPackage(ctx, pkg) + require.NoErrorf(t, err, "unable to install pkg") + // check that the package file is in place + _, err = os.Stat(cacheApkDir) + require.NoError(t, err, "apk file not found in cache") + // check that the contents are the same + exp, err := a.cachedPackage(ctx, pkg, cacheApkDir) + if err != nil { + t.Logf("did not find cachedPackage(%q) in %s: %v", pkg.Name, cacheApkDir, err) + files, err := os.ReadDir(cacheApkDir) + require.NoError(t, err, "listing "+cacheApkDir) + for _, f := range files { + t.Logf(" found %q", f.Name()) + } + } + require.NoError(t, err, "unable to read cache apk file") + f, err := exp.APK() + require.NoError(t, err, "unable to read cached files as apk") + defer f.Close() + + apk1, err := io.ReadAll(f) + require.NoError(t, err, "unable to read cached apk bytes") + + apk2, err := os.ReadFile(filepath.Join(testPrimaryPkgDir, testPkgFilename)) + require.NoError(t, err, "unable to read previous apk file") + require.Equal(t, apk1, apk2, "apk files do not match") + }) + t.Run("handle missing cache files when expanding APK", func(t *testing.T) { + tmpDir := t.TempDir() + a := prepLayout(t, http.DefaultTransport, tmpDir) + + // Fill the cache + exp, err := a.expandPackage(ctx, pkg) + require.NoError(t, err, "unable to expand package") + _, err = os.Stat(exp.TarFile) + require.NoError(t, err, "unable to stat cached tar file") + + // Delete the tar file from the cache + require.NoError(t, os.Remove(exp.TarFile), "unable to delete cached tar file") + _, err = os.Stat(exp.TarFile) + require.ErrorIs(t, err, os.ErrNotExist, "unexpectedly able to stat cached tar file that should have been deleted") + + // Expand the package again, this should re-populate the cache. + exp2, err := a.expandPackage(ctx, pkg) + require.NoError(t, err, "unable to expandPackage after deleting cached tar file") + _, err = os.Stat(exp2.TarFile) + require.NoError(t, err, "unable to stat cached tar file") + + // Delete and recreate the tar file from the cache (changing its inodes) + bs, err := os.ReadFile(exp2.TarFile) + require.NoError(t, err, "unable to read cached tar file") + require.NoError(t, os.Remove(exp2.TarFile), "unable to delete cached tar file") + require.NoError(t, os.WriteFile(exp2.TarFile, bs, 0o644), "unable to recreate cached tar file") + + // Ensure that the underlying reader is different (i.e. we re-read the file) + exp3, err := a.expandPackage(ctx, pkg) + require.NoError(t, err, "unable to expandPackage after deleting and recreating cached tar file") + require.NotEqual(t, exp2.TarFS.UnderlyingReader(), exp3.TarFS.UnderlyingReader()) + + // We should be able to read the APK contents + rc, err := exp3.APK() + require.NoError(t, err, "unable to get reader for APK()") + _, err = io.ReadAll(rc) + require.NoError(t, err, "unable to read APK contents") + }) + */ + t.Run("cache hit no etag", func(t *testing.T) { + tmpDir := t.TempDir() + a := prepLayout(t, + &testLocalTransport{root: testAlternatePkgDir, basenameOnly: true, headers: map[string][]string{http.CanonicalHeaderKey("etag"): {testEtag}}}, + tmpDir) + // fill the cache + repoDir := filepath.Join(tmpDir, url.QueryEscape(testAlpineRepos), testArch) + err := os.MkdirAll(repoDir, 0o755) + require.NoError(t, err, "unable to mkdir cache") + + contents, err := os.ReadFile(filepath.Join(testPrimaryPkgDir, testPkgFilename)) + require.NoError(t, err, "unable to read apk file") + cacheApkFile := filepath.Join(repoDir, testPkgFilename) + err = os.WriteFile(cacheApkFile, contents, 0o644) //nolint:gosec // we're writing a test file + require.NoError(t, err, "unable to write cache apk file") + + _, err = a.FetchPackage(ctx, pkg) + require.NoErrorf(t, err, "unable to install pkg") + // check that the package file is in place + _, err = os.Stat(cacheApkFile) + require.NoError(t, err, "apk file not found in cache") + // check that the contents are the same as the original + apk1, err := os.ReadFile(cacheApkFile) + require.NoError(t, err, "unable to read cache apk file") + require.Equal(t, apk1, contents, "apk files do not match") + }) + t.Run("cache hit etag match", func(t *testing.T) { + tmpDir := t.TempDir() + a := prepLayout(t, + &testLocalTransport{root: testAlternatePkgDir, basenameOnly: true, headers: map[string][]string{http.CanonicalHeaderKey("etag"): {testEtag}}}, + tmpDir) + // fill the cache + repoDir := filepath.Join(tmpDir, url.QueryEscape(testAlpineRepos), testArch) + err := os.MkdirAll(repoDir, 0o755) + require.NoError(t, err, "unable to mkdir cache") + + contents, err := os.ReadFile(filepath.Join(testPrimaryPkgDir, testPkgFilename)) + require.NoError(t, err, "unable to read apk file") + cacheApkFile := filepath.Join(repoDir, testPkgFilename) + err = os.WriteFile(cacheApkFile, contents, 0o644) //nolint:gosec // we're writing a test file + require.NoError(t, err, "unable to write cache apk file") + err = os.WriteFile(cacheApkFile+".etag", []byte(testEtag), 0o644) //nolint:gosec // we're writing a test file + require.NoError(t, err, "unable to write etag") + + _, err = a.FetchPackage(ctx, pkg) + require.NoErrorf(t, err, "unable to install pkg") + // check that the package file is in place + _, err = os.Stat(cacheApkFile) + require.NoError(t, err, "apk file not found in cache") + // check that the contents are the same as the original + apk1, err := os.ReadFile(cacheApkFile) + require.NoError(t, err, "unable to read cache apk file") + require.Equal(t, apk1, contents, "apk files do not match") + }) + t.Run("cache hit etag miss", func(t *testing.T) { + tmpDir := t.TempDir() + a := prepLayout(t, + &testLocalTransport{root: testAlternatePkgDir, basenameOnly: true, headers: map[string][]string{http.CanonicalHeaderKey("etag"): {testEtag + "abcdefg"}}}, + tmpDir) + // fill the cache + repoDir := filepath.Join(tmpDir, url.QueryEscape(testAlpineRepos), testArch) + err := os.MkdirAll(repoDir, 0o755) + require.NoError(t, err, "unable to mkdir cache") + + contents, err := os.ReadFile(filepath.Join(testPrimaryPkgDir, testPkgFilename)) + require.NoError(t, err, "unable to read apk file") + cacheApkFile := filepath.Join(repoDir, testPkgFilename) + err = os.WriteFile(cacheApkFile, contents, 0o644) //nolint:gosec // we're writing a test file + require.NoError(t, err, "unable to write cache apk file") + err = os.WriteFile(cacheApkFile+".etag", []byte(testEtag), 0o644) //nolint:gosec // we're writing a test file + require.NoError(t, err, "unable to write etag") + + _, err = a.FetchPackage(ctx, pkg) + require.NoErrorf(t, err, "unable to install pkg") + // check that the package file is in place + _, err = os.Stat(cacheApkFile) + require.NoError(t, err, "apk file not found in cache") + // check that the contents are the same as the original + apk1, err := os.ReadFile(cacheApkFile) + require.NoError(t, err, "unable to read cache apk file") + apk2, err := os.ReadFile(filepath.Join(testAlternatePkgDir, testPkgFilename)) + require.NoError(t, err, "unable to read testdata apk file") + require.Equal(t, apk1, apk2, "apk files do not match") + }) +} + +// TestAuth_good_original is the original TestAuth_good added back to support FetchPackage method +func TestAuth_good_original(t *testing.T) { + called := false + s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + called = true + if gotuser, gotpass, ok := r.BasicAuth(); !ok || gotuser != testUser || gotpass != testPass { + w.WriteHeader(http.StatusForbidden) + return + } + http.FileServer(http.Dir(testPrimaryPkgDir)).ServeHTTP(w, r) + })) + defer s.Close() + host := strings.TrimPrefix(s.URL, "http://") + + repo := Repository{URI: s.URL} + repoWithIndex := repo.WithIndex(&APKIndex{Packages: []*Package{&testPkg}}) + pkg := NewRepositoryPackage(&testPkg, repoWithIndex) + ctx := context.Background() + + src := apkfs.NewMemFS() + err := src.MkdirAll("usr/lib/apk/db", 0o755) + require.NoError(t, err, "unable to mkdir /usr/lib/apk/db") + + a, err := New(ctx, WithFS(src), WithAuthenticator(auth.StaticAuth(host, testUser, testPass))) + require.NoError(t, err, "unable to create APK") + err = a.InitDB(ctx) + require.NoError(t, err) + + _, err = a.FetchPackage(ctx, pkg) + require.NoErrorf(t, err, "unable to install package") + require.True(t, called, "did not make request") +} + +// TestAuth_bad_original is the original TestAuth_bad added back to support FetchPackage method +func TestAuth_bad_original(t *testing.T) { + called := false + s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + called = true + if gotuser, gotpass, ok := r.BasicAuth(); !ok || gotuser != testUser || gotpass != testPass { + w.WriteHeader(http.StatusForbidden) + return + } + http.FileServer(http.Dir(testPrimaryPkgDir)).ServeHTTP(w, r) + })) + defer s.Close() + host := strings.TrimPrefix(s.URL, "http://") + + repo := Repository{URI: s.URL} + repoWithIndex := repo.WithIndex(&APKIndex{Packages: []*Package{&testPkg}}) + pkg := NewRepositoryPackage(&testPkg, repoWithIndex) + ctx := context.Background() + + src := apkfs.NewMemFS() + err := src.MkdirAll("usr/lib/apk/db", 0o755) + require.NoError(t, err, "unable to mkdir /usr/lib/apk/db") + + a, err := New(ctx, WithFS(src), WithAuthenticator(auth.StaticAuth(host, "baduser", "badpass"))) + require.NoError(t, err, "unable to create APK") + err = a.InitDB(ctx) + require.NoError(t, err) + + _, err = a.FetchPackage(ctx, pkg) + require.Error(t, err, "should fail with bad auth") + require.True(t, called, "did not make request") +} ++++++ apko.obsinfo ++++++ --- /var/tmp/diff_new_pack.Kg5nuP/_old 2026-02-03 21:34:00.298931965 +0100 +++ /var/tmp/diff_new_pack.Kg5nuP/_new 2026-02-03 21:34:00.306932301 +0100 @@ -1,5 +1,5 @@ name: apko -version: 1.1.2 -mtime: 1769857167 -commit: aee88fb0b3633ca59825330fb5f97b13f08736e5 +version: 1.1.3 +mtime: 1770056133 +commit: 300620ee8c7cf2d51e152ac68c3e8bd60d3c323e ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/apko/vendor.tar.gz /work/SRC/openSUSE:Factory/.apko.new.1995/vendor.tar.gz differ: char 87, line 1
