-
Notifications
You must be signed in to change notification settings - Fork 62
176 lines (167 loc) · 5.65 KB
/
Copy pathsecurity-pipeline.yml
File metadata and controls
176 lines (167 loc) · 5.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
name: Security Pipeline
# Unified security gate: SAST, SCA, secret scanning, IaC scanning, and SBOM.
# Runs on every PR and nightly on main. Secret scanning blocks the merge gate.
# SAST and SCA run in report-only mode (upload SARIF for visibility).
# See docs/SECURITY_PIPELINE.md for policy, baselines, and runbooks.
on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
- cron: "0 3 * * *"
workflow_dispatch:
permissions:
contents: read
security-events: write
actions: read
concurrency:
group: security-${{ github.ref }}
cancel-in-progress: false
jobs:
# ---------------------------------------------------------------
# Secret scanning — gitleaks CLI (no license required for org repos)
# ---------------------------------------------------------------
secret-scan:
name: Secret Scan (gitleaks)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 }
- name: Install gitleaks
run: |
GITLEAKS_VERSION="8.21.2"
curl -sSL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" -o gitleaks.tar.gz
tar -xzf gitleaks.tar.gz gitleaks
chmod +x gitleaks
sudo mv gitleaks /usr/local/bin/
gitleaks version
- name: Run gitleaks scan
run: |
gitleaks detect \
--config .github/security/gitleaks.toml \
--no-git \
--verbose \
--redact \
--report-format json \
--report-path gitleaks-report.json || true
if [ -f gitleaks-report.json ]; then
CONTENT=$(cat gitleaks-report.json | tr -d '[:space:]')
if [ "$CONTENT" != "[]" ] && [ "$CONTENT" != "null" ] && [ -n "$CONTENT" ]; then
echo "::error::Secrets detected by gitleaks. See report for details."
cat gitleaks-report.json
exit 1
fi
fi
echo "✅ No secrets detected"
# ---------------------------------------------------------------
# SAST — Semgrep CLI (report-only mode)
# ---------------------------------------------------------------
sast:
name: SAST (semgrep)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install semgrep
run: |
python3 -m pip install --user semgrep==1.85.0
semgrep --version
- name: Semgrep scan
run: |
semgrep scan \
--config p/typescript \
--config p/javascript \
--config p/owasp-top-ten \
--config p/react \
--config p/nodejs \
--config p/docker \
--config p/sql-injection \
--config p/xss \
--sarif --output semgrep.sarif \
|| true
echo "✅ Semgrep scan completed (report-only mode)"
- name: Upload Semgrep SARIF
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: semgrep.sarif
# ---------------------------------------------------------------
# SCA + IaC — Trivy (report-only mode, upload SARIF)
# ---------------------------------------------------------------
sca-and-iac:
name: SCA + IaC (trivy)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Trivy FS (dependency vulnerabilities)
uses: aquasecurity/trivy-action@v0.36.0
with:
scan-type: fs
scan-ref: .
severity: HIGH,CRITICAL
exit-code: "0"
ignore-unfixed: true
format: sarif
output: trivy-fs.sarif
- name: Trivy config (IaC misconfigs)
uses: aquasecurity/trivy-action@v0.36.0
with:
scan-type: config
scan-ref: .
severity: HIGH,CRITICAL
exit-code: "0"
format: sarif
output: trivy-config.sarif
- name: Upload Trivy SARIF
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: trivy-fs.sarif
# ---------------------------------------------------------------
# SBOM — CycloneDX via Syft
# ---------------------------------------------------------------
sbom:
name: SBOM (syft)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Generate CycloneDX SBOM
uses: anchore/sbom-action@v0
with:
format: cyclonedx-json
output-file: sbom.cyclonedx.json
upload-artifact: true
upload-artifact-name: sbom.cyclonedx.json
- name: Upload SBOM artifact
uses: actions/upload-artifact@v4
with:
name: sbom-cyclonedx
path: sbom.cyclonedx.json
retention-days: 90
# ---------------------------------------------------------------
# Aggregate security report (digest) — non-blocking, always runs
# ---------------------------------------------------------------
security-report:
name: Security Report Digest
runs-on: ubuntu-latest
needs: [secret-scan, sast, sca-and-iac, sbom]
if: always()
steps:
- uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with: { node-version: "20" }
- name: Install
run: npm ci
working-directory: ./security-tests
- name: Generate report
run: npm run report:security
working-directory: ./security-tests
if: always()
- name: Upload report
uses: actions/upload-artifact@v4
if: always()
with:
name: security-report-digest
path: security-tests/reports/
retention-days: 30