mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-02-17 16:07:40 +01:00
feat(security): add gitleaks secret scanning to pre-commit hook and CI
Add three layers of secret leak prevention: 1. .gitleaks.toml — config extending the default ruleset (~150 rules for AWS, GCP, Stripe, OpenAI, private keys, JWTs, etc.) with allowlists tuned to suppress false positives from test fixtures and docs. 2. .husky/pre-commit — enhanced with gitleaks protect --staged (graceful skip if not installed), sensitive file type blocking (.pem, .key, .enc, id_rsa, etc.), and broadened fallback patterns covering AWS, OpenAI, GCP, and private key headers alongside existing Stripe checks. 3. .github/workflows/build-and-test.yml — new secret-scan CI job using gitleaks-action that runs in parallel with build on every push/PR, serving as the last gate if someone bypasses local hooks.
This commit is contained in:
14
.github/workflows/build-and-test.yml
vendored
14
.github/workflows/build-and-test.yml
vendored
@@ -10,6 +10,20 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
secret-scan:
|
||||
name: Secret Scan
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Run gitleaks
|
||||
uses: gitleaks/gitleaks-action@v2
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
build:
|
||||
name: Frontend & Backend
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
34
.gitleaks.toml
Normal file
34
.gitleaks.toml
Normal file
@@ -0,0 +1,34 @@
|
||||
# Gitleaks configuration for Pulse
|
||||
# https://github.com/gitleaks/gitleaks
|
||||
#
|
||||
# Extends the default ruleset (AWS, GCP, Stripe, OpenAI, private keys, etc.)
|
||||
# with allowlists to suppress false positives from test fixtures, docs, and templates.
|
||||
|
||||
[extend]
|
||||
useDefault = true
|
||||
|
||||
[allowlist]
|
||||
paths = [
|
||||
# Template/example files with placeholder credentials
|
||||
'''\.env\.example$''',
|
||||
'''mock\.env$''',
|
||||
# Test files use fake tokens, keys, and credentials throughout
|
||||
'''_test\.go$''',
|
||||
'''_test\.ts$''',
|
||||
'''tests/integration/''',
|
||||
# tmp/ is gitignored but shows up in --no-git scans
|
||||
'''^tmp/''',
|
||||
]
|
||||
regexTarget = "match"
|
||||
regexes = [
|
||||
# PULSE_LICENSE_PUBLIC_KEY is an env var name, not a secret value
|
||||
'''PULSE_LICENSE_PUBLIC_KEY''',
|
||||
# Documentation placeholder tokens in curl examples
|
||||
'''your-token''',
|
||||
'''your-api-token''',
|
||||
'''your-original-token''',
|
||||
# Dev credentials documented in CLAUDE.md and scripts (admin:admin)
|
||||
'''admin:admin''',
|
||||
# E2E test bootstrap token (deterministic, not a real secret)
|
||||
'''0123456789abcdef''',
|
||||
]
|
||||
@@ -4,31 +4,61 @@
|
||||
# Pre-commit hook to prevent committing restricted or sensitive data
|
||||
RESTRICTED_FILES="active_subs.json charges.json customers.json subscriptions.json"
|
||||
|
||||
echo "🔒 Running sensitivity check..."
|
||||
echo "Running sensitivity check..."
|
||||
|
||||
for file in $RESTRICTED_FILES; do
|
||||
if git diff --cached --name-only | grep -q "^${file}$"; then
|
||||
echo "❌ BLOCKED: restricted file pattern matched: ${file}"
|
||||
echo "BLOCKED: restricted file pattern matched: ${file}"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Check for potential credentials or internal identifiers
|
||||
if git diff --cached | grep -E "^\+" | grep -v ".husky/pre-commit" | grep -qE "(cus_|sub_|ch_|pi_|pm_|sk_live_|sk_test_)"; then
|
||||
echo "⚠️ WARNING: Potential API keys or identifiers found in staged changes."
|
||||
echo " Use 'git diff --cached' to review before proceeding."
|
||||
if [ -t 0 ]; then
|
||||
printf " Proceed anyway? (y/N): "
|
||||
read REPLY < /dev/tty
|
||||
echo
|
||||
if [ "$REPLY" != "y" ] && [ "$REPLY" != "Y" ]; then
|
||||
# Block sensitive file types from ever being committed
|
||||
SENSITIVE_EXTENSIONS="\.pem$|\.p12$|\.pfx$|\.key$|\.keystore$|\.jks$|\.enc$|id_rsa$|id_ed25519$|id_ecdsa$"
|
||||
if git diff --cached --name-only | grep -qE "$SENSITIVE_EXTENSIONS"; then
|
||||
echo "BLOCKED: sensitive file type staged for commit:"
|
||||
git diff --cached --name-only | grep -E "$SENSITIVE_EXTENSIONS"
|
||||
echo "If this is intentional (e.g. a template), use: git commit --no-verify"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Gitleaks: comprehensive secret scanning (gracefully skips if not installed)
|
||||
if command -v gitleaks >/dev/null 2>&1; then
|
||||
echo "Running gitleaks secret scan..."
|
||||
if ! gitleaks protect --staged --config .gitleaks.toml --no-banner 2>/dev/null; then
|
||||
echo "BLOCKED: gitleaks detected secrets in staged changes."
|
||||
echo "Run 'gitleaks protect --staged --verbose' for details."
|
||||
exit 1
|
||||
fi
|
||||
echo "Gitleaks scan passed."
|
||||
else
|
||||
# Fallback: broader pattern check when gitleaks is not installed
|
||||
# Covers Stripe, AWS, GCP, OpenAI, private keys, and generic high-entropy tokens
|
||||
STAGED_DIFF=$(git diff --cached | grep -E "^\+" | grep -v ".husky/pre-commit" | grep -v "_test\.go")
|
||||
|
||||
if echo "$STAGED_DIFF" | grep -qE "(cus_|sub_|ch_|pi_|pm_|sk_live_|sk_test_|rk_live_|rk_test_|whsec_)"; then
|
||||
echo "WARNING: Potential Stripe identifiers found in staged changes."
|
||||
echo " Use 'git diff --cached' to review before proceeding."
|
||||
if [ -t 0 ]; then
|
||||
printf " Proceed anyway? (y/N): "
|
||||
read REPLY < /dev/tty
|
||||
echo
|
||||
if [ "$REPLY" != "y" ] && [ "$REPLY" != "Y" ]; then
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo " (Skipping confirmation in non-interactive shell)"
|
||||
fi
|
||||
|
||||
if echo "$STAGED_DIFF" | grep -qE "(AKIA[0-9A-Z]{16}|-----BEGIN (RSA |EC |OPENSSH )?PRIVATE KEY-----|sk-[a-zA-Z0-9]{20,}|AIza[0-9A-Za-z_-]{35})"; then
|
||||
echo "BLOCKED: Likely secret detected in staged changes (AWS key, private key, or API key)."
|
||||
echo " Use 'git diff --cached' to review."
|
||||
echo " Install gitleaks for more precise scanning: brew install gitleaks"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
echo "✅ Check passed."
|
||||
echo "Sensitivity check passed."
|
||||
|
||||
|
||||
# Run Go formatting
|
||||
|
||||
Reference in New Issue
Block a user