Skip to content

MILAB-6714: verify a block's docker images exist before publishing (v4-beta to v4) - #199

Merged
xnacly merged 5 commits into
v4from
merge-2026-08-11
Aug 12, 2026
Merged

MILAB-6714: verify a block's docker images exist before publishing (v4-beta to v4)#199
xnacly merged 5 commits into
v4from
merge-2026-08-11

Conversation

@xnacly

@xnacly xnacly commented Aug 11, 2026

Copy link
Copy Markdown
Member

Promotes v4-beta to v4.

Main content: pre-publish docker image verification

A block's .sw.json descriptors carry the image tag the backend pulls at runtime, and the build writes them whether or not the push happened. A misconfigured package produced a green build and a block that 404s on first run, with nothing in CI saying so. That is MILAB-6714, where gpu-test shipped referencing an image that was never uploaded.

New composite action blocks/monorepo/verify-docker-images, wired into node-simple-pnpm.yaml after the pre-publish build and before the publish steps. It resolves every docker tag in the repo's own descriptors against the registry and blocks publication when one is missing.

Design notes:

  • Gate, not report. It runs before publish so a broken block never ships, rather than telling us after users can install it.
  • Checks the pull address, not the push alias. The descriptor records containers.pl-open.science/... while the push targets quay.io/.... Verifying what the backend actually resolves also covers the CDN mapping in front of the registry.
  • Excludes node_modules. Those descriptors belong to published dependencies (SDK runenvs); failing a release on upstream state would be wrong.
  • Publish path only (main + no pending changeset commits), so PR and branch builds that legitimately do not push cannot fail spuriously.
  • Per-block opt-out via verify-docker-images: false.
  • Uses docker manifest inspect, falling back to docker buildx imagetools inspect, both of which reuse the logins this workflow already performs. If neither exists it fails loudly rather than reporting every image as missing.

Verification

Script logic exercised against fixtures built from the real tags in this incident:

Case Result
gpu-test June tag (present in the registry) ok, exit 0
gpu-test July tag (the missing one) MISSING, exit 1, step summary written
binary-only descriptor ignored
node_modules descriptor not scanned
no docker entrypoints / no descriptors exit 0, explicit "nothing to verify"
fail-on-missing: false warning, exit 0
buildx imagetools fallback branch same results on both present and missing

Both YAML files parse. node-simple-pnpm-k8s.yaml has no block publish path, so it needs no change.

Also carried

merge-beta.sh changes from #196, already on v4-beta and not yet on v4. Existing drift, not part of this work.

Rollout note

This gates every block publish. Nothing has exercised it on a real runner yet, since the step only fires on the main publish path and so cannot be canaried from a PR build. The natural first subject is platforma-open/gpu-test#6: once that merges, its main build publishes a block whose image is present again, which is exactly the passing case.

Ticket: MILAB-6714

Greptile Summary

This PR promotes the beta workflow changes to v4, adds a pre-publication Docker-image verification action, and fixes beta-merge self-reference rewriting.

  • Docker image descriptor — A generated .sw.json entrypoint description containing the image pull address. The PR adds discovery and registry verification of these descriptors.
  • Pull image tag — The .docker.tag value that Platforma resolves at runtime. The new action checks this address rather than a registry push alias.
  • Publication gate — A workflow condition that must pass before npm publication and release creation. The PR adds image existence verification to the existing clean-main-branch publication path.
  • Source branch — The bare beta branch name used when rewriting @v4-beta references. It is now kept separate from the Git ref used for merging.
  • Source ref — The local or origin/... ref supplied to git merge. The PR introduces this value so remote merges do not corrupt self-reference matching.

Confidence Score: 4/5

The parsing failure path in the Docker-image publication gate should be fixed before merging because it can silently skip all image checks.

The new action treats an empty tag list as success, while the process-substituted jq command can fail independently and leave exactly that empty list, allowing publication to continue without the intended verification.

Files Needing Attention: blocks/monorepo/verify-docker-images/action.yaml

Important Files Changed

Filename Overview
.github/workflows/node-simple-pnpm.yaml Adds an opt-out-enabled Docker-image verification step under the same main-branch and clean-tree conditions as publication.
blocks/monorepo/verify-docker-images/action.yaml Introduces registry checks for descriptor-referenced images, but parsing failures can be converted into a successful empty scan.
merge-beta.sh Separates the bare source branch name from its merge ref so remote beta merges still rewrite self-references correctly.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Build packages and descriptors] --> B{Main branch and clean tree?}
    B -- No --> C[Skip publication]
    B -- Yes --> D[Discover .sw.json descriptors]
    D --> E[Extract docker.tag values]
    E --> F{Every image exists?}
    F -- Yes --> G[Security scan and publication]
    F -- No --> H[Block publication]
