fix(http): gate streamRequest XSRF cookie read on withXSRFToken — closes queue #64#86
fix(http): gate streamRequest XSRF cookie read on withXSRFToken — closes queue #64#86Goosterhof wants to merge 2 commits into
Conversation
…g (queue #64) Previously, streamRequest unconditionally read document.cookie for XSRF-TOKEN and emitted X-XSRF-TOKEN on every streaming POST, ignoring the withXSRFToken flag that gates the axios methods at line 39. This violated the library invariant that withXSRFToken: false (the default) suppresses XSRF behavior across all transports. Apply the same default-resolution semantics used at line 39 (options?.withXSRFToken ?? false) so streamRequest and the axios methods share identical XSRF behavior under the same consumer config. Tests rework the three existing XSRF cases to set withXSRFToken: true (the gate-open condition they implicitly assumed) and add two new cases: - omits XSRF header when withXSRFToken: false even with cookie present - omits XSRF header by default (withXSRFToken unset) even with cookie present Symmetry: createHttpService:39 already passes withXSRFToken: false as the axios default. streamRequest now honors the same default. Closes enforcement queue #64.
Patch bump for the streamRequest XSRF gate fix (queue #64). Additive guard on previously-undefined behavior — no API change. Caret-range ^0.3.0 in fs-loading + fs-adapter-store peer ranges matches 0.3.1 under semver; no cascade widening required.
Deploying fs-packages with
|
| Latest commit: |
df4af51
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://c64e14ca.fs-packages.pages.dev |
| Branch Preview URL: | https://engineer-queue-64-streamrequ.fs-packages.pages.dev |
|
Superseded by an upcoming streamRequest removal PR targeting fs-http Why removal over the cookie-read gate this PR landed: the cross-stack review that followed PR #86 surfaced two additional option-honoring asymmetries on What the replacement PR will ship:
If streaming eventually becomes a real requirement, axios's native Closing here; the replacement PR will reference this for context. |
Summary
Gate
streamRequest'sdocument.cookieXSRF read onoptions?.withXSRFToken ?? false, matching the default-resolution semantics applied to the axios methods atcreateHttpService:39. The streaming transport now honors the samewithXSRFTokenconfig as the standard request methods.Closes enforcement queue #64 (war-room item — see
enforcement/queue.md).Why
packages/http/src/http.ts:108-128(pre-fix) unconditionally read the XSRF-TOKEN cookie on every streaming POST and emittedX-XSRF-TOKEN, regardless of the service'swithXSRFTokensetting. This violated the library invariant established at line 39, wherewithXSRFToken: false(the factory default) gates the axios-method cookie read.The asymmetry was surfaced by Sapper M3 Finding #1 during the 2026-05-15 staleness refresh. The same PR #62 hardening pass that wired
withCredentialsto honor consumer config instreamRequestdid not apply the parallel discipline towithXSRFToken. Author comment at the original lines 116-119 documents thewithCredentialsdiscipline; this PR extends it to XSRF.Severity recalibration (General-verified)
Sapper M3 originally rated this High conditioned on the consumer scan. General-led verification (
grep -rn "streamRequest(" territories/{kendo,brick-inventory-orchestrator,the-laboratory,ublgenie,entreezuil,emmie}/) confirmed zero production call sites tostreamRequestacross the entire consumer fleet — only export/re-export, mock-server, andvi.fn()references. Severity drops to Medium correctness defect: real library invariant violation, no exploiting consumer today, would catch the first consumer to adopt the stream API without auditing the code path.The library-side fix is warranted as defense-in-depth and to close the test gap that lets the defect persist undetected. Campaign report:
campaigns/fs-packages/2026-05-15-m3-staleness-refresh-wave.md.Changes
packages/http/src/http.ts:108-131— gate cookie read onwantsXsrf = options?.withXSRFToken ?? false. One-line sibling comment naming the discipline (symmetric with axios methods at line 39).packages/http/tests/http.spec.ts— five XSRF cases in the streamRequest block:withXSRFToken: true(reworked)withXSRFToken: trueand no cookie present (reworked sanity-check; gate-open case)withXSRFToken: true(reworked)withXSRFToken: falseeven with cookie present (new — the bypass case the test gap missed)withXSRFTokenunset) even with cookie present (new — confirms?? falsedefault semantics)packages/http/package.json— bump 0.3.0 → 0.3.1 (additive guard on previously-undefined behavior; no API change).packages/http/CHANGELOG.md— prepend## 0.3.1 — 2026-05-15entry.package-lock.json— single-line version-string regeneration; no nested@script-development/*copies (verified).Verification — 8 fs-packages CI gates
npm auditnpm run format:checknpm run lintnpm run buildnpm run typechecknpm run lint:pkgmainsideEffectssuggestion on all 11 packages, including ones this PR does not touch — flagged below in Notes for follow-upnpm run test:coveragenpx stryker run(fs-http)unregisterhelper line 29 — pre-existing equivalent mutants unrelated to this fix). Up from M2 baseline of 95.74% — the new tests killed two previously-surviving mutants on the XSRF read path.Lockfile sanity:
node -e "..."scan confirms zero nestednode_modules/@script-development/*registry copies; all resolve to workspace links.Out-of-scope coordination
0.3.1bump. This PR's bump is0.3.0 → 0.3.1. If queue chore(deps-dev): bump the oxc group with 2 updates #21's Medic order opens before this merges, the two CHANGELOG entries can be merged under the same0.3.1heading at PR-open time.^0.3.0infs-loadingandfs-adapter-storepeer ranges matches0.3.1under semver.streamRequest(...)call sites in production code).docs/packages/http.md): Authentication & XSRF section (lines 102-123) does not currently mentionstreamRequest; skipped per orders.Test plan
withXSRFToken: trueconsumerswithXSRFToken: false+ cookie present → noX-XSRF-TOKENheaderX-XSRF-TOKENheader even with cookie presentwithXSRFToken: true+ cookie → header present and URL-decoded?? falsediscriminator andif (wantsXsrf)branch