--- name: docker-pin-latest-census description: "Prove a Docker Hub / lscr.io image pin is the latest version before bumping it: registry-API tag census plus digest-equals-latest verification, no docker CLI needed." --- # Is my pinned image actually the latest? Use when bumping a pinned container image tag (e.g. `lscr.io/linuxserver/*` quadlet `Image=` lines) and "latest" must be PROVEN, not assumed. Works from any box with curl — no podman/docker daemon required. `lscr.io` fronts Docker Hub; its tags are NOT on quay.io (querying quay returns nothing and reads like "no newer tags exist" — false). ## 1. Full tag census via the registry API ```bash tok=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:/:pull" \ | python3 -c "import json,sys;print(json.load(sys.stdin)['token'])") curl -s "https://registry-1.docker.io/v2///tags/list?n=2000" \ -H "Authorization: Bearer $tok" | python3 - <<'PY' import json,sys,re tags=json.load(sys.stdin).get('tags') or [] # linuxserver form: --ls; group by version, keep newest ls per version v={} for t in tags: m=re.match(r'^(\d+(?:\.\d+)+)-([0-9a-f]+)-ls(\d+)$',t) if m: v.setdefault(tuple(map(int,m.group(1).split('.'))),[]).append((int(m.group(3)),t)) for k in sorted(v)[-5:]: print('.'.join(map(str,k)),'-> newest:',max(v[k])[1]) # max on (ls#, tag) tuple PY ``` - Sort versions as **tuples of ints**, never strings (`1.4.10 < 1.4.9` lexicographically). - Keep the max `ls` build per version, then the newest version — both can lag independently. - Trap already eaten: joining the tuple key to a string mid-loop then re-looking-it-up → `KeyError`. Keep keys as tuples; format only when printing. - Some channels have NO `latest` tag in `/tags/list` (or the endpoint truncates) — absence there is not evidence. ## 2. Digest-proof the candidate against `latest` ```bash for t in latest ; do curl -sI "https://registry-1.docker.io/v2///manifests/$t" \ -H "Authorization: Bearer $tok" \ -H "Accept: application/vnd.oci.image.index.v1+json,application/vnd.docker.distribution.manifest.list.v2+json,application/vnd.docker.distribution.manifest.v2+json" \ | grep -i '^docker-content-digest' done ``` Equal digests ⇒ the pinned tag IS what `latest` serves right now — the strongest "ensure latest" evidence, and recordable in the endpoint page's pin note (the dank-fleet law: *pinned; verified == the registry's `latest` manifest digest at pin time*). A multi-arch index digest matches only if both requests send the same Accept set — send all three types above. ## 3. Bump through git, not by hand Edit the quadlet/unit `Image=` line + the vault page's pin row (one owner each), run the repo suite, PR, deploy `--service ` only. Rollback stays "revert one line".