mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
Conformance row 44 obligates that API token lookups key on (community_id, token_hash), not on token_hash alone. The storage UNIQUE index `idx_api_tokens_hash` already enforces this as a *storage* guarantee — but the query side was filtering on `token_hash = $1` only, relying on uniqueness as load-bearing for tenancy. That's a structural gap: any future relaxation of the index (or an adversarial mint that landed two rows via a tx race) would let a token minted in community A authorize against a request bound to community B. This change closes the query-side gap. All eight Db API surface methods now take a `CommunityId` first parameter, and the underlying SQL adds `AND community_id = $N` (or includes the column on INSERT). The `create_api_token*` family additionally INSERTs into the `community_id` column, which it previously omitted — schema declares it NOT NULL, so those functions would have failed at runtime if invoked. They have no callers today (token mint is staged but not wired), but fixing them in the same diff un-rots the public API and prevents the next caller from hitting a runtime FK error. The only live caller is `crates/buzz-relay/src/api/media.rs::resolve_ upload_scopes`, called from the `AuthenticatedUpload` extractor. The extractor previously resolved scopes BEFORE binding the request's tenant via `bind_community`, so threading the community through would have been impossible — the tenant didn't yet exist. Reordered: row-zero tenant bind moves to step 4 (immediately after header validation), scope resolution to step 5 with `&TenantContext` in hand. The lookup in `resolve_upload_scopes` now calls `get_api_token_by_hash_including_ revoked(tenant.community(), &hash)`. Sharp regression test added at `api_token::tests::lookup_by_hash_is_ scoped_to_community` (#[ignore = "requires Postgres"]): inserts two same-hash tokens in two communities (legal under UNIQUE(community_id, token_hash)) and asserts each lookup returns only its own community's row, and that a third unrelated community returns None. Mirror test `active_lookup_by_hash_is_scoped_to_community` covers the `revoked_at IS NULL` variant on `Db::get_api_token_by_hash`. Mutate-bite proof (verified manually before commit): stripping `AND community_id = $1` from the WHERE clause fails the test with `community-B lookup must return B's row` — Postgres returns the first-inserted (A's) row when filtering on hash alone, as expected. Restored the clause and re-ran clean. Verification: - cargo build --workspace --tests: clean (1.95.0) - cargo test -p buzz-db -- --include-ignored --test-threads=1: 101/101 - cargo test -p buzz-relay -- --test-threads=1: 399 + 1/1 - cargo clippy --workspace --tests -- -D warnings: clean - Line-read final diff for tenant provenance: every binding correctly threads the request-resolved CommunityId; no client-supplied path. Co-authored-by: Tyler Longwell <tlongwell@block.xyz> Signed-off-by: Tyler Longwell <tlongwell@block.xyz>