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-06 16:41:18
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/apko (Old)
 and      /work/SRC/openSUSE:Factory/.apko.new.16738 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "apko"

Thu Aug  6 16:41:18 2026 rev:133 rq:1370055 version:1.2.35

Changes:
--------
--- /work/SRC/openSUSE:Factory/apko/apko.changes        2026-08-04 
23:28:38.170252474 +0200
+++ /work/SRC/openSUSE:Factory/.apko.new.16738/apko.changes     2026-08-06 
16:41:21.700319256 +0200
@@ -1,0 +2,27 @@
+Thu Aug 06 11:00:52 UTC 2026 - Johannes Kastl 
<[email protected]>
+
+- Update to version 1.2.35:
+  * fix(apk): honour offline mode in InitDB key discovery without a
+    cache (#2377)
+  * test: set source date epoch to `0` (#2372)
+  * Disable Go module caching in goreleaser workflows (#2375)
+
+-------------------------------------------------------------------
+Wed Aug 05 10:35:10 UTC 2026 - Johannes Kastl 
<[email protected]>
+
+- Update to version 1.2.34:
+  * apk: handle Alpine key fetches without a cache (#2374)
+  * build: add a disk cache opt-out (#2373)
+
+-------------------------------------------------------------------
+Wed Aug 05 05:18:08 UTC 2026 - Johannes Kastl 
<[email protected]>
+
+- Update to version 1.2.33:
+  * build(deps): bump github.com/google/go-containerregistry from
+    0.21.7 to 0.21.8 (#2371)
+  * build(deps): bump chainguard.dev/sdk from 0.1.163 to 0.1.164
+    (#2370)
+  * build(deps): bump zizmorcore/zizmor-action from 0.6.1 to 0.6.2
+    (#2369)
+
+-------------------------------------------------------------------

Old:
----
  apko-1.2.32.obscpio

New:
----
  apko-1.2.35.obscpio

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

Other differences:
------------------
++++++ apko.spec ++++++
--- /var/tmp/diff_new_pack.uaGfcT/_old  2026-08-06 16:41:25.304443614 +0200
+++ /var/tmp/diff_new_pack.uaGfcT/_new  2026-08-06 16:41:25.308443752 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           apko
-Version:        1.2.32
+Version:        1.2.35
 Release:        0
 Summary:        Build OCI images from APK packages directly without Dockerfile
 License:        Apache-2.0

++++++ _service ++++++
--- /var/tmp/diff_new_pack.uaGfcT/_old  2026-08-06 16:41:25.356445408 +0200
+++ /var/tmp/diff_new_pack.uaGfcT/_new  2026-08-06 16:41:25.360445547 +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.32</param>
+    <param name="revision">refs/tags/v1.2.35</param>
     <param name="versionformat">@PARENT_TAG@</param>
     <param name="versionrewrite-pattern">v(.*)</param>
     <param name="changesgenerate">enable</param>

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.uaGfcT/_old  2026-08-06 16:41:25.388446512 +0200
+++ /var/tmp/diff_new_pack.uaGfcT/_new  2026-08-06 16:41:25.392446651 +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">ea62bef5271a0c94f3fba641ee0e8d506b9b57ef</param></service></servicedata>
+              <param 
name="changesrevision">766682c7e7f87cc932ff02abeb889f5eab5edc9f</param></service></servicedata>
 (No newline at EOF)
 

++++++ apko-1.2.32.obscpio -> apko-1.2.35.obscpio ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/apko-1.2.32/go.mod new/apko-1.2.35/go.mod
--- old/apko-1.2.32/go.mod      2026-08-04 07:48:25.000000000 +0200
+++ new/apko-1.2.35/go.mod      2026-08-06 11:49:06.000000000 +0200
@@ -3,12 +3,12 @@
 go 1.26.0
 
 require (
-       chainguard.dev/sdk v0.1.163
+       chainguard.dev/sdk v0.1.164
        github.com/chainguard-dev/clog v1.8.1
        github.com/charmbracelet/log v1.0.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.7
+       github.com/google/go-containerregistry v0.21.8
        github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
        github.com/hashicorp/go-cleanhttp v0.5.2
        github.com/hashicorp/go-retryablehttp v0.7.8
@@ -66,7 +66,7 @@
        github.com/cyphar/filepath-securejoin v0.7.0 // indirect
        github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // 
indirect
        github.com/distribution/reference v0.6.0 // indirect
-       github.com/docker/cli v29.6.1+incompatible // indirect
+       github.com/docker/cli v29.6.2+incompatible // indirect
        github.com/docker/docker-credential-helpers v0.9.8 // indirect
        github.com/docker/go-connections v0.7.0 // indirect
        github.com/docker/go-units v0.5.0 // indirect
@@ -97,7 +97,7 @@
        github.com/mattn/go-runewidth v0.0.24 // indirect
        github.com/moby/docker-image-spec v1.3.1 // indirect
        github.com/moby/moby/api v1.55.0 // indirect
-       github.com/moby/moby/client v0.5.0 // indirect
+       github.com/moby/moby/client v0.5.1 // indirect
        github.com/muesli/termenv v0.16.0 // indirect
        github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // 
indirect
        github.com/opencontainers/go-digest v1.0.0 // indirect
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/apko-1.2.32/go.sum new/apko-1.2.35/go.sum
--- old/apko-1.2.32/go.sum      2026-08-04 07:48:25.000000000 +0200
+++ new/apko-1.2.35/go.sum      2026-08-06 11:49:06.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.163 h1:G85vXLU7qJ2pJo1hHcPRYWWZnGRUAVIomZfoq9dg8Dk=
-chainguard.dev/sdk v0.1.163/go.mod 
h1:y5AGo04erWjKtEyGX7fO9zZA4vtj9cLGXZjgIYxeMdo=
+chainguard.dev/sdk v0.1.164 h1:k2Ir/l1cuHDS/vg29sLNjJYm2kInnCfR5w0uFD0Y1Hg=
+chainguard.dev/sdk v0.1.164/go.mod 
h1:y5AGo04erWjKtEyGX7fO9zZA4vtj9cLGXZjgIYxeMdo=
 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=
 cloud.google.com/go/auth/oauth2adapt v0.2.8 
h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
@@ -66,8 +66,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.6.1+incompatible 
h1:oO7F4nn3Ovr/5TlfTUWFbMwBSS/B7Xs6Epv26gBrUP8=
-github.com/docker/cli v29.6.1+incompatible/go.mod 
h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
+github.com/docker/cli v29.6.2+incompatible 
h1:/bjePvcbbFTnRrMfWJBY7AjfICdsiLVgHn6LwTVOcqw=
+github.com/docker/cli v29.6.2+incompatible/go.mod 
h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
 github.com/docker/docker-credential-helpers v0.9.8 
h1:bIREROb7So6PRlq6KTtdS9MPEjC29OQRkFNlvK2OX8Q=
 github.com/docker/docker-credential-helpers v0.9.8/go.mod 
h1:v1S+hepowrQXITkEfw6o4+BMbGot02wiKpzWhGUZK6c=
 github.com/docker/go-connections v0.7.0 
h1:6SsRfJddP22WMrCkj19x9WKjEDTB+ahsdiGYf0mN39c=
@@ -111,8 +111,8 @@
 github.com/google/go-cmp v0.6.0/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.7 
h1:/vPFuVXDjtFREsVArW+0h1CIl5urnOhzei4X2DMW9IU=
-github.com/google/go-containerregistry v0.21.7/go.mod 
h1:kjSbt7/zMsKLWfnHrIvKvhXHUw91jbe9DNjPPJ32gXE=
+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/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
 github.com/google/s2a-go v0.1.9/go.mod 
h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 
h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
@@ -172,8 +172,8 @@
 github.com/moby/docker-image-spec v1.3.1/go.mod 
h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
 github.com/moby/moby/api v1.55.0 
h1:2/sexvQyqIWS8pRSCFddBfpW2qE7vR7FCL+vN8pxwMc=
 github.com/moby/moby/api v1.55.0/go.mod 
h1:+RQ6wluLwtYaTd1WnPLykIDPekkuyD/ROWQClE83pzs=
-github.com/moby/moby/client v0.5.0 
h1:5XhyPk2fuOWf6RlSFa3MkIIgDZkF25xToXW8Q/BH7cc=
-github.com/moby/moby/client v0.5.0/go.mod 
h1:rcVpF8ncl9vo5gaIBdol6CnbEtSj1uxMvEV/UrykF/s=
+github.com/moby/moby/client v0.5.1 
h1:tYNaJno4c0HXz12y5BiqEDy0rVTYkWzI26lGvnTMiJw=
+github.com/moby/moby/client v0.5.1/go.mod 
h1:odLstlZ6uSnfvAgVxMpvgmb8SUdd+siH2T0GBuxVAlM=
 github.com/muesli/termenv v0.16.0 
h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
 github.com/muesli/termenv v0.16.0/go.mod 
h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 
h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/apko-1.2.32/internal/cli/build_test.go 
new/apko-1.2.35/internal/cli/build_test.go
--- old/apko-1.2.32/internal/cli/build_test.go  2026-08-04 07:48:25.000000000 
+0200
+++ new/apko-1.2.35/internal/cli/build_test.go  2026-08-06 11:49:06.000000000 
+0200
@@ -16,7 +16,6 @@
 
 import (
        "bytes"
-       "context"
        "encoding/json"
        "os"
        "path/filepath"
@@ -34,7 +33,9 @@
 )
 
 func TestBuild(t *testing.T) {
-       ctx := context.Background()
+       unsetSourceDateEpoch(t)
+
+       ctx := t.Context()
        tmp := t.TempDir()
 
        golden := filepath.Join("testdata", "golden")
@@ -114,11 +115,13 @@
 }
 
 func TestBuildWithBase(t *testing.T) {
+       unsetSourceDateEpoch(t)
+
        // top_image golden file can be regenerated using 
./internal/cli/testdata/regenerate_golden_top_image.sh script.
 
        // TODO(sfc-gh-mhazy) Check sboms after base image support is reflected 
in them.
 
-       ctx := context.Background()
+       ctx := t.Context()
        tmp := t.TempDir()
        apkoTempDir := t.TempDir()
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/apko-1.2.32/internal/cli/helpers_test.go 
new/apko-1.2.35/internal/cli/helpers_test.go
--- old/apko-1.2.32/internal/cli/helpers_test.go        1970-01-01 
01:00:00.000000000 +0100
+++ new/apko-1.2.35/internal/cli/helpers_test.go        2026-08-06 
11:49:06.000000000 +0200
@@ -0,0 +1,31 @@
+// 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 cli_test
+
+import (
+       "os"
+       "testing"
+)
+
+// unsetSourceDateEpoch clears SOURCE_DATE_EPOCH for the duration of the
+// test, so the build derives its epoch from the installed packages. The
+// golden fixtures were generated this way. t.Setenv registers restoration
+// of the caller's value and prevents the test from running in parallel.
+func unsetSourceDateEpoch(t *testing.T) {
+       t.Helper()
+
+       t.Setenv("SOURCE_DATE_EPOCH", "")
+       os.Unsetenv("SOURCE_DATE_EPOCH")
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/apko-1.2.32/internal/cli/publish_test.go 
new/apko-1.2.35/internal/cli/publish_test.go
--- old/apko-1.2.32/internal/cli/publish_test.go        2026-08-04 
07:48:25.000000000 +0200
+++ new/apko-1.2.35/internal/cli/publish_test.go        2026-08-06 
11:49:06.000000000 +0200
@@ -16,7 +16,6 @@
 
 import (
        "archive/tar"
-       "context"
        "fmt"
        "io"
        "io/fs"
@@ -45,7 +44,9 @@
 )
 
 func TestPublish(t *testing.T) {
-       ctx := context.Background()
+       unsetSourceDateEpoch(t)
+
+       ctx := t.Context()
        tmp := t.TempDir()
 
        // Set up a registry that requires we see a magic header.
@@ -119,7 +120,9 @@
 }
 
 func TestPublishLayering(t *testing.T) {
-       ctx := context.Background()
+       unsetSourceDateEpoch(t)
+
+       ctx := t.Context()
        tmp := t.TempDir()
 
        // Set up a registry that requires we see a magic header.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/apko-1.2.32/pkg/apk/apk/implementation.go 
new/apko-1.2.35/pkg/apk/apk/implementation.go
--- old/apko-1.2.32/pkg/apk/apk/implementation.go       2026-08-04 
07:48:25.000000000 +0200
+++ new/apko-1.2.35/pkg/apk/apk/implementation.go       2026-08-06 
11:49:06.000000000 +0200
@@ -66,6 +66,7 @@
        ignoreMknodErrors  bool
        client             *http.Client
        cache              *cache
+       offline            bool
        ignoreSignatures   bool
        noSignatureIndexes []string
        auth               auth.Authenticator
@@ -95,6 +96,9 @@
                        return nil, err
                }
        }
+       if opt.cache != nil {
+               opt.cache.offline = opt.offline
+       }
 
        if opt.fs == nil {
                // This is expensive so we only want to do it if we aren't 
passed WithFS.
@@ -114,6 +118,9 @@
        client.Logger = clog.FromContext(ctx)
 
        httpClient := client.StandardClient()
+       if opt.offline {
+               httpClient.Transport = offlineTransport{}
+       }
 
        // Create default PackageGetter if none provided
        packageGetter := opt.packageGetter
@@ -138,6 +145,7 @@
                ignoreMknodErrors:  opt.ignoreMknodErrors,
                version:            opt.version,
                cache:              opt.cache,
+               offline:            opt.offline,
                ignoreSignatures:   opt.ignoreSignatures,
                noSignatureIndexes: opt.noSignatureIndexes,
                installedFiles:     map[string]*Package{},
@@ -345,8 +353,12 @@
                if ver, ok := ParseAlpineVersion(repo); ok {
                        if err := a.fetchAlpineKeys(ctx, ver); err != nil {
                                var nokeysErr *NoKeysFoundError
-                               if !a.cache.offline && !errors.As(err, 
&nokeysErr) {
-                                       return fmt.Errorf("failed to fetch 
alpine-keys: %w", err)
+                               if !a.offline && !errors.As(err, &nokeysErr) {
+                                       return &AlpineKeyFetchError{
+                                               Repository: repo,
+                                               Version:    ver,
+                                               Err:        err,
+                                       }
                                }
                                log.Debugf("ignoring missing keys: %v", err)
                        }
@@ -896,6 +908,22 @@
        return fmt.Sprintf("no keys found for arch %s and releases %v", e.arch, 
e.releases)
 }
 
+// AlpineKeyFetchError reports a failure to retrieve signing keys for an
+// Alpine package repository.
+type AlpineKeyFetchError struct {
+       Repository string
+       Version    string
+       Err        error
+}
+
+func (e *AlpineKeyFetchError) Error() string {
+       return fmt.Sprintf("failed to fetch Alpine keys for %s: %v", 
e.Repository, e.Err)
+}
+
+func (e *AlpineKeyFetchError) Unwrap() error {
+       return e.Err
+}
+
 // FetchAlpineReleases fetches and returns the Alpine releases metadata from 
alpinelinux.org.
 func FetchAlpineReleases(ctx context.Context, client *http.Client) (*Releases, 
error) {
        u := alpineReleasesURL
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/apko-1.2.32/pkg/apk/apk/implementation_test.go 
new/apko-1.2.35/pkg/apk/apk/implementation_test.go
--- old/apko-1.2.32/pkg/apk/apk/implementation_test.go  2026-08-04 
07:48:25.000000000 +0200
+++ new/apko-1.2.35/pkg/apk/apk/implementation_test.go  2026-08-06 
11:49:06.000000000 +0200
@@ -111,6 +111,48 @@
        require.Len(t, ent, 0) // No keys discovered
 }
 
+func TestInitDBWithoutCacheReturnsAlpineKeyFetchError(t *testing.T) {
+       const repository = "https://example.invalid/alpine/v3.22/main";
+
+       src := apkfs.NewMemFS()
+       a, err := New(t.Context(),
+               WithFS(src),
+               WithIgnoreMknodErrors(ignoreMknodErrors),
+               WithTransport(&testLocalTransport{fail: true}),
+       )
+       require.NoError(t, err)
+
+       ctx, cancel := context.WithCancel(t.Context())
+       cancel()
+
+       err = a.InitDB(ctx, repository)
+       var got *AlpineKeyFetchError
+       require.ErrorAs(t, err, &got)
+       require.Equal(t, &AlpineKeyFetchError{
+               Repository: repository,
+               Version:    "v3.22",
+               Err:        got.Err,
+       }, got)
+       require.ErrorIs(t, err, context.Canceled)
+}
+
+func TestInitDBOfflineWithoutCacheIgnoresMissingAlpineKeys(t *testing.T) {
+       src := apkfs.NewMemFS()
+       a, err := New(t.Context(),
+               WithFS(src),
+               WithIgnoreMknodErrors(ignoreMknodErrors),
+               WithOffline(true),
+       )
+       require.NoError(t, err)
+
+       err = a.InitDB(t.Context(), "https://example.invalid/alpine/v3.22/main";)
+       require.NoError(t, err)
+
+       ent, err := fs.ReadDir(src, "etc/apk/keys")
+       require.NoError(t, err)
+       require.Empty(t, ent)
+}
+
 func TestInitDB_ChainguardDiscovery(t *testing.T) {
        src := apkfs.NewMemFS()
        apk, err := New(t.Context(), WithFS(src), 
WithIgnoreMknodErrors(ignoreMknodErrors))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/apko-1.2.32/pkg/apk/apk/options.go 
new/apko-1.2.35/pkg/apk/apk/options.go
--- old/apko-1.2.32/pkg/apk/apk/options.go      2026-08-04 07:48:25.000000000 
+0200
+++ new/apko-1.2.35/pkg/apk/apk/options.go      2026-08-06 11:49:06.000000000 
+0200
@@ -33,6 +33,7 @@
        fs                 apkfs.FullFS
        version            string
        cache              *cache
+       offline            bool
        noSignatureIndexes []string
        auth               auth.Authenticator
        ignoreSignatures   bool
@@ -113,10 +114,19 @@
                        }
                }
                o.cache = &cache{
-                       dir:     cacheDir,
-                       offline: offline,
-                       shared:  shared,
+                       dir:    cacheDir,
+                       shared: shared,
                }
+               o.offline = offline
+               return nil
+       }
+}
+
+// WithOffline controls whether network requests are permitted. Cached and
+// local resources remain available in offline mode.
+func WithOffline(offline bool) Option {
+       return func(o *opts) error {
+               o.offline = offline
                return nil
        }
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/apko-1.2.32/pkg/apk/apk/transport.go 
new/apko-1.2.35/pkg/apk/apk/transport.go
--- old/apko-1.2.32/pkg/apk/apk/transport.go    2026-08-04 07:48:25.000000000 
+0200
+++ new/apko-1.2.35/pkg/apk/apk/transport.go    2026-08-06 11:49:06.000000000 
+0200
@@ -21,6 +21,25 @@
        "net/http"
 )
 
+// OfflineNetworkError reports a network request blocked by offline mode.
+type OfflineNetworkError struct {
+       Method string
+       URL    string
+}
+
+func (e *OfflineNetworkError) Error() string {
+       return fmt.Sprintf("network request blocked in offline mode: %s %s", 
e.Method, e.URL)
+}
+
+type offlineTransport struct{}
+
+func (offlineTransport) RoundTrip(req *http.Request) (*http.Response, error) {
+       return nil, &OfflineNetworkError{
+               Method: req.Method,
+               URL:    req.URL.Redacted(),
+       }
+}
+
 type rangeRetryTransport struct {
        base http.RoundTripper
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/apko-1.2.32/pkg/build/build.go 
new/apko-1.2.35/pkg/build/build.go
--- old/apko-1.2.32/pkg/build/build.go  2026-08-04 07:48:25.000000000 +0200
+++ new/apko-1.2.35/pkg/build/build.go  2026-08-06 11:49:06.000000000 +0200
@@ -289,22 +289,18 @@
                        HTTPResponseMaxSize:         
bc.o.SizeLimits.HTTPResponseMaxSize,
                }),
        }
-       // only try to pass the cache dir if one of the following is true:
-       // - the user has explicitly set a cache dir
-       // - the user's system-determined cachedir, as set by 
os.UserCacheDir(), can be found
-       // if neither of these are true, then we don't want to pass a cache 
dir, because
-       // go-apk will try to set it to os.UserCacheDir() which returns an 
error if $HOME
-       // is not set.
-
-       // note that this is not easy to do in a switch statement, because of 
the second
-       // condition, if err := ...; err == nil {}
-       if bc.o.CacheDir != "" {
-               apkOpts = append(apkOpts, apk.WithCache(bc.o.CacheDir, 
bc.o.Offline, bc.o.SharedCache))
-       } else if _, err := os.UserCacheDir(); err == nil {
-               apkOpts = append(apkOpts, apk.WithCache(bc.o.CacheDir, 
bc.o.Offline, bc.o.SharedCache))
-       } else {
-               log.Warnf("cache disabled because cache dir was not set, and 
cannot determine system default: %v", err)
+       // WithCache resolves an empty directory through os.UserCacheDir. Check 
it
+       // here so builds can run in environments without a system cache 
directory.
+       if bc.o.DiskCacheEnabled {
+               if bc.o.CacheDir != "" {
+                       apkOpts = append(apkOpts, apk.WithCache(bc.o.CacheDir, 
bc.o.Offline, bc.o.SharedCache))
+               } else if _, err := os.UserCacheDir(); err == nil {
+                       apkOpts = append(apkOpts, apk.WithCache(bc.o.CacheDir, 
bc.o.Offline, bc.o.SharedCache))
+               } else {
+                       log.Warnf("cache disabled because cache dir was not 
set, and cannot determine system default: %v", err)
+               }
        }
+       apkOpts = append(apkOpts, apk.WithOffline(bc.o.Offline))
 
        if bc.ic.Contents.BaseImage != nil {
                imgPath, err := 
paths.ResolvePath(bc.ic.Contents.BaseImage.Image, bc.o.IncludePaths)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/apko-1.2.32/pkg/build/build_test.go 
new/apko-1.2.35/pkg/build/build_test.go
--- old/apko-1.2.32/pkg/build/build_test.go     2026-08-04 07:48:25.000000000 
+0200
+++ new/apko-1.2.35/pkg/build/build_test.go     2026-08-06 11:49:06.000000000 
+0200
@@ -21,12 +21,15 @@
        "fmt"
        "net/http"
        "net/http/httptest"
+       "os"
        "path/filepath"
        "strings"
+       "sync/atomic"
        "testing"
 
        "github.com/stretchr/testify/require"
 
+       "chainguard.dev/apko/pkg/apk/apk"
        "chainguard.dev/apko/pkg/apk/auth"
        "chainguard.dev/apko/pkg/apk/fs"
        "chainguard.dev/apko/pkg/build"
@@ -127,6 +130,125 @@
        require.Equal(t, installed[1].Version, "1.0.0-r0")
 }
 
+func TestLockImageConfigurationWithoutDiskCache(t *testing.T) {
+       cacheDir := t.TempDir()
+       t.Setenv("XDG_CACHE_HOME", cacheDir)
+
+       srv := 
httptest.NewServer(http.FileServer(http.Dir("testdata/packages")))
+       defer srv.Close()
+
+       ic := types.ImageConfiguration{
+               Contents: types.ImageContents{
+                       Repositories: []string{srv.URL},
+                       Keyring:      []string{srv.URL + "/melange.rsa.pub"},
+                       Packages:     []string{"pretend-baselayout"},
+               },
+               Archs: []types.Architecture{types.ParseArchitecture("amd64")},
+       }
+
+       _, _, err := build.LockImageConfiguration(t.Context(), ic, 
build.WithoutDiskCache())
+       require.NoError(t, err)
+
+       entries, err := os.ReadDir(cacheDir)
+       require.NoError(t, err)
+       require.Empty(t, entries)
+}
+
+func TestLockImageConfigurationOfflineWithoutDiskCache(t *testing.T) {
+       t.Run("local repository", func(t *testing.T) {
+               repository, err := filepath.Abs("testdata/packages")
+               require.NoError(t, err)
+
+               ic := types.ImageConfiguration{
+                       Contents: types.ImageContents{
+                               Repositories: []string{repository},
+                               Keyring:      
[]string{filepath.Join(repository, "melange.rsa.pub")},
+                               Packages:     []string{"pretend-baselayout"},
+                       },
+                       Archs: 
[]types.Architecture{types.ParseArchitecture("amd64")},
+               }
+
+               _, _, err = build.LockImageConfiguration(t.Context(), ic,
+                       build.WithOffline(true),
+                       build.WithoutDiskCache(),
+               )
+               require.NoError(t, err)
+       })
+
+       t.Run("remote repository", func(t *testing.T) {
+               var requests atomic.Int64
+               files := http.FileServer(http.Dir("testdata/packages"))
+               srv := httptest.NewServer(http.HandlerFunc(func(w 
http.ResponseWriter, r *http.Request) {
+                       requests.Add(1)
+                       files.ServeHTTP(w, r)
+               }))
+               defer srv.Close()
+
+               ic := types.ImageConfiguration{
+                       Contents: types.ImageContents{
+                               Repositories: []string{srv.URL},
+                               Keyring:      []string{srv.URL + 
"/melange.rsa.pub"},
+                               Packages:     []string{"pretend-baselayout"},
+                       },
+                       Archs: 
[]types.Architecture{types.ParseArchitecture("amd64")},
+               }
+
+               _, _, err := build.LockImageConfiguration(t.Context(), ic,
+                       build.WithCache(t.TempDir(), true, apk.NewCache(false)),
+                       build.WithoutDiskCache(),
+               )
+               var got *apk.OfflineNetworkError
+               require.ErrorAs(t, err, &got)
+               require.Equal(t, &apk.OfflineNetworkError{
+                       Method: http.MethodGet,
+                       URL:    srv.URL + "/melange.rsa.pub",
+               }, got)
+               require.Equal(t, int64(0), requests.Load())
+       })
+}
+
+func TestDiskCacheOptions(t *testing.T) {
+       sharedCache := apk.NewCache(false)
+
+       tests := []struct {
+               name        string
+               options     []build.Option
+               wantEnabled bool
+       }{
+               {
+                       name:        "default",
+                       wantEnabled: true,
+               },
+               {
+                       name:    "disabled",
+                       options: []build.Option{build.WithoutDiskCache()},
+               },
+               {
+                       name: "empty directory enables automatic location",
+                       options: []build.Option{
+                               build.WithoutDiskCache(),
+                               build.WithCache("", false, sharedCache),
+                       },
+                       wantEnabled: true,
+               },
+               {
+                       name: "last option disables",
+                       options: []build.Option{
+                               build.WithCache("custom", false, sharedCache),
+                               build.WithoutDiskCache(),
+                       },
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       got, _, err := build.NewOptions(tt.options...)
+                       require.NoError(t, err)
+                       require.Equal(t, tt.wantEnabled, got.DiskCacheEnabled)
+               })
+       }
+}
+
 func TestBuildImageWithCertPackages(t *testing.T) {
        ctx := context.Background()
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/apko-1.2.32/pkg/build/options.go 
new/apko-1.2.35/pkg/build/options.go
--- old/apko-1.2.32/pkg/build/options.go        2026-08-04 07:48:25.000000000 
+0200
+++ new/apko-1.2.35/pkg/build/options.go        2026-08-06 11:49:06.000000000 
+0200
@@ -202,15 +202,35 @@
        }
 }
 
-// WithCache set the cache directory to use
+// WithCache enables disk caching in cacheDir. An empty cacheDir uses the
+// system cache directory.
 func WithCache(cacheDir string, offline bool, shared *apk.Cache) Option {
        return func(bc *Context) error {
                bc.o.CacheDir = cacheDir
+               bc.o.DiskCacheEnabled = true
                bc.o.Offline = offline
                bc.o.SharedCache = shared
                return nil
        }
 }
+
+// WithOffline controls whether network requests are permitted. Cached and
+// local resources remain available in offline mode.
+func WithOffline(offline bool) Option {
+       return func(bc *Context) error {
+               bc.o.Offline = offline
+               return nil
+       }
+}
+
+// WithoutDiskCache keeps downloaded packages and repository indexes out of
+// the filesystem cache. In-memory package-resolution caches remain available.
+func WithoutDiskCache() Option {
+       return func(bc *Context) error {
+               bc.o.DiskCacheEnabled = false
+               return nil
+       }
+}
 
 func WithLockFile(lockFile string) Option {
        return func(bc *Context) error {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/apko-1.2.32/pkg/options/options.go 
new/apko-1.2.35/pkg/options/options.go
--- old/apko-1.2.32/pkg/options/options.go      2026-08-04 07:48:25.000000000 
+0200
+++ new/apko-1.2.35/pkg/options/options.go      2026-08-06 11:49:06.000000000 
+0200
@@ -76,6 +76,7 @@
        TagSuffix               string                
`json:"tagSuffix,omitempty"`
        Local                   bool                  `json:"local,omitempty"`
        CacheDir                string                
`json:"cacheDir,omitempty"`
+       DiskCacheEnabled        bool                  `json:"-"`
        Offline                 bool                  `json:"offline,omitempty"`
        SharedCache             *apk.Cache            `json:"-"`
        Lockfile                string                
`json:"lockfile,omitempty"`
@@ -90,11 +91,12 @@
 type Auth struct{ User, Pass string }
 
 var Default = Options{
-       Arch:            types.ParseArchitecture(runtime.GOARCH),
-       SourceDateEpoch: time.Unix(0, 0).UTC(),
-       Auth:            auth.DefaultAuthenticators,
-       SharedCache:     apk.NewCache(false),
-       SizeLimits:      DefaultSizeLimits(),
+       Arch:             types.ParseArchitecture(runtime.GOARCH),
+       SourceDateEpoch:  time.Unix(0, 0).UTC(),
+       Auth:             auth.DefaultAuthenticators,
+       DiskCacheEnabled: true,
+       SharedCache:      apk.NewCache(false),
+       SizeLimits:       DefaultSizeLimits(),
 }
 
 // Tempdir returns the temporary directory where apko will create

++++++ apko.obsinfo ++++++
--- /var/tmp/diff_new_pack.uaGfcT/_old  2026-08-06 16:41:26.056469562 +0200
+++ /var/tmp/diff_new_pack.uaGfcT/_new  2026-08-06 16:41:26.060469701 +0200
@@ -1,5 +1,5 @@
 name: apko
-version: 1.2.32
-mtime: 1785822505
-commit: ea62bef5271a0c94f3fba641ee0e8d506b9b57ef
+version: 1.2.35
+mtime: 1786009746
+commit: 766682c7e7f87cc932ff02abeb889f5eab5edc9f
 

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

Reply via email to