Skip to content

test(ci): cover container-run.sh's pin, refusal and opt-out paths - #11483

Draft
basvandijk wants to merge 1 commit into
bas/pin-container-run-image-by-digestfrom
bas/test-container-run-matrix
Draft

test(ci): cover container-run.sh's pin, refusal and opt-out paths#11483
basvandijk wants to merge 1 commit into
bas/pin-container-run-image-by-digestfrom
bas/test-container-run-matrix

Conversation

@basvandijk

Copy link
Copy Markdown
Collaborator

What

Extend the test-container-run job in ci-main.yml with CI coverage for the digest pinning that #11422 adds to ci/container/container-run.sh.

Stacked on #11422: the base of this PR is bas/pin-container-run-image-by-digest and it only changes .github/workflows/ci-main.yml. Once #11422 has merged, the base is retargeted to master.

Why

#11422 makes container-run.sh pull the dev/build image only by the digest committed in ci/container/ic-dev.digest / ci/container/ic-build.digest, refuse tampered pins and edited container inputs, and fall back to a local image or build only with CONTAINER_RUN_ALLOW_UNPINNED=1. The two happy-path legs of the existing test-container-run job cover none of the refusal paths. This coverage was split out of #11422 to keep that review smaller.

How

  • A new test-container-run-preflight job runs once (a single runner) and decides whether the matrix runs at all:
    • only when the container tooling changed (ci/container/**, ci-main.yml, ci-pr-only.yml, container-autobuild.yml) or on master, rc--* and hotfix-*;
    • checks that ci/container/*.digest are well-formed and that every ghcr.io/dfinity/ic-dev / ic-build reference in .devcontainer/ and .github/workflows/ is exactly the pinned digest reference (all of them are written by container-autobuild.yml); this check also runs when only those pins changed;
    • checks that ci/container/TAG matches the container inputs. On a pull request an out-of-sync TAG is transient (the autobuild bot commit brings TAG and *.digest in sync and re-triggers CI), so the matrix is skipped with a notice; anywhere else it is an error.
  • The test-container-run matrix (fail-fast: false) gains, next to the ic-dev default and --image ic-build happy paths:
    • poisoned local tag: an empty image squatting on ghcr.io/dfinity/ic-dev:<TAG> is ignored, the pinned digest is pulled and run, and the tag is re-pointed to it (verified via RepoDigests);
    • malformed pin refused: not-a-digest in ic-dev.digest → "refusing to pull an unpinned image";
    • unknown digest refused: a well-formed digest the registry does not serve → "refusing to build an unpinned image locally";
    • unknown digest with poisoned local tag refused: the same failed pull while a local image squats on the tag → the cached mutable-tag image is not run either;
    • edited inputs refused: ci/container/Dockerfile edited after the preflight gate → "refusing to run an unpinned image";
    • edited inputs with opt-out reuses local image: with CONTAINER_RUN_ALLOW_UNPINNED=1 an image cached under the computed tag is reused, and the output must say it is "NOT verified against a reviewed digest pin";
    • docker runtime: the happy path with CONTAINER_RUNTIME=docker.
  • Every refusal leg asserts a fast non-zero exit (timeout 300, and not 124), the expected message, and that the podman image store and container list are unchanged, i.e. nothing was pulled, built or run.

Stacked on #11422, which makes container-run.sh pull the dev/build image
only by the digest committed in ci/container/*.digest. Extend the
test-container-run job in ci-main.yml with CI coverage for that:

* A test-container-run-preflight job decides once whether the matrix runs
  (the container tooling changed, or master / rc-- / hotfix-), checks that
  ci/container/*.digest agree with the ic-dev pin in .devcontainer/ and
  the ic-build pins in .github/workflows/, and skips the matrix with a
  notice on a pull request whose ci/container/TAG is out of sync with the
  container inputs (the autobuild bot commit brings it in sync and
  re-triggers CI); anywhere else that is an error.
* The matrix gains legs for a local image squatting on the tag (the pinned
  digest must run and the tag is re-pointed to it), a malformed pin, an
  unknown digest with and without a squatting local image, edited
  container inputs with and without CONTAINER_RUN_ALLOW_UNPINNED=1, and
  the docker runtime. Every refusal leg asserts a fast non-zero exit, the
  expected message, and that nothing was pulled, built or run.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The security-sensitive workflow expansion depends on runtime-specific CI behavior that cannot be fully validated statically.

Pull request overview

Adds CI coverage for digest pinning, refusal, and opt-out behavior in container-run.sh.

Changes:

  • Adds a preflight job validating digest references and container input synchronization.
  • Expands the container-run matrix with security, failure, opt-out, and Docker cases.
  • Verifies refusal paths do not alter Podman state.
File summaries
File Description
.github/workflows/ci-main.yml Adds preflight validation and expanded container-run test coverage.
Review details
  • Files reviewed: 1/1 changed files
  • Comments generated: 0
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants