Skip to content

Secrets Detection Scan #334

Secrets Detection Scan

Secrets Detection Scan #334

# Secrets Detection with TruffleHog
# Scans for accidentally committed secrets and credentials
name: Secrets Detection Scan
on:
push:
branches: [ main, dev, 'kcs/*' ]
pull_request:
branches: [ main, dev ]
schedule:
# Run daily at 1 AM UTC
- cron: '0 1 * * *'
jobs:
trufflehog:
name: TruffleHog Secrets Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
# Fetch full git history for comprehensive scanning
fetch-depth: 0
- name: Run TruffleHog secrets scan
uses: trufflesecurity/trufflehog@main
with:
# Scan the entire repository including git history
path: ./
base: ${{ github.event.repository.default_branch }}
head: HEAD
extra_args: --debug --only-verified --json
- name: Run TruffleHog filesystem scan
id: trufflehog-fs
continue-on-error: true
run: |
# Install TruffleHog if not available
if ! command -v trufflehog &> /dev/null; then
curl -sSfL https://raw.githubusercontent.com/trufflesecurity/trufflehog/main/scripts/install.sh | sh -s -- -b /usr/local/bin
fi
# Scan filesystem for secrets
trufflehog filesystem . \
--json \
--only-verified \
--exclude-paths=.trufflehogignore \
> trufflehog-results.json 2>&1 || true
- name: Parse and comment on secrets found
if: always()
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
// Check if results file exists
if (fs.existsSync('trufflehog-results.json')) {
const results = fs.readFileSync('trufflehog-results.json', 'utf8');
const lines = results.trim().split('\n').filter(line => line.trim());
let secrets = [];
for (const line of lines) {
try {
const finding = JSON.parse(line);
if (finding.Verified || finding.verified) {
secrets.push(finding);
}
} catch (e) {
// Skip invalid JSON lines
}
}
if (secrets.length > 0) {
let comment = '## πŸ”‘ Secrets Detection Results\n\n';
comment += `⚠️ **CRITICAL**: Found ${secrets.length} verified secret(s) in the repository!\n\n`;
for (const secret of secrets.slice(0, 5)) { // Show max 5 secrets
const detector = secret.DetectorName || secret.detector_name || 'Unknown';
const file = secret.SourceMetadata?.Data?.Filesystem?.file || 'Unknown file';
comment += `- 🚨 **${detector}** detected in \`${file}\`\n`;
}
if (secrets.length > 5) {
comment += `\n... and ${secrets.length - 5} more secret(s).\n`;
}
comment += '\n**IMMEDIATE ACTION REQUIRED:**\n';
comment += '1. πŸ”„ Rotate all exposed credentials immediately\n';
comment += '2. πŸ—‘οΈ Remove secrets from git history using BFG Repo-Cleaner\n';
comment += '3. πŸ”’ Use environment variables or secret management systems\n';
comment += '4. πŸ“ Add sensitive patterns to `.trufflehogignore`\n';
// Post comment on PR or create issue
if (context.eventName === 'pull_request') {
await github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: comment
});
// Also add labels
await github.rest.issues.addLabels({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
labels: ['security', 'critical', 'secrets-detected']
});
} else {
// Create an issue for secrets found in push events
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: '🚨 CRITICAL: Secrets detected in repository',
body: comment,
labels: ['security', 'critical', 'secrets-detected']
});
}
// Exit with error to fail the workflow
core.setFailed(`Found ${secrets.length} verified secret(s) in the repository`);
} else {
console.log('βœ… No verified secrets found');
}
} else {
console.log('ℹ️ No TruffleHog results file found');
}
- name: Upload secrets scan results
uses: actions/upload-artifact@v4
if: always()
with:
name: secrets-scan-results-${{ github.sha }}
path: |
trufflehog-results.json
retention-days: 30
gitguardian:
name: GitGuardian Secrets Scan (Disabled - API Key Issue)
runs-on: ubuntu-latest
if: false # Disabled due to GitGuardian API key configuration issue
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: GitGuardian scan
uses: GitGuardian/ggshield/actions/secret@main
env:
GITHUB_PUSH_BEFORE_SHA: ${{ github.event.before }}
GITHUB_PUSH_BASE_SHA: ${{ github.event.base }}
GITHUB_PULL_BASE_SHA: ${{ github.event.pull_request.base.sha }}
GITHUB_DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
GITGUARDIAN_API_KEY: ${{ secrets.GITGUARDIAN_API_KEY }}
with:
args: --exit-zero