Skip to content

Repository Security Scanners #329

Repository Security Scanners

Repository Security Scanners #329

name: Repository Security Scanners
on:
push:
branches:
- '**'
pull_request:
branches:
- '**'
schedule:
# Run daily at 2 AM UTC
- cron: '0 2 * * *'
workflow_dispatch:
permissions:
contents: read
security-events: write
actions: read
jobs:
trufflehog:
name: Trufflehog Secret Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run Trufflehog on filesystem
run: |
docker run --rm -v "$(pwd):/repo" \
trufflesecurity/trufflehog:latest \
filesystem /repo --json --no-update --only-verified > trufflehog-fs-results.json || true
if [ -s trufflehog-fs-results.json ]; then
echo "Filesystem scan found potential secrets:"
cat trufflehog-fs-results.json
fi
- name: Run Trufflehog on Git history
run: |
docker run --rm -v "$(pwd):/repo" \
trufflesecurity/trufflehog:latest \
git file:///repo --json --no-update --only-verified > trufflehog-git-results.json || true
if [ -s trufflehog-git-results.json ]; then
echo "Git history scan found potential secrets:"
cat trufflehog-git-results.json
fi
- name: Check for verified secrets
run: |
SECRETS_FOUND=false
# Check if files exist and contain verified secrets
if [ -f trufflehog-fs-results.json ]; then
FS_COUNT=$(jq -s 'length' trufflehog-fs-results.json 2>/dev/null || echo "0")
if [ "$FS_COUNT" -gt 0 ]; then
echo "⚠️ Found $FS_COUNT verified secrets in filesystem!"
SECRETS_FOUND=true
fi
fi
if [ -f trufflehog-git-results.json ]; then
GIT_COUNT=$(jq -s 'length' trufflehog-git-results.json 2>/dev/null || echo "0")
if [ "$GIT_COUNT" -gt 0 ]; then
echo "⚠️ Found $GIT_COUNT verified secrets in Git history!"
SECRETS_FOUND=true
fi
fi
if [ "$SECRETS_FOUND" = true ]; then
exit 1
else
echo "✅ No verified secrets found"
fi
- name: Upload Trufflehog results
if: always()
uses: actions/upload-artifact@v4
with:
name: trufflehog-results
path: |
trufflehog-fs-results.json
trufflehog-git-results.json
retention-days: 30
gitleaks:
name: GitLeaks Secret Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Run GitLeaks scan
run: |
docker pull zricethezav/gitleaks:latest
mkdir -p results
docker run --rm \
--volume "$(pwd):/path" \
--volume "$(pwd)/results:/output" \
zricethezav/gitleaks:latest \
dir -v -f json -r "/output/gitleaks-results.json" /path
# Also generate SARIF format for GitHub Security
docker run --rm \
--volume "$(pwd):/path" \
--volume "$(pwd)/results:/output" \
zricethezav/gitleaks:latest \
dir -v -f sarif -r "/output/gitleaks-results.sarif" /path || true
- name: Display scan results
if: always()
run: |
if [ -f results/gitleaks-results.json ]; then
echo "Gitleaks scan completed"
ls -lh results/gitleaks-results.json
cat results/gitleaks-results.json
else
echo "No results file found"
fi
- name: Upload GitLeaks results to GitHub Security
if: always()
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: 'results/gitleaks-results.sarif'
category: 'gitleaks'
continue-on-error: true
- name: Upload GitLeaks results
if: always()
uses: actions/upload-artifact@v4
with:
name: gitleaks-results
path: results/
retention-days: 30
trivy:
name: Trivy Security Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Run Trivy filesystem scan
uses: aquasecurity/trivy-action@c1824fd6edce30d7ab345a9989de00bbd46ef284
with:
scan-type: 'fs'
scan-ref: '.'
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
exit-code: '1'
skip-dirs: 'tests' # Added: Skip tests directory
continue-on-error: true
- name: Upload Trivy results to GitHub Security
if: always()
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: 'trivy-results.sarif'
category: 'trivy-filesystem'
- name: Run Trivy config scan (JSON)
uses: aquasecurity/trivy-action@c1824fd6edce30d7ab345a9989de00bbd46ef284
with:
scan-type: 'config'
scan-ref: '.'
format: 'json'
output: 'trivy-config-results.json'
skip-dirs: 'tests' # Added: Skip tests directory
exit-code: '0'
- name: Run Trivy config scan (Table for display)
uses: aquasecurity/trivy-action@c1824fd6edce30d7ab345a9989de00bbd46ef284
with:
scan-type: 'config'
scan-ref: '.'
format: 'table'
skip-dirs: 'tests' # Added: Skip tests directory
exit-code: '0'
- name: Check Trivy results and fail if issues found
run: |
if [ -f trivy-config-results.json ]; then
# Check if there are any results with severity >= HIGH
ISSUE_COUNT=$(jq '[.Results[]? | select(.Misconfigurations != null) | .Misconfigurations[] | select(.Severity == "HIGH" or .Severity == "CRITICAL")] | length' trivy-config-results.json)
if [ "$ISSUE_COUNT" -gt 0 ]; then
echo "⚠️ Found $ISSUE_COUNT HIGH or CRITICAL security issues!"
exit 1
else
echo "✅ No critical security issues found"
fi
fi
- name: Upload Trivy filesystem results
if: always()
uses: actions/upload-artifact@v4
with:
name: trivy-results
path: |
trivy-results.sarif
trivy-config-results.json
retention-days: 30
clamav:
name: ClamAV Malware Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install ClamAV
run: |
sudo apt-get update
sudo apt-get install -y clamav
sudo systemctl stop clamav-freshclam || true
sudo freshclam
- name: Run ClamAV scan
run: |
clamscan --recursive --infected --log=clamav-results.log .
echo "✅ No malware found"
- name: Upload ClamAV results
if: always()
uses: actions/upload-artifact@v4
with:
name: clamav-results
path: clamav-results.log
retention-days: 30
govulncheck:
name: Govulncheck Go Vulnerability Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: 'src/go.mod'
cache: false
- name: Install govulncheck
run: go install golang.org/x/vuln/cmd/govulncheck@latest
- name: Run govulncheck
working-directory: src
run: |
set +e
govulncheck -json ./... > govulncheck-results.json 2>&1
EXIT_CODE=$?
govulncheck ./... | tee govulncheck-results.txt
if [ $EXIT_CODE -ne 0 ]; then
echo "⚠️ Vulnerabilities found!"
exit 1
else
echo "✅ No vulnerabilities found"
fi
- name: Upload govulncheck results
if: always()
uses: actions/upload-artifact@v4
with:
name: govulncheck-results
path: |
src/govulncheck-results.json
src/govulncheck-results.txt
retention-days: 30
gosec:
name: Gosec Go Security Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: 'src/go.mod'
cache: false
- name: Install Gosec
run: go install github.com/securego/gosec/v2/cmd/gosec@latest
- name: Run Gosec
working-directory: src
run: |
set +e
gosec -fmt json -out gosec-results.json ./...
EXIT_CODE=$?
gosec -fmt text -out gosec-results.txt ./...
cat gosec-results.txt
if [ $EXIT_CODE -ne 0 ]; then
echo "⚠️ Security issues found!"
exit 1
else
echo "✅ No security issues found"
fi
- name: Upload Gosec results
if: always()
uses: actions/upload-artifact@v4
with:
name: gosec-results
path: |
src/gosec-results.json
src/gosec-results.txt
retention-days: 30
summary:
name: Security Scan Summary
runs-on: ubuntu-latest
needs: [trufflehog, gitleaks, trivy, clamav, govulncheck, gosec]
if: always()
steps:
- name: Generate summary
run: |
echo "# Security Scan Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Scanner | Status |" >> $GITHUB_STEP_SUMMARY
echo "|---------|--------|" >> $GITHUB_STEP_SUMMARY
echo "| Trufflehog | ${{ needs.trufflehog.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| GitLeaks | ${{ needs.gitleaks.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Trivy | ${{ needs.trivy.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| ClamAV | ${{ needs.clamav.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Govulncheck | ${{ needs.govulncheck.result }} |" >> $GITHUB_STEP_SUMMARY
echo "| Gosec | ${{ needs.gosec.result }} |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "View detailed results in the job artifacts." >> $GITHUB_STEP_SUMMARY