registrystack / registrystack/registry-stack

BReg: an attachment download hides quarantine and erasure behind resource.not_found

Offen
#971 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
area:breg enhancement rust
Vorherrschende Sprache
Rust
Sterne
2
Forks
0
Ø Merge
2 Std. 55 Min.
Gemergte PRs (30 T.)
130

Beschreibung

## What happens today

A raw attachment download, `GET /v1/records/{route}/{id}/attachments/{slot}`, answers `404 resource.not_found` in every refusal case. One code covers four authorization outcomes and two post-authorization ones.

Authorization outcomes, concealed on purpose:

- no token, or a token that does not satisfy the profile
- a route the profile cannot reach
- a record outside the caller's row boundary
- an unknown or unreachable slot

Post-authorization outcomes, concealed as a side effect:

- the stored content is held by attachment verification and is not releasable yet
- the stored content has been erased

## Why the second pair is different

The authorization gate runs first and returns before any content lookup. `attachment_version_is_authorized` in `crates/registry-breg/src/postgres/read.rs` short-circuits with `Ok(None)`. The erasure predicate (`a.erased_at IS NULL`) and the verification predicate (`verification_status.permits_content()`) in `crates/registry-breg/src/attachment_store.rs` only run once that gate has passed. A caller who reaches them has already proved the record, the route, the profile, and the row boundary.

The published concealment statement is scoped to authorization only. `docs/site/src/data/breg-api.yaml` describes `resource.not_found` as covering "No token, a token that does not satisfy the profile, a route the profile cannot reach, or a record outside the caller's row boundary. The server does not distinguish these cases." Quarantine and erasure are not on that list.

The same facts are already disclosed to the same caller elsewhere. The attachment metadata served on a record read carries `erased` and `verificationStatus` for each slot. A caller who can reach the download can read that metadata, so distinguishing these two download refusals discloses nothing they cannot already see.

## Cost of leaving it

An operator cannot tell "this attachment was never uploaded, or you may not see it" from "this attachment exists, you may see it, and the server will not release the bytes yet" from "this attachment existed and is gone for good". The first is a caller bug, the second is a wait and retry, the third is permanent. Today all three are one 404 and the only way to separate them is a second call to the metadata route.

## Proposal

Register two codes answered only by the attachment download, and only after authorization has passed:

- quarantined content, under `409 Conflict`, retryable once verification completes
- erased content, under `410 Gone`, permanent

Open questions for whoever picks this up:

1. Naming. Every registered code today uses a stack-wide noun (`resource`, `mutation`, `request`, `action`, `lookup`, and so on), and error codes are stack-wide surface under the compatibility promise. An `attachment.` prefix introduces a new noun owned by one product. `resource.quarantined` and `resource.erased` reuse an existing noun but widen what it means.
2. `ProblemCode::title()` has no 410 arm today and would fall through to its default reason phrase. Adding 410 to that table is part of the work.
3. Compatibility. New error codes are additive under `reference/api-stability`, but the clients fail closed on a code they do not recognise: an older client meeting a quarantined attachment would report a protocol failure where it used to report a clean not-found. That belongs in the release notes, and it is why this is a ticket rather than a drive-by change.

## Scope

- `crates/registry-breg/src/problem.rs`: the two variants, their status mapping, their detail text, `DOCUMENTED`, and the 410 reason phrase
- `crates/registry-breg/src/api/attachments.rs` and `crates/registry-breg/src/attachment_store.rs`: separate the two post-authorization refusals from `concealed()`
- `crates/registry-breg/src/artifacts.rs`: the published problem schema and the OpenAPI document
- `crates/registry-breg-client/src/error.rs` and the Node and Python bindings that render a code to a caller-facing string
- `docs/site/src/data/breg-api.yaml`: the problem table, plus the `resource.not_found` description, which stops being the whole story
- the `request-attachments` acceptance baselines that assert today's 404

Beitragsleitfaden

Beitragsleitfaden öffnen

Rechercherichtung

Beginne mit crates/registry-breg/src/problem.rs und verfolge dann die Verarbeitung von Attachment-Downloads in api/attachments.rs und attachment_store.rs; führe die Acceptance-Baselines für request-attachments aus, die den heutigen 404 bestätigen. Prüfe artifacts.rs, die Error-Renderer des Clients und der Bindings sowie docs/site/src/data/breg-api.yaml. Abgeschlossen ist die Aufgabe, wenn die autorisierten Quarantäne- und Löschfälle über API, Clients, Schema und Tests hinweg dokumentierte unterschiedliche Responses haben.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
node.js, postgresql, python, rust
Bereich
api, backend-api-design, databases, documentation
Issue-Typ
Feature
Schwierigkeit
4/5
Geschätzter Aufwand
3-5 Tage
Aktivitätsstatus
Aktiv
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
52/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.