Skip to content

Restorer fails to use selected mirror when extending run image (Platform API 0.14) #1590

@jjbustamante

Description

@jjbustamante

Summary

When using Platform API 0.14 with the -run flag, the restorer fails to pull the run image because it attempts to access the primary (inaccessible) run image instead of using the mirror that was already selected by the analyzer.

Reproduction

Steps

  1. Set up a builder with an intentionally inaccessible primary run image and an accessible mirror:

    [[run.images]]
    image = "pack-test/run"  # Intentionally inaccessible (401 from Docker Hub)
    mirrors = ["localhost:5000/pack-test/run"]  # Accessible local registry
  2. Build an application using Platform API 0.14+ with image extensions that extend the run image:

    pack build myapp \
      --builder mybuilder \
      --network host \
      --env EXT_RUN=1
  3. Observe that the analyzer correctly selects the accessible mirror and writes it to analyzed.toml:

    [run-image]
    reference = "localhost:5000/pack-test/run"
    image = "localhost:5000/pack-test/run"
  4. Observe that the restorer receives the -run flag with run.toml containing both primary and mirrors

  5. The restorer fails with:

    [restorer] Pulling run image metadata for pack-test/run...
    [restorer] ERROR: failed to pull run image pack-test/run: failed to get remote image
    

Current Behavior

The restorer's runImageAccessCheck method (cmd/lifecycle/restorer.go:206-221) calls FindByRef() with the selected mirror, which returns the full entry including the primary image. Then BestRunImageMirrorFor() attempts to validate the primary image first (platform/run_image.go:89-90), which fails with authentication errors, and never tries the mirrors.

Relevant code:

// cmd/lifecycle/restorer.go:206-221
func (r *restoreCmd) runImageAccessCheck(runImageName string) (string, error) {
    // ...
    return platform.BestRunImageMirrorFor("", runToml.FindByRef(runImageName), r.AccessChecker())
}

// platform/run_image.go:89-90
runImageMirrors = append(runImageMirrors, runImageMD.Image)       // Primary FIRST
runImageMirrors = append(runImageMirrors, runImageMD.Mirrors...)  // Then mirrors

Expected Behavior

The restorer should use the accessible mirror image that was selected by the analyzer, rather than failing when the primary image is inaccessible.

Context

Lifecycle Version

  • v0.21.0 (where the bug occurs)
  • The -run flag was introduced in v0.20.0

Platform Version(s)

  • Platform API: 0.14+
  • This bug only manifests when using Platform API 0.14+ with the -run flag for run image extensions

Additional Context

  • Reproducer: This issue can be reproduced using the PR at Support Platform API 0.14 - Add -run flag to restorer pack#2516 which implements Platform API 0.14 support in pack
  • Test case: The acceptance test at pack's acceptance/acceptance_test.go:1228-1253 consistently reproduces this issue
  • Intentional test setup: The pack-test/run image is intentionally inaccessible to validate mirror selection functionality
  • Scope: This bug only affects the "extending" scenario where extensions modify the run image, not the "switching" scenario

The analyzer correctly handles mirror selection, but the restorer's re-validation logic doesn't respect that selection when authentication fails on the primary image.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions