Secret Scan (Gitleaks) #100
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
| # .github/workflows/secret-scan.yml | |
| # | |
| # Copyright © 2025 Network Pro Strategies (Network Pro™) | |
| # SPDX-License-Identifier: CC-BY-4.0 OR GPL-3.0-or-later | |
| # This file is part of Network Pro | |
| name: Secret Scan (Gitleaks) | |
| on: | |
| pull_request: | |
| schedule: | |
| - cron: '0 8 * * *' # nightly scan at 8 AM UTC | |
| workflow_dispatch: | |
| jobs: | |
| gitleaks-scan: | |
| runs-on: ubuntu-24.04 | |
| permissions: | |
| contents: read | |
| security-events: write | |
| issues: write | |
| env: | |
| CODEQL_ACTION_ANALYSIS_KEY: gitleaks | |
| ENV_MODE: ci | |
| steps: | |
| # --------------------------------------------------------------------- | |
| # Checkout the full repo history (needed for Gitleaks to scan all commits) | |
| # --------------------------------------------------------------------- | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| # --------------------------------------------------------------------- | |
| # Run Gitleaks scan | |
| # Uses org license key (safe because GitHub never passes secrets to forks) | |
| # --------------------------------------------------------------------- | |
| - name: Run Gitleaks scan | |
| id: gitleaks | |
| uses: gitleaks/gitleaks-action@v2 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }} | |
| GITLEAKS_REPORT_PATH: gitleaks-report.json | |
| # --------------------------------------------------------------------- | |
| # LAYER 2: Secret-handling / fork guard | |
| # Upload artifact only if workflow runs in trusted context | |
| # (either not a PR, or a PR from the same repo) | |
| # --------------------------------------------------------------------- | |
| - name: Upload Gitleaks Report | |
| if: always() && (github.event.pull_request.head.repo.full_name == github.repository || github.event_name != 'pull_request') | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: gitleaks-report | |
| path: gitleaks-report.json | |
| # --------------------------------------------------------------------- | |
| # LAYER 1: Output redaction | |
| # Public-safe summary – shows only secret descriptions, hides file paths. | |
| # --------------------------------------------------------------------- | |
| - name: Post Gitleaks summary | |
| if: always() | |
| run: | | |
| echo "### 🧩 Gitleaks Scan Summary" >> $GITHUB_STEP_SUMMARY | |
| # If the JSON report doesn't exist, that usually means no leaks were found. | |
| if [ ! -f gitleaks-report.json ]; then | |
| echo "✅ No leaks detected — Gitleaks did not generate a JSON report (expected behavior)." >> $GITHUB_STEP_SUMMARY | |
| exit 0 | |
| fi | |
| if [ -s gitleaks-report.json ]; then | |
| count=$(jq '.findings | length' gitleaks-report.json) | |
| if [ "$count" -gt 0 ]; then | |
| echo "🚨 **$count potential secret$( [ "$count" -ne 1 ] && echo "s" ) detected!**" >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| # 🔒 Redacted output: no file paths or secret values | |
| jq -r '.findings[] | "- \(.Description) (at undisclosed path)"' gitleaks-report.json | head -n 10 >> $GITHUB_STEP_SUMMARY | |
| echo "" >> $GITHUB_STEP_SUMMARY | |
| echo "_Full report available in Artifacts section (maintainers only)._ " >> $GITHUB_STEP_SUMMARY | |
| else | |
| echo "✅ No secrets detected." >> $GITHUB_STEP_SUMMARY | |
| fi | |
| else | |
| echo "⚠️ Report file exists but is empty." >> $GITHUB_STEP_SUMMARY | |
| fi | |
| # --------------------------------------------------------------------- | |
| # LAYER 2: Secret-handling / fork guard | |
| # Create issue only in trusted repo context (avoids using tokens on forks) | |
| # --------------------------------------------------------------------- | |
| - name: Create issue for detected secrets | |
| if: failure() && (github.event.pull_request.head.repo.full_name == github.repository || github.event_name != 'pull_request') | |
| uses: actions/github-script@v7 | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| script: | | |
| const issueTitle = `🚨 Secret(s) detected in ${context.repo.repo}`; | |
| const issueBody = `Gitleaks found potential secrets in commit ${context.sha}.\n\nCheck workflow logs and artifacts for details.`; | |
| await github.rest.issues.create({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| title: issueTitle, | |
| body: issueBody, | |
| labels: ['security', 'gitleaks'] | |
| }); | |
| # --------------------------------------------------------------------- | |
| # LAYER 2: Secret-handling / fork guard | |
| # Send ntfy alert only for trusted repo context. | |
| # --------------------------------------------------------------------- | |
| - name: Send ntfy notification | |
| if: failure() && (github.event.pull_request.head.repo.full_name == github.repository || github.event_name != 'pull_request') | |
| run: | | |
| curl -d "🚨 Gitleaks found secrets in repo: $GITHUB_REPOSITORY on commit $GITHUB_SHA" \ | |
| https://ntfy.neteng.pro/${{ secrets.NTFY_TOPIC }} |