Skip to content

ci(release): docker backfill repoints :latest/:X.Y backward, and manifest publishes any digests present #238

Description

@beardthelion

Two publish-safety gaps in the docker-manifest job added in #235 (.github/workflows/release.yml).

1. Backfilling an older tag rolls :latest and :X.Y backward

docker_backfill_tag is meant to republish an already-cut release. The manifest step applies the floating tags unconditionally:

docker buildx imagetools create \
  -t "$IMAGE:$VERSION" \
  -t "$IMAGE:$MAJOR_MINOR" \
  -t "$IMAGE:latest" \
  $digests

Nothing checks that the resolved tag is the newest release. Dispatching docker_backfill_tag=v0.5.0 while v0.6.0 is the current release re-points :latest (and :0.5) at the older 0.5.0 image, so every consumer pulling :latest silently downgrades. Since dispatch only needs write access, a write-access actor can also deliberately point :latest at known-vulnerable code. Before #235 the docker job ran only on the freshly cut (newest) release, so :latest could only advance.

The immediate v0.6.0 backfill is safe because it is the newest tag; the footgun is every later historical backfill.

Fix: on a backfill, publish only the immutable :X.Y.Z by default, and gate the moving :latest / :X.Y behind either an explicit "move floating tags" dispatch input or a semver check that the backfill version is >= the currently published latest.

2. Manifest stitches whatever is in /tmp/digests with no arity check

digests=""
for f in /tmp/digests/*; do
  digests="$digests $IMAGE@sha256:$(basename "$f")"
done
docker buildx imagetools create ... $digests

needs.docker.result == 'success' guarantees both matrix legs passed today, so both digests are present. But the manifest trusts the artifact set blindly: a future third arch, a leg switched to continue-on-error, or an unexpected extra docker-digest-* artifact would publish a wrong-arity image under :latest while the job still reports success. Add a count assertion before imagetools create, e.g. [ "$(ls /tmp/digests | wc -l)" -eq 2 ] (or match the exact arch names), so an unexpected set fails loudly instead of shipping a degraded "multi-arch" manifest.

Metadata

Metadata

Assignees

No one assigned

    Labels

    kind:ciCI, release, or packaging pipelinesev:highMajor break or real security/trust risk, no easy workaround

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions