From 214c9d9bb5132466fd1311715e8f5014a4bd6013 Mon Sep 17 00:00:00 2001 From: Isaiah Grigsby Date: Wed, 13 Aug 2025 14:15:47 -0500 Subject: [PATCH 01/23] Test --- .github/workflows/reusable-trufflehog.yml | 105 ++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 .github/workflows/reusable-trufflehog.yml diff --git a/.github/workflows/reusable-trufflehog.yml b/.github/workflows/reusable-trufflehog.yml new file mode 100644 index 000000000..7a9bdb4fb --- /dev/null +++ b/.github/workflows/reusable-trufflehog.yml @@ -0,0 +1,105 @@ +name: Reusable Trufflehog Scan + +on: + workflow_call: + inputs: + fail-on-secrets: + description: "Fail the workflow if verified secrets are found" + required: false + default: "true" + type: string + +permissions: + contents: read + pull-requests: write + +jobs: + trufflehog-scan: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install Trufflehog CLI (Go v3+) + run: | + wget https://github.com/trufflesecurity/trufflehog/releases/download/v3.90.3/trufflehog_3.90.3_linux_amd64.tar.gz + tar -xzf trufflehog_3.90.3_linux_amd64.tar.gz + chmod +x trufflehog + ./trufflehog --version + + - name: Run Trufflehog (JSON) + id: trufflehog + run: ./trufflehog filesystem . --json > trufflehog-results.json + + - name: Add summary to PR + if: ${{ hashFiles('trufflehog-results.json') != '' }} + run: | + echo "### Trufflehog Verified Findings" >> $GITHUB_STEP_SUMMARY + jq -r 'select(type=="object" and .Raw and .SourceMetadata and .SourceMetadata.Data and .SourceMetadata.Data.path and .Verified == true) | "- \(.SourceMetadata.Data.path):\(.SourceMetadata.Data.line // "?") \(.Raw | @json)"' trufflehog-results.json >> $GITHUB_STEP_SUMMARY || true + + - name: Comment on PR with verified Trufflehog findings (with clickable file links) + if: ${{ hashFiles('trufflehog-results.json') != '' && github.event_name == 'pull_request' }} + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const fs = require('fs'); + const pr = context.payload.pull_request; + const owner = context.repo.owner; + const repo = context.repo.repo; + const branch = pr.head.ref; + let findings = []; + try { + const lines = fs.readFileSync('trufflehog-results.json', 'utf8') + .split('\n') + .filter(Boolean); + for (const line of lines) { + let finding; + try { + finding = JSON.parse(line); + } catch (e) { + continue; + } + if ( + finding.Verified === true && + finding.SourceMetadata && + finding.SourceMetadata.Data && + typeof finding.SourceMetadata.Data.path === 'string' && + finding.SourceMetadata.Data.path.length > 0 + ) { + const path = finding.SourceMetadata.Data.path; + const lineNum = finding.SourceMetadata.Data.line || 1; + const fileUrl = `https://github.com/${owner}/${repo}/blob/${branch}/${path}#L${lineNum}`; + findings.push([ + `**File:** [\`${path}\` line ${lineNum}](${fileUrl})`, + `**Detector:** ${finding.DetectorName || 'N/A'}`, + `**Rule ID:** ${finding.RuleID || 'N/A'}`, + `**Secret Preview:** \`${finding.Raw ? finding.Raw.slice(0, 80) : ''}...\``, + finding.Redacted ? `**Redacted:** \`${finding.Redacted}\`` : '', + finding.Entropy ? `**Entropy:** ${finding.Entropy}` : '', + finding.Source ? `**Source:** ${finding.Source}` : '', + `**Verified:** ${finding.Verified}`, + finding.Decoded ? `**Decoded:** \`${finding.Decoded}\`` : '', + finding.Comment ? `**Comment:** ${finding.Comment}` : '', + finding.Metadata ? `**Metadata:** \`${JSON.stringify(finding.Metadata)}\`` : '' + ].filter(Boolean).join('\n')); + } + } + } catch (e) { + findings = ['(Could not parse Trufflehog report)']; + } + const body = findings.length + ? `🚨 **Trufflehog found verified secrets in this PR!**\n\n${findings.map(f => `---\n${f}`).join('\n')}` + : "✅ Trufflehog ran and no verified secrets with file locations were found."; + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner, + repo, + body + }); + + - name: Fail if verified secrets found + if: ${{ inputs.fail-on-secrets == 'true' && hashFiles('trufflehog-results.json') != '' }} + run: | + if jq -e 'select(.Verified == true)' trufflehog-results.json > /dev/null; then + exit 1 + fi \ No newline at end of file From 292971585a55ef08ebc097b511fa3b36c4d46317 Mon Sep 17 00:00:00 2001 From: Isaiah Grigsby Date: Wed, 13 Aug 2025 14:21:38 -0500 Subject: [PATCH 02/23] Testing --- .github/workflows/reusable-trufflehog.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/.github/workflows/reusable-trufflehog.yml b/.github/workflows/reusable-trufflehog.yml index 7a9bdb4fb..495728b15 100644 --- a/.github/workflows/reusable-trufflehog.yml +++ b/.github/workflows/reusable-trufflehog.yml @@ -4,7 +4,7 @@ on: workflow_call: inputs: fail-on-secrets: - description: "Fail the workflow if verified secrets are found" + description: "Fail the workflow if any secrets are found" required: false default: "true" type: string @@ -33,8 +33,8 @@ jobs: - name: Add summary to PR if: ${{ hashFiles('trufflehog-results.json') != '' }} run: | - echo "### Trufflehog Verified Findings" >> $GITHUB_STEP_SUMMARY - jq -r 'select(type=="object" and .Raw and .SourceMetadata and .SourceMetadata.Data and .SourceMetadata.Data.path and .Verified == true) | "- \(.SourceMetadata.Data.path):\(.SourceMetadata.Data.line // "?") \(.Raw | @json)"' trufflehog-results.json >> $GITHUB_STEP_SUMMARY || true + echo "### Trufflehog Findings" >> $GITHUB_STEP_SUMMARY + jq -r 'select(type=="object" and .Raw and .SourceMetadata and .SourceMetadata.Data and .SourceMetadata.Data.path) | "- \(.SourceMetadata.Data.path):\(.SourceMetadata.Data.line // "?") \(.Raw | @json)"' trufflehog-results.json >> $GITHUB_STEP_SUMMARY || true - name: Comment on PR with verified Trufflehog findings (with clickable file links) if: ${{ hashFiles('trufflehog-results.json') != '' && github.event_name == 'pull_request' }} @@ -60,7 +60,6 @@ jobs: continue; } if ( - finding.Verified === true && finding.SourceMetadata && finding.SourceMetadata.Data && typeof finding.SourceMetadata.Data.path === 'string' && @@ -88,8 +87,8 @@ jobs: findings = ['(Could not parse Trufflehog report)']; } const body = findings.length - ? `🚨 **Trufflehog found verified secrets in this PR!**\n\n${findings.map(f => `---\n${f}`).join('\n')}` - : "✅ Trufflehog ran and no verified secrets with file locations were found."; + ? `🚨 **Trufflehog found secrets in this PR!**\n\n${findings.map(f => `---\n${f}`).join('\n')}` + : "✅ Trufflehog ran and no secrets were found."; github.rest.issues.createComment({ issue_number: context.issue.number, owner, @@ -97,9 +96,9 @@ jobs: body }); - - name: Fail if verified secrets found + - name: Fail if any secrets found if: ${{ inputs.fail-on-secrets == 'true' && hashFiles('trufflehog-results.json') != '' }} run: | - if jq -e 'select(.Verified == true)' trufflehog-results.json > /dev/null; then + if grep -q . trufflehog-results.json; then exit 1 fi \ No newline at end of file From 3eb0c488e7af71d82841185edac58ecc2aab2737 Mon Sep 17 00:00:00 2001 From: Isaiah Grigsby Date: Wed, 13 Aug 2025 14:25:44 -0500 Subject: [PATCH 03/23] Testing --- .github/workflows/reusable-trufflehog.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/reusable-trufflehog.yml b/.github/workflows/reusable-trufflehog.yml index 495728b15..b0ce2c265 100644 --- a/.github/workflows/reusable-trufflehog.yml +++ b/.github/workflows/reusable-trufflehog.yml @@ -36,7 +36,7 @@ jobs: echo "### Trufflehog Findings" >> $GITHUB_STEP_SUMMARY jq -r 'select(type=="object" and .Raw and .SourceMetadata and .SourceMetadata.Data and .SourceMetadata.Data.path) | "- \(.SourceMetadata.Data.path):\(.SourceMetadata.Data.line // "?") \(.Raw | @json)"' trufflehog-results.json >> $GITHUB_STEP_SUMMARY || true - - name: Comment on PR with verified Trufflehog findings (with clickable file links) + - name: Comment on PR with all Trufflehog findings (verified and unverified) if: ${{ hashFiles('trufflehog-results.json') != '' && github.event_name == 'pull_request' }} uses: actions/github-script@v7 with: @@ -76,7 +76,7 @@ jobs: finding.Redacted ? `**Redacted:** \`${finding.Redacted}\`` : '', finding.Entropy ? `**Entropy:** ${finding.Entropy}` : '', finding.Source ? `**Source:** ${finding.Source}` : '', - `**Verified:** ${finding.Verified}`, + `**Verified:** ${finding.Verified === true ? '✅ Verified' : '⚠️ Unverified'}`, finding.Decoded ? `**Decoded:** \`${finding.Decoded}\`` : '', finding.Comment ? `**Comment:** ${finding.Comment}` : '', finding.Metadata ? `**Metadata:** \`${JSON.stringify(finding.Metadata)}\`` : '' From af089452ab3759b871ae336a50764934d2a4189d Mon Sep 17 00:00:00 2001 From: Isaiah Grigsby Date: Wed, 13 Aug 2025 14:28:16 -0500 Subject: [PATCH 04/23] Testing --- .github/workflows/reusable-trufflehog.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/reusable-trufflehog.yml b/.github/workflows/reusable-trufflehog.yml index b0ce2c265..afebebd05 100644 --- a/.github/workflows/reusable-trufflehog.yml +++ b/.github/workflows/reusable-trufflehog.yml @@ -59,7 +59,9 @@ jobs: } catch (e) { continue; } + // Only process lines that look like findings (have a Raw field) if ( + finding.Raw && finding.SourceMetadata && finding.SourceMetadata.Data && typeof finding.SourceMetadata.Data.path === 'string' && @@ -99,6 +101,6 @@ jobs: - name: Fail if any secrets found if: ${{ inputs.fail-on-secrets == 'true' && hashFiles('trufflehog-results.json') != '' }} run: | - if grep -q . trufflehog-results.json; then + if grep -q '"Raw":' trufflehog-results.json; then exit 1 fi \ No newline at end of file From 7a37b3a0c80dfb013e32ec34b9f721f08e7bbad6 Mon Sep 17 00:00:00 2001 From: Isaiah Grigsby Date: Wed, 13 Aug 2025 14:36:24 -0500 Subject: [PATCH 05/23] Testing --- .github/workflows/reusable-trufflehog.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/reusable-trufflehog.yml b/.github/workflows/reusable-trufflehog.yml index afebebd05..8c711911c 100644 --- a/.github/workflows/reusable-trufflehog.yml +++ b/.github/workflows/reusable-trufflehog.yml @@ -28,7 +28,7 @@ jobs: - name: Run Trufflehog (JSON) id: trufflehog - run: ./trufflehog filesystem . --json > trufflehog-results.json + run: ./trufflehog filesystem . --json 2>&1 | tee trufflehog-results.json - name: Add summary to PR if: ${{ hashFiles('trufflehog-results.json') != '' }} From 32d42738b039735fd3c921694d0ff412465153f8 Mon Sep 17 00:00:00 2001 From: Isaiah Grigsby Date: Wed, 13 Aug 2025 14:42:51 -0500 Subject: [PATCH 06/23] Testing --- .github/workflows/reusable-trufflehog.yml | 65 ++++++++++------------- 1 file changed, 27 insertions(+), 38 deletions(-) diff --git a/.github/workflows/reusable-trufflehog.yml b/.github/workflows/reusable-trufflehog.yml index 8c711911c..ab3dec10d 100644 --- a/.github/workflows/reusable-trufflehog.yml +++ b/.github/workflows/reusable-trufflehog.yml @@ -1,43 +1,33 @@ -name: Reusable Trufflehog Scan +name: Trufflehog Secret Scan on: - workflow_call: - inputs: - fail-on-secrets: - description: "Fail the workflow if any secrets are found" - required: false - default: "true" - type: string - -permissions: - contents: read - pull-requests: write + pull_request: + branches: [main] jobs: trufflehog-scan: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - name: Checkout code + uses: actions/checkout@v4 - - name: Install Trufflehog CLI (Go v3+) - run: | - wget https://github.com/trufflesecurity/trufflehog/releases/download/v3.90.3/trufflehog_3.90.3_linux_amd64.tar.gz - tar -xzf trufflehog_3.90.3_linux_amd64.tar.gz - chmod +x trufflehog - ./trufflehog --version + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.x' - - name: Run Trufflehog (JSON) - id: trufflehog - run: ./trufflehog filesystem . --json 2>&1 | tee trufflehog-results.json + - name: Install Trufflehog + run: pip install trufflehog - - name: Add summary to PR - if: ${{ hashFiles('trufflehog-results.json') != '' }} + - name: Run Trufflehog run: | - echo "### Trufflehog Findings" >> $GITHUB_STEP_SUMMARY - jq -r 'select(type=="object" and .Raw and .SourceMetadata and .SourceMetadata.Data and .SourceMetadata.Data.path) | "- \(.SourceMetadata.Data.path):\(.SourceMetadata.Data.line // "?") \(.Raw | @json)"' trufflehog-results.json >> $GITHUB_STEP_SUMMARY || true + trufflehog filesystem . --json --no-update > trufflehog-results.json || true + + - name: Debug Trufflehog output + run: cat trufflehog-results.json || echo "No trufflehog-results.json found" - name: Comment on PR with all Trufflehog findings (verified and unverified) - if: ${{ hashFiles('trufflehog-results.json') != '' && github.event_name == 'pull_request' }} + if: ${{ github.event_name == 'pull_request' }} uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} @@ -59,16 +49,14 @@ jobs: } catch (e) { continue; } - // Only process lines that look like findings (have a Raw field) - if ( - finding.Raw && - finding.SourceMetadata && - finding.SourceMetadata.Data && - typeof finding.SourceMetadata.Data.path === 'string' && - finding.SourceMetadata.Data.path.length > 0 - ) { - const path = finding.SourceMetadata.Data.path; - const lineNum = finding.SourceMetadata.Data.line || 1; + if (finding.Raw) { + // Defensive: try to get file/line from Filesystem, fallback to path/line, fallback to unknown + let path = finding.SourceMetadata?.Data?.Filesystem?.file + || finding.SourceMetadata?.Data?.path + || 'unknown'; + let lineNum = finding.SourceMetadata?.Data?.Filesystem?.line + || finding.SourceMetadata?.Data?.line + || 1; const fileUrl = `https://github.com/${owner}/${repo}/blob/${branch}/${path}#L${lineNum}`; findings.push([ `**File:** [\`${path}\` line ${lineNum}](${fileUrl})`, @@ -99,8 +87,9 @@ jobs: }); - name: Fail if any secrets found - if: ${{ inputs.fail-on-secrets == 'true' && hashFiles('trufflehog-results.json') != '' }} + if: ${{ hashFiles('trufflehog-results.json') != '' }} run: | if grep -q '"Raw":' trufflehog-results.json; then + echo "Secrets found! Failing the workflow." exit 1 fi \ No newline at end of file From b45a2ff8e3242a9c20e7ff3d8960cab166877e55 Mon Sep 17 00:00:00 2001 From: Isaiah Grigsby Date: Wed, 13 Aug 2025 14:45:15 -0500 Subject: [PATCH 07/23] Updated --- .github/workflows/reusable-trufflehog.yml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/reusable-trufflehog.yml b/.github/workflows/reusable-trufflehog.yml index ab3dec10d..ce0930080 100644 --- a/.github/workflows/reusable-trufflehog.yml +++ b/.github/workflows/reusable-trufflehog.yml @@ -1,8 +1,13 @@ -name: Trufflehog Secret Scan +name: Reusable Trufflehog Scan on: - pull_request: - branches: [main] + workflow_call: + inputs: + fail-on-secrets: + description: 'Fail the workflow if secrets are found' + required: false + default: 'true' + type: string jobs: trufflehog-scan: @@ -50,7 +55,6 @@ jobs: continue; } if (finding.Raw) { - // Defensive: try to get file/line from Filesystem, fallback to path/line, fallback to unknown let path = finding.SourceMetadata?.Data?.Filesystem?.file || finding.SourceMetadata?.Data?.path || 'unknown'; @@ -87,7 +91,7 @@ jobs: }); - name: Fail if any secrets found - if: ${{ hashFiles('trufflehog-results.json') != '' }} + if: ${{ inputs.fail-on-secrets == 'true' && hashFiles('trufflehog-results.json') != '' }} run: | if grep -q '"Raw":' trufflehog-results.json; then echo "Secrets found! Failing the workflow." From ae40386b6edbde4fdb5cb35a73d76d490c716cdd Mon Sep 17 00:00:00 2001 From: Isaiah Grigsby Date: Wed, 13 Aug 2025 17:08:40 -0500 Subject: [PATCH 08/23] test --- .github/workflows/reusable-trufflehog.yml | 86 ++++++++++------------- 1 file changed, 38 insertions(+), 48 deletions(-) diff --git a/.github/workflows/reusable-trufflehog.yml b/.github/workflows/reusable-trufflehog.yml index ce0930080..12eeac67b 100644 --- a/.github/workflows/reusable-trufflehog.yml +++ b/.github/workflows/reusable-trufflehog.yml @@ -4,44 +4,45 @@ on: workflow_call: inputs: fail-on-secrets: - description: 'Fail the workflow if secrets are found' + description: "Fail the workflow if secrets are found" required: false - default: 'true' + default: "true" type: string +permissions: + contents: read + pull-requests: write + jobs: trufflehog-scan: runs-on: ubuntu-latest steps: - - name: Checkout code - uses: actions/checkout@v4 + - uses: actions/checkout@v4 - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: '3.x' + - name: Install Trufflehog CLI (Go v3+) + run: | + wget https://github.com/trufflesecurity/trufflehog/releases/download/v3.90.3/trufflehog_3.90.3_linux_amd64.tar.gz + tar -xzf trufflehog_3.90.3_linux_amd64.tar.gz + chmod +x trufflehog + ./trufflehog --version - - name: Install Trufflehog - run: pip install trufflehog + - name: Run Trufflehog (JSON) + id: trufflehog + run: ./trufflehog filesystem . --json > trufflehog-results.json - - name: Run Trufflehog + - name: Add summary to PR + if: ${{ hashFiles('trufflehog-results.json') != '' }} run: | - trufflehog filesystem . --json --no-update > trufflehog-results.json || true - - - name: Debug Trufflehog output - run: cat trufflehog-results.json || echo "No trufflehog-results.json found" + echo "### Trufflehog Findings" >> $GITHUB_STEP_SUMMARY + jq -r 'select(type=="object" and .Raw and .SourceMetadata and .SourceMetadata.Data and .SourceMetadata.Data.path and .Verified == true) | "- \(.SourceMetadata.Data.path):\(.SourceMetadata.Data.line // "?") \(.Raw | @json)"' trufflehog-results.json >> $GITHUB_STEP_SUMMARY || true - - name: Comment on PR with all Trufflehog findings (verified and unverified) - if: ${{ github.event_name == 'pull_request' }} + - name: Comment on PR with verified Trufflehog findings + if: ${{ hashFiles('trufflehog-results.json') != '' && github.event_name == 'pull_request' }} uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | const fs = require('fs'); - const pr = context.payload.pull_request; - const owner = context.repo.owner; - const repo = context.repo.repo; - const branch = pr.head.ref; let findings = []; try { const lines = fs.readFileSync('trufflehog-results.json', 'utf8') @@ -54,46 +55,35 @@ jobs: } catch (e) { continue; } - if (finding.Raw) { - let path = finding.SourceMetadata?.Data?.Filesystem?.file - || finding.SourceMetadata?.Data?.path - || 'unknown'; - let lineNum = finding.SourceMetadata?.Data?.Filesystem?.line - || finding.SourceMetadata?.Data?.line - || 1; - const fileUrl = `https://github.com/${owner}/${repo}/blob/${branch}/${path}#L${lineNum}`; + if ( + finding.Verified === true && + finding.SourceMetadata && + finding.SourceMetadata.Data + ) { findings.push([ - `**File:** [\`${path}\` line ${lineNum}](${fileUrl})`, - `**Detector:** ${finding.DetectorName || 'N/A'}`, - `**Rule ID:** ${finding.RuleID || 'N/A'}`, - `**Secret Preview:** \`${finding.Raw ? finding.Raw.slice(0, 80) : ''}...\``, - finding.Redacted ? `**Redacted:** \`${finding.Redacted}\`` : '', - finding.Entropy ? `**Entropy:** ${finding.Entropy}` : '', - finding.Source ? `**Source:** ${finding.Source}` : '', - `**Verified:** ${finding.Verified === true ? '✅ Verified' : '⚠️ Unverified'}`, - finding.Decoded ? `**Decoded:** \`${finding.Decoded}\`` : '', - finding.Comment ? `**Comment:** ${finding.Comment}` : '', - finding.Metadata ? `**Metadata:** \`${JSON.stringify(finding.Metadata)}\`` : '' - ].filter(Boolean).join('\n')); + `**File:** \`${finding.SourceMetadata.Data.path}\``, + `**Line:** ${finding.SourceMetadata.Data.line || '?'}`, + `**Secret Preview:** \`${finding.Raw.slice(0, 80)}...\``, + `**Detector:** ${finding.DetectorName || 'N/A'}` + ].join('\n')); } } } catch (e) { findings = ['(Could not parse Trufflehog report)']; } const body = findings.length - ? `🚨 **Trufflehog found secrets in this PR!**\n\n${findings.map(f => `---\n${f}`).join('\n')}` - : "✅ Trufflehog ran and no secrets were found."; + ? `🚨 **Trufflehog found verified secrets in this PR!**\n\n${findings.map(f => `---\n${f}`).join('\n')}` + : "✅ Trufflehog ran and no verified secrets were found."; github.rest.issues.createComment({ issue_number: context.issue.number, - owner, - repo, + owner: context.repo.owner, + repo: context.repo.repo, body }); - - name: Fail if any secrets found + - name: Fail if verified secrets found if: ${{ inputs.fail-on-secrets == 'true' && hashFiles('trufflehog-results.json') != '' }} run: | - if grep -q '"Raw":' trufflehog-results.json; then - echo "Secrets found! Failing the workflow." + if jq -e 'select(.Verified == true)' trufflehog-results.json > /dev/null; then exit 1 fi \ No newline at end of file From 9661385333c7a252f41e9ef86d6c42c893d44151 Mon Sep 17 00:00:00 2001 From: Isaiah Grigsby Date: Wed, 13 Aug 2025 17:49:05 -0500 Subject: [PATCH 09/23] Added --- .github/workflows/reusable-trufflehog.yml | 86 +++++++++++++---------- 1 file changed, 48 insertions(+), 38 deletions(-) diff --git a/.github/workflows/reusable-trufflehog.yml b/.github/workflows/reusable-trufflehog.yml index 12eeac67b..ce0930080 100644 --- a/.github/workflows/reusable-trufflehog.yml +++ b/.github/workflows/reusable-trufflehog.yml @@ -4,45 +4,44 @@ on: workflow_call: inputs: fail-on-secrets: - description: "Fail the workflow if secrets are found" + description: 'Fail the workflow if secrets are found' required: false - default: "true" + default: 'true' type: string -permissions: - contents: read - pull-requests: write - jobs: trufflehog-scan: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - name: Checkout code + uses: actions/checkout@v4 - - name: Install Trufflehog CLI (Go v3+) - run: | - wget https://github.com/trufflesecurity/trufflehog/releases/download/v3.90.3/trufflehog_3.90.3_linux_amd64.tar.gz - tar -xzf trufflehog_3.90.3_linux_amd64.tar.gz - chmod +x trufflehog - ./trufflehog --version + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.x' - - name: Run Trufflehog (JSON) - id: trufflehog - run: ./trufflehog filesystem . --json > trufflehog-results.json + - name: Install Trufflehog + run: pip install trufflehog - - name: Add summary to PR - if: ${{ hashFiles('trufflehog-results.json') != '' }} + - name: Run Trufflehog run: | - echo "### Trufflehog Findings" >> $GITHUB_STEP_SUMMARY - jq -r 'select(type=="object" and .Raw and .SourceMetadata and .SourceMetadata.Data and .SourceMetadata.Data.path and .Verified == true) | "- \(.SourceMetadata.Data.path):\(.SourceMetadata.Data.line // "?") \(.Raw | @json)"' trufflehog-results.json >> $GITHUB_STEP_SUMMARY || true + trufflehog filesystem . --json --no-update > trufflehog-results.json || true + + - name: Debug Trufflehog output + run: cat trufflehog-results.json || echo "No trufflehog-results.json found" - - name: Comment on PR with verified Trufflehog findings - if: ${{ hashFiles('trufflehog-results.json') != '' && github.event_name == 'pull_request' }} + - name: Comment on PR with all Trufflehog findings (verified and unverified) + if: ${{ github.event_name == 'pull_request' }} uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | const fs = require('fs'); + const pr = context.payload.pull_request; + const owner = context.repo.owner; + const repo = context.repo.repo; + const branch = pr.head.ref; let findings = []; try { const lines = fs.readFileSync('trufflehog-results.json', 'utf8') @@ -55,35 +54,46 @@ jobs: } catch (e) { continue; } - if ( - finding.Verified === true && - finding.SourceMetadata && - finding.SourceMetadata.Data - ) { + if (finding.Raw) { + let path = finding.SourceMetadata?.Data?.Filesystem?.file + || finding.SourceMetadata?.Data?.path + || 'unknown'; + let lineNum = finding.SourceMetadata?.Data?.Filesystem?.line + || finding.SourceMetadata?.Data?.line + || 1; + const fileUrl = `https://github.com/${owner}/${repo}/blob/${branch}/${path}#L${lineNum}`; findings.push([ - `**File:** \`${finding.SourceMetadata.Data.path}\``, - `**Line:** ${finding.SourceMetadata.Data.line || '?'}`, - `**Secret Preview:** \`${finding.Raw.slice(0, 80)}...\``, - `**Detector:** ${finding.DetectorName || 'N/A'}` - ].join('\n')); + `**File:** [\`${path}\` line ${lineNum}](${fileUrl})`, + `**Detector:** ${finding.DetectorName || 'N/A'}`, + `**Rule ID:** ${finding.RuleID || 'N/A'}`, + `**Secret Preview:** \`${finding.Raw ? finding.Raw.slice(0, 80) : ''}...\``, + finding.Redacted ? `**Redacted:** \`${finding.Redacted}\`` : '', + finding.Entropy ? `**Entropy:** ${finding.Entropy}` : '', + finding.Source ? `**Source:** ${finding.Source}` : '', + `**Verified:** ${finding.Verified === true ? '✅ Verified' : '⚠️ Unverified'}`, + finding.Decoded ? `**Decoded:** \`${finding.Decoded}\`` : '', + finding.Comment ? `**Comment:** ${finding.Comment}` : '', + finding.Metadata ? `**Metadata:** \`${JSON.stringify(finding.Metadata)}\`` : '' + ].filter(Boolean).join('\n')); } } } catch (e) { findings = ['(Could not parse Trufflehog report)']; } const body = findings.length - ? `🚨 **Trufflehog found verified secrets in this PR!**\n\n${findings.map(f => `---\n${f}`).join('\n')}` - : "✅ Trufflehog ran and no verified secrets were found."; + ? `🚨 **Trufflehog found secrets in this PR!**\n\n${findings.map(f => `---\n${f}`).join('\n')}` + : "✅ Trufflehog ran and no secrets were found."; github.rest.issues.createComment({ issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, + owner, + repo, body }); - - name: Fail if verified secrets found + - name: Fail if any secrets found if: ${{ inputs.fail-on-secrets == 'true' && hashFiles('trufflehog-results.json') != '' }} run: | - if jq -e 'select(.Verified == true)' trufflehog-results.json > /dev/null; then + if grep -q '"Raw":' trufflehog-results.json; then + echo "Secrets found! Failing the workflow." exit 1 fi \ No newline at end of file From 7d2e829efaf952fe4874768e45abf3261993d51d Mon Sep 17 00:00:00 2001 From: Isaiah Grigsby Date: Wed, 13 Aug 2025 17:53:39 -0500 Subject: [PATCH 10/23] Added this for testing --- .github/workflows/reusable-trufflehog.yml | 52 +++++++---------------- 1 file changed, 16 insertions(+), 36 deletions(-) diff --git a/.github/workflows/reusable-trufflehog.yml b/.github/workflows/reusable-trufflehog.yml index ce0930080..b1f301f58 100644 --- a/.github/workflows/reusable-trufflehog.yml +++ b/.github/workflows/reusable-trufflehog.yml @@ -1,13 +1,8 @@ -name: Reusable Trufflehog Scan +name: Trufflehog Secret Scan on: - workflow_call: - inputs: - fail-on-secrets: - description: 'Fail the workflow if secrets are found' - required: false - default: 'true' - type: string + pull_request: + branches: [main] jobs: trufflehog-scan: @@ -31,17 +26,13 @@ jobs: - name: Debug Trufflehog output run: cat trufflehog-results.json || echo "No trufflehog-results.json found" - - name: Comment on PR with all Trufflehog findings (verified and unverified) + - name: Comment on PR with all Trufflehog findings (full JSON, clean format) if: ${{ github.event_name == 'pull_request' }} uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | const fs = require('fs'); - const pr = context.payload.pull_request; - const owner = context.repo.owner; - const repo = context.repo.repo; - const branch = pr.head.ref; let findings = []; try { const lines = fs.readFileSync('trufflehog-results.json', 'utf8') @@ -55,43 +46,32 @@ jobs: continue; } if (finding.Raw) { - let path = finding.SourceMetadata?.Data?.Filesystem?.file - || finding.SourceMetadata?.Data?.path - || 'unknown'; - let lineNum = finding.SourceMetadata?.Data?.Filesystem?.line - || finding.SourceMetadata?.Data?.line - || 1; - const fileUrl = `https://github.com/${owner}/${repo}/blob/${branch}/${path}#L${lineNum}`; findings.push([ - `**File:** [\`${path}\` line ${lineNum}](${fileUrl})`, - `**Detector:** ${finding.DetectorName || 'N/A'}`, - `**Rule ID:** ${finding.RuleID || 'N/A'}`, - `**Secret Preview:** \`${finding.Raw ? finding.Raw.slice(0, 80) : ''}...\``, - finding.Redacted ? `**Redacted:** \`${finding.Redacted}\`` : '', - finding.Entropy ? `**Entropy:** ${finding.Entropy}` : '', - finding.Source ? `**Source:** ${finding.Source}` : '', - `**Verified:** ${finding.Verified === true ? '✅ Verified' : '⚠️ Unverified'}`, - finding.Decoded ? `**Decoded:** \`${finding.Decoded}\`` : '', - finding.Comment ? `**Comment:** ${finding.Comment}` : '', - finding.Metadata ? `**Metadata:** \`${JSON.stringify(finding.Metadata)}\`` : '' - ].filter(Boolean).join('\n')); + '---', + '**Trufflehog Finding:**', + '', + '```json', + JSON.stringify(finding, null, 2), + '```', + '' + ].join('\n')); } } } catch (e) { findings = ['(Could not parse Trufflehog report)']; } const body = findings.length - ? `🚨 **Trufflehog found secrets in this PR!**\n\n${findings.map(f => `---\n${f}`).join('\n')}` + ? `🚨 **Trufflehog found secrets in this PR!**\n\n${findings.join('\n')}` : "✅ Trufflehog ran and no secrets were found."; github.rest.issues.createComment({ issue_number: context.issue.number, - owner, - repo, + owner: context.repo.owner, + repo: context.repo.repo, body }); - name: Fail if any secrets found - if: ${{ inputs.fail-on-secrets == 'true' && hashFiles('trufflehog-results.json') != '' }} + if: ${{ hashFiles('trufflehog-results.json') != '' }} run: | if grep -q '"Raw":' trufflehog-results.json; then echo "Secrets found! Failing the workflow." From 10f65ba3868c24e3e8e65b617be77c09f7bfecf7 Mon Sep 17 00:00:00 2001 From: Isaiah Grigsby Date: Wed, 13 Aug 2025 17:56:09 -0500 Subject: [PATCH 11/23] Interesting --- .github/workflows/reusable-trufflehog.yml | 25 ++++++++++++----------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/.github/workflows/reusable-trufflehog.yml b/.github/workflows/reusable-trufflehog.yml index b1f301f58..1a5afbfac 100644 --- a/.github/workflows/reusable-trufflehog.yml +++ b/.github/workflows/reusable-trufflehog.yml @@ -1,8 +1,7 @@ -name: Trufflehog Secret Scan +name: Reusable Trufflehog Secret Scan on: - pull_request: - branches: [main] + workflow_call: jobs: trufflehog-scan: @@ -46,15 +45,17 @@ jobs: continue; } if (finding.Raw) { - findings.push([ - '---', - '**Trufflehog Finding:**', - '', - '```json', - JSON.stringify(finding, null, 2), - '```', - '' - ].join('\n')); + findings.push( + [ + '---', + '**Trufflehog Finding:**', + '', + '```json', + JSON.stringify(finding, null, 2), + '```', + '' + ].join('\n') + ); } } } catch (e) { From 564b9e9fa6a04b72454c5c5f29585323c6fbb679 Mon Sep 17 00:00:00 2001 From: Isaiah Grigsby Date: Wed, 13 Aug 2025 17:59:32 -0500 Subject: [PATCH 12/23] Testing --- .github/workflows/reusable-trufflehog.yml | 49 +++++++++++++++-------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/.github/workflows/reusable-trufflehog.yml b/.github/workflows/reusable-trufflehog.yml index 1a5afbfac..ab3dec10d 100644 --- a/.github/workflows/reusable-trufflehog.yml +++ b/.github/workflows/reusable-trufflehog.yml @@ -1,7 +1,8 @@ -name: Reusable Trufflehog Secret Scan +name: Trufflehog Secret Scan on: - workflow_call: + pull_request: + branches: [main] jobs: trufflehog-scan: @@ -25,13 +26,17 @@ jobs: - name: Debug Trufflehog output run: cat trufflehog-results.json || echo "No trufflehog-results.json found" - - name: Comment on PR with all Trufflehog findings (full JSON, clean format) + - name: Comment on PR with all Trufflehog findings (verified and unverified) if: ${{ github.event_name == 'pull_request' }} uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | const fs = require('fs'); + const pr = context.payload.pull_request; + const owner = context.repo.owner; + const repo = context.repo.repo; + const branch = pr.head.ref; let findings = []; try { const lines = fs.readFileSync('trufflehog-results.json', 'utf8') @@ -45,29 +50,39 @@ jobs: continue; } if (finding.Raw) { - findings.push( - [ - '---', - '**Trufflehog Finding:**', - '', - '```json', - JSON.stringify(finding, null, 2), - '```', - '' - ].join('\n') - ); + // Defensive: try to get file/line from Filesystem, fallback to path/line, fallback to unknown + let path = finding.SourceMetadata?.Data?.Filesystem?.file + || finding.SourceMetadata?.Data?.path + || 'unknown'; + let lineNum = finding.SourceMetadata?.Data?.Filesystem?.line + || finding.SourceMetadata?.Data?.line + || 1; + const fileUrl = `https://github.com/${owner}/${repo}/blob/${branch}/${path}#L${lineNum}`; + findings.push([ + `**File:** [\`${path}\` line ${lineNum}](${fileUrl})`, + `**Detector:** ${finding.DetectorName || 'N/A'}`, + `**Rule ID:** ${finding.RuleID || 'N/A'}`, + `**Secret Preview:** \`${finding.Raw ? finding.Raw.slice(0, 80) : ''}...\``, + finding.Redacted ? `**Redacted:** \`${finding.Redacted}\`` : '', + finding.Entropy ? `**Entropy:** ${finding.Entropy}` : '', + finding.Source ? `**Source:** ${finding.Source}` : '', + `**Verified:** ${finding.Verified === true ? '✅ Verified' : '⚠️ Unverified'}`, + finding.Decoded ? `**Decoded:** \`${finding.Decoded}\`` : '', + finding.Comment ? `**Comment:** ${finding.Comment}` : '', + finding.Metadata ? `**Metadata:** \`${JSON.stringify(finding.Metadata)}\`` : '' + ].filter(Boolean).join('\n')); } } } catch (e) { findings = ['(Could not parse Trufflehog report)']; } const body = findings.length - ? `🚨 **Trufflehog found secrets in this PR!**\n\n${findings.join('\n')}` + ? `🚨 **Trufflehog found secrets in this PR!**\n\n${findings.map(f => `---\n${f}`).join('\n')}` : "✅ Trufflehog ran and no secrets were found."; github.rest.issues.createComment({ issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, + owner, + repo, body }); From d1777779c0b0cc961da9a55f18bf50d6d45bf5b4 Mon Sep 17 00:00:00 2001 From: Isaiah Grigsby Date: Wed, 13 Aug 2025 18:00:22 -0500 Subject: [PATCH 13/23] Testing --- .github/workflows/reusable-trufflehog.yml | 65 +++++++++++++---------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/.github/workflows/reusable-trufflehog.yml b/.github/workflows/reusable-trufflehog.yml index ab3dec10d..8c711911c 100644 --- a/.github/workflows/reusable-trufflehog.yml +++ b/.github/workflows/reusable-trufflehog.yml @@ -1,33 +1,43 @@ -name: Trufflehog Secret Scan +name: Reusable Trufflehog Scan on: - pull_request: - branches: [main] + workflow_call: + inputs: + fail-on-secrets: + description: "Fail the workflow if any secrets are found" + required: false + default: "true" + type: string + +permissions: + contents: read + pull-requests: write jobs: trufflehog-scan: runs-on: ubuntu-latest steps: - - name: Checkout code - uses: actions/checkout@v4 + - uses: actions/checkout@v4 - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: '3.x' + - name: Install Trufflehog CLI (Go v3+) + run: | + wget https://github.com/trufflesecurity/trufflehog/releases/download/v3.90.3/trufflehog_3.90.3_linux_amd64.tar.gz + tar -xzf trufflehog_3.90.3_linux_amd64.tar.gz + chmod +x trufflehog + ./trufflehog --version - - name: Install Trufflehog - run: pip install trufflehog + - name: Run Trufflehog (JSON) + id: trufflehog + run: ./trufflehog filesystem . --json 2>&1 | tee trufflehog-results.json - - name: Run Trufflehog + - name: Add summary to PR + if: ${{ hashFiles('trufflehog-results.json') != '' }} run: | - trufflehog filesystem . --json --no-update > trufflehog-results.json || true - - - name: Debug Trufflehog output - run: cat trufflehog-results.json || echo "No trufflehog-results.json found" + echo "### Trufflehog Findings" >> $GITHUB_STEP_SUMMARY + jq -r 'select(type=="object" and .Raw and .SourceMetadata and .SourceMetadata.Data and .SourceMetadata.Data.path) | "- \(.SourceMetadata.Data.path):\(.SourceMetadata.Data.line // "?") \(.Raw | @json)"' trufflehog-results.json >> $GITHUB_STEP_SUMMARY || true - name: Comment on PR with all Trufflehog findings (verified and unverified) - if: ${{ github.event_name == 'pull_request' }} + if: ${{ hashFiles('trufflehog-results.json') != '' && github.event_name == 'pull_request' }} uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} @@ -49,14 +59,16 @@ jobs: } catch (e) { continue; } - if (finding.Raw) { - // Defensive: try to get file/line from Filesystem, fallback to path/line, fallback to unknown - let path = finding.SourceMetadata?.Data?.Filesystem?.file - || finding.SourceMetadata?.Data?.path - || 'unknown'; - let lineNum = finding.SourceMetadata?.Data?.Filesystem?.line - || finding.SourceMetadata?.Data?.line - || 1; + // Only process lines that look like findings (have a Raw field) + if ( + finding.Raw && + finding.SourceMetadata && + finding.SourceMetadata.Data && + typeof finding.SourceMetadata.Data.path === 'string' && + finding.SourceMetadata.Data.path.length > 0 + ) { + const path = finding.SourceMetadata.Data.path; + const lineNum = finding.SourceMetadata.Data.line || 1; const fileUrl = `https://github.com/${owner}/${repo}/blob/${branch}/${path}#L${lineNum}`; findings.push([ `**File:** [\`${path}\` line ${lineNum}](${fileUrl})`, @@ -87,9 +99,8 @@ jobs: }); - name: Fail if any secrets found - if: ${{ hashFiles('trufflehog-results.json') != '' }} + if: ${{ inputs.fail-on-secrets == 'true' && hashFiles('trufflehog-results.json') != '' }} run: | if grep -q '"Raw":' trufflehog-results.json; then - echo "Secrets found! Failing the workflow." exit 1 fi \ No newline at end of file From 5c3586ef374cbc8a56bba92c450fab260136f6fe Mon Sep 17 00:00:00 2001 From: Isaiah Grigsby Date: Wed, 13 Aug 2025 18:07:01 -0500 Subject: [PATCH 14/23] Made updates --- .github/workflows/reusable-trufflehog.yml | 121 +++++++++++----------- 1 file changed, 62 insertions(+), 59 deletions(-) diff --git a/.github/workflows/reusable-trufflehog.yml b/.github/workflows/reusable-trufflehog.yml index 8c711911c..34dc26952 100644 --- a/.github/workflows/reusable-trufflehog.yml +++ b/.github/workflows/reusable-trufflehog.yml @@ -1,52 +1,37 @@ -name: Reusable Trufflehog Scan +name: Reusable Trufflehog Secret Scan on: workflow_call: - inputs: - fail-on-secrets: - description: "Fail the workflow if any secrets are found" - required: false - default: "true" - type: string - -permissions: - contents: read - pull-requests: write jobs: trufflehog-scan: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - name: Checkout code + uses: actions/checkout@v4 - - name: Install Trufflehog CLI (Go v3+) - run: | - wget https://github.com/trufflesecurity/trufflehog/releases/download/v3.90.3/trufflehog_3.90.3_linux_amd64.tar.gz - tar -xzf trufflehog_3.90.3_linux_amd64.tar.gz - chmod +x trufflehog - ./trufflehog --version + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.x' - - name: Run Trufflehog (JSON) - id: trufflehog - run: ./trufflehog filesystem . --json 2>&1 | tee trufflehog-results.json + - name: Install Trufflehog + run: pip install trufflehog - - name: Add summary to PR - if: ${{ hashFiles('trufflehog-results.json') != '' }} + - name: Run Trufflehog run: | - echo "### Trufflehog Findings" >> $GITHUB_STEP_SUMMARY - jq -r 'select(type=="object" and .Raw and .SourceMetadata and .SourceMetadata.Data and .SourceMetadata.Data.path) | "- \(.SourceMetadata.Data.path):\(.SourceMetadata.Data.line // "?") \(.Raw | @json)"' trufflehog-results.json >> $GITHUB_STEP_SUMMARY || true + trufflehog filesystem . --json --no-update > trufflehog-results.json || true + + - name: Debug Trufflehog output + run: cat trufflehog-results.json || echo "No trufflehog-results.json found" - - name: Comment on PR with all Trufflehog findings (verified and unverified) - if: ${{ hashFiles('trufflehog-results.json') != '' && github.event_name == 'pull_request' }} + - name: Comment on PR with all Trufflehog findings (full JSON, clean format) + if: ${{ github.event_name == 'pull_request' }} uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | const fs = require('fs'); - const pr = context.payload.pull_request; - const owner = context.repo.owner; - const repo = context.repo.repo; - const branch = pr.head.ref; let findings = []; try { const lines = fs.readFileSync('trufflehog-results.json', 'utf8') @@ -59,48 +44,66 @@ jobs: } catch (e) { continue; } - // Only process lines that look like findings (have a Raw field) - if ( - finding.Raw && - finding.SourceMetadata && - finding.SourceMetadata.Data && - typeof finding.SourceMetadata.Data.path === 'string' && - finding.SourceMetadata.Data.path.length > 0 - ) { - const path = finding.SourceMetadata.Data.path; - const lineNum = finding.SourceMetadata.Data.line || 1; - const fileUrl = `https://github.com/${owner}/${repo}/blob/${branch}/${path}#L${lineNum}`; - findings.push([ - `**File:** [\`${path}\` line ${lineNum}](${fileUrl})`, - `**Detector:** ${finding.DetectorName || 'N/A'}`, - `**Rule ID:** ${finding.RuleID || 'N/A'}`, - `**Secret Preview:** \`${finding.Raw ? finding.Raw.slice(0, 80) : ''}...\``, - finding.Redacted ? `**Redacted:** \`${finding.Redacted}\`` : '', - finding.Entropy ? `**Entropy:** ${finding.Entropy}` : '', - finding.Source ? `**Source:** ${finding.Source}` : '', - `**Verified:** ${finding.Verified === true ? '✅ Verified' : '⚠️ Unverified'}`, - finding.Decoded ? `**Decoded:** \`${finding.Decoded}\`` : '', - finding.Comment ? `**Comment:** ${finding.Comment}` : '', - finding.Metadata ? `**Metadata:** \`${JSON.stringify(finding.Metadata)}\`` : '' - ].filter(Boolean).join('\n')); + if (finding.Raw) { + findings.push( + [ + '---', + '**Trufflehog Finding:**', + '', + '```json', + JSON.stringify(finding, null, 2), + '```', + '' + ].join('\n') + ); } } } catch (e) { findings = ['(Could not parse Trufflehog report)']; } const body = findings.length - ? `🚨 **Trufflehog found secrets in this PR!**\n\n${findings.map(f => `---\n${f}`).join('\n')}` + ? `🚨 **Trufflehog found secrets in this PR!**\n\n${findings.join('\n')}` : "✅ Trufflehog ran and no secrets were found."; github.rest.issues.createComment({ issue_number: context.issue.number, - owner, - repo, + owner: context.repo.owner, + repo: context.repo.repo, body }); - name: Fail if any secrets found - if: ${{ inputs.fail-on-secrets == 'true' && hashFiles('trufflehog-results.json') != '' }} + if: ${{ hashFiles('trufflehog-results.json') != '' }} + run: | + if grep -q '"Raw":' trufflehog-results.json; then + echo "Secrets found! Failing the workflow." + exit 1 + fi + + security-secrets: + runs-on: ubuntu-latest + container: + image: alpine:latest + env: + SCAN_PATH: "." # Set the relative path in the repo to scan + steps: + - name: Install dependencies + run: apk add --no-cache git curl jq + + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install Trufflehog + run: | + curl -sSfL https://raw.githubusercontent.com/trufflesecurity/trufflehog/main/scripts/install.sh | sh -s -- -b /usr/local/bin + + - name: Run Trufflehog scan (GitLab style) + run: | + trufflehog filesystem "$SCAN_PATH" --results=verified,unknown --fail --json > trufflehog-results.json || true + cat trufflehog-results.json | jq + + - name: Fail if any secrets found run: | if grep -q '"Raw":' trufflehog-results.json; then + echo "Secrets found! Failing the workflow." exit 1 fi \ No newline at end of file From 4c01a666d9187d4243f53bdef76c3bf59c8c97f7 Mon Sep 17 00:00:00 2001 From: Isaiah Grigsby Date: Wed, 13 Aug 2025 18:13:01 -0500 Subject: [PATCH 15/23] Testing this --- .github/workflows/reusable-trufflehog.yml | 49 ++++++++--------------- 1 file changed, 16 insertions(+), 33 deletions(-) diff --git a/.github/workflows/reusable-trufflehog.yml b/.github/workflows/reusable-trufflehog.yml index 34dc26952..b93b07ea4 100644 --- a/.github/workflows/reusable-trufflehog.yml +++ b/.github/workflows/reusable-trufflehog.yml @@ -2,10 +2,16 @@ name: Reusable Trufflehog Secret Scan on: workflow_call: + inputs: + fail-on-secrets: + description: 'Fail the workflow if secrets are found' + required: false + default: 'true' + type: string jobs: trufflehog-scan: - runs-on: ubuntu-latest + runs-on: ubuntu-x64-small steps: - name: Checkout code uses: actions/checkout@v4 @@ -18,9 +24,15 @@ jobs: - name: Install Trufflehog run: pip install trufflehog - - name: Run Trufflehog + - name: Run Trufflehog (full scan) run: | - trufflehog filesystem . --json --no-update > trufflehog-results.json || true + trufflehog filesystem . \ + --json \ + --no-update \ + --only-verified=false \ + --max-depth=0 \ + --exclude-paths=.git,.github,node_modules,venv,env \ + > trufflehog-results.json || true - name: Debug Trufflehog output run: cat trufflehog-results.json || echo "No trufflehog-results.json found" @@ -72,36 +84,7 @@ jobs: }); - name: Fail if any secrets found - if: ${{ hashFiles('trufflehog-results.json') != '' }} - run: | - if grep -q '"Raw":' trufflehog-results.json; then - echo "Secrets found! Failing the workflow." - exit 1 - fi - - security-secrets: - runs-on: ubuntu-latest - container: - image: alpine:latest - env: - SCAN_PATH: "." # Set the relative path in the repo to scan - steps: - - name: Install dependencies - run: apk add --no-cache git curl jq - - - name: Checkout code - uses: actions/checkout@v4 - - - name: Install Trufflehog - run: | - curl -sSfL https://raw.githubusercontent.com/trufflesecurity/trufflehog/main/scripts/install.sh | sh -s -- -b /usr/local/bin - - - name: Run Trufflehog scan (GitLab style) - run: | - trufflehog filesystem "$SCAN_PATH" --results=verified,unknown --fail --json > trufflehog-results.json || true - cat trufflehog-results.json | jq - - - name: Fail if any secrets found + if: ${{ inputs.fail-on-secrets == 'true' && hashFiles('trufflehog-results.json') != '' }} run: | if grep -q '"Raw":' trufflehog-results.json; then echo "Secrets found! Failing the workflow." From 7a9d410fce40c2c469001d1dcbeff1988c4d3531 Mon Sep 17 00:00:00 2001 From: Isaiah Grigsby Date: Wed, 13 Aug 2025 18:18:46 -0500 Subject: [PATCH 16/23] Testing this --- .github/workflows/reusable-trufflehog.yml | 101 ++++++++++++---------- 1 file changed, 57 insertions(+), 44 deletions(-) diff --git a/.github/workflows/reusable-trufflehog.yml b/.github/workflows/reusable-trufflehog.yml index b93b07ea4..7a9bdb4fb 100644 --- a/.github/workflows/reusable-trufflehog.yml +++ b/.github/workflows/reusable-trufflehog.yml @@ -1,49 +1,52 @@ -name: Reusable Trufflehog Secret Scan +name: Reusable Trufflehog Scan on: workflow_call: inputs: fail-on-secrets: - description: 'Fail the workflow if secrets are found' + description: "Fail the workflow if verified secrets are found" required: false - default: 'true' + default: "true" type: string +permissions: + contents: read + pull-requests: write + jobs: trufflehog-scan: - runs-on: ubuntu-x64-small + runs-on: ubuntu-latest steps: - - name: Checkout code - uses: actions/checkout@v4 + - uses: actions/checkout@v4 - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: '3.x' + - name: Install Trufflehog CLI (Go v3+) + run: | + wget https://github.com/trufflesecurity/trufflehog/releases/download/v3.90.3/trufflehog_3.90.3_linux_amd64.tar.gz + tar -xzf trufflehog_3.90.3_linux_amd64.tar.gz + chmod +x trufflehog + ./trufflehog --version - - name: Install Trufflehog - run: pip install trufflehog + - name: Run Trufflehog (JSON) + id: trufflehog + run: ./trufflehog filesystem . --json > trufflehog-results.json - - name: Run Trufflehog (full scan) + - name: Add summary to PR + if: ${{ hashFiles('trufflehog-results.json') != '' }} run: | - trufflehog filesystem . \ - --json \ - --no-update \ - --only-verified=false \ - --max-depth=0 \ - --exclude-paths=.git,.github,node_modules,venv,env \ - > trufflehog-results.json || true - - - name: Debug Trufflehog output - run: cat trufflehog-results.json || echo "No trufflehog-results.json found" + echo "### Trufflehog Verified Findings" >> $GITHUB_STEP_SUMMARY + jq -r 'select(type=="object" and .Raw and .SourceMetadata and .SourceMetadata.Data and .SourceMetadata.Data.path and .Verified == true) | "- \(.SourceMetadata.Data.path):\(.SourceMetadata.Data.line // "?") \(.Raw | @json)"' trufflehog-results.json >> $GITHUB_STEP_SUMMARY || true - - name: Comment on PR with all Trufflehog findings (full JSON, clean format) - if: ${{ github.event_name == 'pull_request' }} + - name: Comment on PR with verified Trufflehog findings (with clickable file links) + if: ${{ hashFiles('trufflehog-results.json') != '' && github.event_name == 'pull_request' }} uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | const fs = require('fs'); + const pr = context.payload.pull_request; + const owner = context.repo.owner; + const repo = context.repo.repo; + const branch = pr.head.ref; let findings = []; try { const lines = fs.readFileSync('trufflehog-results.json', 'utf8') @@ -56,37 +59,47 @@ jobs: } catch (e) { continue; } - if (finding.Raw) { - findings.push( - [ - '---', - '**Trufflehog Finding:**', - '', - '```json', - JSON.stringify(finding, null, 2), - '```', - '' - ].join('\n') - ); + if ( + finding.Verified === true && + finding.SourceMetadata && + finding.SourceMetadata.Data && + typeof finding.SourceMetadata.Data.path === 'string' && + finding.SourceMetadata.Data.path.length > 0 + ) { + const path = finding.SourceMetadata.Data.path; + const lineNum = finding.SourceMetadata.Data.line || 1; + const fileUrl = `https://github.com/${owner}/${repo}/blob/${branch}/${path}#L${lineNum}`; + findings.push([ + `**File:** [\`${path}\` line ${lineNum}](${fileUrl})`, + `**Detector:** ${finding.DetectorName || 'N/A'}`, + `**Rule ID:** ${finding.RuleID || 'N/A'}`, + `**Secret Preview:** \`${finding.Raw ? finding.Raw.slice(0, 80) : ''}...\``, + finding.Redacted ? `**Redacted:** \`${finding.Redacted}\`` : '', + finding.Entropy ? `**Entropy:** ${finding.Entropy}` : '', + finding.Source ? `**Source:** ${finding.Source}` : '', + `**Verified:** ${finding.Verified}`, + finding.Decoded ? `**Decoded:** \`${finding.Decoded}\`` : '', + finding.Comment ? `**Comment:** ${finding.Comment}` : '', + finding.Metadata ? `**Metadata:** \`${JSON.stringify(finding.Metadata)}\`` : '' + ].filter(Boolean).join('\n')); } } } catch (e) { findings = ['(Could not parse Trufflehog report)']; } const body = findings.length - ? `🚨 **Trufflehog found secrets in this PR!**\n\n${findings.join('\n')}` - : "✅ Trufflehog ran and no secrets were found."; + ? `🚨 **Trufflehog found verified secrets in this PR!**\n\n${findings.map(f => `---\n${f}`).join('\n')}` + : "✅ Trufflehog ran and no verified secrets with file locations were found."; github.rest.issues.createComment({ issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, + owner, + repo, body }); - - name: Fail if any secrets found + - name: Fail if verified secrets found if: ${{ inputs.fail-on-secrets == 'true' && hashFiles('trufflehog-results.json') != '' }} run: | - if grep -q '"Raw":' trufflehog-results.json; then - echo "Secrets found! Failing the workflow." + if jq -e 'select(.Verified == true)' trufflehog-results.json > /dev/null; then exit 1 fi \ No newline at end of file From deaf6f2eb058ceb76459d3decc838b7f4d0cecde Mon Sep 17 00:00:00 2001 From: Isaiah Grigsby Date: Wed, 13 Aug 2025 18:24:58 -0500 Subject: [PATCH 17/23] Made updates --- .github/workflows/reusable-trufflehog.yml | 109 ++++++++++------------ 1 file changed, 51 insertions(+), 58 deletions(-) diff --git a/.github/workflows/reusable-trufflehog.yml b/.github/workflows/reusable-trufflehog.yml index 7a9bdb4fb..b8de523ee 100644 --- a/.github/workflows/reusable-trufflehog.yml +++ b/.github/workflows/reusable-trufflehog.yml @@ -1,52 +1,55 @@ -name: Reusable Trufflehog Scan +name: Reusable Trufflehog Secret Scan on: workflow_call: inputs: fail-on-secrets: - description: "Fail the workflow if verified secrets are found" + description: 'Fail the workflow if secrets are found' required: false - default: "true" + default: 'true' + type: string + extra_args: + description: 'Extra arguments to pass to Trufflehog' + required: false + default: '' type: string - -permissions: - contents: read - pull-requests: write jobs: trufflehog-scan: - runs-on: ubuntu-latest + runs-on: ubuntu-x64-small steps: - - uses: actions/checkout@v4 + - name: Checkout code + uses: actions/checkout@v4 - - name: Install Trufflehog CLI (Go v3+) - run: | - wget https://github.com/trufflesecurity/trufflehog/releases/download/v3.90.3/trufflehog_3.90.3_linux_amd64.tar.gz - tar -xzf trufflehog_3.90.3_linux_amd64.tar.gz - chmod +x trufflehog - ./trufflehog --version + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.x' - - name: Run Trufflehog (JSON) - id: trufflehog - run: ./trufflehog filesystem . --json > trufflehog-results.json + - name: Install Trufflehog + run: pip install trufflehog - - name: Add summary to PR - if: ${{ hashFiles('trufflehog-results.json') != '' }} + - name: Run Trufflehog (full scan) run: | - echo "### Trufflehog Verified Findings" >> $GITHUB_STEP_SUMMARY - jq -r 'select(type=="object" and .Raw and .SourceMetadata and .SourceMetadata.Data and .SourceMetadata.Data.path and .Verified == true) | "- \(.SourceMetadata.Data.path):\(.SourceMetadata.Data.line // "?") \(.Raw | @json)"' trufflehog-results.json >> $GITHUB_STEP_SUMMARY || true + trufflehog filesystem . \ + --json \ + --no-update \ + --only-verified=false \ + --max-depth=0 \ + --exclude-paths=.git,.github,node_modules,venv,env \ + ${{ inputs.extra_args }} \ + > trufflehog-results.json || true + + - name: Debug Trufflehog output + run: cat trufflehog-results.json || echo "No trufflehog-results.json found" - - name: Comment on PR with verified Trufflehog findings (with clickable file links) - if: ${{ hashFiles('trufflehog-results.json') != '' && github.event_name == 'pull_request' }} + - name: Comment on PR with all Trufflehog findings (full JSON, clean format) + if: ${{ github.event.pull_request != null }} uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | const fs = require('fs'); - const pr = context.payload.pull_request; - const owner = context.repo.owner; - const repo = context.repo.repo; - const branch = pr.head.ref; let findings = []; try { const lines = fs.readFileSync('trufflehog-results.json', 'utf8') @@ -59,47 +62,37 @@ jobs: } catch (e) { continue; } - if ( - finding.Verified === true && - finding.SourceMetadata && - finding.SourceMetadata.Data && - typeof finding.SourceMetadata.Data.path === 'string' && - finding.SourceMetadata.Data.path.length > 0 - ) { - const path = finding.SourceMetadata.Data.path; - const lineNum = finding.SourceMetadata.Data.line || 1; - const fileUrl = `https://github.com/${owner}/${repo}/blob/${branch}/${path}#L${lineNum}`; - findings.push([ - `**File:** [\`${path}\` line ${lineNum}](${fileUrl})`, - `**Detector:** ${finding.DetectorName || 'N/A'}`, - `**Rule ID:** ${finding.RuleID || 'N/A'}`, - `**Secret Preview:** \`${finding.Raw ? finding.Raw.slice(0, 80) : ''}...\``, - finding.Redacted ? `**Redacted:** \`${finding.Redacted}\`` : '', - finding.Entropy ? `**Entropy:** ${finding.Entropy}` : '', - finding.Source ? `**Source:** ${finding.Source}` : '', - `**Verified:** ${finding.Verified}`, - finding.Decoded ? `**Decoded:** \`${finding.Decoded}\`` : '', - finding.Comment ? `**Comment:** ${finding.Comment}` : '', - finding.Metadata ? `**Metadata:** \`${JSON.stringify(finding.Metadata)}\`` : '' - ].filter(Boolean).join('\n')); + if (finding.Raw) { + findings.push( + [ + '---', + '**Trufflehog Finding:**', + '', + '```json', + JSON.stringify(finding, null, 2), + '```', + '' + ].join('\n') + ); } } } catch (e) { findings = ['(Could not parse Trufflehog report)']; } const body = findings.length - ? `🚨 **Trufflehog found verified secrets in this PR!**\n\n${findings.map(f => `---\n${f}`).join('\n')}` - : "✅ Trufflehog ran and no verified secrets with file locations were found."; + ? `🚨 **Trufflehog found secrets in this PR!**\n\n${findings.join('\n')}` + : "✅ Trufflehog ran and no secrets were found."; github.rest.issues.createComment({ - issue_number: context.issue.number, - owner, - repo, + issue_number: context.payload.pull_request.number, + owner: context.repo.owner, + repo: context.repo.repo, body }); - - name: Fail if verified secrets found + - name: Fail if any secrets found if: ${{ inputs.fail-on-secrets == 'true' && hashFiles('trufflehog-results.json') != '' }} run: | - if jq -e 'select(.Verified == true)' trufflehog-results.json > /dev/null; then + if grep -q '"Raw":' trufflehog-results.json; then + echo "Secrets found! Failing the workflow." exit 1 fi \ No newline at end of file From feb1163c71319640a3103594bf5dee32fcb669cc Mon Sep 17 00:00:00 2001 From: Isaiah Grigsby Date: Wed, 13 Aug 2025 18:27:29 -0500 Subject: [PATCH 18/23] Testing --- .github/workflows/reusable-trufflehog.yml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/workflows/reusable-trufflehog.yml b/.github/workflows/reusable-trufflehog.yml index b8de523ee..ee30eafe7 100644 --- a/.github/workflows/reusable-trufflehog.yml +++ b/.github/workflows/reusable-trufflehog.yml @@ -21,21 +21,23 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: '3.x' + - name: Remove old Trufflehog (if present) + run: | + pip uninstall -y truffleHog || true + pip uninstall -y trufflehog || true - - name: Install Trufflehog - run: pip install trufflehog + - name: Install Trufflehog v3+ (official script) + run: | + curl -sSfL https://raw.githubusercontent.com/trufflesecurity/trufflehog/main/scripts/install.sh | sh -s -- -b /usr/local/bin + trufflehog --version - name: Run Trufflehog (full scan) run: | trufflehog filesystem . \ --json \ --no-update \ - --only-verified=false \ - --max-depth=0 \ + --results=verified,unknown \ + --fail \ --exclude-paths=.git,.github,node_modules,venv,env \ ${{ inputs.extra_args }} \ > trufflehog-results.json || true From 331c613f8576c19fbf4a703f87d2698d7115ec50 Mon Sep 17 00:00:00 2001 From: Isaiah Grigsby Date: Thu, 14 Aug 2025 08:51:27 -0500 Subject: [PATCH 19/23] Findings --- .github/workflows/reusable-trufflehog.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/reusable-trufflehog.yml b/.github/workflows/reusable-trufflehog.yml index ee30eafe7..1048bfbfe 100644 --- a/.github/workflows/reusable-trufflehog.yml +++ b/.github/workflows/reusable-trufflehog.yml @@ -26,12 +26,12 @@ jobs: pip uninstall -y truffleHog || true pip uninstall -y trufflehog || true - - name: Install Trufflehog v3+ (official script) + - name: Install Trufflehog v3+ run: | curl -sSfL https://raw.githubusercontent.com/trufflesecurity/trufflehog/main/scripts/install.sh | sh -s -- -b /usr/local/bin trufflehog --version - - name: Run Trufflehog (full scan) + - name: Run Trufflehog run: | trufflehog filesystem . \ --json \ From dba73c1a855d8a69d0c837c120c36da061987d21 Mon Sep 17 00:00:00 2001 From: Isaiah Grigsby Date: Wed, 20 Aug 2025 09:47:13 -0500 Subject: [PATCH 20/23] Updated to pinned commit --- .github/workflows/reusable-trufflehog.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/reusable-trufflehog.yml b/.github/workflows/reusable-trufflehog.yml index 1048bfbfe..205f5e139 100644 --- a/.github/workflows/reusable-trufflehog.yml +++ b/.github/workflows/reusable-trufflehog.yml @@ -26,9 +26,9 @@ jobs: pip uninstall -y truffleHog || true pip uninstall -y trufflehog || true - - name: Install Trufflehog v3+ + - name: Install Trufflehog (pinned to commit) run: | - curl -sSfL https://raw.githubusercontent.com/trufflesecurity/trufflehog/main/scripts/install.sh | sh -s -- -b /usr/local/bin + curl -sSfL https://raw.githubusercontent.com/trufflesecurity/trufflehog/0f58ae7c5036094a1e3e750d18772af92821b503/scripts/install.sh | sh -s -- -b /usr/local/bin trufflehog --version - name: Run Trufflehog From 22663e8baeb9363eae4241aae7b3654bd6f9567c Mon Sep 17 00:00:00 2001 From: Isaiah Grigsby Date: Wed, 20 Aug 2025 09:59:34 -0500 Subject: [PATCH 21/23] Fixed zizmor findings --- .github/workflows/reusable-trufflehog.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/reusable-trufflehog.yml b/.github/workflows/reusable-trufflehog.yml index 205f5e139..4d1f00d72 100644 --- a/.github/workflows/reusable-trufflehog.yml +++ b/.github/workflows/reusable-trufflehog.yml @@ -20,6 +20,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + with: + persist-credentials: false - name: Remove old Trufflehog (if present) run: | @@ -32,6 +34,8 @@ jobs: trufflehog --version - name: Run Trufflehog + env: + EXTRA_ARGS: ${{ inputs.extra_args }} run: | trufflehog filesystem . \ --json \ @@ -39,7 +43,7 @@ jobs: --results=verified,unknown \ --fail \ --exclude-paths=.git,.github,node_modules,venv,env \ - ${{ inputs.extra_args }} \ + $EXTRA_ARGS \ > trufflehog-results.json || true - name: Debug Trufflehog output From f7944fdb852a6ba76769b3d02a88a11295823dbd Mon Sep 17 00:00:00 2001 From: Isaiah Grigsby Date: Wed, 20 Aug 2025 10:02:53 -0500 Subject: [PATCH 22/23] chore: fix Prettier formatting --- .github/workflows/reusable-trufflehog.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/reusable-trufflehog.yml b/.github/workflows/reusable-trufflehog.yml index 4d1f00d72..57dd1c49e 100644 --- a/.github/workflows/reusable-trufflehog.yml +++ b/.github/workflows/reusable-trufflehog.yml @@ -4,14 +4,14 @@ on: workflow_call: inputs: fail-on-secrets: - description: 'Fail the workflow if secrets are found' + description: "Fail the workflow if secrets are found" required: false - default: 'true' + default: "true" type: string extra_args: - description: 'Extra arguments to pass to Trufflehog' + description: "Extra arguments to pass to Trufflehog" required: false - default: '' + default: "" type: string jobs: @@ -101,4 +101,4 @@ jobs: if grep -q '"Raw":' trufflehog-results.json; then echo "Secrets found! Failing the workflow." exit 1 - fi \ No newline at end of file + fi From 24cda0e1221936b7f149c4b063da1c22bfed01a2 Mon Sep 17 00:00:00 2001 From: Isaiah Grigsby Date: Wed, 20 Aug 2025 10:10:41 -0500 Subject: [PATCH 23/23] Fixes pre-commit failure --- .github/workflows/reusable-trufflehog.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/reusable-trufflehog.yml b/.github/workflows/reusable-trufflehog.yml index 57dd1c49e..ff5f55502 100644 --- a/.github/workflows/reusable-trufflehog.yml +++ b/.github/workflows/reusable-trufflehog.yml @@ -43,7 +43,7 @@ jobs: --results=verified,unknown \ --fail \ --exclude-paths=.git,.github,node_modules,venv,env \ - $EXTRA_ARGS \ + "$EXTRA_ARGS" \ > trufflehog-results.json || true - name: Debug Trufflehog output