fix(secrets): vault-pr commits pass the repo's hook; the deploy gate refuses an uncommitted vault #167

Merged
jfraeys merged 1 commit from jfraeys/fix/vault-pr-hook-venv into main 2026-10-14 19:03:38 -04:00
Owner

What happened (2026-10-14): ./infra rotate forgejo rotated FORGEJO_METRICS_TOKEN, then vault-pr.py's commit failed: its temporary worktree ran the repo's pre-commit hook, and check-secret-hygiene.py crashed there because it needs the checkout's .venv (PyYAML), which a fresh worktree does not have (.venv is gitignored). As designed on failure, the rotated vault stayed in the checkout. The later ./infra deploy --tags forgejo,prometheus read the working-tree vault and shipped it: production has a new metrics token (working: scrape up, no alerts) that main does not have.

Fixes

  • vault-pr.py links the checkout's .venv into its worktree before committing. test-vault-pr.sh now runs a real pre-commit hook that needs it; without the fix the test fails exactly like the real run (verified).
  • Deploy gate: promotion_verify refuses when secrets/vault.sops.yml in the working tree differs from the commit being deployed (deploys read the working-tree vault, so uncommitted secrets reached production without main). The refusal says how to fix it; the logged emergency bypass still applies. test-promotion.sh +2.

Follow-up (separate): record the live vault on main with the fixed helper, close #161/#162 (never deployed).

Touches scripts/lib/ (staged path), so merging starts a staging run. Checked: test-vault-pr, test-promotion, test-approve-promotion, test-infra-cli.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Ge5tovcwdEUBtPwUktsZZZ

**What happened (2026-10-14):** `./infra rotate forgejo` rotated `FORGEJO_METRICS_TOKEN`, then `vault-pr.py`'s commit failed: its temporary worktree ran the repo's pre-commit hook, and `check-secret-hygiene.py` crashed there because it needs the checkout's `.venv` (PyYAML), which a fresh worktree does not have (`.venv` is gitignored). As designed on failure, the rotated vault stayed in the checkout. The later `./infra deploy --tags forgejo,prometheus` read the working-tree vault and shipped it: production has a new metrics token (working: scrape up, no alerts) that `main` does not have. **Fixes** - `vault-pr.py` links the checkout's `.venv` into its worktree before committing. `test-vault-pr.sh` now runs a real pre-commit hook that needs it; without the fix the test fails exactly like the real run (verified). - **Deploy gate:** `promotion_verify` refuses when `secrets/vault.sops.yml` in the working tree differs from the commit being deployed (deploys read the working-tree vault, so uncommitted secrets reached production without main). The refusal says how to fix it; the logged emergency bypass still applies. `test-promotion.sh` +2. **Follow-up (separate):** record the live vault on main with the fixed helper, close #161/#162 (never deployed). Touches `scripts/lib/` (staged path), so merging starts a staging run. Checked: test-vault-pr, test-promotion, test-approve-promotion, test-infra-cli. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01Ge5tovcwdEUBtPwUktsZZZ
fix(secrets): vault-pr commits pass the repo's hook; the gate refuses an uncommitted vault
All checks were successful
Lint / lint (pull_request) Successful in 1m57s
Secret scan / scan (pull_request) Successful in 14s
4a9be6e970
Seen 2026-10-14 with `./infra rotate forgejo`: vault-pr.py's commit in its
temporary worktree ran the repo's pre-commit hook, and check-secret-hygiene.py
crashed there because it needs the checkout's .venv (PyYAML), which a fresh
worktree does not have (.venv is gitignored). The PR was not opened, the rotated
vault stayed in the checkout as designed, and the later `./infra deploy` shipped
it: production got a new FORGEJO_METRICS_TOKEN that main does not have.

- vault-pr.py links the checkout's .venv into its worktree. test-vault-pr.sh now
  uses a real pre-commit hook that needs it; without the fix the test fails the
  same way.
- promotion_verify (the deploy gate) refuses when secrets/vault.sops.yml in the
  working tree differs from the commit being deployed: deploys read the
  working-tree vault, so uncommitted secrets would reach production without main
  having them. The emergency bypass still applies. test-promotion.sh +2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ge5tovcwdEUBtPwUktsZZZ
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jfraeys/infra!167
No description provided.