Repository navigation
security(repo): enable secret scanning and push protection (#485) - #503
Open
michealross wants to merge 1 commit into
Open
michealross wants to merge 1 commit into
michealross wants to merge 1 commit into
Conversation
…Issue#485) GitHub's secret-protection features live in the repository settings, not in the tree, so this change adds the in-repo half of the protection plus the tooling that makes the settings verifiable and reproducible: - .github/workflows/secret-scan.yml: gitleaks gate on pushes to main and on incoming pull requests. Pinned release verified against the published checksum, always run with --redact, and the SARIF result is uploaded to code scanning so findings show up in the Security tab. - .gitleaks.toml: default gitleaks rules with a minimal allowlist for the values in this repo that look like credentials but are not (Stellar contract IDs, account IDs and SHA-256 hashes in fixtures, mainnet artifacts and demo traces). The allowlist pairs file paths with value shapes, so a real credential in those files does not match it and still fails the job. - scripts/check-secret-protection.mjs: reads, and with --enable turns on, secret_scanning, secret_scanning_push_protection, secret_scanning_non_provider_patterns and secret_scanning_validity_checks through the GitHub API. It reports every protection and exits non-zero when a required one is off or not reported at all; optional protections the plan does not offer are reported as not available instead of failing. - scripts/check-secret-protection.test.mjs: unit tests against a fake API server (enabled, disabled, unavailable, unreadable, enable flow). - docs/SECRET_PROTECTION.md: the settings, how to enable and verify them, what each one covers for main and incoming pull requests, and how to review alerts without posting secret values. The settings themselves need Administration: write on the repository, which a contributor token does not have, so a maintainer runs `pnpm secrets:enable` and then `pnpm secrets:check` to confirm the state. The initial scan of the full history (402 commits) with these rules found no credential: the only matches were generic-api-key hits on public, non-secret values, all of them allowlisted in .gitleaks.toml. No rotation and no history rewrite are needed, and no secret value is reproduced here. 🤖 Generated with Codebuff Co-Authored-By: Codebuff <noreply@codebuff.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #485
Why
The secret-protection features for this repository are configured in the repository settings, not in the tree: secret scanning, push protection, non-provider pattern detection and validity checks were all off, so a credential could be pushed — and merged into
main— with nothing stopping it.This PR delivers everything that can live in the repository, plus the tooling that turns the settings on and proves they are on:
mainand incoming pull requests —.github/workflows/secret-scan.ymlruns gitleaks on every push tomainand on every pull request, with a pinned release verified against its published checksum, always with--redact, and uploads the SARIF result to code scanning so findings land in the Security tab next to native alerts.scripts/check-secret-protection.mjs(pnpm secrets:check/pnpm secrets:enable) reads thesecurity_and_analysisblock of the repository and enables the four protections one request at a time, so a protection the plan does not offer is reported as not available instead of failing the run.Required maintainer action (one command)
The four settings live in GitHub's configuration for the repository and need Administration: write. A contributor token cannot do it:
PATCH /repos/{owner}/{repo}answers403 Resource not accessible by integration, andsecurity_and_analysisis only returned to repository admins, so the current state cannot even be read from a contributor token.Expected output of
pnpm secrets:check:non-provider pattern detectionandvalidity checksdepend on the plan: when GitHub does not offer them the script printsN/Aand still exits 0, because the criterion is "where available". A required protection that is offered but off always fails the run.The same thing can be done from the web UI (Settings → Code security and analysis → Secret scanning → Enable, and the same for Push protection); the script just makes it reproducible and verifiable.
What each protection covers
main.Initial scan — no credential found, nothing to rotate
The initial scan of the full history reachable from
main(402 commits) with the rules the CI gate uses found no credential. The only matches weregeneric-api-keyhits on public, non-secret values — Stellar contract IDs, Stellar account IDs and SHA-256 hashes in fixtures, mainnet artifacts and demo traces. Those are exactly the values allowlisted in.gitleaks.toml, so no rotation and no history rewrite are needed.When native secret scanning is switched on it will raise its own alerts for some of those same values, because a generic pattern cannot tell a contract ID from a key. They can be resolved as false positives. No secret value is reproduced in this PR, in the issue, or in any log: the gate runs gitleaks with
--redact, and the SARIF report carries the rule, the file and the line only.Files
.github/workflows/secret-scan.ymlmainand on pull requests; redacted; SARIF → code scanning.gitleaks.tomlscripts/check-secret-protection.mjsscripts/check-secret-protection.test.mjsdocs/SECRET_PROTECTION.mdpackage.jsonsecrets:check,secrets:enable,secrets:test.github/workflows/coverage.ymlpnpm secrets:testso the new script stays coveredREADME.md,docs/CI.md,scripts/check-links.jsReview notes
C…contract IDs,G…account IDs, 64-hex hashes). A real credential dropped into one of those files matches none of them and still fails the job — checked locally with a freshly generated token value, which was still reported.secrets:checkprints states only. It never prints the token and never prints a secret value.gh api "repos/OWNER/REPO/secret-scanning/alerts?hide_secret=true".Verification
pnpm secrets:test— 9 tests, all pass.node scripts/check-links.js— 46 local links checked, OK.gitleaks detect --source . --config .gitleaks.toml --redactover the history and over the working tree — no leaks found.