Loading

Fix All in Claude Code

Prompt To Fix All With AI
### Issue 1
blocks/monorepo/verify-docker-images/action.yaml:48
**Descriptor parse failures pass verification**

When a descriptor is malformed or unreadable, or `jq` is unavailable, the process substitution can fail without failing `mapfile`, leaving `tags` empty and causing the publication gate to exit successfully without checking any images.

```suggestion
        tags_file="$(mktemp)"
        trap 'rm -f "${tags_file}"' EXIT
        if ! jq -r 'select(.docker != null and .docker.tag != null) | .docker.tag' "${descriptors[@]}" | sort -u > "${tags_file}"; then
          echo "::error::failed to parse entrypoint descriptors"
          exit 1
        fi
        mapfile -t tags < "${tags_file}"
```

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "Merge v4-beta into v4" | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

When no local source branch exists, merge-beta.sh reassigned SOURCE_BRANCH
to "origin/<branch>", so the self-ref rewrite sed searched for the
non-existent tag "@origin/v4-beta" and silently rewrote nothing — leaving
@v4-beta milaboratory/github-ci self-refs on the target branch. This bites
any local `merge-beta.sh` run (CI happens to have a local v4-beta branch).

Split the mergeable ref (new SOURCE_REF, may be origin/<branch>) from the
bare branch name (SOURCE_BRANCH) that the `@<name>` rewrite depends on.
Found while promoting v4-beta -> v4 for MILAB-6707.
fix(merge-beta): keep bare branch name for @v4-beta self-ref rewrite
@xnacly xnacly changed the title Merge v4-beta to v4 (2026-08-11) MILAB-6714: verify a block's docker images exist before publishing (v4-beta to v4) Aug 11, 2026
@notion-workspace

Copy link
Copy Markdown

fi
echo "Scanning ${#descriptors[@]} entrypoint descriptor(s)."

mapfile -t tags < <(jq -r 'select(.docker != null and .docker.tag != null) | .docker.tag' "${descriptors[@]}" | sort -u)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Descriptor parse failures pass verification

When a descriptor is malformed or unreadable, or jq is unavailable, the process substitution can fail without failing mapfile, leaving tags empty and causing the publication gate to exit successfully without checking any images.

Suggested change
mapfile -t tags < <(jq -r 'select(.docker != null and .docker.tag != null) | .docker.tag' "${descriptors[@]}" | sort -u)
tags_file="$(mktemp)"
trap 'rm -f "${tags_file}"' EXIT
if ! jq -r 'select(.docker != null and .docker.tag != null) | .docker.tag' "${descriptors[@]}" | sort -u > "${tags_file}"; then
echo "::error::failed to parse entrypoint descriptors"
exit 1
fi
mapfile -t tags < "${tags_file}"
Prompt To Fix With AI
This is a comment left during a code review.
Path: blocks/monorepo/verify-docker-images/action.yaml
Line: 48

Comment:
**Descriptor parse failures pass verification**

When a descriptor is malformed or unreadable, or `jq` is unavailable, the process substitution can fail without failing `mapfile`, leaving `tags` empty and causing the publication gate to exit successfully without checking any images.

```suggestion
        tags_file="$(mktemp)"
        trap 'rm -f "${tags_file}"' EXIT
        if ! jq -r 'select(.docker != null and .docker.tag != null) | .docker.tag' "${descriptors[@]}" | sort -u > "${tags_file}"; then
          echo "::error::failed to parse entrypoint descriptors"
          exit 1
        fi
        mapfile -t tags < "${tags_file}"
```

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Claude Code

xnacly added 3 commits August 11, 2026 13:23
A block's .sw.json descriptors carry the image tag the backend pulls at
runtime, and the build writes them whether or not the push happened. A
misconfigured package (a stray "private": true gates pl-pkg auto-push)
therefore produced a green build and a block that 404s on first run,
with nothing in CI saying so.

New composite action resolves every docker tag in the repo's own
descriptors against the registry and blocks publication when one is
missing. It checks the pull address recorded in the descriptor, not the
push alias, so it also covers any CDN mapping in front of the registry.
node_modules is excluded: dependency images are not this block's to
guarantee. Opt out per block with verify-docker-images: false.
docker manifest inspect has no precedent in this repo, and the check
gates every block publish. Fall back to docker buildx imagetools
inspect, and fail loudly if neither exists rather than silently
treating every image as missing.
@xnacly
xnacly merged commit 2c3262f into v4 Aug 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants