From ca6404134e6a10695be352de1488bd7e96abd0eb Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Wed, 5 Aug 2026 06:53:43 +0100 Subject: [PATCH] fix(security): upgrade secret scanning from retired trufflehog to gitleaks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This repo's only leak scanning was an inline trufflehog job, and trufflehog was retired estate-wide. The standards secret-scanner reusable records the ruling in its own header: "Trufflehog was removed as redundant; gitleaks catches what we need" "Trufflehog removed: gitleaks provides sufficient coverage at lower cost." So this is an UPGRADE, not a removal. A sweep is currently deleting leftover trufflehog steps across the estate, and this repo was deliberately EXCLUDED from it: with no other scanner present, deleting would have left the repo with no secret scanning at all. Replacing the inline job adds gitleaks and drops the retired scanner in one move. What changes in practice: - gitleaks over the whole working tree with --no-git, exiting non-zero on a finding. The inline job scanned a base..head diff, which is narrower. - the reusable's rust-secrets and shell-secrets jobs come along with it, so the local rust-secrets grep is no longer needed separately. - a pinned, checksum-verified gitleaks binary rather than an action that injects one. `secrets: inherit` is REQUIRED and included. Without it the gitleaks action's inner secrets.GITHUB_TOKEN is empty and the scan silently degrades — a quiet failure exactly of the kind this campaign exists to remove. The workflow's `name:` is preserved verbatim, so no required status-check context is stranded. Job-level context names DO change, because they now come from the reusable; this repo's rulesets were checked first and require no secret-scanning context. Where an actions.lock exists it gains a hand-authored [] entry for this file: gh actions-lock SKIPS reusable-workflow callers, and without the entry the workflow is rejected as startup_failure with no log. Co-Authored-By: Claude Fable 5 Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com> --- .github/workflows/secret-scanner.yml | 68 +++++----------------------- 1 file changed, 12 insertions(+), 56 deletions(-) diff --git a/.github/workflows/secret-scanner.yml b/.github/workflows/secret-scanner.yml index 5ec44f5..437776e 100644 --- a/.github/workflows/secret-scanner.yml +++ b/.github/workflows/secret-scanner.yml @@ -1,66 +1,22 @@ # SPDX-License-Identifier: MPL-2.0 -# // Copyright (c) Jonathan D.A. Jewell -# SPDX-License-Identifier: MPL-2.0 -name: Secret Scanner +# Calls the estate's shared secret scanner (gitleaks + rust-secrets + +# shell-secrets). Replaces an inline trufflehog job: trufflehog was retired +# estate-wide as redundant, and this repo had no other leak scanning, so the +# scanner is UPGRADED here rather than removed. +# +# `secrets: inherit` is REQUIRED — without it the gitleaks action's inner +# secrets.GITHUB_TOKEN is empty and the scan silently degrades. +name: 'Secret Scanner' on: pull_request: push: - branches: [main] -# Estate guardrail: cancel superseded runs so re-pushes / rebased PR -# updates do not pile up queued runs against the shared account-wide -# Actions concurrency pool. Applied only to read-only check workflows -# (no publish/mutation), so cancelling a superseded run is always safe. + branches: [main, master] concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true permissions: - actions: read contents: read jobs: - trufflehog: - runs-on: ubuntu-latest - timeout-minutes: 15 - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4 - with: - fetch-depth: 0 # Full history for scanning - - name: TruffleHog Secret Scan - uses: trufflesecurity/trufflehog@6c05c4a00b91aa542267d8e32a8254774799d68d # v3 - with: - # The v3 action injects --fail automatically on pull_request events. - # Passing --fail here triggers "flag 'fail' cannot be repeated". - extra_args: --only-verified - # Rust-specific: Check for hardcoded crypto values - rust-secrets: - runs-on: ubuntu-latest - timeout-minutes: 15 - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4 - - name: Check for hardcoded secrets in Rust - run: | - if ! find . -name Cargo.toml -not -path './target/*' -print -quit | grep -q .; then - echo 'No Cargo.toml found — skipping Rust secrets check' - exit 0 - fi - # Patterns that suggest hardcoded secrets - PATTERNS=( - 'const.*SECRET.*=.*"' - 'const.*KEY.*=.*"[a-zA-Z0-9]{16,}"' - 'const.*TOKEN.*=.*"' - 'let.*api_key.*=.*"' - 'HMAC.*"[a-fA-F0-9]{32,}"' - 'password.*=.*"[^"]+"' - ) - - found=0 - for pattern in "${PATTERNS[@]}"; do - if grep -rn --include="*.rs" -E "$pattern" src/; then - echo "WARNING: Potential hardcoded secret found matching: $pattern" - found=1 - fi - done - - if [ $found -eq 1 ]; then - echo "::error::Potential hardcoded secrets detected. Use environment variables instead." - exit 1 - fi + scan: + uses: hyperpolymath/standards/.github/workflows/secret-scanner-reusable.yml@bd0df9ead7faf0cdfe0e13e7966d91e28d0101d4 + secrets: inherit