local-secrets-manage — is my secret file tracked or ignored?
The engine is local-secrets.js (portable Node, zero deps). It answers a narrow,
high-value question: for every file whose NAME looks like it holds credentials, is
git about to leak it? It walks the working tree, matches basenames against the
secret-file name rules, and for each candidate asks git — ls-files (tracked?) and
check-ignore (ignored?) — then assigns a verdict. That is the whole job.
This is the FILE-STATUS half of secret hygiene. It scans names, never contents:
it never opens a candidate file, never prints a byte of one, never edits
.gitignore. The CONTENT / git-history half — is an actual key string committed
anywhere in history — is history-leak-scan's job (pm-secretscan.js). Run both:
this one catches "my .env is about to be added", that one catches "an AWS key is
already in commit abc123".
Verdicts
| verdict | meaning | fix |
|---|---|---|
TRACKED-SECRET |
the file is in the git index — already leaking (or one push from public) | rotate the credential, then git rm --cached <path> and ignore it |
UNIGNORED |
on disk, not tracked yet, and not ignored — one git add . from leaking |
add a .gitignore line (--fix-print gives you the exact line) |
OK |
ignored — git refuses to add it without -f |
none |
Commands
node local-secrets.js [--dir <path>] audit repo at cwd (or <path>)
node local-secrets.js [--dir <path>] --fix-print also print proposed .gitignore lines
node local-secrets.js --canary self-test (the done-check)
node local-secrets.js --help
- audit prints a table (verdict / path / matched rule) plus a count line.
Exit 1 if any
TRACKED-SECRETorUNIGNORED; exit 0 clean. - --fix-print appends the
.gitignorelines it WOULD add — the exact path per risky row (/.env,/config/id_rsa, …), so a sibling is never over-ignored. It prints them to stdout only; you copy them in. It never writes the file.
Candidate name rules (basename): .env*, *.pem, *.key, id_rsa*,
id_ed25519*, *_keys.env, credentials*.json, secrets.*. Names containing
example/sample/template/fixture (and .dist/.sample suffixes) are
exempt — a placeholder is not a secret. .git, node_modules, .venv, and
similar build/dep dirs are skipped during the walk.
Examples
- Before making a repo public — confirm no key file is staged:
node local-secrets.js --dir /path/to/repo. A*_keys.env(e.g. a provider API-key file) showingTRACKED-SECRETmeans rotate the credential first, then untrack;UNIGNOREDmeans add the ignore line now. - A backend service holding sensitive user data — a
.envwith a database URL must readOK. If it showsUNIGNORED:node local-secrets.js --dir /path/to/service --fix-printand paste the proposed/.envline into.gitignoreyourself. - This repo — a quick pre-commit sanity check from the repo root:
node local-secrets.js. Clean → exit 0.
Windows notes
- Paths with spaces: quote
--dir(--dir "D:/path with spaces"). Forward slashes work in both PowerShell and Git Bash; git resolves them. - This tool never writes
.gitignore. If you do apply the--fix-printlines by hand in PowerShell, useAdd-Content -Encoding utf8(Set-Content defaults to the ANSI codepage) — a single non-ASCII byte in.gitignoreis harmless, but keep the file UTF-8 to be safe.
Storage / side effects
None. Read-only toward the world: it runs git ls-files / git check-ignore
(both read-only) and fs.readdirSync on directory entries. It writes nothing
outside its own --canary temp dir.
Exit codes
0 clean · 1 any TRACKED-SECRET/UNIGNORED (or canary failure) · 2 usage
error (missing --dir, not a git repo, git unavailable).
Verification (the done-check)
node local-secrets.js --canary
Builds a throwaway git repo, plants a committed .env (→ TRACKED-SECRET), an
on-disk .env.local (→ UNIGNORED), an ignored .env.ok (→ OK), and an exempt
.env.example; asserts all four verdicts, exit 1, and the exact --fix-print
lines — then asserts a clean repo exits 0 and a non-repo exits 2. Cleans up.
MUST print CANARY PASS n/n before you trust a result.