Fix About-page version check broken by OCI image index (0.22.4)#46
Merged
Conversation
CheckLatestVersion read manifest.Config.Digest, assuming a single-platform Docker v2 manifest. Since CI moved to docker/build-push-action@v6 (PR #43), buildx pushes boltcard/card:latest as an OCI image index (provenance attestations on by default) — a manifests[] array with no top-level config. The digest came back empty, logged "no config digest in manifest", and the About page showed "Latest Version: unable to check" with the update button permanently hidden on every deployed hub. Add parseManifest: for a plain image manifest it returns the config digest; for an image index / manifest list it returns the linux/amd64 image manifest digest (skipping the attestation manifest, falling back to any non-attestation platform). resolveConfigDigest follows one index indirection, and the manifest fetch now advertises the index/list media types in its Accept header. Verified end-to-end against the live registry: CheckLatestVersion() now returns 0.22.3. Unit tests in update_test.go cover the index, plain-manifest, fallback, and error paths. Fixes #45 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Go fix in this PR only helps hubs running the new code. Already-deployed hubs (<=0.22.3) still run the broken parser, so they would never see the button that offers the very update containing the fix — a chicken-and-egg lockout. The only lever over an already-running hub is what we publish to Docker Hub. docker/build-push-action enables provenance attestations by default, which wraps boltcard/card:latest in an OCI image index (no top-level config) that the old parser can't read. Set provenance: false so the published tag is a plain single-platform manifest again. Verified against the live registry: Docker Hub serves a single-platform manifest (even an OCI one) to the old code's narrow Accept header with a top-level config.digest, so the old parser succeeds and the button reappears. Applied to webproxy too for consistency. Documented the constraint in CLAUDE.md so it isn't silently re-enabled. Refs #45 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The About page shows Latest Version: "unable to check" and the "Update available" button never appears on any deployed hub — logged as
WARN CheckLatestVersion: no config digest in manifest.CheckLatestVersionreadmanifest.Config.Digest, assuming a single-platform Docker v2 manifest with a top-levelconfig. Since CI switched todocker/build-push-action@v6(#43, v0.22.2), buildx pushesboltcard/card:latestas an OCI image index (application/vnd.oci.image.index.v1+json) with provenance attestations on by default — amanifests[]array and no top-levelconfig. So the digest came back empty and the check bailed out, even though the version label is present one level deeper. See #45 for the full investigation with registry evidence.Two complementary fixes
1. Go: parse the index (forward fix — new hubs)
parseManifest— a plain image manifest yields the config digest; an image index / manifest list yields thelinux/amd64child manifest digest (skips theattestation-manifestentry, falls back to any non-attestation platform for arm64-only builds).resolveConfigDigest— follows one index indirection (index → image manifest → config).fetchManifest—Acceptheader now advertises the OCI index / Docker manifest-list types alongside the single-image types.2. CI: publish a single-platform manifest (rescues existing installs)
The Go fix only helps hubs already running the new code. Already-deployed hubs (
<=0.22.3) still run the broken parser, so they'd never see the button offering the update that fixes them — a chicken-and-egg lockout.The only lever over an already-running hub is what we publish to Docker Hub. Setting
provenance: falseon thebuild-push-actionsteps makes buildx publish a plain single-platform manifest instead of a provenance index. Verified against the live registry: Docker Hub serves a single-platform manifest (even an OCI one) to the old code's narrowAcceptheader with a top-levelconfig.digest— so the old parser succeeds and the button reappears. After the first release built this way, every stuck hub can finally see and click Update.Verification
update_test.go) cover the OCI index, plain-manifest, fallback, and error paths.CheckLatestVersion()now returns0.22.3(was"").Acceptheader still gets a parseable single manifest.go vet,go build, andgo test -race ./...all pass;ci.ymlvalidated.Fixes #45
🤖 Generated with Claude Code