Skip to content

ci: pin postgres-meta by digest and pre-pull it off ECR - #63

Merged
tornidomaroc-web merged 1 commit into
mainfrom
ci/pin-postgres-meta-image
Jul 21, 2026
Merged

ci: pin postgres-meta by digest and pre-pull it off ECR#63
tornidomaroc-web merged 1 commit into
mainfrom
ci/pin-postgres-meta-image

Conversation

@tornidomaroc-web

Copy link
Copy Markdown
Owner

Fixes the ECR throttle that redded db-types on main twice (d8c8fde) with no code defect behind it.

The defect

supabase gen types does not talk to Postgres itself — it shells out to docker run public.ecr.aws/supabase/postgres-meta:v0.96.6, a reference compiled into the CLI binary:

Unable to find image 'public.ecr.aws/supabase/postgres-meta:v0.96.6' locally
docker: toomanyrequests: Rate exceeded
error running container: exit 125

That was the one dependency of this job that was not pinned — in a job whose stated premise is that an unpinned toolchain "turns any upstream release into a spontaneous red main, with no commit to this repo." So this closes a pinning hole, not just a reliability one: db-types is a git diff --exit-code gate, and a republished v0.96.6 with a changed emitter is indistinguishable from schema drift.

The fix

Pin by the multi-arch index digest, as PG_IMAGE is, and pull from Docker Hub:

  • sha256:a84cc713… is byte-identical at Docker Hub and public.ecr.aws — verified with buildx imagetools inspect against both. Content addressing means docker verifies these bytes or fails the pull; it cannot silently substitute. This is the same image over a registry that works.
  • Docker Hub is already in this script's trust set (PG_IMAGE has no registry prefix, so it resolves there) and it succeeded in the very run where ECR refused, 9 seconds earlier.
  • No credential, no new registry, no mirror to maintain. This removes the ECR dependency rather than raising its quota.

The retag is required, not defensive. Pulling by digest stores the image under docker.io/supabase/postgres-meta@sha256:…; the CLI asks for public.ecr.aws/supabase/postgres-meta:v0.96.6. Different registry, different repo path, no tag — docker would not match it and would pull from ECR exactly as before. The target string is verified byte-exact against the reference docker itself reported as missing. Nothing relies on digest-to-tag back-reference behaviour, which varies by daemon version.

In the script, not db-types.yml, per the workflow's own principle (db-types.yml:57-60): one code path for CI and developers, no second pinning site that only CI exercises. Local runs get the fix too.

Coupling (documented at both pins)

v0.96.6 is compiled into CLI 2.109.1. Bumping SUPABASE_CLI_VERSION may change it, leaving META_TAG naming an image the new CLI never asks for — the retag would go unused and the CLI would fall back to an ECR pull. That degrades to today's flakiness, never to a wrong result, but it is invisible until the throttle hits, so a CLI bump requires re-deriving the tag from the new binary (grep -a postgres-meta).

Evidence

Local proof, with the image deleted outright first so the test was honest:

Deleted: sha256:a84cc713585eea7b401e4a2561ec4a1e48c87083d1c7ecb4502f204bb4391300
Error response from daemon: No such image: public.ecr.aws/supabase/postgres-meta:v0.96.6

==> Pre-pulling postgres-meta (docker.io/supabase/postgres-meta@sha256:a84cc713...)
--> tagged as public.ecr.aws/supabase/postgres-meta:v0.96.6 (the reference the CLI resolves)

id=sha256:a84cc713585eea7b401e4a2561ec4a1e48c87083d1c7ecb4502f204bb4391300
RepoTags=[... public.ecr.aws/supabase/postgres-meta:v0.96.6]

db-types passing on this PR is the live proof — the CLI must reach postgres-meta with no ECR pull.

Scope

One file, scripts/gen-db-types.sh. No migration, no DB, no app code, no workflow change, no docs. database.types.ts unchanged.

🤖 Generated with Claude Code

db-types went red twice on main (d8c8fde) with no code defect behind it:

    Unable to find image 'public.ecr.aws/supabase/postgres-meta:v0.96.6' locally
    docker: toomanyrequests: Rate exceeded
    error running container: exit 125

`gen types` does not talk to Postgres itself -- it shells out to
`docker run public.ecr.aws/supabase/postgres-meta:v0.96.6`, a reference
compiled into the CLI binary. That was the one dependency of this job
that was NOT pinned, in a job whose stated premise is that an unpinned
toolchain "turns any upstream release into a spontaneous red main, with
no commit to this repo". So this closes a PINNING hole, not just a
reliability one: db-types is a `git diff --exit-code` gate, and a
republished v0.96.6 with a changed emitter is indistinguishable from
schema drift.

