Contribution Date
Contribution Project
Contribution Details
G22b: the library a token is answered from comes from the token
`/d/{token}` reads the tenant out of the verified claim, resolves the slug through
`provision::slug_of`, and opens one `TenantConn` for the request. Which library answers
a delivery URL is no longer a configuration setting.
**One transaction for the whole request, and it is right rather than convenient.** The
rule elsewhere here is to release the connection before store I/O — `integrity::scrub`
and `tiering::one_policy` both do, because a transaction held across a network round
trip pins a connection for minutes. Delivery does not need to: every step is a local
read and `presign_get` signs with HMAC rather than calling S3. Checked before relying
on it, since that is exactly the assumption the rule exists to catch.
**The circular dependency.** `connectors` is a tenant table and a connector's own secret
verifies its token, so the tenant must be known before the signature can be checked —
and the tenant is inside the signature. `tenant_id_of` reads it unverified to pick the
schema, mirroring what `key_id_of` already does for the key, and the verified claim is
asserted against that value so nothing downstream trusts the unverified read.
**The protection became structural, and a test proved it by not failing.** Disabling the
claim-versus-scope comparison left the cross-tenant case green — the library is chosen
*from* the token, so no path can answer one out of the wrong library. The comparison
stays, cheap, pinning that the two reads cannot drift; the test was rewritten to
exercise the real mechanism against a second tenant that genuinely exists.
**That new case found a 500.** A valid token for a tenant whose schema lacks the asset
reaches the rights evaluation, gets `NotFound`, and delivery mapped every database error
to `Internal`. It is a flat refusal now. The fault was unreachable before — a
cross-tenant token was stopped by a comparison — so G22b created it and the same
change's test caught it, which is the argument for writing the test that looks for the
mechanism rather than the symptom.
`ConnectorAuth` loses its configured slug: dead once the slug arrives per request, and
the thing that limited a process to one tenant's connectors.
**What this does not do, and why it is now its own item.** `/p/{key}` and `/s/{token}`
name a portal and a share, not a library, and both are tenant tables — so the visitor
surface still reads its tenant from configuration, which is why `delivery_tenant`
survives. Giving those URLs a tenant is a decision about the public URL space with three
non-equivalent shapes, written up as G22c. The README says the narrower thing now
instead of claiming delivery is single-tenant, which stopped being true.
Contribution Issue Link
Files count
0
Patches count
1