fix(adapters): refuse unauthenticated send when capability is absent (FWD-16)

The FWD-08 remediation made every malformed credential fail loudly, but
an authed operation whose registry capability was entirely absent fell
through the build_request match: the request was sent with no credential
and no diagnostic, producing corrupted upstream 401s at call time.

- build_request now returns an INTERNAL error naming the missing
  capability keys (api_key:{ns} / http_token:{ns}) when an auth scheme
  is declared and Capabilities::get is empty; the request is not sent
- auth_scheme: None behavior unchanged (unauthenticated ops stay
  unauthenticated); error message carries key names only, no secret
- module doc: loud-missing matrix now covers malformed name/value AND
  absent capability
- tests: unit loud-error across all three schemes, unchanged-arm pin,
  wire test asserting the upstream receives zero requests (mirrors the
  FWD-08 test family)
- from_openapi/from_jsonschema no_env_vars tests updated: they pinned
  the old silent fall-through; still assert no env material echoes

Verification: cargo test (380 passed), cargo test --all-features
(496 passed), clippy --all-targets -D warnings (default + all-features),
cargo fmt --check — all via scripts/verify.sh
This commit is contained in:
2026-08-30 23:55:42 +00:00
parent 9819c24b4f
commit a427dc194d
3 changed files with 187 additions and 60 deletions
+11 -4
View File
@@ -619,7 +619,7 @@ mod tests {
fn no_env_vars_read_in_build_request() {
std::env::set_var("OPENAI_API_KEY", "should-not-be-used");
let ctx = noop_context("req-14", Capabilities::new());
let (_, _, _, headers) = build_request(
let err = build_request(
"https://api.openai.com",
"/v1/chat",
"POST",
@@ -630,10 +630,17 @@ mod tests {
&serde_json::json!({"body":{"prompt":"hi"}}),
&ctx,
)
.unwrap();
.expect_err("absent capability is a loud error (FWD-16), never an unauthenticated send");
assert_eq!(err.code, "INTERNAL");
assert!(
headers.get(AUTHORIZATION).is_none(),
"no auth header when capabilities absent"
err.message
.contains("capability for namespace `openai` is absent"),
"message was: {}",
err.message
);
assert!(
!err.message.contains("should-not-be-used"),
"error must not echo env material"
);
std::env::remove_var("OPENAI_API_KEY");
}