# SPDX-License-Identifier: MPL-2.0 # Single required context remains scan / gitleaks in direct callers. name: Bounded secret scanner (reusable) on: workflow_call: inputs: fast-pr: description: Security-owner-approved introduced-commit PR scan; non-PR runs always scan full history type: boolean default: false permissions: contents: read jobs: gitleaks: outputs: subject_sha: ${{ steps.scan.outputs.subject_sha }} rust_status: ${{ steps.scan.outputs.rust_status }} shell_status: ${{ steps.scan.outputs.shell_status }} runs-on: ubuntu-24.04 timeout-minutes: 15 permissions: contents: read defaults: run: shell: bash steps: - name: Check out subject and complete ancestry uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: ${{ github.event.pull_request.head.sha || github.sha }} path: subject fetch-depth: 0 persist-credentials: false - name: Resolve exact suite pin from the direct scan caller id: suite env: CALLER_REF: ${{ github.workflow_ref }} CALLER_REPO: ${{ github.repository }} run: | set -euo pipefail file="${CALLER_REF#"$CALLER_REPO"/}"; file="${file%@*}" case "$file" in .github/workflows/*.yml|.github/workflows/*.yaml) ;; *) exit 2 ;; esac ref=$(yq -r '.jobs.scan.uses' "subject/$file") prefix=hyperpolymath/cicd-suite/.github/workflows/secret-scanner-reusable.yml@ [[ $ref == "$prefix"* ]] || { echo '::error::requires a direct scan caller'; exit 2; } sha=${ref#"$prefix"} [[ $sha =~ ^[0-9a-f]{40}$ ]] || { echo '::error::caller must pin a full SHA'; exit 2; } echo "sha=$sha" >> "$GITHUB_OUTPUT" - name: Check out pinned scanner implementation outside subject uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: repository: hyperpolymath/cicd-suite ref: ${{ steps.suite.outputs.sha }} path: suite persist-credentials: false - name: Verify pinned checkout and install checksum-pinned Gitleaks env: EXPECTED: ${{ steps.suite.outputs.sha }} run: | set -euo pipefail [[ $(git -C suite rev-parse HEAD) == "$EXPECTED" ]] || exit 2 bash suite/actions/secret-scan-check/install.sh "$RUNNER_TEMP/suite-gitleaks" - name: Run real detector controls before trusting the scan env: GITLEAKS_BIN: ${{ runner.temp }}/suite-gitleaks/gitleaks run: bash suite/actions/secret-scan-check/control.sh - name: Scan subject (bounded, redacted, both populations) id: scan env: GITLEAKS_BIN: ${{ runner.temp }}/suite-gitleaks/gitleaks SUBJECT: ${{ github.workspace }}/subject ESTATE_BASELINE: ${{ github.workspace }}/suite/config/gitleaks/estate-baseline.toml FAST_PR: ${{ inputs.fast-pr }} EVENT: ${{ github.event_name }} PR_BASE: ${{ github.event.pull_request.base.sha }} PR_HEAD: ${{ github.event.pull_request.head.sha }} run: | set -euo pipefail export SCAN_MODE=full SCAN_TIMEOUT_SECONDS=180 if [[ "$EVENT" == pull_request && "$FAST_PR" == true ]]; then export SCAN_MODE=pr-range HEAD_SHA="$PR_HEAD" # A PR may be behind the base tip: scan from their common ancestor, # not from the final file diff and not from a guessed depth. export BASE_SHA BASE_SHA=$(git -C "$SUBJECT" merge-base "$PR_BASE" "$PR_HEAD") fi bash suite/actions/secret-scan-check/check.sh supplemental-results: # Compatibility contexts consumed by fleet branch rules. These validate # receipts from detectors already executed in gitleaks, not echo-only passes. needs: gitleaks if: ${{ always() }} name: ${{ matrix.language }}-secrets runs-on: ubuntu-24.04 timeout-minutes: 2 strategy: fail-fast: false matrix: language: [rust, shell] steps: - name: Verify completed detector result and subject binding shell: bash env: LANGUAGE: ${{ matrix.language }} UPSTREAM_RESULT: ${{ needs.gitleaks.result }} SUBJECT_SHA: ${{ needs.gitleaks.outputs.subject_sha }} EXPECTED_SHA: ${{ github.event.pull_request.head.sha || github.sha }} DETECTOR_STATUS: ${{ needs.gitleaks.outputs[format('{0}_status', matrix.language)] }} run: | set -euo pipefail case "$LANGUAGE" in rust|shell) ;; *) exit 2 ;; esac case "$UPSTREAM_RESULT" in success|failure) ;; *) echo 'No completed scan receipt'; exit 2 ;; esac [[ "$EXPECTED_SHA" =~ ^[0-9a-f]{40}$ && "$SUBJECT_SHA" == "$EXPECTED_SHA" ]] \ || { echo 'Missing or mismatched subject receipt'; exit 2; } case "$DETECTOR_STATUS" in 0) echo "$LANGUAGE detector actually completed successfully for $SUBJECT_SHA" ;; 1) echo "$LANGUAGE detector found hardcoded credentials"; exit 1 ;; *) echo "$LANGUAGE detector did not produce a trustworthy passing result"; exit 2 ;; esac