Skip to content

Commit 8c98999

Browse files
committed
chore(security): add scheduled audit workflow
1 parent 22d68be commit 8c98999

1 file changed

Lines changed: 82 additions & 0 deletions

File tree

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
name: Security Audit
2+
3+
on:
4+
schedule:
5+
# 09:00 UTC every 3 days
6+
- cron: '0 9 */3 * *'
7+
workflow_dispatch:
8+
push:
9+
branches: [main, master]
10+
11+
permissions:
12+
contents: read
13+
security-events: write
14+
issues: write
15+
16+
jobs:
17+
gitleaks:
18+
name: Gitleaks (secret history)
19+
runs-on: ubuntu-latest
20+
steps:
21+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
22+
with:
23+
fetch-depth: 0
24+
- uses: gitleaks/gitleaks-action@dcedce43c6f43de0b836d1fe38946645c9c638dc # v2
25+
env:
26+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
27+
28+
trufflehog:
29+
name: TruffleHog (verified secrets)
30+
runs-on: ubuntu-latest
31+
steps:
32+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
33+
with:
34+
fetch-depth: 0
35+
- name: TruffleHog scan
36+
run: |
37+
docker run --rm -v "$GITHUB_WORKSPACE:/tmp" -w /tmp \
38+
ghcr.io/trufflesecurity/trufflehog:latest \
39+
git file:///tmp/ \
40+
--only-verified \
41+
--fail \
42+
--no-update \
43+
--github-actions
44+
45+
semgrep:
46+
name: Semgrep (SAST)
47+
runs-on: ubuntu-latest
48+
container:
49+
image: semgrep/semgrep
50+
steps:
51+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
52+
- run: semgrep ci --config=p/secrets --config=p/owasp-top-ten --config=p/javascript --config=p/typescript --config=p/python
53+
env:
54+
SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
55+
56+
notify:
57+
name: Open issue on failure
58+
needs: [gitleaks, trufflehog, semgrep]
59+
if: failure()
60+
runs-on: ubuntu-latest
61+
steps:
62+
- uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
63+
with:
64+
script: |
65+
const title = `Security audit failed: ${new Date().toISOString().split('T')[0]}`;
66+
const body = [
67+
`Scheduled security audit failed on \`${context.sha.slice(0,7)}\`.`,
68+
``,
69+
`**Run:** ${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`,
70+
``,
71+
`Triage:`,
72+
`1. Open the run, identify which job failed (gitleaks / trufflehog / semgrep).`,
73+
`2. Real finding: rotate credential, purge from history, close issue with note.`,
74+
`3. False positive: add to \`.gitleaksignore\` or \`.semgrepignore\` with justification.`,
75+
].join('\n');
76+
await github.rest.issues.create({
77+
owner: context.repo.owner,
78+
repo: context.repo.repo,
79+
title,
80+
body,
81+
labels: ['security', 'automated']
82+
});

0 commit comments

Comments
 (0)