diff --git a/.gitea/workflows/secret-scan.yml b/.gitea/workflows/secret-scan.yml new file mode 100644 index 0000000..43c5323 --- /dev/null +++ b/.gitea/workflows/secret-scan.yml @@ -0,0 +1,51 @@ +name: secret-scan + +# Scans the FULL git history, not just the working tree: a credential that was +# committed and later deleted is still published, and only a history scan sees it. +# The weekly run exists because new detector rules find old secrets that passed +# when they were first pushed. +# +# This repository carries a .gitleaksignore: its tests assert that a redaction +# function masks secret-shaped input, so the fixtures trip the scanner. Those +# entries are pinned per commit, file, rule and line, never by directory. + +on: + push: + pull_request: + schedule: + - cron: "0 5 * * 1" + +jobs: + gitleaks: + runs-on: ubuntu-latest + steps: + - name: Check out full history + # Pinned to a commit, not a mutable tag: a security job must not silently + # change what it runs when upstream retags. + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + with: + fetch-depth: 0 + + - name: Install pinned Gitleaks + env: + GITLEAKS_VERSION: "8.30.1" + GITLEAKS_SHA256: "551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb" + run: | + set -euo pipefail + archive="gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" + curl -fsSL -o "${archive}" \ + "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/${archive}" + # Fail loudly on any mismatch rather than scanning with an unverified binary. + printf '%s %s\n' "${GITLEAKS_SHA256}" "${archive}" | sha256sum -c - + tar -xzf "${archive}" gitleaks + chmod 0755 gitleaks + ./gitleaks version + + - name: Scan full history for secrets + # --redact=100 keeps matched values out of the CI log, which is itself + # readable by anyone who can see the run. + run: ./gitleaks git . --redact=100 --no-banner --exit-code 1 + + - name: Remove the downloaded scanner + if: always() + run: rm -f gitleaks gitleaks_*.tar.gz diff --git a/.gitleaksignore b/.gitleaksignore new file mode 100644 index 0000000..387605f --- /dev/null +++ b/.gitleaksignore @@ -0,0 +1,13 @@ +# Allowlisted Gitleaks fingerprints. +# +# Both entries are deliberate test fixtures for this project's own redaction +# function, not credentials: each asserts that a secret-shaped input is masked. +# They are history-only -- the current tests assemble those strings at runtime -- +# and a historical commit cannot be cleaned without rewriting history, which is +# not warranted for fixture data. +# +# Each entry is pinned to an exact commit, file, rule and line rather than +# ignoring the tests/ directory, so a real secret committed to the same files +# later is still reported. +a9e828706529bab38759f9a8bea4aafc721853aa:tests/test_redact.py:generic-api-key:30 +a9e828706529bab38759f9a8bea4aafc721853aa:tests/test_judge.py:generic-api-key:71