Skip to content

container-size-diff prevents first-image bootstrap when the edge baseline does not exist #1576

Open

Description

@rjaegers

Summary

The reusable build pipeline cannot complete the first pull-request build of a new image when that image has no published :edge baseline.
The image builds and is merged/tagged successfully, but .github/actions/container-size-diff unconditionally inspects the missing baseline and throws.
An expected bootstrap condition therefore becomes a fatal build failure.

Please support a genuinely missing baseline image without weakening validation of the newly built image or hiding registry/authentication failures.
The report should clearly say that comparison is unavailable because no baseline exists, while still reporting the current image's platform sizes.

Affected versions and entry points

  • Observed with philips-software/amp-devcontainer/.github/workflows/wc-build-push-test.yml@af840070c907d71ce06334ea65eded00dc3946a4 (actions/v2.3.2).
  • The same unconditional baseline inspection is present on default branch main at b918131cee77028a37ac9a18fb05d0c0b46a0c4f.
  • Affects direct callers of the container-size-diff composite action and derived repositories using the reusable build pipeline.
  • The failing phase is the Merge Image job, not Dockerfile compilation.

Relevant upstream source:

Reproduction

  1. Add a new image/flavor to a repository consuming wc-build-push-test.yml.
  2. Give it a new image name that has never had an edge tag published.
  3. Build it in a pull request with enable-edge-tag: false, as the normal PR/merge-queue tagging policy expects.
  4. Allow the architecture builds, manifest merge, version tagging, and digest extraction to succeed.
  5. The workflow then invokes size analysis with the absent <new-image>:edge as from-container and the newly published PR image as to-container.
  6. docker manifest inspect -v <new-image>:edge fails with a missing-manifest error, and the size action terminates the merge job.

An anonymized example of the action inputs:

from-container: registry.example.invalid/my-org/fake-new-flavor:edge
to-container: registry.example.invalid/my-org/fake-new-flavor:pr-123

The image names above are illustrative, not registry endpoints to contact.
A real first-build PR exhibited the following error; private registry/image names have been replaced:

ExecaSyncError: Command failed with exit code 1:
docker manifest inspect -v 'registry.example.invalid/my-org/fake-new-flavor:edge'

no such manifest: registry.example.invalid/my-org/fake-new-flavor:edge

at inspectManifest (.../container-size-diff.js)
at getSizes (.../container-size-diff.js)
at containerSizeDiff (.../container-size-diff.js)

Unhandled error: ExecaSyncError

The preceding semantic diffoci comparison also reports that the edge image is not found, but its command is already best-effort (|| true).
The subsequent size comparison is not: actions/github-script propagates the exception.

Actual behavior and impact

  • A successful first image build fails solely because a previous version of that image does not exist.
  • The failure occurs before subsequent SBOM, curated inventory, attestation, and verification steps in the merge job can complete.
  • Integration tests depending on the successful build/publish workflow cannot proceed.
  • New flavors, renamed images, newly adopted registries, and legitimately deleted/expired baselines can all hit this condition.
  • Derived repositories need manual baseline provisioning or a workaround even though the reusable build system is intended to support a family of newly introduced images.

This is not a request to suppress an actual compiler, image, signature, platform, or registry failure.
Absence of the old comparison target is the specific expected condition.

Root cause

inspectManifest() executes docker manifest inspect -v through execaSync, which throws on a nonzero result.
containerSizeDiff() immediately calls getSizes(fromContainer, inspect) with no baseline-absence handling.
Consequently the current image is never inspected when the old image is absent.
The existing test suite verifies normal reports, invalid images, and platform mismatch, but does not cover a known missing baseline with a valid current image.

platformRow() already has behavior for a zero-sized platform, but a zero-sized existing image is not the same as a nonexistent image.
There is also a strict platform-set comparison, so simply changing the baseline to an empty map is not sufficient: bootstrap must be handled explicitly and separately from normal two-image comparison.

Expected behavior / acceptance criteria

  1. A confirmed missing from-container manifest does not fail the action or the reusable pipeline when the current image is valid.
  2. The current image is still inspected and validated, including when the baseline is missing.
  3. A useful Markdown output is always produced for the bootstrap case, with the current image's platform sizes and an explicit explanation that the baseline does not exist.
  4. Previous size and percentage/delta are clearly marked unavailable, or the comparison portion is explicitly omitted; do not silently invent 0 B, a growth percentage, or a misleading successful comparison.
  5. The normal existing-baseline report and strict platform-set validation remain unchanged.
  6. A missing or inaccessible current image, malformed manifest, or current image without valid platform sizes remains a hard failure.
  7. Baseline authentication/authorization failures, networking/timeouts, unexpected registry errors, and malformed/no-platform baseline data are not indiscriminately treated as missing images.
  8. Recognition of genuine manifest absence works with the relevant Docker/registry diagnostic formats; do not rely on catching every exception or treating every nonzero exit as absence.
  9. The PR comment remains usable in bootstrap builds and the workflow can continue to its normal supply-chain and integration-test gates.
  10. Existing PR versus merge-queue/release tag semantics are preserved; do not create or overwrite edge in a PR just to manufacture a comparison target.

Implementation guidance

  • Keep the fix upstream and reusable rather than requiring every derived repository to preseed an image or special-case this action.
  • Preserve strict behavior in the general manifest/size reader where possible; make the permissible absence behavior specific to the baseline comparison path.
  • Prefer a small, explicit representation of a missing manifest or narrowly classified inspection failure over broad catch/continue-on-error handling.
  • Avoid globally setting continue-on-error: true, which would hide unrelated failures and could allow misleading reports.
  • Keep the public action/function/output API stable unless an additive status field is genuinely necessary.
  • Check the semantic-diff/artifact path for bootstrap consistency, but do not expand this into unrelated workflow refactoring.
  • Update the action README, which currently states that inability to inspect either image is always fatal, and document the first-image exception.
  • If the reusable-build-system documentation needs clarification, add a short bootstrap explanation rather than duplicating implementation details.

Focused regression coverage

Use the existing node:test suite and injected fake inspectors; no live registry, credentials, or container engine should be required.
Use clearly fake image references and generated manifests.

Scenario Required result
Confirmed missing baseline; valid AMD64 + ARM64 current image Nonfatal explicit bootstrap report with current sizes
Existing baseline and current image Existing report preserved
Zero-sized existing baseline Existing zero-size behavior preserved; not mislabeled as absent
Existing baseline/current platform mismatch Hard failure preserved
Missing current image Hard failure
Both baseline and current missing Hard failure identifying the current-image problem
Baseline unauthorized/forbidden Hard failure, not bootstrap
Baseline timeout/network/unexpected inspection error Hard failure
Baseline invalid JSON or no known platforms Hard failure
Baseline missing but current invalid JSON/no platforms Hard failure
Recognized missing-manifest diagnostic variants Correct narrow classification without swallowing unrelated errors

At minimum, run:

npm ci --ignore-scripts --prefix .github/actions/container-size-diff
npm test --prefix .github/actions/container-size-diff

Follow the repository instructions and existing lint/format checks.
GitHub workflow execution itself should be verified through an actual new-image bootstrap run where available, rather than claimed from mocked tests alone.

Completion and downstream adoption

Submit a focused upstream PR with regression tests and documentation.
The changes to the reusable action/workflow should be released through the repository's actions/vX.Y.Z release path.
Consumers pinned to af840070... will then need to adopt the verified fixed action-release commit; merely changing main does not repair an already-pinned downstream workflow.

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

Metadata

Metadata

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions