feat(registry): per-repo blob membership index — substrate (cloister-7c0a0b, ADR-0029 slice 1)#89
Closed
jamestexas wants to merge 1 commit into
Closed
feat(registry): per-repo blob membership index — substrate (cloister-7c0a0b, ADR-0029 slice 1)#89jamestexas wants to merge 1 commit into
jamestexas wants to merge 1 commit into
Conversation
…bstrate (cloister-7c0a0b, ADR-0029)
First implementation slice of ADR-0029 (per-repo membership boundary for
the OCI registry surface). This PR ships the storage layer ONLY — the
membership table, helpers, and TrustStore RPC surface. Two follow-ups:
the pull-side gate (consult before BlobStore.get) and the push-side
write (record after BlobStore.put) land as separate beads.
Why split into slices: per ADR-0029, the design has multiple coupling
seams (pull-side check, push-side record, lazy backfill for pre-existing
blobs, manifest-walk transitive grant, peerFp propagation, _catalog
auth-gate). Each is independently testable and reviewable. Substrate
first; the seams that consume it land next.
Changes:
1. **src/storage/registry-membership.ts** — pure-function helpers over
an injected SQL executor, mirroring src/storage/registry-tags.ts:
- SCHEMA_REGISTRY_BLOB_MEMBERSHIP — table DDL with (repo, digest,
kind) PK + idx_membership_digest secondary index
- recordMembership(sql, repo, digest, kind, nowMs, peerFp?) —
UPSERT-on-conflict refreshes recorded_at + recorded_by in place
- hasMembership(sql, repo, digest, kind): boolean — the pull-side
probe; must return constant-shape 404 when false per §9.4 / ADR-0024
- listReposWithMembership(sql, digest) — diagnostic helper for GC
reachability scans and operator forensics
2. **src/trust-store.ts** — wires the table into the TrustStore schema
migration and exposes three RPC methods: recordRegistryMembership,
hasRegistryMembership, listRegistryReposWithMembership. RPC surface
thin-wraps the helpers. Sibling shape to upsertRegistryTag et al.
3. **test/storage/registry-membership.test.ts** — 10 tests covering:
- round-trip (record then has)
- empty-substrate has-check returns false
- **CROSS-TENANT GUARANTEE** — recording under REPO_A does NOT grant
REPO_B membership (the core ADR-0029 invariant; if this ever
accidentally passes, the multi-tenant story is broken)
- blob/manifest kinds independent
- idempotency on (repo, digest, kind) — no duplicate-row error
- UPSERT refreshes recorded_at + recorded_by
- dev-mode null peerFp accepted
- listReposWithMembership lex-ordered, no double-count across kinds,
empty-when-empty
Tests exercise real workerd SqlStorage (via runInDurableObject on a
BEAD_STORE stub) — same pattern as test/storage/workerd.test.ts —
so PRIMARY KEY, ON CONFLICT, ORDER BY semantics are validated against
the actual engine, not an in-memory shim.
Verification: task lint → 1136/1136 tests pass (was 1126 on main, +10
from this PR's new file).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
3 tasks
Contributor
Author
|
Superseded by #91 (consolidated ADR-0029 + membership substrate). Closing to reduce review load. |
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.
First implementation slice of ADR-0029 (PR #88). Ships the storage layer ONLY — table, helpers, TrustStore RPC. Pull-side gate + push-side record land as separate beads.
Changes
src/storage/registry-membership.ts— helpers (recordMembership,hasMembership,listReposWithMembership) + schema DDL. Mirrorsregistry-tags.ts.src/trust-store.ts— wires the table into the schema migration; exposes 3 RPC methods.test/storage/registry-membership.test.ts— 10 tests against real workerd SqlStorage. Includes the CROSS-TENANT GUARANTEE test (recording under REPO_A does NOT grant REPO_B membership) — the core ADR-0029 invariant.Test plan
task lint→ 1136/1136 (was 1126 on main, +10)🤖 Generated with Claude Code