Skip to content

Merge pull request #7 from nboyers/dev #11

Merge pull request #7 from nboyers/dev

Merge pull request #7 from nboyers/dev #11

name: Secret Scanning
on:
pull_request:
branches:
- main
push:
branches:
- main
- "feature/**"
- "fix/**"
permissions:
contents: write
pull-requests: write
issues: write
jobs:
gitleaks:
name: Gitleaks Secret Scanning
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch all history for accurate scanning
- name: Run Gitleaks
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITLEAKS_ENABLE_COMMENTS: true
- name: Upload Gitleaks Report
if: failure()
uses: actions/upload-artifact@v4
with:
name: gitleaks-report
path: results.sarif
retention-days: 7
trufflehog:
name: TruffleHog Secret Scanning
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: TruffleHog OSS
uses: trufflesecurity/trufflehog@main
with:
path: ./
base: ${{ github.event.repository.default_branch }}
head: HEAD
extra_args: --debug --only-verified
custom-pattern-check:
name: Custom Pattern Detection
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Check for common secret patterns
id: secret_check
run: |
echo "Scanning for common secret patterns..."
# Define patterns to search for
PATTERNS=(
"aws_access_key_id"
"aws_secret_access_key"
"AKIA[0-9A-Z]{16}" # AWS Access Key
"(?i)api[_-]?key.*['\"][0-9a-zA-Z]{32,}['\"]" # Generic API keys
"(?i)password.*['\"][^'\"]{8,}['\"]" # Passwords in quotes
"(?i)secret.*['\"][0-9a-zA-Z]{32,}['\"]" # Generic secrets
"(?i)token.*['\"][0-9a-zA-Z]{32,}['\"]" # Tokens
"private[_-]?key"
"-----BEGIN (RSA|OPENSSH|DSA|EC) PRIVATE KEY-----" # Private keys
"ghp_[0-9a-zA-Z]{36}" # GitHub Personal Access Token
"ghs_[0-9a-zA-Z]{36}" # GitHub OAuth Secret
"sk_live_[0-9a-zA-Z]{24,}" # Stripe Live Secret Key
"pk_live_[0-9a-zA-Z]{24,}" # Stripe Live Public Key
)
FOUND_SECRETS=0
REPORT_FILE="secret_scan_report.txt"
echo "=== Secret Scanning Report ===" > $REPORT_FILE
echo "Timestamp: $(date)" >> $REPORT_FILE
echo "" >> $REPORT_FILE
# Get list of changed files
if [ "${{ github.event_name }}" = "pull_request" ]; then
FILES=$(git diff --name-only origin/${{ github.base_ref }}...HEAD)
else
FILES=$(git diff --name-only HEAD~1 HEAD)
fi
# Skip certain file types and directories
FILES=$(echo "$FILES" | grep -v ".terraform/" | grep -v ".git/" | grep -v "node_modules/" || true)
for FILE in $FILES; do
if [ -f "$FILE" ]; then
echo "Scanning: $FILE" >> $REPORT_FILE
for PATTERN in "${PATTERNS[@]}"; do
MATCHES=$(grep -niE "$PATTERN" "$FILE" 2>/dev/null || true)
if [ ! -z "$MATCHES" ]; then
FOUND_SECRETS=1
echo " ❌ FOUND POTENTIAL SECRET:" >> $REPORT_FILE
echo " Pattern: $PATTERN" >> $REPORT_FILE
echo "$MATCHES" | while IFS= read -r line; do
# Redact the actual secret value
REDACTED=$(echo "$line" | sed -E 's/['\''"][0-9a-zA-Z]{8,}['\''"]/***REDACTED***/g')
echo " $REDACTED" >> $REPORT_FILE
done
echo "" >> $REPORT_FILE
fi
done
fi
done
if [ $FOUND_SECRETS -eq 1 ]; then
echo "status=failed" >> $GITHUB_OUTPUT
cat $REPORT_FILE
echo ""
echo "❌ SECRETS DETECTED! Please remove sensitive data before committing."
exit 1
else
echo "status=passed" >> $GITHUB_OUTPUT
echo "✅ No secrets detected"
fi
- name: Comment on PR with findings
if: failure() && github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const fs = require('fs');
let report = '⚠️ **Secret Scanning Failed**\n\n';
report += '**Potential secrets or API keys were detected in your changes.**\n\n';
report += 'Please review and remove any sensitive data before merging.\n\n';
report += '### What to do:\n';
report += '1. Remove the secret from your code\n';
report += '2. Use environment variables or GitHub Secrets instead\n';
report += '3. If the secret was already committed, you must:\n';
report += ' - Rotate/invalidate the exposed secret\n';
report += ' - Remove it from git history using `git filter-branch` or BFG Repo-Cleaner\n\n';
report += '### Common secret patterns detected:\n';
report += '- AWS Access Keys (AKIA...)\n';
report += '- API Keys\n';
report += '- Private Keys\n';
report += '- Passwords or tokens in code\n\n';
report += '**This PR cannot be merged until all secrets are removed.**';
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: report
});
block-merge:
name: Block Merge if Secrets Found
runs-on: ubuntu-latest
needs: [gitleaks, trufflehog, custom-pattern-check]
if: always()
steps:
- name: Check scan results
run: |
if [ "${{ needs.gitleaks.result }}" = "failure" ] || \
[ "${{ needs.trufflehog.result }}" = "failure" ] || \
[ "${{ needs.custom-pattern-check.result }}" = "failure" ]; then
echo "❌ Secret scanning failed. Blocking merge."
exit 1
else
echo "✅ All secret scans passed. Safe to merge."
fi
# Optional: Auto-revert commits with secrets on main branch
auto-revert:
name: Auto-revert Commits with Secrets
runs-on: ubuntu-latest
needs: [gitleaks, trufflehog, custom-pattern-check]
if: |
failure() &&
github.event_name == 'push' &&
github.ref == 'refs/heads/main'
permissions:
contents: write
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Configure git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- name: Revert last commit
run: |
COMMIT_SHA="${{ github.sha }}"
COMMIT_MSG=$(git log -1 --pretty=%B $COMMIT_SHA)
echo "⚠️ Reverting commit: $COMMIT_SHA"
echo "Commit message: $COMMIT_MSG"
git revert --no-edit $COMMIT_SHA
git push origin main
- name: Create issue for manual review
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const issue = await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: '🚨 Secrets Detected - Commit Automatically Reverted',
body: `## Security Alert: Secrets Detected
**Commit**: \`${{ github.sha }}\`
**Author**: @${{ github.actor }}
**Branch**: main
### What happened?
Secret scanning detected potential secrets or API keys in a commit to the main branch.
The commit has been automatically reverted to prevent exposure.
### Required Actions:
1. **⚠️ ROTATE ALL EXPOSED SECRETS IMMEDIATELY**
- If the secret was an API key, revoke it
- If it was an AWS key, disable it in IAM
- Generate new credentials
2. **Clean up your local branch**:
\`\`\`bash
git fetch origin
git reset --hard origin/main
\`\`\`
3. **Remove the secret properly**:
- Use environment variables
- Use GitHub Secrets
- Use AWS Secrets Manager / Parameter Store
- Add pattern to .gitignore
4. **Re-commit without secrets**:
- Make your changes again
- Ensure no secrets are in the code
- Submit a new PR
### Preventing Future Incidents:
- Always use \`.tfvars\` files for sensitive values (they're gitignored)
- Use \`backend.tf\` for backend config (also gitignored)
- Store secrets in GitHub Secrets or AWS Secrets Manager
- Run \`git diff\` before committing to review changes
- Enable pre-commit hooks for local secret scanning
**This issue will remain open until confirmed that exposed secrets have been rotated.**`,
labels: ['security', 'urgent', 'secrets-detected']
});
console.log('Created issue:', issue.data.number);
- name: Send alert notification
if: always()
run: |
echo "🚨 SECURITY ALERT: Secrets detected in commit ${{ github.sha }}"
echo "Commit has been reverted and an issue has been created."
echo "Please rotate any exposed credentials immediately."