Skip to content

Secret Scan (Gitleaks) #101

Secret Scan (Gitleaks)

Secret Scan (Gitleaks) #101

Workflow file for this run

# .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 }}