ci(models): mirror pinned models to S3 and publish from CI (ATR-218) - #33
Conversation
A mirror is a base-URL swap, not a new code path, but filling one still
needs the file list, digests and keys. "alcatraz models pins" emits them
as JSON so a publisher reads the same pin table the downloader verifies
against, instead of keeping a second list that drifts.
Each file carries a precomputed key, {model}/resolve/{revision}/{file},
so the layout lives in one place. PinnedFile gains Path alongside Name:
Name is what lands on disk, Path is what the fetch URL is built from,
and the two only agree because every model pinned today is flat.
hack/mirror-model.sh drives the aws CLI from that output. It verifies
locally before uploading, is write-once by default since a pinned
revision that changes bytes is a mistake, and round-trips through the
public origin at the end -- the upload arriving and the downloader
accepting it are different questions.
No credentials in the repo; the script uses the ambient AWS config.
Refs ATR-218.
The bucket is usually filled before anything serves it, so requiring the round-trip verify up front blocks the upload it is supposed to follow.
Mirroring a model needed write access to the bucket, which meant a long-lived key on someone's machine. This repository is public, so that is the one credential shape worth avoiding: the publish job assumes a role via OIDC instead, scoped in its trust policy to the models-publish environment rather than to the repo, so a run that skipped the reviewer gate cannot assume it. There is no staging bucket, because there is nothing to stage. The artifact is content-addressed — the key carries an immutable commit sha and every file is checked against a pinned digest on load — so the bytes a mirror serves during review are the bytes production reads, or the downloader rejects them. Promotion is the pin reaching main, and then a version bump in whatever image consumes it. A second bucket would hold a second copy of identical bytes and add a step that can fail. Mirror check is the half that earns its keep on an ordinary day: pinning a model nobody mirrored otherwise surfaces in a production image build, far from the PR that caused it. It needs no credentials, since the mirror is served publicly, and it compares content-length rather than just status, because a half-uploaded object answers a HEAD perfectly well and only fails later, on its digest. pins grew -list so that loop does not have to carry its own idea of which models are in the table.
PR Summary by QodoMirror pinned models to S3 and publish from GitHub Actions
AI Description
Diagram
High-Level Assessment
Files changed (10)
|
The first real run caught it: an origin pasted with a trailing slash asks S3 for a key that starts with one, and every file reports missing. The downloader has trimmed these since it learned to take an --origin at all, so an origin that works there has to work here — the check being stricter than the thing it checks is the wrong way round.
Code Review by Qodo
1.
|
The prose promised revision, origin, licence and every file; the example showed revision and files. Someone writing a mirror tool against the example would not know origin and license are there to read.
The script leaves --origin optional so a bucket can be filled before anything serves it, which is the bootstrap case and only happens once. A publish from CI has no such excuse: without the round-trip the job reports success on bytes nobody has proved the downloader can consume. A dry run still runs without one — it uploads nothing to verify.
Mirrors the pinned NER models to an S3 bucket so a deployment does not depend
on reaching huggingface.co, and publishes them from a workflow rather than from
someone's laptop.
What lands
alcatraz models pinsprints the pin table's entry for a model as JSON —revision, origin, licence, and every file with its digest, size and the key the
downloader requests.
-listprints every pinned model id, one per line, so aloop does not have to carry its own idea of what is in the table.
hack/mirror-model.shdrives theawsCLI from that output. It downloadsthrough the normal path — so every file is verified against its pinned digest
on the way in, and nothing unverified can reach the bucket — uploads write-once,
then round-trips back through
--originto prove the mirror serves what thedownloader will accept.
Mirror modelis the publish job. Manual: a model is mirrored when its pinlands, a handful of times a year. Credentials are assumed via OIDC and last
minutes, so this repository — which is public — never holds a key with write
access to the bucket. The role's trust policy is scoped to the
models-publishenvironment rather than to the repo, so a run that skipped the reviewer gate
cannot assume it.
Mirror checkis the half that earns its keep on an ordinary day. Pinning amodel nobody mirrored otherwise surfaces in a production image build, far from
the PR that caused it. It needs no credentials, since the mirror is served
publicly, and it compares
content-lengthrather than just status, because ahalf-uploaded object answers a HEAD perfectly well and only fails later, on its
digest.
Why there is no staging bucket
The artifact is content-addressed — the key carries an immutable commit sha and
every file is checked against a pinned digest on load, including cache hits. So
the bytes a mirror serves during review are the bytes production reads, or the
downloader rejects them. Promotion is the pin reaching
main, and then aversion bump in whatever image consumes it. A second bucket would hold a second
copy of identical bytes and add a step that can fail.
For the same reason a mirror is a base-URL swap, not a second code path: an
origin is trusted for availability, never for content.
Deploying this
The workflows no-op until the infrastructure exists.
Mirror checkwarns andexits 0 while
MODELS_ORIGINis unset, which is deliberate — it must not failPRs against an empty bucket, including this one.
Bucket
hoop-alcatraz-models(us-east-1, versioned, private) is served throughCloudFront with an OAC, and the publisher role is assumed via OIDC. The
models-publishenvironment carriesMODELS_PUBLISH_ROLEas a secret — the arnis the one value here holding the account id — plus
MODELS_BUCKET,MODELS_ORIGINandMODELS_REGIONas variables, so a failed run shows whichbucket and origin it used.
Order after merge: run
Mirror modelas a dry run, then for real, then addMODELS_ORIGINat the repository level to arm the PR gate.Part of ATR-189. Closes ATR-218.