Context
Follow-up from #37 (docs/privacy/session-custody.md, requirement SC-03). CONTRIBUTING.md rule 1 states "No credentials, cookies, session/storage dumps... Secret-scanning CI fails the build on matches." Verified empirically during the audit: it does not, for the shape that matters most.
scripts/secret-scan.mjs's cookie-header pattern requires the literal text Set-Cookie:, and session-json requires a JSON key literally named sessionid/sessiontoken/sessionkey. Playwright's actual context.storageState() output looks like:
{"cookies":[{"name":"grafana_session","value":"...","domain":"...","httpOnly":true,"sameSite":"Lax"}],
"origins":[{"origin":"...","localStorage":[{"name":"...","value":"..."}]}]}
— tested against all 8 PATTERNS in scripts/secret-scan.mjs with a synthetic (fake-valued) fixture of this exact shape: zero matched. src/recorder/redact.ts's assertNoLiteralSecrets patterns ("cookies?"\s*:, "localStorage"\s*:) do catch it, but that function only runs inside TrajectoryRecorder.write() — it is never applied repo-wide.
What to produce
- One or two new patterns in
scripts/secret-scan.mjs's PATTERNS array that match Playwright's storageState shape structurally (e.g., "cookies"\s*:\s*\[ co-occurring with "httpOnly" or "sameSite" on the same file) — narrow enough not to flag prose. This doc itself (and docs/privacy/session-custody.md, docs/gate/recorder.md, docs/architecture.md) legitimately contain the words "cookies" / "storageState" / "localStorage" in prose; the pattern must not fire on those, only on the JSON shape. Test both directions.
- A committed synthetic fixture (fake values only, same posture as
CANARY_TENANT) that exercises the new pattern, plus a test asserting secret-scan exits non-zero against it and exits zero against this doc's own prose.
Constraints
- No real session material anywhere in the diff, ever — synthetic values only.
- Verify the new pattern against every existing doc that discusses cookies/storage in prose before merging — a false positive here breaks CI for unrelated PRs.
How to test
npm run secret-scan
npm run ci
Before you open the PR
Context
Follow-up from #37 (
docs/privacy/session-custody.md, requirement SC-03).CONTRIBUTING.mdrule 1 states "No credentials, cookies, session/storage dumps... Secret-scanning CI fails the build on matches." Verified empirically during the audit: it does not, for the shape that matters most.scripts/secret-scan.mjs'scookie-headerpattern requires the literal textSet-Cookie:, andsession-jsonrequires a JSON key literally namedsessionid/sessiontoken/sessionkey. Playwright's actualcontext.storageState()output looks like:{"cookies":[{"name":"grafana_session","value":"...","domain":"...","httpOnly":true,"sameSite":"Lax"}], "origins":[{"origin":"...","localStorage":[{"name":"...","value":"..."}]}]}— tested against all 8
PATTERNSinscripts/secret-scan.mjswith a synthetic (fake-valued) fixture of this exact shape: zero matched.src/recorder/redact.ts'sassertNoLiteralSecretspatterns ("cookies?"\s*:,"localStorage"\s*:) do catch it, but that function only runs insideTrajectoryRecorder.write()— it is never applied repo-wide.What to produce
scripts/secret-scan.mjs'sPATTERNSarray that match Playwright's storageState shape structurally (e.g.,"cookies"\s*:\s*\[co-occurring with"httpOnly"or"sameSite"on the same file) — narrow enough not to flag prose. This doc itself (anddocs/privacy/session-custody.md,docs/gate/recorder.md,docs/architecture.md) legitimately contain the words "cookies" / "storageState" / "localStorage" in prose; the pattern must not fire on those, only on the JSON shape. Test both directions.CANARY_TENANT) that exercises the new pattern, plus a test assertingsecret-scanexits non-zero against it and exits zero against this doc's own prose.Constraints
How to test
Before you open the PR
docs/gate/recorder.md, ordocs/architecture.md's prose mentions of cookies/storagedocs/privacy/session-custody.mdSC-03 gap note updated