Skip to content

About page "Latest Version: unable to check" — update check broken by OCI image index #45

Description

@PeterRounce

Summary

The About page shows Latest Version: "unable to check" and the "Update available" button never appears, even when a newer image (e.g. 0.22.3) has been published to Docker Hub. The version check is silently broken for every deployed hub.

Log line confirming the failure:

WARN CheckLatestVersion: no config digest in manifest

Root cause

web/update.go::CheckLatestVersion() fetches the manifest for boltcard/card:latest and reads manifest.Config.Digest (update.go:70-83). That assumes a single-platform Docker v2 image manifest, which has a top-level config object.

Docker Hub no longer serves that. The tag now resolves to an OCI image index (multi-manifest), which has a manifests[] array and no top-level config, so manifest.Config.Digest == "" and the function bails out with "no config digest in manifest", returning "" → the UI renders "unable to check".

Verified directly against the registry (same calls the code makes):

GET https://registry-1.docker.io/v2/boltcard/card/manifests/latest
Accept: application/vnd.docker.distribution.manifest.v2+json

{
  "schemaVersion": 2,
  "mediaType": "application/vnd.oci.image.index.v1+json",
  "manifests": [
    { "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "digest": "sha256:d9ddd6...", "platform": {"architecture":"amd64","os":"linux"} },
    { "mediaType": "application/vnd.oci.image.manifest.v1+json",
      "digest": "sha256:7ea8e9...",
      "annotations": {"vnd.docker.reference.type":"attestation-manifest"},
      "platform": {"architecture":"unknown","os":"unknown"} }
  ]
}

The version label is still correct — it's just one level deeper. Following the amd64 entry → its image manifest → its config blob yields:

org.opencontainers.image.version: 0.22.3

When this regressed

Commit 37712c6 ("CI: cache Docker layers and parallelize image builds", PR #43, v0.22.2) switched the image build/push from plain docker build + docker push to docker/build-push-action@v6 (buildx). buildx enables provenance attestations by default, so the pushed tag becomes an OCI image index containing the real image manifest plus an attestation-manifest (the platform: unknown/unknown entry above). Before that commit, docker push produced a single-platform v2 manifest with the top-level config the code expects.

Fix options

  1. (Recommended) Handle the OCI image index in CheckLatestVersion. Detect when the manifest is an index/list (mediaType is application/vnd.oci.image.index.v1+json or ...manifest.list.v2+json, or the JSON has a manifests[] array), pick the linux/amd64 entry (skip attestation-manifest / platform: unknown), then fetch that child manifest to obtain config.digest and continue as today. Also broaden the Accept header to advertise the index/list media types. This is forward-compatible and keeps provenance attestations.

  2. (Workaround) Disable provenance in CI by adding provenance: false to the docker/build-push-action@v6 step for the card image, restoring a plain single-platform manifest. Simpler but loses attestations and breaks again if multi-arch is ever added.

I recommend option 1 (with option 2 as a stopgap if needed). Happy to put up a PR.

Affected code

  • docker/card/web/update.goCheckLatestVersion() (manifest parsing at lines ~49-83)
  • .github/workflows/ci.yml — "Build and push card image" step (docker/build-push-action@v6)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions