Skip to content

fix(phpup): publish bundles under canonical tags, propagate annotations#87

Merged
phramz merged 1 commit into
mainfrom
fix-phpup-push-canonical-tags
Apr 27, 2026
Merged

fix(phpup): publish bundles under canonical tags, propagate annotations#87
phramz merged 1 commit into
mainfrom
fix-phpup-push-canonical-tags

Conversation

@phramz

@phramz phramz commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

Summary

`phpup push` was writing every promoted manifest to a digest-prefix tag like `sha256-` instead of the canonical `----` shape. Bundles landed on GHCR but were unreachable to `phpup lockfile-update`, which queries the canonical tag and got 404 — silently dropping every entry from `bundles.lock`.

This PR fixes `PushAll` to:

  • Use `ListKeyed` instead of `List`, which surfaces each source manifest's `io.buildrush.bundle.key` annotation.
  • Derive the canonical `(image-name, tag)` pair from the bundle key via a new `canonicalRefFromBundleKey` helper that mirrors what `internal/lockfileupdate` queries.
  • Propagate `BundleKey` and `SpecHash` annotations to the destination manifest so post-push consumers (`lockfile-update`, `LookupBySpec`) both resolve correctly.

How this surfaced

Post-merge of #76 (redis 6.2.0 → 6.3.0), the main-branch `publish` job promoted redis 6.3.0 bundles to GHCR under tags like `php-ext-redis:sha256-11ddf05509c9`. The `Update lockfile` step then queried `php-ext-redis:6.3.0-8.5-nts-linux-x86_64` (canonical), got 404 for all 10 redis 6.3.0 cells, and emitted them as warnings — leaving the regenerated `bundles.lock` without any 6.3.0 entries. Direct GHCR query confirms: redis canonical tags top out at `6.2.0-`, while 9 `sha256-` tags exist as orphans (the bundles ARE pushed, just not addressable).

The previous `deriveTagForPromotion` function's comment explicitly flagged this as a PR-4-era stub that "PR 6 will fix via manifest annotations" — that fix never landed in PR #71 (the actual PR 6/6).

Verification

Local round-trip test `TestPushAll_RoundTrip_LayoutToInProcessRegistry` seeds a layout with two annotated manifests (php-core + php-ext-redis), runs `PushAll` against an in-process OCI registry, and verifies:

  1. `php-core:8.5-linux-x86_64-nts` resolves on the destination.
  2. `php-ext-redis:6.3.0-8.5-nts-linux-x86_64` resolves on the destination.
  3. Layer 0 bytes match the seeded payloads.
  4. Destination manifests have `io.buildrush.bundle.key`, `io.buildrush.bundle.name`, and `io.buildrush.bundle.spec-hash` annotations propagated from the source.

Plus `TestCanonicalRefFromBundleKey` covers all key shapes (core, ext, tool-rejection, malformed input).

`make check` green; full `internal/build` test suite passes.

After this lands

The next push to main will trigger `publish`. With this fix, the 10 redis 6.3.0 cells get pushed to GHCR under canonical tags, `lockfile-update` finds them, and `bundles.lock` finally gets the `ext:redis:6.3.0:*` entries that PR #76 needed. Main returns to a fully consistent state.

Note: the `Commit lockfile (if changed)` step still hits the repository ruleset (`Changes must be made through a pull request`) — that's a separate concern (filed conceptually; needs a follow-up PR to either bot-create-PR or ruleset-bypass). For this fix, after merge a maintainer can manually re-run `phpup lockfile-update` locally and open a one-line bundles.lock PR.

Related

phpup push wrote each promoted manifest to a digest-prefix tag like
'sha256-<first12hex>' instead of the canonical
'<version>-<phpver>-<ts>-<os>-<arch>' shape. Bundles landed on GHCR but
were unreachable to lockfile-update, which queries the canonical tag and
got 404, silently dropping the entry from bundles.lock.

Switch PushAll to ListKeyed (which exposes the source manifest's
io.buildrush.bundle.key annotation), derive the canonical (image-name,
tag) pair from the key via canonicalRefFromBundleKey, and propagate
BundleKey + SpecHash annotations to the destination so LookupBySpec
also resolves on the promoted remote.

Reproduces the failure that left main with redis 6.3.0 in the catalog
but no 6.3.0 entries in bundles.lock or canonical GHCR tags after PR
#76 merged: phpup push pushed redis 6.3.0 blobs+manifests under
sha256-* tags, lockfile-update HEAD'd 'redis:6.3.0-8.5-nts-linux-x86_64'
and got 404, and the canonical-tag listing on GHCR remained
6.2.0-only. Comment on the previous deriveTagForPromotion explicitly
flagged this as a 'PR 6 will fix' stub that never landed.

Updates push_test.go to assert canonical tags + propagated annotations,
adds TestCanonicalRefFromBundleKey covering core/ext/error shapes, and
fixes a stale ext-key example in registry/annotations.go that used the
defunct '8.4-nts' joined PHPAbi format.
@phramz
phramz merged commit eae118a into main Apr 27, 2026
28 checks passed
@phramz
phramz deleted the fix-phpup-push-canonical-tags branch April 27, 2026 11:30
phramz added a commit that referenced this pull request Apr 27, 2026
actions/download-artifact's merge-multiple: true overwrote each cell's
oci-layout/index.json (same relative path across all 20 artifacts),
leaving the merged layout's index referencing only the last cell's
manifests. Cell blob bytes survived in blobs/sha256/ but were
unreferenced, so phpup push only saw a fraction of the manifests it
should have promoted.

Symptom seen post-merge of #87 (canonical-tag fix): the publish job's
Promote step succeeded but only one redis 6.3.0 canonical tag landed
on GHCR — the rest were the index.json entries that got overwritten
during the merge. Update lockfile then 404'd on 9 of 10 redis 6.3.0
cells.

Drop merge-multiple, let each artifact land in its own subdir under
out/, and loop over them in the Promote step. Each phpup push call
sees a complete per-cell index.json. Net work is identical (each
manifest is still pushed once).
phramz added a commit that referenced this pull request Apr 27, 2026
…89)

Manually-regenerated bundles.lock from `phpup lockfile-update` against
ghcr.io/buildrush. Replaces the 8 existing `ext:redis:6.2.0:{8.1..8.4}:*`
entries with the corresponding 6.3.0 entries, and adds 2 new
`ext:redis:6.3.0:8.5:*` entries (8.5 was previously excluded for
redis pre-#76).

Brings main back to a fully consistent state — catalog, lockfile, and
GHCR all agree on redis 6.3.0 — completing the work started in #76.

The non-redis line-level churn in this diff is in-entry digest/spec_hash
refresh from the multiple publish runs that fired during the chain of
fixes (#85, #86, #87, #88). Bundle keys themselves are unchanged
outside of redis. Per internal/testsuite/runner.go:345-346, manifest
digests are non-reproducible across pushes because meta.json carries a
build-time timestamp; this is expected behavior, not a regression.

Why this is committed by hand rather than auto-committed by the publish
job: the publish job's git push is rejected by the main-branch ruleset
("Changes must be made through a pull request"). A follow-up will
either switch the auto-commit to a bot-PR flow or grant the publish
identity a ruleset bypass; until then, version-bump PRs require this
manual lockfile-update PR step.
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.

1 participant