Secret-rules PR gate — operations playbook
Implemented by: Phase 4 of the token-audit plan (#7882).
Workflow file: .github/workflows/secret-rules-pr-gate.yml
Check script: scripts/secret-rules-pr-gate.sh
What it is
A deterministic CI check that runs on every PR touching the files that define
secret-protection behaviour: CLAUDE.md, .claude/**, infra/agent-prompts/**,
and standards/**. It blocks PRs that lower the protection level and passes neutral
changes.
No LLM probe runs here — that lives in the weekly audit
(.claude/commands/weekly-token-audit.md).
What the gate checks
| # | Check | Failure means |
|---|---|---|
| 1 | Hook file inventory — pre-bash-safety.sh, pre-read-safety.sh, pre-grep-safety.sh exist in .claude/hooks/ | A hook file was deleted or renamed |
| 2 | Hooks wired in settings.json — all three hooks appear in .claude/settings.json under PreToolUse | A hook was de-registered from the Claude Code trigger |
| 3 | Sentinel hash valid — standards/common/secret-rules-core.md hash in line 1 matches sha256sum(lines 2+) | The file was edited without refreshing the hash |
| 4 | Sentinel presence — required files contain <!-- SECRET-RULES:v1 --> | The sentinel marker was removed from a worker prompt or skill |
| 5 | CLAUDE.md size ≤ 80 KB | The always-loaded context grew past the token threshold |
| 6 | Hook provocations — hooks actually block known-bad inputs | A hook script was broken (exits 0 when it should exit 1) |
How to pass the gate
After editing standards/common/secret-rules-core.md
The file carries a content-hash sentinel on line 1. Any body edit (lines 2+) invalidates it:
bash scripts/update-secret-rules-hash.sh
git add standards/common/secret-rules-core.mdVerify locally before pushing:
bash scripts/secret-rules-pr-gate.shAfter modifying a hook file
Ensure the hook still blocks its known-bad cases:
bash scripts/secret-rules-pr-gate.shIf a provocation test fails, the hook logic changed in a way that weakens it. Review the diff and restore the intended behaviour.
After modifying .claude/settings.json
The gate checks that pre-bash-safety, pre-read-safety, and pre-grep-safety
still appear under PreToolUse. Ensure you did not remove or rename a hook command.
After editing a sentinel-required file
Sentinel-required files (infra/agent-prompts/worker-issue.md,
infra/agent-prompts/review-pr-worker.md,
.claude/commands/weekly-supabase-advisor-audit.md,
.claude/commands/weekly-token-audit.md) must contain the line:
<!-- SECRET-RULES:v1 -->
If you removed it by accident, restore it. If you intentionally removed the rules block, do not remove the sentinel marker — leave it in place and update the block’s content instead. The sentinel marks that the file was reviewed for secret rules compliance, not that a specific text block is present.
If CLAUDE.md exceeds 80 KB
The limit exists because CLAUDE.md is loaded into every session’s context, directly raising the first-turn token count. To reduce its size:
- Move rarely-used sections to separate files under
docs/playbooks/and add a one-line reference link in CLAUDE.md. - Consolidate duplicate guidance (e.g. two descriptions of the same SOPS pattern).
- Remove stale content (decommissioned services, resolved incidents).
Do not raise the 80 KB limit without a design decision — that threshold exists to protect the 55k-median-start-context alarm from the weekly token audit.
Branch protection
The gate is most valuable as a required status check on main. Until the workflow
has run at least once on a PR to main, GitHub won’t list secret-rules-check as an
available check name. Run it once manually or wait for the first qualifying PR, then
add it:
# Step 1 — read the current required checks (must be preserved in Step 2's array)
gh api repos/radieu/p24-infra/branches/main/protection/required_status_checks \
--jq '.checks[]'
# Step 2 — add secret-rules-check alongside the existing checks
# Replace EXISTING_CHECK_1 / EXISTING_CHECK_2 with the names from Step 1.
gh api repos/radieu/p24-infra/branches/main/protection/required_status_checks \
--method PATCH \
--input - <<'JSON'
{
"strict": false,
"checks": [
{"context": "EXISTING_CHECK_1", "app_id": -1},
{"context": "EXISTING_CHECK_2", "app_id": -1},
{"context": "secret-rules-check", "app_id": -1}
]
}
JSONNote: GitHub’s
PATCH /required_status_checksreplaces the whole list. Always include the existing checks in the array, or they will be removed.
For et-operational-platform, the same workflow needs to be added to that repo
(sync is out of scope for this issue). The branch protection command is the same
with radieu/et-operational-platform and the target branch.
Running the check locally
# From the repo root
bash scripts/secret-rules-pr-gate.shExit 0 = all checks passed.
Exit 1 = one or more checks failed (details printed to stdout).
Adding a new sentinel-required file
- Add the file path to the
SENTINEL_FILESarray in:scripts/secret-rules-pr-gate.sh.claude/commands/weekly-token-audit.md(Phase 2 Part B section)
- Ensure the file contains
<!-- SECRET-RULES:v1 -->at a reasonable location. - Run
bash scripts/secret-rules-pr-gate.shto verify. - Commit both the sentinel-required file and the updated arrays together.
Incident response
Gate fails on a push to main (protection was lowered):
- The workflow opens a
bugissue automatically and fires a Discord alert. - Identify which commit introduced the failure (
git log --oneline -5). - Restore the protection (re-add the sentinel, re-wire the hook, etc.).
- Open a PR with the fix — the gate must pass on the fix PR before merging.
- Close the auto-opened bug issue.
Gate fails on a PR that should be neutral:
- Run
bash scripts/secret-rules-pr-gate.shlocally against your branch. - The script prints which specific check(s) failed.
- Apply the remediation above for the relevant check.
- If the failure is a false positive (the gate’s logic is wrong), open a separate issue — do not bypass the check in the PR under review.