Files
alkhttp/tasks/client/review-002-client-policy-wire-tests.md
T
glm-5.3-flash e2c255d40c docs(tasks): decompose review-002 into 24 tasks (23 implementation + 1 bracketed follow-up)
Decomposition of docs/reviews/002-post-remediation-review.md per its
5-unit remediation plan:

- Unit 1 (security-critical): gw15-publish-body-cap,
  prj16-schema-via-call (CF-004 filed alkcall-side), fwd13-dot-segments,
  fwd16-missing-capability, oai11-ref-memoization
- Unit 2 (timeout/terminality): ws13-idle-progress,
  fwd15-stream-timeout, cli01-retry-after-budget, con17-mcp-pagination,
  con18-wss-sweep-exit
- Unit 3 (projection/docs): projection-truthfulness, mcp-batch-cap,
  gw16-status-drift
- Unit 4 (spec-import): yaml-normalization, oai13-path-item-wildcards,
  import-loudness-cluster, js01-placeholder-check,
  fwd17-19-contract-decisions
- Unit 5 (WS polish + tests): con18b-ws-polish,
  client-policy-wire-tests, cov-deployment-knobs, cov13-dead-code,
  srv11-srv12-router-ordering
- review-002-bracketed-followup: tentatively planned post-bulk pass
  (stale-check, OQA-18 enforcement decision, CON-08/09 close() lever,
  cross-crate re-checks) — deliberately not serialized against the
  bulk

Also: review-002 numbering repair (CON-14 was double-booked; MCP
pagination now CON-14, from_wss monitor renumbered CON-18, missing
CON-14 section added).

taskgraph: 66 valid, no cycles; 24 pending (all review-002);
gen-1/gen-2 parallel waves identified; workflow-cost hotspots are
prj16 (12.8) and ws13 (11.1), both carrying the reviewed slicing
guidance in their Notes.
2026-08-30 10:50:34 +00:00

81 lines
4.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
id: review-002-client-policy-wire-tests
name: Wire tests — redirect policy, retry gate/budget, streaming terminal arms, TLS error arms (CLI-02/03, COV-10/11)
status: pending
depends_on: [review-002-fwd15-stream-timeout, review-002-cli01-retry-after-budget]
scope: moderate
risk: low
impact: component
level: implementation
tags: [client, review-002, coverage, adapters]
---
## Description
The crate's highest-value coverage gap: the outbound client's policy
stack — the code that protects credentials — has never run against a
redirect or a retry on the wire, and `forward_stream`'s terminal arms
are dark end-to-end (review 002 COV-11: `same_host_redirect_policy`
100% dark; COV-10: SSE terminal arms dark). Concretely:
- **CLI-02 (redirect)**: no test in the crate sends any 3xx. Add:
(a) same-host 302 → followed, credential headers forwarded;
(b) cross-host 302 → response surfaced (HTTP_302-family), the second
endpoint receives **zero requests** (count at the attacker server) —
the FWD-03 property, pinned. Hop-cap (>10) → loud error, third test.
The `spawn_responder` seam at forward.rs:1415-1477 already speaks
raw HTTP and can emit `location:`.
- **CLI-03 (retry)**: counting-responder tests: POST + 500 ⇒ exactly
1 upstream hit (method gate, :362-366); GET + 500×2 ⇒ 3 hits then
success; budget exhaustion (`max_total_retry_duration` small) stops
retries even under a generous attempt cap (:381); PEM
parse-failure arms (:487-507) via garbage-PEM files asserting
`CaBundleParse`/`ClientCertParse` + path (never key material).
- **COV-10 (streaming/forward terminal arms)**: (a) upstream SSE line
> 1 MiB without newline through the real `forward_stream` → single
INTERNAL terminal envelope, stream ends; (b) responder sends
`data: a\n\n` then aborts the socket → terminal error envelope;
(c) responder ends without trailing blank line → pending event
dispatched at EOF; (d) dead-port transport failure through both
`forward` (:719-722) and `forward_stream` (:851-853) → INTERNAL
envelope; (e) binary `application/octet-stream` 200 → byte-array
envelope (:638-643); (f) `application/json` 200 with malformed body
→ INTERNAL decode envelope (:656-658).
- Plus the small dark arms from COV-12 that live in this seam:
ApiKey/Basic malformed-credential loud arms (extend the FWD-08 test
family), declared-header-param invalid name/value rejections, and
`SharedHttpClient::config()` reflecting a reloaded config
(FWD-12's atomicity assertion).
## Acceptance Criteria
- [ ] Redirect: 3 tests (same-host follow, cross-host refuse +
zero-contact assert, hop-cap error) passing
- [ ] Retry: 3 tests (POST single-hit, GET retry-to-success with
counted hits, budget-bounded) passing
- [ ] TLS: 2 parse-failure tests (CaBundleParse, ClientCertParse) +
config()-after-reload assertion
- [ ] Streaming: 6 terminal-arm tests (oversized line, socket abort,
EOF-flush, dead-port×2, binary decode, malformed-JSON decode)
passing
- [ ] Credential arms: ApiKey/Basic malformed-value tests land
- [ ] `cargo test --all-features`, `cargo clippy --all-features
--all-targets -- -D warnings`, `cargo fmt --check` pass
## References
- docs/reviews/002-post-remediation-review.md (Part D', CLI-02/03; Part G', COV-09/10/11/12)
- src/client/http_client.rs:300-316 (redirect policy), :354-395 (retry gate/budget), :487-507 (PEM arms)
- src/adapters/forward.rs:1415-1477 (spawn_responder seam), :887-925 (stream terminal arms)
- tests/client_tls.rs (the TLS harness pattern)
- tasks/client/review-002-fwd15-stream-timeout.md and review-002-cli01-retry-after-budget.md (land first — these tests pin their new behavior too)
## Notes
Pure test-addition task (plus any test-seam helpers). Land after the
two client behavior tasks so the tests assert final semantics, not
interim ones. Slice: (1) redirect tests, (2) retry tests, (3)
streaming terminal arms, (4) TLS + config arms — independent commits.
If `spawn_responder` needs a "count requests per host" surface, build
it once and reuse — the cross-host zero-contact assertion is the
load-bearing one.