Update trufflehog-scan.yml #7
Workflow file for this run
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
| name: TruffleHog Secret Scan | ||
| on: | ||
| pull_request: | ||
| types: [opened, synchronize, reopened] | ||
| pull_request_target: | ||
| types: [opened, synchronize, reopened] | ||
| workflow_dispatch: | ||
| permissions: | ||
| contents: read | ||
| pull-requests: write | ||
| statuses: write | ||
| # Default exclusion patterns (regex format) | ||
| # Supports: exact filenames, wildcards, regex patterns | ||
| # Examples: | ||
| # Exact file: ^config/settings\.json$ | ||
| # Directory: ^node_modules/ | ||
| # Extension: \.lock$ | ||
| # Wildcard: .*\.min\.js$ | ||
| # Regex: ^src/test/.*_test\.py$ | ||
| env: | ||
| DEFAULT_EXCLUDES: | | ||
| ^node_modules/ | ||
| ^vendor/ | ||
| ^\.git/ | ||
| \.lock$ | ||
| ^package-lock\.json$ | ||
| ^yarn\.lock$ | ||
| ^pnpm-lock\.yaml$ | ||
| \.min\.js$ | ||
| \.min\.css$ | ||
| jobs: | ||
| trufflehog-scan: | ||
| name: Scan PR for Secrets | ||
| runs-on: ubuntu-latest | ||
| # Run pull_request_target only for fork PRs, pull_request only for same-repo PRs | ||
| # This prevents duplicate runs | ||
| if: | | ||
| (github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name != github.repository) || | ||
| (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository) || | ||
| github.event_name == 'workflow_dispatch' | ||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
| - name: Fetch PR head commits | ||
| if: github.event_name != 'workflow_dispatch' | ||
| run: | | ||
| # Fetch PR commits using GitHub's merge ref (works for all PRs including forks) | ||
| git fetch origin +refs/pull/${{ github.event.pull_request.number }}/head:refs/remotes/origin/pr-head | ||
| echo "Fetched PR #${{ github.event.pull_request.number }} head commit: ${{ github.event.pull_request.head.sha }}" | ||
| - name: Setup exclude config | ||
| id: config | ||
| run: | | ||
| # Always include default exclusions first | ||
| echo "Adding default exclusions..." | ||
| cat << 'EOF' > .trufflehog-ignore | ||
| ${{ env.DEFAULT_EXCLUDES }} | ||
| EOF | ||
| # Append user-defined exclusions if set (additive, not replacement) | ||
| if [ -n "${{ vars.TRUFFLEHOG_EXCLUDES }}" ]; then | ||
| echo "Adding repo/org-level TRUFFLEHOG_EXCLUDES patterns..." | ||
| echo "${{ vars.TRUFFLEHOG_EXCLUDES }}" | tr ',' '\n' | sed '/^$/d' >> .trufflehog-ignore | ||
| fi | ||
| echo "Exclusion patterns:" | ||
| cat .trufflehog-ignore | ||
| echo "exclude_args=--exclude-paths=.trufflehog-ignore" >> $GITHUB_OUTPUT | ||
| - name: TruffleHog Scan | ||
| id: trufflehog | ||
| uses: trufflesecurity/trufflehog@main | ||
| continue-on-error: true | ||
| with: | ||
| base: ${{ github.event.pull_request.base.sha }} | ||
| head: ${{ github.event.pull_request.head.sha }} | ||
| extra_args: --json ${{ steps.config.outputs.exclude_args }} | ||
| - name: Process scan results | ||
| id: process | ||
| if: github.event_name != 'workflow_dispatch' | ||
| run: | | ||
| # Check if TruffleHog found any secrets | ||
| if [ "${{ steps.trufflehog.outcome }}" == "failure" ]; then | ||
| echo "has_secrets=true" >> $GITHUB_OUTPUT | ||
| echo "status=failure" >> $GITHUB_OUTPUT | ||
| echo "description=Secret scanning found exposed credentials" >> $GITHUB_OUTPUT | ||
| else | ||
| echo "has_secrets=false" >> $GITHUB_OUTPUT | ||
| echo "status=success" >> $GITHUB_OUTPUT | ||
| echo "description=No secrets detected in PR changes" >> $GITHUB_OUTPUT | ||
| fi | ||
| - name: Post PR comment on findings | ||
| if: steps.process.outputs.has_secrets == 'true' && github.event_name != 'workflow_dispatch' | ||
| uses: actions/github-script@v7 | ||
| with: | ||
| script: | | ||
| const commentMarker = '<!-- TRUFFLEHOG-SCAN-COMMENT -->'; | ||
| const commitSha = '${{ github.event.pull_request.head.sha }}'; | ||
| const shortSha = commitSha.substring(0, 7); | ||
| const scanTime = new Date().toISOString().replace('T', ' ').substring(0, 19) + ' UTC'; | ||
| const body = `${commentMarker} | ||
| ## :rotating_light: Secret Scanning Alert | ||
| **TruffleHog detected potential secrets in this pull request.** | ||
| | Scan Details | | | ||
| |--------------|---| | ||
| | **Commit** | [\`${shortSha}\`](${{ github.server_url }}/${{ github.repository }}/commit/${commitSha}) | | ||
| | **Scanned At** | ${scanTime} | | ||
| | **Workflow Run** | [View Logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) | | ||
| ### What to do: | ||
| 1. **Remove the exposed secret** from your code | ||
| 2. **Rotate the credential immediately** - assume it's compromised | ||
| 3. **Push the fix** to this branch | ||
| 4. The scan will re-run automatically | ||
| ### Finding Details | ||
| Check the [workflow run logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for: | ||
| - File paths containing secrets | ||
| - Line numbers | ||
| - Secret types (API key, password, token, etc.) | ||
| - Verification status (verified = confirmed active) | ||
| --- | ||
| *Only files modified in this PR were scanned. Secrets are classified as **verified** (confirmed active) or **unverified** (potential match).* | ||
| `; | ||
| // Find existing comment | ||
| const { data: comments } = await github.rest.issues.listComments({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: context.payload.pull_request.number, | ||
| per_page: 100 | ||
| }); | ||
| const existing = comments.find(c => c.body && c.body.includes(commentMarker)); | ||
| if (existing) { | ||
| await github.rest.issues.updateComment({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| comment_id: existing.id, | ||
| body: body | ||
| }); | ||
| } else { | ||
| await github.rest.issues.createComment({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: context.payload.pull_request.number, | ||
| body: body | ||
| }); | ||
| } | ||
| - name: Set commit status | ||
| if: github.event_name != 'workflow_dispatch' | ||
| uses: actions/github-script@v7 | ||
| with: | ||
| script: | | ||
| await github.rest.repos.createCommitStatus({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| sha: '${{ github.event.pull_request.head.sha }}', | ||
| state: '${{ steps.process.outputs.status }}', | ||
| target_url: '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}', | ||
| description: '${{ steps.process.outputs.description }}', | ||
| context: 'TruffleHog Secret Scan' | ||
| }); | ||
| - name: Fail workflow if secrets found | ||
| if: steps.process.outputs.has_secrets == 'true' | ||
| run: | | ||
| echo "::error::Secrets detected in PR. Review the logs and PR comment for details." | ||
| exit 1 | ||