Skip to content

feat: run the secret scan locally, not only in CI - #74

Merged
ExtraToast merged 1 commit into
mainfrom
chore/68-local-secret-scan
Sep 14, 2026
Merged

ExtraToast merged 1 commit into
mainfrom
chore/68-local-secret-scan

Conversation

@ExtraToast

Copy link
Copy Markdown
Contributor

Closes #68 (parent #21)

What this branch does

npm run verify runs the same secret scan CI runs, so a leaked credential is caught on the machine that wrote it rather than after a push.

The scan previously existed only as a CI step with its own command line, so a contributor running the full gate locally got no such check and nothing kept the two in step. scripts/lint-secrets.ts now wraps it in the shape lint-manifests.ts uses for kubeconform: the binary comes from the GITLEAKS environment variable or from the PATH, and when it is absent the gate skips loudly and exits 0 rather than passing in silence:

secret scan: SKIPPED because <bin> is not on PATH. CI installs a pinned release; set GITLEAKS to run it locally.

The workflow calls the same script with the pinned release it downloads, so there is one command and one set of patterns:

curl ... | tar -xz gitleaks
GITLEAKS="${PWD}/gitleaks" npm run lint:secrets

REQ-013 in docs/requirements.md, count to 13. The Gates table keeps its thirteen gates; only the secret scan's command column changes.

One correction

The CI command never passed --verbose, so a failing scan printed a count and not the file. The acceptance criterion says the failure names the file, and it did not. The script passes --verbose, and it does now.

Fixtures

No secret-shaped literal enters the repository. The committed tests drive a stand-in gitleaks written into a temporary directory at test time, the way the manifest tests drive a stand-in kubeconform, so the repository never scans its own fixtures. The live check used an untracked planted file, deleted before the commit.

Ratchet

Statements 97.88 to 97.94, branches 90.27 to 90.72, functions 100, lines 97.69 to 97.76. README numbers follow, which lint:docs and REQ-011 require.

Verification

  • A planted credential fails the gate, and the output names the file: File: .../tmp-planted-secret.txt, WRN leaks found: 2
  • With no scanner and no environment variable, the skip above prints and the gate exits 0
  • CI invokes the script and still pins 8.30.1
  • A clean tree passes with INF no leaks found; a scanner exiting non-zero fails the build, proven live and in unit tests covering a missing binary, a spawn error and a signal-killed process

npm run verify clean. actionlint 1.7.7, the version CI pins, clean.

scripts/lint-secrets.ts wraps gitleaks the way lint-manifests.ts wraps
kubeconform: the binary comes from GITLEAKS or the PATH, and a machine
without it skips loudly instead of passing quietly. `npm run verify`
runs it, and the secret-scan CI job now runs the same script against
the pinned binary it downloads, so one command and one set of patterns
serve both.
@ExtraToast ExtraToast added type: chore Maintenance work without intended behavior change. area: tooling Reusable workflows, Gradle, templates, Renovate, and API tooling. component: security Security, permissions, secrets, or vulnerability handling. labels Sep 14, 2026
@ExtraToast
ExtraToast merged commit fcb4d4a into main Sep 14, 2026
16 checks passed
@ExtraToast
ExtraToast deleted the chore/68-local-secret-scan branch September 14, 2026 09:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: tooling Reusable workflows, Gradle, templates, Renovate, and API tooling. component: security Security, permissions, secrets, or vulnerability handling. type: chore Maintenance work without intended behavior change.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Run the secret scan in the local gate, not only in CI

1 participant