The gate scanned only `*.md *.yml *.yaml *.json *.toml *.sh *.ts *.js`. A
`postgres.env`, a `.container` quadlet, an `.ini`, or an extension-less dotfile
— exactly the shapes the dotfiles tier is made of — was never read at all.
Discovered while deciding what else belongs in `dotfiles/`: `~/.config`
carries `containers/systemd/postgres.env` with a real `POSTGRES_PASSWORD`,
which the ignore list did not cover either (`git check-ignore` says so: `.env`
does not match `postgres.env`).
Token SHAPES now scan the entire staged diff, every file type; bcrypt hashes
and `Authorization: Basic` headers joined the shape list. Credential
ASSIGNMENTS are scanned in non-prose files only — the auto-learned memory tier
is prose *about* credentials (7 such hits measured on the tracked tree), and a
gate that fires there gets overridden until it means nothing. Markdown keeps
shape detection, which is what it had before.
Three invariants, each pinned by a test in tests/secret-gate.bats (13 tests,
black-box: the hook is copied into a scratch repo and git itself runs it):
- Fail closed. The first version of this rewrite passed `-I` to `git diff`,
which is not valid there; the empty file list made every secret commit sail
through, and a blind gate looks exactly like a clean tree. If the hook cannot
read the staged diff it now refuses the commit.
- Only ADDED lines can leak. The gate refused the redaction commit in this
branch because the diff still carried the removed password — a gate that
blocks the removal of a secret holds the leak hostage.
- Path-valued variables (`…_FILE=`, `…_PATH=`) and placeholder/indirected
values are not secrets, so the gate stays worth listening to.
`.gitignore` quarantines `*.env` at any name, and gains the theme-media rule
whose untracking lands in the next commit. `AGENTS.md` states the new contract.
Refs #40
autoresearch/ runs, agent/predict/ ngram models, local/ artifact dumps, wt/
worktrees and memories/--home-blank-.omp-wt-* buckets are runtime state keyed
on ephemeral paths; none were tracked, so the rules are purely additive.
Memory-file flush for the dotfiles-deploy session with the blankpad admin
credential scrubbed to a placeholder; sessions transcripts untracked
(gitignored) since harness transcripts can carry raw secrets.
Managed skills: command-center-dotfiles-import, ssh-fish-host-remote-exec,
stash-supersession-audit-before-drop.
Import Dankware's environment layer into the repo as home-relative package
trees (niri, gtk-3/4, ghostty, alacritty, fish, zsh, bash, profile,
systemd-user, dconf). scripts/deploy.sh implements stow-equivalent semantics
(check|adopt|sync modes): identical files adopt to symlinks, new files link,
divergent files quarantine-and-replace under .quarantine/<host>/<ts>/ (gitignored).
zz-<hostname> override packages deploy last with override semantics.
Secrets never enter git: GITEA_TOKEN moved from .zshrc into untracked
~/.config/environment.d/secrets.env (0600); tracked .zshrc sources it
guarded. core.hooksPath armed by deploy.sh so the pre-commit secret gate is
live on every machine that deploys.
Config in, state out: databases, WAL/SHM sidecars, caches, logs, sessions,
run dirs, ssh-control sockets stay OUT of history. Quarantine list: auth.json,
.env, trust.json, private keys never tracked. Pre-commit hook scans staged diff
for live-secret shapes (sk-, ghp_, github_pat_, glpat-, xox, AKIA, PEM headers,
JWTs) before anything reaches the Gitea remote.