Add gitleaks secret scanning to CI #62

Closed
opened 2026-06-15 12:37:49 +00:00 by james · 0 comments
Owner

Follow-up to #39 / PR #61. The local pre-commit hook scans staged changes for secrets via gitleaks, but the lefthook layer is bypassable:

  • A contributor without gitleaks installed gets the "fail closed" message and might disable the hook locally.
  • git commit --no-verify skips the hook entirely.
  • A force-push to a long-lived branch can land commits that were never run through the local hook.

A server-side scan in CI is the safety net for all three.

Scope

  • Add a gitleaks job to .forgejo/workflows/pr.yml that scans the PR diff (and the full default-branch history on push: branches: [main] runs, for a one-time backfill check).
  • Use the same gitleaks binary as the local hook (or pin a version) — run gitleaks detect --source . --redact --report-format sarif --report-path gitleaks.sarif so the output is uploadable.
  • Pin the gitleaks binary by SHA per the CLAUDE.md convention (download URL + checksum, OR a Forgejo action pinned by SHA — match whatever pattern the existing security jobs in PR #14 / ADR-0005 use).
  • Fail the PR check on a finding. Threshold is binary for gitleaks (any leak fails); no high|medium|low knob like the npm-audit / Trivy / OSV jobs need.
  • Surface findings in $GITHUB_STEP_SUMMARY via scripts/ci/security-summary.mjs (or extend it) so the format matches the other security scans landed in PR #14.
  • Document an allowlist mechanism (.gitleaks.toml or commit-message footer) for when a finding is a known-good test fixture, so a single false positive doesn't permanently block the PR.

Acceptance criteria

  • A throwaway branch with a synthetic GitHub PAT in a committed file fails the CI gitleaks job.
  • A PR with no secrets surfaces the gitleaks job as green in under 30 seconds.
  • Findings appear in the PR step summary in the same Markdown-table style as the existing scans (PR #14, ADR-0005).
  • The job runs even when --no-verify was used locally — i.e. it scans the actual commits being merged, not the local hook's pass/fail.
  • An allowlist mechanism is documented (in the workflow comment, ADR, or both) and a sample allowlist entry is in the repo.

Out of scope: rotating any historical secrets surfaced by the backfill scan (separate ticket if any turn up). Out of scope: removing the local pre-commit hook — local + CI are complementary, not redundant.

Part of epic #2.

Follow-up to #39 / PR #61. The local `pre-commit` hook scans staged changes for secrets via gitleaks, but the lefthook layer is bypassable: - A contributor without gitleaks installed gets the "fail closed" message and might disable the hook locally. - `git commit --no-verify` skips the hook entirely. - A force-push to a long-lived branch can land commits that were never run through the local hook. A server-side scan in CI is the safety net for all three. ## Scope - Add a `gitleaks` job to `.forgejo/workflows/pr.yml` that scans the PR diff (and the full default-branch history on `push: branches: [main]` runs, for a one-time backfill check). - Use the same gitleaks binary as the local hook (or pin a version) — run `gitleaks detect --source . --redact --report-format sarif --report-path gitleaks.sarif` so the output is uploadable. - Pin the gitleaks binary by SHA per the CLAUDE.md convention (download URL + checksum, OR a Forgejo action pinned by SHA — match whatever pattern the existing security jobs in PR #14 / ADR-0005 use). - Fail the PR check on a finding. Threshold is binary for gitleaks (any leak fails); no `high|medium|low` knob like the npm-audit / Trivy / OSV jobs need. - Surface findings in `$GITHUB_STEP_SUMMARY` via `scripts/ci/security-summary.mjs` (or extend it) so the format matches the other security scans landed in PR #14. - Document an allowlist mechanism (`.gitleaks.toml` or commit-message footer) for when a finding is a known-good test fixture, so a single false positive doesn't permanently block the PR. ## Acceptance criteria - [ ] A throwaway branch with a synthetic GitHub PAT in a committed file fails the CI gitleaks job. - [ ] A PR with no secrets surfaces the gitleaks job as green in under 30 seconds. - [ ] Findings appear in the PR step summary in the same Markdown-table style as the existing scans (PR #14, ADR-0005). - [ ] The job runs even when `--no-verify` was used locally — i.e. it scans the actual commits being merged, not the local hook's pass/fail. - [ ] An allowlist mechanism is documented (in the workflow comment, ADR, or both) and a sample allowlist entry is in the repo. Out of scope: rotating any historical secrets surfaced by the backfill scan (separate ticket if any turn up). Out of scope: removing the local pre-commit hook — local + CI are complementary, not redundant. Part of epic #2.
james closed this issue 2026-06-15 13:23:02 +00:00
Sign in to join this conversation.
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
james/carol#62
No description provided.