fix(security): enable gitleaks default rules in .gitleaks.toml template (#1395)

Merged
DO
12d ago
+170-6

Summary

.gitleaks.toml and the standards/gitleaks.toml template held only an [allowlist]. A file passed via --config replaces gitleaks' built-in ruleset, so the Secret scan (gitleaks) job loaded zero detection rules and passed on any history. This PR adds [extend] useDefault = true to both files, adds detection regression tests that run the real scanner, and documents the requirement.

Fixes #1395

How it was confirmed. Local gitleaks is v8.30.1, the same version ci.yml pins (.github/workflows/ci.yml secret-scan job; standards/workflows/ci.yml pins 8.30.1 too). I generated synthetic, obviously fake credentials at runtime (an AWS-access-key-shaped string and a ghp_-shaped string) and scanned them:

ConfigResult
.gitleaks.toml (origin/main)no leaks found, exit 0
standards/gitleaks.toml (origin/main)no leaks found, exit 0
same file + [extend] useDefault = true3 findings (aws-access-token, github-pat, generic-api-key), exit 1

I got the same results with gitleaks dir, gitleaks detect --no-git, and git-history mode (gitleaks detect --source <repo>, the invocation CI uses).

Fix

  • .gitleaks.toml and standards/gitleaks.toml: add [extend] useDefault = true, with a comment saying it must not be removed. The _bmad/ path allowlist from #996 is unchanged, so default rules plus that allowlist is the behavior #996 originally intended.
  • .github/workflows/ci.yml: comment only. The Run gitleaks comment wrongly said --config exists to avoid the default ruleset. It now explains the allowlist and the mandatory extend block. The command is unchanged.
  • standards/push-protection.md: the template block now includes the extend block, plus a paragraph explaining why it is mandatory.
  • standards/workflows/ci.yml is unchanged, because the root cause is the config file and not the job.

History check with default rules enabled. I ran gitleaks detect --source . --config .gitleaks.toml --redact --exit-code 1 over this repo's full history (all refs, 1,401 commits, including this branch) with the new config: no leaks found. Turning the rules on does not red main.

Regression tests (test/workflows/ci/secret-scan-config.bats, TDD: written first; on origin/main tests 4–7 and 9 fail, and all pass with the fix)

  • Both configs set useDefault = true inside [extend] (static parse).
  • Both configs detect the synthetic secrets when gitleaks detect runs in git-history mode against a throwaway repo. Assertions are on exit 1 plus the aws-access-token and github-pat RuleIDs in the JSON report.
  • Control: an allowlist-only config detects nothing. This documents the failure mode and shows the tests can tell a working config from a zero-rule one.
  • ci-tests.yml installs the same gitleaks version and checksum as ci.yml, so the tests can't silently drift from the binary CI scans with.
  • Fixture values are put together at test time from split string pieces. No secret-shaped literal is committed, and the repo's own scan stays clean (confirmed by the history scan above).
  • If gitleaks is missing, the tests fail with a message and are never skipped (AGENTS.md).

CI wiring: .github/workflows/ci-tests.yml now installs gitleaks v8.30.1 exactly the way ci.yml does: gh release download with a bounded retry loop and sha256sum -c against the same pinned checksum. Its paths: filters now include .gitleaks.toml and standards/gitleaks.toml.

Test commands

  • bats test/workflows/ci/: 21/21 ok
  • actionlint .github/workflows/ci.yml .github/workflows/ci-tests.yml: clean
  • shellcheck -s bash test/workflows/ci/secret-scan-config.bats: clean
  • markdownlint-cli2 standards/push-protection.md: 0 errors
  • Full-history gitleaks detect with the new config: no leaks found

Follow-ups / rollout (needs a human decision)

  • Downstream repos are affected too. Every repo that copied the old standards/gitleaks.toml (seeded by seed-repo-template.sh, which lives outside this repo) is also scanning with zero rules. This PR fixes the template only. Existing copies need a standards-sync pass, and those repos' histories have never been scanned with real rules. Turning the rules on may red their Secret scan (gitleaks) required check until findings are triaged or rotated. I'd suggest running gitleaks git --redact per repo before or alongside the sync.
  • No compliance check currently validates .gitleaks.toml contents (scripts/lib/push-protection.sh only checks that ci.yml invokes gitleaks). A content check such as gitleaks_config_extends_defaults could catch regressions fleet-wide. It is left out here because it would flag every existing repo at once, so it should be planned together with the sync above.

šŸ¤– Generated with Claude Code

Problem

See the linked issue.

Risk

Medium — changes GitHub Actions workflow behavior, which is exercised only post-merge; verify via the affected workflow runs.

Test plan

Tests added/updated: test/workflows/ci/secret-scan-config.bats. Verification: bash scripts/dev-lead-lint.sh (shellcheck --severity=warning) ran pre-commit; the bats suite runs in CI.

Rollback

Revert this PR. No non-revertible side effects (no tags, migrations, or external state).

Monitoring

Watch the affected workflow run(s) in the Actions tab and this PR's Lint check for regressions.