fix: Skip platform-specific digest resolution with --pull-policy never (#2498)

* fix: Skip platform-specific digest resolution with --pull-policy never

When using --pull-policy never, pack now skips the platform-specific
digest resolution that requires network access to fetch the manifest list.
Instead, it uses the image name directly from the daemon.

This fix addresses issue #2496 where builds fail when using --pull-policy
never because pack cannot resolve the platform-specific digest of the
lifecycle image without network access.

The trade-off is that users may encounter containerd storage issues if
Docker is configured to use containerd storage. In such cases, users
should manually pull the platform-specific digest or use a different
pull policy.

Related to PR #2467 which introduced platform-specific digest resolution
to fix containerd storage issues.

Fixes #2496

Signed-off-by: Juan Bustamante <bustamantejj@gmail.com>

* test: Use daemon OS instead of runtime OS in PullNever test

This fixes test failures on Windows runners running Linux containers.
The test was using runtime.GOOS which returns 'windows' on Windows hosts,
but the Docker daemon may be running Linux containers. Now we use the
daemon's actual OS type queried via docker.Info().

Signed-off-by: Juan Bustamante <bustamantejj@gmail.com>

---------

Signed-off-by: Juan Bustamante <bustamantejj@gmail.com>
This commit is contained in:
Juan Bustamante 2025-12-09 07:01:25 -05:00 committed by GitHub
parent 3a89ee80f8
commit e157bb6e02
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 54 additions and 1 deletions

View File

@ -257,6 +257,17 @@ func (f *Fetcher) FetchForPlatform(ctx context.Context, name string, options Fet
return nil, err
}
platformStr := options.Target.ValuesAsPlatform()
// When PullPolicy is PullNever, skip platform-specific digest resolution as it requires
// network access to fetch the manifest list. Instead, use the image as-is from the daemon.
// Note: This may cause issues with containerd storage. Users should pre-pull the platform-specific
// digest if they encounter errors.
if options.Daemon && options.PullPolicy == PullNever {
f.logger.Debugf("Using lifecycle %s with platform %s (skipping digest resolution due to --pull-policy never)", name, platformStr)
return f.Fetch(ctx, name, options)
}
// Build platform and registry settings from options
platform := imgutil.Platform{
OS: options.Target.OS,
@ -275,7 +286,6 @@ func (f *Fetcher) FetchForPlatform(ctx context.Context, name string, options Fet
}
// Log the resolution for visibility
platformStr := options.Target.ValuesAsPlatform()
f.logger.Debugf("Using lifecycle %s; pulling digest %s for platform %s", name, resolvedName, platformStr)
return f.Fetch(ctx, resolvedName, options)

View File

@ -732,6 +732,49 @@ func testFetcher(t *testing.T, when spec.G, it spec.S) {
h.AssertError(t, err, "")
})
})
when("pull policy is PullNever with daemon", func() {
var localImageName string
it.Before(func() {
// Use a different name for the local image to avoid conflicts
localImageName = "pack.local/test-" + h.RandString(10)
// Create a local daemon image with platform information
// Use osType (daemon OS) instead of runtime.GOOS to handle cases where
// Windows runner is running Linux containers
img, err := local.NewImage(localImageName, docker, local.WithDefaultPlatform(imgutil.Platform{
OS: osType,
Architecture: runtime.GOARCH,
}))
h.AssertNil(t, err)
h.AssertNil(t, img.Save())
})
it.After(func() {
h.DockerRmi(docker, localImageName)
})
it("skips platform-specific digest resolution and uses tag directly", func() {
target := dist.Target{
OS: osType,
Arch: runtime.GOARCH,
}
fetchedImg, err := imageFetcher.FetchForPlatform(context.TODO(), localImageName, image.FetchOptions{
Daemon: true,
PullPolicy: image.PullNever,
Target: &target,
})
// Should succeed without network access (digest resolution skipped)
h.AssertNil(t, err)
h.AssertNotNil(t, fetchedImg)
// Verify debug message about skipping digest resolution
h.AssertContains(t, outBuf.String(), "skipping digest resolution due to --pull-policy never")
})
})
})
when("#CheckReadAccess", func() {