feat(dev-env): wire shared pre-commit secret scanner via core.hooksPath
Ships `modules/dev-env/scripts/git-hooks/pre-commit` — the same secret-scanner pattern omnixy uses, lightly adapted (drops the omnixy-specific test_auth.py skip, generic header comment). New option `lnbits-sensei.devEnv.gitHooks.enable` (off by default). When on, modules/dev-env/config.nix installs the hook at `~/.local/share/lnbits-sensei/git-hooks/pre-commit` and sets the consumer's git `core.hooksPath` to that directory, so every repo on the machine picks it up without per-repo wiring. The hook refuses to commit obvious secrets (PRIVATE KEY blocks, `password=…`, `secret=…`, `api_key=…`, `admin_key=…`, AWS keys, non-placeholder POSTGRES_PASSWORD) and unencrypted sops files (checks for a top-level `sops:` block AND `mac: ENC[…]` — either signal alone is forgeable). False positives are handled via `# pragma: allowlist secret` line- or block-level markers (gitleaks convention). docs/secrets-management.md gets a new subsection covering what the hook does, when to enable it, and the false-positive escape hatches. The Pitfalls section's reference to "the pre-commit hook most consumers use" is replaced with a concrete pointer to this option. `nix flake check --no-build` stays green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
fc1d31244a
commit
773632562e
4 changed files with 202 additions and 7 deletions
|
|
@ -43,11 +43,38 @@ This repo already wires sops-nix:
|
|||
- **`secrets/`** is gitignored except for `*.yaml` (which is
|
||||
encrypted) and `README.md`.
|
||||
- **`configuration.nix`** imports `modules/secrets.nix`.
|
||||
- **`modules/dev-env/scripts/git-hooks/pre-commit`** is the shared
|
||||
secret-scanner hook. Opt in by setting
|
||||
`lnbits-sensei.devEnv.gitHooks.enable = true;` — see below.
|
||||
|
||||
All of this is **inert until you create your first encrypted file**.
|
||||
`nix flake check` stays green meanwhile because the module gates on
|
||||
`builtins.pathExists`.
|
||||
|
||||
### The pre-commit hook (recommended)
|
||||
|
||||
`lnbits-sensei.devEnv.gitHooks.enable = true` installs a single
|
||||
secret-scanner pre-commit hook under
|
||||
`~/.local/share/lnbits-sensei/git-hooks/` and sets git's
|
||||
`core.hooksPath` so **every** repo on the machine picks it up
|
||||
without per-repo wiring. The hook refuses to commit:
|
||||
|
||||
- Lines matching `PRIVATE KEY`, `BEGIN RSA/EC/OPENSSH PRIVATE`,
|
||||
`password=…`, `secret=…`, `api_key=…`, `admin_key=…`,
|
||||
`AWS_SECRET_ACCESS_KEY`, `POSTGRES_PASSWORD=…` (unless the value
|
||||
is `example|changeme|placeholder`).
|
||||
- Files under `secrets/` matching `*.yaml` that lack a `sops:`
|
||||
metadata block (i.e. unencrypted secrets files staged by accident).
|
||||
|
||||
False positives (legitimate matches on placeholder values, prose
|
||||
comments, test fixtures) are handled via line- or block-level
|
||||
`# pragma: allowlist secret` markers — same convention as gitleaks.
|
||||
See the hook source for the full marker semantics.
|
||||
|
||||
Last resort: `git commit --no-verify` bypasses the hook entirely.
|
||||
Use sparingly, after confirming the diff doesn't actually contain
|
||||
secret material.
|
||||
|
||||
## Step-by-step
|
||||
|
||||
### 1. Install the tools
|
||||
|
|
@ -287,10 +314,13 @@ its own, and the operator can decrypt both.
|
|||
|
||||
## Pitfalls
|
||||
|
||||
- **Don't commit unencrypted YAML under `secrets/`.** The pre-commit
|
||||
hook most consumers use catches obvious cases, but it's not
|
||||
foolproof. Always verify with `cat secrets/<file>.yaml` that you
|
||||
see `sops:` metadata + base64 blobs, not plaintext.
|
||||
- **Don't commit unencrypted YAML under `secrets/`.** The shared
|
||||
pre-commit hook (enable via `devEnv.gitHooks.enable = true`)
|
||||
catches the obvious cases by checking for a `sops:` metadata
|
||||
block + `mac: ENC[…]` line — both are required for a real
|
||||
sops-encrypted file. Always verify with `cat secrets/<file>.yaml`
|
||||
that you see metadata + base64 blobs, not plaintext, before
|
||||
trusting the hook.
|
||||
- **Don't lose the private key.** No recovery. Back up the file at
|
||||
`~/.config/sops/age/keys.txt` (or `/var/lib/sops-nix/key.txt` on
|
||||
servers) somewhere safe and offline.
|
||||
|
|
|
|||
Reference in a new issue