3.2 KiB
id, name, status, depends_on, scope, risk, impact, level, tags
| id | name | status | depends_on | scope | risk | impact | level | tags | ||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| review-002-fwd16-missing-capability | Loud error on missing capability instead of silent unauthenticated request (FWD-16) | completed | narrow | low | component | implementation |
|
Description
Review 002 FWD-16 [major]. The FWD-08 remediation made every
malformed credential fail loudly, but the missing-capability arm
stays silent: forward.rs:200-238 —
if let Some(scheme) = auth_scheme {
if let Some(secret) = context.capabilities.get(namespace) {
// ... four loud arms for malformed names/values
}
// capability == None → falls through: the request is sent
// with NO credential and NO diagnostic
}
Capabilities::get keys on api_key:/http_token: prefixes
(alkcall core/types.rs:97-107), so an assembly layer that registered
the secret under a wrong key form (or forgot) produces corrupted
upstream 401s at call time with zero local diagnostics. This is the
most probable misconfiguration shape and the one inconsistent arm in
an otherwise-loud match — every other arm was made loud by review-001's
FWD-08 fix (tested at forward.rs:1646-1736).
Acceptance Criteria
- When
auth_scheme.is_some()and the capability is absent, the request is NOT sent; the caller gets anINTERNAL-family error naming the missing capability key (e.g. "capabilityhttp_token:{namespace}is absent; refusing to send the request unauthenticated") — message contains no secret material - When
auth_scheme.is_none()the behavior is unchanged (unauthenticated ops stay unauthenticated) - Wire test: authed op, empty capabilities → error envelope (and
the test asserts via the existing
spawn_responder-style seam that the upstream received zero requests) - Existing FWD-08 loud-arm tests unchanged and passing
- Doc note in the module doc: the loud-missing matrix now covers malformed name/value AND absent capability
cargo test,cargo clippy --all-targets -- -D warnings,cargo fmt --checkpass
References
- docs/reviews/002-post-remediation-review.md (Part D', FWD-16)
- src/adapters/forward.rs:200-238 (the silent arm), :1646-1736 (the FWD-08 test family to mirror)
- docs/architecture/decisions/014-secret-material-flow-and-capability-injection.md
- tasks/adapters/review-001-forward-url-safety.md (FWD-08's loud-error work this completes)
Notes
Error class choice: INTERNAL (misconfiguration, not caller fault) —
matches the FWD-08 precedent. Non-retryable, since re-sending cannot
succeed without the assembly layer changing. If a deployment legitimately
runs authed-ops with optionally-present credentials (none known
today), that would be a new config flag — do not preemptively add one;
the invariant (ADR-014: credentials flow only via Capabilities) argues
loud-and-closed.
Summary
Silent missing-capability arm now fails with INTERNAL naming both key forms (api_key:/http_token:) and refusing the unauthenticated send; module doc loud-missing-matrix paragraph; 3 tests incl. a zero-upstream-requests wire test. Two pre-existing no-env-vars tests updated (they pinned the silent arm).