security: add secret-scan CI gate + persisted-key allowlist tripwire (#163)

An unsolicited scanner reported CRITICAL "LLM output written to a
persistent memory store" findings against src/lib/notifications.ts:145,
src/lib/sdk.ts:392 and src/lib/session-grouping.ts:24. All three are
false positives: the cited lines are an in-memory notification dedupe
Map, a URLSearchParams limit param, and a bucket push inside a pure
grouping helper. The app persists nothing model-derived — sessions and
messages live on the server and are held in memory by the stores.

Two gates so that stays true and so the one class of report that WAS
real for us (credentials in git history) gets caught before a push:

- security-scan.yml: gitleaks on push/PR to main, full history fetch.
- persisted-keys.test.ts: enumerates every SecureStore write by key.
  A new persistence sink fails the suite until someone adds the key
  with a note saying what it holds — which is the moment to notice if
  it's model output rather than user config. Verified it trips by
  adding a throwaway "cache the assistant reply" write.

Co-authored-by: engineer <engineer@macbookpro.lan>
Co-authored-by: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Den
2026-08-13 22:45:46 -07:00
committed by GitHub
parent a750e1b080
commit c92327570b
2 changed files with 115 additions and 0 deletions

31
.github/workflows/security-scan.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
name: Security scan
# Why this exists: the one accurate external report we ever received was
# Postgres credentials committed to public repo history. The finding itself
# was cheap to fix; what was missing was a gate that would have caught it
# before the push. This is that gate.
on:
push:
branches: [main]
pull_request:
branches: [main]
permissions:
contents: read
jobs:
secrets:
name: Secret scan (gitleaks)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
# Full history so a secret introduced in an earlier commit on the
# branch is caught, not just the tip diff.
fetch-depth: 0
- name: gitleaks
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}