test(protect): port engine unit suite + restructure tests/protect/#58
Merged
Conversation
…SSRF; array params
Brings the output-side protection into the vendored runtime, as RULES (nothing hardcoded),
via rule phases:
- new rule properties: `phase` (request|response|egress, default request) + `category`
- engine: resolve `response.status|body|header.*` and `egress.url|host|method`; new
`internal_host` match type (private/loopback/link-local/metadata ranges)
- runtime (createProtection): response phase screens the outgoing body; egress phase
(opt-in `egress:true`) wraps global fetch to screen outbound calls. Driven by default
bundles in defaults.js (overridable via responseRules/egressRules).
Response leak handling supports per-rule `action`:
- `redact` (default for the secret rules) — mask only the offending span(s) and still
serve the page; a legit response that leaks one key gets that key masked, not withheld
- `block` — withhold the whole response
Also fixes a real engine bug: array `parameter` (["get.a","post.b"]) — used pervasively in
rule_v2 — silently never matched (`parameter.indexOf('.')` on an array returns -1).
#evaluateCondition now resolves each element and ORs them.
Enforcement only in block mode; dry-run observes + serves original. Fail-open throughout.
createSupabaseGuard / createServerFnGuard unchanged. Full suite: 151 pass; build + typecheck green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
When the node-waf engine was vendored into src/protect/engine/, its ~180 unit tests did NOT come along — connect only had the runtime integration test, leaving matchValue / resolver / normalizer / mutations / adapters with no direct coverage. Ports the engine suite from the upstream engine (adapted to vitest) and groups all protect tests under tests/protect/: - engine.test.ts (54) — match types incl. internal_host, evaluate, inclusive/OR, whitelist, nested rules, ctype value-inversion, array parameters, fail-open, safeRegExp - request.test.ts (38) — resolver: get/post/request/cookie/server/files/raw/all + response.*/egress.* + wildcards + mutations - normalizer.test.ts (63) — normalize pipeline + _rawBody prototype-pollution serialization - fetch.test.ts (6) / node.test.ts (5) — the fetch + node request adapters - middleware.test.ts (16) — the Express middleware + rule client (mocked fetch) - runtime.test.ts (11) — createProtection integration (moved from tests/protect.test.ts): request/response-redact/response-block/egress, dry-run/block, Supabase + server-fn guards Full suite 333 pass; typecheck + build green. Engine source unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Comprehensive and well-structured test suite covering engine and middleware modules. 🎯 Quality: 88% Excellent · 📦 Size: Oversized — strongly consider breaking this down 🛡️ Standards: no pre-flight fit check ran for this change — wire 📈 This month: Your 23rd PR — above team average · Averaging Good |
…id rules) The ported suite covered the engine well but the Tier-3 protect-layer features only had happy-path coverage. Adds tests/protect/tier3.test.ts (17): - response redaction: every default secret type; multiple spans in one body; maskWith (string + per-category fn); contains-literal redaction; redact-with-no-maskable-pattern falls back to withholding; response.header.* rules - response gating/robustness: non-text content-type skipped; oversized (content-length) skipped; malformed rule (no rule_v2 array) skipped; invalid regex never matches / no crash - egress: every internal range blocked via the guard (127/10/192.168/172.16/localhost/::1/ metadata) + external allowed; allowHosts exemption; onEgressBlock payload; uninstallEgress restores global fetch - options/phases: default dry-run; responseRules replaces defaults; rules split by phase (a phase:response rule screens responses, NOT requests) protect coverage 193 → 210; full suite 350 pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
Author
|
/review |
ejntaylor
approved these changes
Jul 14, 2026
…essRules override - runtime .node() (body buffering + block/allow) and .express() guards - rule source: token path caches the fetched bundle, then falls back to last-known-good when the API fails; no-token/no-cache → empty request ruleset (allows) - egressRules override replaces the default SSRF rule Notes a pre-existing gap: runtime.node() consumes the body to screen it but doesn't re-expose req.body downstream (follow-up on the feature branch). Full suite 355 pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Resolves the conflict from #57 (squash-merged): #57 modified tests/protect.test.ts while this branch renamed it to tests/protect/runtime.test.ts — accepted the rename (its content is preserved there). Picks up #57's node() req.body fix + node-body.test.ts from main, and flips the now-obsolete "not re-exposed" note in runtime-guards to a real assertion. Full suite 358 pass; typecheck green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
When the node-waf engine was vendored into
src/protect/engine/, its ~180 unit tests didn't come along — connect only had the runtime integration test, somatchValue/ resolver / normalizer / mutations / adapters had no direct coverage. This ports them and groups all protect tests undertests/protect/.engine.test.tsinternal_host), evaluate, inclusive/OR, whitelist, nested rules, ctype value-inversion, array parameters, fail-open,safeRegExprequest.test.tsraw/all+response.*/egress.*+ wildcards + mutationsnormalizer.test.ts_rawBodyprototype-pollution serializationfetch.test.ts/node.test.tsmiddleware.test.tsruntime.test.tscreateProtectionintegration (moved fromtests/protect.test.ts): request / response-redact / response-block / egress, dry-run/block, Supabase + server-fn guardsAdapted from the upstream engine tests to vitest (paths +
describe/itimport);node:assertkept. Engine source unchanged. Full suite 333 pass, typecheck + build green.🤖 Generated with Claude Code