Files
alkhttp/tasks/adapters/review-001-input-schema-enforcement.md
T
glm-5.3-flash a9d17405a7 fix(adapters): input-schema enforcement + header/cookie params (OAI-02, OAI-03, OAI-07, OAI-09)
- build_request takes the op's input_schema and rejects undeclared
  input keys (INVALID_INPUT) before any outbound request is built;
  explicit `additionalProperties: true` opts into catch-all input;
  non-object inputs rejected (OAI-02)
- in: header parameters are stamped `wire: header` in the generated
  input schema and sent as upstream request headers, not query params;
  in: cookie fails import with a clear error (OAI-03)
- a spec parameter named `body` is rejected at import unconditionally
  (OAI-07)
- FromJsonSchema::new returns Result and validates method/path template/
  base_url at construction; registered visibility forced to Internal
  like from_openapi; module doc corrected (OAI-09)

Verified: cargo test, cargo test --all-features, clippy (both feature
sets, -D warnings), cargo fmt --check
2026-08-29 12:48:13 +00:00

5.0 KiB

id, name, status, depends_on, scope, risk, impact, level, tags
id name status depends_on scope risk impact level tags
review-001-input-schema-enforcement Send exactly what the input schema advertises (OAI-02, OAI-03, OAI-07, OAI-09) completed
review-001-openapi-import-integrity
narrow medium component implementation
adapters
review-001
from-openapi
from-jsonschema

Description

Review 001 findings OAI-02 + OAI-03 + OAI-07 + OAI-09 — the request a forwarder sends must match the contract /schema advertises:

  • OAI-02 (forward.rs:60-72): no input-schema enforcement — every input key that isn't a path placeholder (and isn't literally "body") becomes an upstream query parameter regardless of the registered input_schema. Peer input like "debug": "true" or "impersonate_id": "…" reaches the upstream. ADR-066's "input schema validation before send" is implemented nowhere. Fix: enforce input_schema at call time — reject undeclared keys (or document pass-through as an explicit, per-adapter choice).
  • OAI-03 (openapi_spec.rs:35-40): in: header parameters are silently sent as query parameters (in_ is a dead field). Upstream auth/trace headers never arrive, and header-designated values land in upstream access logs instead. Honor in: header; fix in: cookie (reject with a clear unsupported error).
  • OAI-07: the magic "body" key collides with a spec parameter actually named body — the declared parameter is silently diverted. Namespace the body input or reject the collision loudly.
  • OAI-09 (from_jsonschema.rs:36-51): malformed method/ path_template/base_url validate only at first invoke; and the module doc says "Internal by default" while the adapter passes the caller's spec through verbatim (from_openapi hardcodes Visibility::Internal). Validate at construction; align the doc or default the visibility.

Acceptance Criteria

  • Undeclared input keys are rejected (or the pass-through is explicit config, tested) — peer input cannot add upstream query params (test)
  • in: header parameters send as headers; in: cookie errors clearly at import (tests)
  • body-named parameter collision handled loudly (test)
  • from_jsonschema validates method/path_template/base_url at construction; Internal-by-default matches from_openapi or the doc is corrected
  • cargo test and cargo clippy --all-targets -- -D warnings pass

References

  • docs/reviews/001-initial-implementation-review.md (Part E, OAI-02, OAI-03, OAI-07, OAI-09)
  • docs/architecture/decisions/066-from-jsonschema-as-http-adapter.md

Notes

Agent fills during implementation. Depends on ref-resolution only for shared fixtures/types in openapi_spec.rs; start after it lands to avoid churn. OAI-06 (silent feature degradation) is deliberately deferred — revisit after this task.

Summary

Forwarders now send exactly what the input schema advertises.

OAI-02 (forward.rs): build_request takes the operation's input_schema and enforces it at call time — every input key must be declared in properties (path placeholders included; from_openapi declares them) or the input is rejected as INVALID_INPUT before any outbound request is built. An explicit "additionalProperties": true opts an operation into catch-all input (JSON Schema semantics — the schema advertises that extra keys are valid); non-object inputs are rejected. No pass-through knob: the review's preferred reject-undeclared posture is the behavior, documented in the module doc.

OAI-03 (forward.rs + from_openapi.rs): the Parameter.in_ field is no longer dead. from_openapi builds header-param properties as {"wire": "header", "schema": …} in the generated input schema; build_request routes marked properties into HTTP request headers (validated name/value, loud INTERNAL on refusal) instead of the query string. in: cookie fails import with a clear SchemaParse message (OAI-06's silent-degradation pattern avoided here).

OAI-07 (from_openapi.rs): a spec parameter named body is rejected at import unconditionally (previously only when a requestBody coexisted) — the magic gateway body key would divert the declared parameter.

OAI-09 (from_jsonschema.rs): FromJsonSchema::new now returns Result and validates at construction — method parses, path template placeholders are balanced and bound by the input schema, base URL is a userinfo-free http(s) URL — instead of surfacing INTERNAL on first invoke. The registered visibility is forced to Internal (ADR-015) like from_openapi; the module doc corrected (it previously claimed verbatim pass-through).

Integration note: from_openapi's declaration-side checks (unbound_placeholders, collision rejection) now have a call-time counterpart; to_openapi's gateway projection was untouched (its CallRequest shape passes through unchanged).

Verification: cargo test (297 lib), cargo test --all-features (368 + integration suites), cargo clippy --all-targets -- -D warnings (default + all features), cargo fmt --check — all green.