Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
b730775
chore(security): owner rotation runbook and CI secret scan (refs #22)
claude Sep 29, 2026
67342ab
test: use a global regex for the lone-CR fixture (fixes CodeQL alert)
claude Sep 29, 2026
d14ff3a
fix(security): close scanner bypasses and stage the Neon rotation (re…
claude Sep 29, 2026
a57121b
fix(security): make the scanner fail closed and close four more bypasses
claude Sep 29, 2026
b42c83a
fix(security): fix six more scanner gaps by class, scan the staged bl…
claude Sep 29, 2026
d1d33e3
fix(security): remove an exponentially backtracking path regex (CodeQ…
claude Sep 29, 2026
d915c7a
fix(security): scan lockfiles, PR commit ranges, XML config and more …
claude Sep 29, 2026
7df222a
fix(security): keep pair context in range scans, compare index before…
claude Sep 29, 2026
ab14804
fix(security): close four more scanner gaps (indented pipes, unmerged…
claude Sep 29, 2026
42d1f30
fix(security): read fish/shell set forms, multiline literals, skip bi…
claude Sep 29, 2026
9e80e71
docs(security): limit file-type claim to scanned files, add rollback …
claude Sep 29, 2026
27d428e
fix(security): flag punctuated XML passphrases, keep range context in…
claude Sep 29, 2026
d7bcaea
fix(security): logical assignment ops, YAML block pairs, quoted SQL, …
claude Sep 29, 2026
b789e76
fix(security): scan auth headers, terraform variable labels, redis-st…
claude Sep 29, 2026
b055207
fix(security): scan merge results, quoted basic-auth passphrases, loc…
claude Sep 29, 2026
1df880a
fix(security): properties whitespace keys, variable refs, env setters…
claude Sep 29, 2026
e404ef7
fix(security): drop JS hashing of file/match text, compare in memory
claude Sep 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ on:
branches: [main]
workflow_dispatch:

permissions:
contents: read

jobs:
lint-test-build:
name: Lint · Test · Build
Expand Down Expand Up @@ -46,3 +49,69 @@ jobs:

- name: Build
run: npm run build

secret-scan:
name: Secret scan
runs-on: ubuntu-latest
# A normal run takes seconds. The cap keeps a pathological file from holding a runner for the default 6 hours.
timeout-minutes: 5

permissions:
contents: read

steps:
# Full history (not the default depth 1): the range scan below needs the base and head commits of the change and
# everything between them. No credentials are kept in the checkout, since nothing here pushes.
- name: Checkout
uses: actions/checkout@v4
Comment thread
paccloud marked this conversation as resolved.
with:
fetch-depth: 0
persist-credentials: false

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20

# Scans git-tracked files only. The report lists file, line and rule name, never the matched text.
# The --history mode is deliberately not run here: the known leak in old commits would fail forever.
- name: Scan tracked files for secrets
run: node scripts/check-secrets.mjs
Comment thread
paccloud marked this conversation as resolved.

# The tip scan cannot see a secret that was committed and then removed by a later commit of the same pull request or
# push, and that value is still in the pushed history. This step scans the ADDED lines of every commit in the range:
# pull_request base.sha..head.sha (commits reachable from the PR head and not from its base; a fork's head commit
# arrives through the PR merge commit that checkout fetches, and is present with fetch-depth 0)
# push before..sha (a new branch has an all-zero "before": only the pushed tip commit is scanned)
# A commit that is not in the clone (a force-push removed the old tip, a fetch was partial) or a shallow clone fails the
# step with exit code 2 and a message. It never passes silently and never falls back to the full-history audit.
# Event values reach the script only through env vars, are checked to be plain commit ids, and are quoted.
- name: Scan commits in this change for secrets
env:
EVENT_NAME: ${{ github.event_name }}
PR_BASE_SHA: ${{ github.event.pull_request.base.sha }}
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
PUSH_BEFORE_SHA: ${{ github.event.before }}
PUSH_AFTER_SHA: ${{ github.sha }}
run: |
set -euo pipefail
case "$EVENT_NAME" in
pull_request)
base="$PR_BASE_SHA"
head="$PR_HEAD_SHA"
;;
push)
base="$PUSH_BEFORE_SHA"
head="$PUSH_AFTER_SHA"
;;
*)
echo "No commit range for a '$EVENT_NAME' run: only the tracked-file scan above applies."
exit 0
;;
esac
id_pattern='^([0-9a-f]{40}|[0-9a-f]{64})$'
if ! [[ "$base" =~ $id_pattern && "$head" =~ $id_pattern ]]; then
echo "::error::The event did not give plain base and head commit ids, so the commits in this change cannot be scanned."
exit 2
fi
node scripts/check-secrets.mjs --range "$base..$head"
5 changes: 3 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,9 @@ cd app && npm run build
```bash
cd app && npm install
cd ../server && npm install
# Copy and configure env files (no quotes around values — Vite includes them literally)
cp app/.env.example app/.env.development
# Create your untracked local env file (no quotes around values — Vite includes them literally).
# Never overwrite the tracked app/.env.development or app/.env.production; see SECURITY_NOTICE.md.
[ -e app/.env.development.local ] || cp app/.env.example app/.env.development.local
```

## Architecture
Expand Down
Loading
Loading