Pinned by the multi-arch INDEX digest, as PG_IMAGE is, and pulled from
Docker Hub. The digest is byte-identical at Docker Hub and public.ecr.aws
(sha256:a84cc713...), so this is the SAME image over a registry that
works -- content addressing means docker verifies these bytes or fails
the pull; it cannot silently substitute. Docker Hub is already in this
script's trust set (PG_IMAGE has no registry prefix, so it resolves
there) and it succeeded in the very run where ECR refused, 9 seconds
earlier. No credential, no new registry, no mirror to maintain: this
REMOVES the ECR dependency rather than raising its quota.

The retag is REQUIRED, not defensive. Pulling by digest stores the image
under `docker.io/supabase/postgres-meta@sha256:...`; the CLI asks for
`public.ecr.aws/supabase/postgres-meta:v0.96.6`. Different registry,
different repo path, no tag -- docker would not match it and would pull
from ECR exactly as before. Verified byte-exact against the reference
docker itself reported as missing. Nothing relies on digest-to-tag
back-reference behaviour, which varies by daemon version.

In the SCRIPT, not db-types.yml, per the workflow's own principle
(db-types.yml:57-60): one code path for CI and developers, no second
pinning site that only CI exercises. Local runs get the fix too.

COUPLING, documented at both pins: v0.96.6 is compiled into CLI 2.109.1.
Bumping SUPABASE_CLI_VERSION may change it, leaving META_TAG naming an
image the new CLI never asks for -- the retag would go unused and the CLI
would fall back to an ECR pull. That degrades to today's flakiness, never
to a wrong result, but it is invisible until the throttle hits, so a CLI
bump requires re-deriving the tag from the new binary.

Proven locally: the image was deleted outright, then the script pulled it
from Docker Hub and retagged, after which
`public.ecr.aws/supabase/postgres-meta:v0.96.6` resolves to
id sha256:a84cc713... with no ECR contact. Generated output unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 21, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
knowflow Ready Ready Preview, Comment Jul 21, 2026 3:48pm

@tornidomaroc-web
tornidomaroc-web merged commit 3378dd8 into main Jul 21, 2026
4 checks passed
@tornidomaroc-web
tornidomaroc-web deleted the ci/pin-postgres-meta-image branch July 21, 2026 15:55
tornidomaroc-web added a commit that referenced this pull request Jul 21, 2026
…64)

Records three register moves from one purpose: the db-types REQUIRED
check can no longer pass on a wrong result, nor red on a third party's
traffic. Logged under Option C — a single-purpose current entry, with
docs-PR provenance closed in the header lines, not changelog prose.

Four edit regions, nothing else:
- Line 8: PREPEND a gate-integrity current entry (#40 closed, #43
  opened+closed, #44 opened) and advance the "Last updated" stamp to
  2026-07-21. The prior #60/#58 current entry is NOT demoted or
  rewrapped — byte-identical.
- Lines 9-10: advance Active-branch + Main-tip to the merged state. The
  Main-tip provenance chain now names 3378dd8 (PR #63) on top of
  d8c8fde (PR #62) on 71e1c9d (PR #60) via the PR #61 docs merge
  b62cbd5 — this is where PR #62's zero-mention lag is closed, in
  provenance, not in changelog prose.
- Register #40 row: CONVERT IN PLACE to CLOSED (PR #62, merge d8c8fde),
  per the #38 template for a closed row that keeps its history. The lead
  flips to ✅ and preserves the original marker after "Was:". The "Where
  addressed" cell records WHICH branch was taken — the content-aware
  skip; `storage` was NOT provisioned — so the untaken alternative is not
  later mistaken for unfinished work, and carries the honest limit (a
  fail-closed STATIC heuristic with a documented undecidable case, not a
  proof of application). Columns 2 and 3 are byte-identical: both remain
  historically accurate.
- Register rows #43 and #44 APPENDED, strictly sequential. #43 (closed,
  PR #63) carries its residual IN the row per the #38 precedent — Docker
  Hub is also anonymous-quota'd, and a SUPABASE_CLI_VERSION bump can
  silently fall back to an ECR pull. #44 (open, unfixed) records the
  npx integrity gap so the class is not considered "handled" because #43
  closed.

Frozen-history invariant proven, both hashes before == after:
  primary   (Option C region, old entry's opening paren -> EOL8)
            sha256 d0c031b5a7ee2623e7b0443e337a612411563cea5329235adcc57118e69776fd
  secondary (first "Prior update" -> EOL8)
            sha256 22019b90c7ae5884e7531abb7916eb095c41745ed2b80cb01b6ab91a117aaf20
The insert is 2615 bytes and the frozen region shifted right by exactly
that (byte 32 -> 2647); "Prior update" markers stay 15, so nothing was
demoted. The historical "#40" mention inside the frozen region (now byte
11030) still describes #40 as OPEN and is deliberately UNCHANGED: it was
true when written, and editing it would break the invariant.

Not touched: §1 (Phase 7 stays ⬜ NOT STARTED — #40 was bucketed Phase 7
and closed early, the phase is unchanged); register #39 (its repo↔live
parity claim is unaffected by either fix and the row is marked
non-closable); PIVOT_PLAN.md. Docs-only; no code, no migration, no DB.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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