Skip to content

Support explicit local-only image validation without pre-start Docker pulls #65390

Description

@mmeeuwa

Request

Please add an opt-in, fail-closed local-image mode to actions/setup/sh/download_docker_images.sh. This follows the community contribution process in CONTRIBUTING.md (an implementation-plan issue rather than a direct PR).

Use case: a separate trusted acquisition job verifies images, then passes credential-free image content to an isolated agent/detection job. The consuming job must not contact a registry or receive registry credentials. Preloading images alone does not currently prevent the generated download step from pulling.

Root cause and scope

Inspected v0.88.2 (8e30bcd8897f5047051fa3971188e1dd4cdb23cf), v0.89.21 (c35393777e5604a63721d09512263b1383301d4f), and current main bec92a97e46fbdb5ba924470401725b92b18bd4e. The helper still unconditionally invokes timeout 5m docker pull --quiet $image through its retry function. AWF's later --skip-pull cannot suppress that earlier pull.

Relevant pinned sources:

Existing authored jobs.agent.pre-steps and jobs.detection.pre-steps were checked with a compile-only v0.88.2 fixture: a selector can precede downloads in both jobs, and both can depend on a separate acquisition job. This is ordering evidence, not an executed transport or security boundary.

Bounded implementation plan

  1. Add a selector such as GH_AW_DOCKER_IMAGE_PULL_POLICY: unset/always retains the original download path; never selects local-only validation; empty/unknown values reject. The name/interface is a proposal for maintainer review.
  2. In never, require a nonempty input set of fully qualified repository[:tag]@sha256:<64 lowercase hex> references. Handle registry ports separately from image tags. Inspect each exact reference with a bounded docker image inspect; require an exact repository@sha256:... entry in RepoDigests, not a substring, mutable tag, image ID or config digest.
  3. Validate the entire set and reject conflicting requested aliases before any alias is created. Only then create the exact requested local aliases with bounded docker tag. Do not create an implicit latest alias for a versioned reference; document/test required runtime alias compatibility. On failure, stop: no pull, retry or network fallback.
  4. Add mock-command regression tests using the existing upstream test conventions, plus documentation of the selector and both consumer hooks. Preserve default behavior. Run normal upstream development-container validation before accepting a release.

Reproducer and acceptance cases

A fake docker executable that logs its arguments shows the unmodified helper calls pull --quiet <digest-pinned reference> even when its synthetic image inspect response would contain that exact RepoDigest. The proposed branch was exercised downstream with 33 fake-command cases (no real daemon, registry requests or credentials), including:

  • exact digest present -> inspection and requested alias only, zero pulls;
  • missing image, inspect failure/timeout, empty/wrong repository/digest metadata -> failure, zero pulls;
  • unqualified/tag-only/malformed/newline input, unknown policy and conflicting aliases -> failure;
  • all images validated before aliases; port-qualified registries handled correctly;
  • alias failure -> no retry/fallback; unset/always retains successful original behavior.

A minimal selection example for a future supported helper is:

jobs:
  agent:
    pre-steps:
      - name: Require preloaded images
        run: echo 'GH_AW_DOCKER_IMAGE_PULL_POLICY=never' >> $GITHUB_ENV
  detection:
    pre-steps:
      - name: Require preloaded images
        run: echo 'GH_AW_DOCKER_IMAGE_PULL_POLICY=never' >> $GITHUB_ENV

The current helper ignores this proposed selector; the example is not a working workaround today.

Explicit limitations

This only checks local Docker metadata availability. It is not independent image-byte, provenance, scanner or policy verification. docker save/load may lose registry RepoDigests; missing metadata must deny rather than fabricate bindings or substitute config IDs. The actual descriptor-preserving handoff and every conditional startup image/helper still need independent exercise. A hostile/shared daemon or concurrent alias mutation is outside this prototype; use an isolated disposable consumer runtime. Partial alias creation is not atomic recovery.

No request to weaken sandboxing, grant registry credentials to an agent, change default pull behavior, or approve an untested end-to-end admission design. Is this narrow opt-in helper interface acceptable for upstream implementation, or is there an existing supported no-registry startup route we should use instead?

Activity

  1. locked and limited conversation to collaborators on Oct 3, 2026
  2. unlocked this conversation on Oct 3, 2026
  3. pelikhan commented on Oct 6, 2026

    @pelikhan
    Collaborator

    @copilot add front matter to specify the docker redownload policy

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions