feat(api): retrieve stored export authorization by idempotency key - #471
Conversation
Publish GET /v1/exports/by-idempotency/{idempotency_key}/request so
operators who hold a 200 authorization receipt can recover the stored
create without a second hop through export_id stored-request.
Metric-free. Zero and ambiguous matches fail closed. LineageWeave
refused. NaruonLiveService stays POST-only.
There was a problem hiding this comment.
Preserved as a landing gate rather than claimed green. The folded #466 exact head now contains additional RED/GREEN security branches, so predecessor coverage evidence is invalid by construction. #466 requires fresh exact-head 100% owned line/branch coverage and hosted Rust/documentation/security gates before Ready/merge; queued/pending evidence is non-passing.
| /// The route is segmented before percent decoding, so an encoded `/` remains | ||
| /// data inside one opaque key rather than becoming an extra path segment. |
There was a problem hiding this comment.
Addressed on surviving #466. GREEN 45754fdb46d4a2c84db9e440f5eb0001c2f26d10 rejects both raw / and percent-decoded %2F in the key, and the client builder rejects slash-containing keys before activation. ADR 0099 was updated in 14ef78c26a54a9a9e2e431d50731f830f65097e6 so path-normalization semantics now match code.
| let consumer = require_headers(headers, self.bound_addr, false)?; | ||
| if consumer != NARUON_CONSUMER_CODE { | ||
| return Err(ApiError::InvalidWirePayload); | ||
| } | ||
| refuse_metrics_on_export_lookup_stored_request_payload(body)?; | ||
| let prefix = format!("{consumer}\u{1f}"); | ||
| let mut matches: Vec<&StoredExport> = self | ||
| .authorized_exports | ||
| .iter() | ||
| .filter(|(replay_key, stored)| { | ||
| replay_key.starts_with(&prefix) | ||
| && stored.retrieval.idempotency_key == idempotency_key | ||
| }) |
There was a problem hiding this comment.
There was a problem hiding this comment.
Verified as valid after the strict-ancestor fold into #466 and repaired there rather than leaving the finding as a blocker. RED 8f38c2708771ead5ca197b65b3c8973ac7aebfea requires the unscoped stored-request lookup to fail closed and not echo tenant/principal/artifact identity. GREEN 45754fdb46d4a2c84db9e440f5eb0001c2f26d10 quarantines the route: serialized tenant_workspace_id/principal_id are forbidden on this response boundary and the client builder returns AuthorizationDenied until an authenticated tenant+principal binding exists. The surviving landing vehicle is #466; do not reactivate by trusting caller-controlled scope headers.
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Team Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
29e87b8
into
feat/export-idempotency-lookup-cli-gap-003a
Summary
GAP-003A unique slice:
GET /v1/exports/by-idempotency/{idempotency_key}/requestreturns the stored naruon export-authorization request of the unique accepted export onAnalysisRunLiveService/tepp-loopback.Lookup GET (#466) returns identity only. Stored-request GET (#459) requires
export_id. Operators who hold a 200 authorization receipt or log key still needed two hops. This is the dual-identity analog of{export_id}/request.tepp.scientific_acceptance.v1never appears.by-idempotency/{key}/request→ lookup by-idempotency → GET-by-id.NaruonLiveServicestays POST-only.feat/export-idempotency-lookup-cli-gap-003a@ 0c5efc3. Do not unstack onto main.Does not duplicate lookup GET/CLI (#465/#466), stored-request GET/CLI (#457/#459), GET-by-id (#411), retrieval CLI (#417), collection GET/CLI (#443/#444), export-authorize CLI (#410), analysis-run lookup (#380), interpretation-run lookup stored-request (#469/#470), or cancel lineages (closed). Stale snapshots that still prefer export lookup CLI on #465 are wrong — that CLI is already #466. Stale snapshots that still prefer temporal-context stored-request on #451 are wrong — already #464.
Test plan
cargo test -p tepp_api --offline --test export_idempotency_lookup_stored_request_http_contract --lib handler_covers_metric_free_exportcargo clippy -p tepp_api --all-targets --offline -- -D warnings