Skip to content

Let the reset test make its own premise instead of inheriting it (ER69) #927

Let the reset test make its own premise instead of inheriting it (ER69)

Let the reset test make its own premise instead of inheriting it (ER69) #927

Workflow file for this run

name: Secret Scan
# Secret scanning with gitleaks (HARD FAIL).
#
# gitleaks scans the full git history for committed credentials (API keys,
# tokens, private keys). It complements the SAST workflow: bandit and
# semgrep look for insecure *code*, gitleaks looks for leaked *secrets*.
#
# Known non-secrets (synthetic test fixtures, deterministic CI dummy
# secrets, and documentation placeholders) are allowlisted in
# .gitleaks.toml. A one-time full-history scan confirmed there are no real
# leaked credentials. When gitleaks flags a genuine secret: remove it,
# rotate the credential, and do NOT add it to the allowlist.
#
# Unlike ci.yml / sast.yml this workflow deliberately has NO paths-ignore:
# a secret can be committed in any file type (including docs and config),
# the scan is cheap (a few seconds), and it must never be skipped.
on:
push:
branches: [main]
pull_request:
workflow_dispatch: {}
# Least-privilege: gitleaks only needs to read the checked-out source.
permissions:
contents: read
concurrency:
group: secret-scan-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
gitleaks:
name: gitleaks (HARD FAIL on leak)
runs-on: ubuntu-22.04
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
with:
# Full history so gitleaks scans every commit, not just the tip.
fetch-depth: 0
- name: Install gitleaks
env:
GITLEAKS_VERSION: "8.30.1"
run: |
curl -sSfL \
"https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" \
-o gitleaks.tar.gz
tar -xzf gitleaks.tar.gz gitleaks
./gitleaks version
- name: Run gitleaks (HARD FAIL on any leak)
# `detect` scans the COMMIT HISTORY reachable from HEAD, not the
# checked-out files. Two consequences worth stating, because both have
# cost real time:
#
# 1. Deleting the value and committing the deletion does NOT clear
# this. The commit that introduced it is still on the branch, and
# commits are what is scanned. The failure survives the fix, which
# reads like the fix not being picked up. The `if: failure()` step
# below says so at the moment it happens.
# 2. Another contributor's branch cannot fail your pull request.
# `fetch-depth: 0` means "all of this ref's history", not "all
# branches": actions/checkout fetches only the pull-request ref,
# so no other branch is present for gitleaks to read. A
# cross-branch failure was reported once; the run logs show each
# pull request scanning main's commit count plus its own (289 + n
# at the time), never the whole repository.
#
# `--exit-code 1` makes a finding fail the job. Findings are redacted
# in the log and written to the SARIF artifact for the Security tab.
# Suppress provable non-secrets only in .gitleaks.toml, never by
# relaxing this gate.
run: |
./gitleaks detect \
--source . \
--config .gitleaks.toml \
--redact \
--verbose \
--report-format sarif \
--report-path gitleaks.sarif \
--exit-code 1
- name: Explain what a finding means
if: failure()
run: |
cat <<'EOF'
============================================================
gitleaks scanned this branch's COMMIT HISTORY, not its files.
============================================================
If you already removed the value, that is why this still fails: the
commit that added it is still on the branch, and the scan reads
commits. Taking it out of the working tree does not take it out of
history.
To clear it the commit has to go. From a clean tree, with no one
else building on your branch:
git fetch origin
git rebase origin/main # FIRST, before collapsing anything
git reset --soft origin/main # your whole diff becomes one staged change
git commit # one commit, without the bad value
git push --force-with-lease
Rebase before the reset, not after. `git reset --soft` moves the
branch to wherever origin/main points NOW while keeping your tree, so
if main advanced after you branched, the single commit you create
silently reverts everything merged in between. That has happened
here: 125 lines from two merged pull requests were undone this way,
and the only signal was a diffstat with far more deletions than the
change could account for. Before committing, check
`git diff --stat origin/main`, and check that
`git diff --name-only origin/main` lists no file you did not touch.
If the value is a real credential: rotate it. It reached a remote, so
treat it as disclosed no matter what the history says afterwards.
If it is provably not a secret, add it to .gitleaks.toml with the
reason. Never allowlist a value you cannot prove is safe.
More: docs-site/docs/contributor-guide/coding-standards.md
EOF
- name: Upload gitleaks SARIF
if: always()
uses: actions/upload-artifact@v4
with:
name: gitleaks-report
path: gitleaks.sarif
if-no-files-found: warn
retention-days: 14