-
Notifications
You must be signed in to change notification settings - Fork 0
182 lines (156 loc) · 5.39 KB
/
security.yml
File metadata and controls
182 lines (156 loc) · 5.39 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
177
178
179
180
181
182
name: Security
on:
push:
branches: [main]
paths-ignore:
- '**.md'
- '.github/workflows/ci.yml'
- '.github/workflows/release.yml'
pull_request:
branches: [main]
paths-ignore:
- '**.md'
schedule:
- cron: '0 6 * * 1' # Weekly on Monday
# Cancel in-progress runs when a new run is triggered
concurrency:
group: security-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
security-events: write
jobs:
# ============================================================================
# Rust Security Audit
# ============================================================================
cargo-audit:
name: Cargo Audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Install cargo-audit
run: cargo install cargo-audit
- name: Run audit
run: |
cargo audit --json > audit-results.json 2>&1
echo "Audit completed"
- name: Upload audit results
uses: actions/upload-artifact@v6
if: always()
with:
name: cargo-audit-results
path: audit-results.json
cargo-deny:
name: Cargo Deny
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Install cargo-deny
run: cargo install cargo-deny
- name: Check advisories
run: cargo deny check advisories
- name: Check licenses
run: cargo deny check licenses
- name: Check bans
run: cargo deny check bans
# ============================================================================
# Dependency Review (PRs only)
# ============================================================================
dependency-review:
name: Dependency Review
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v4
- name: Dependency Review
uses: actions/dependency-review-action@v4
with:
fail-on-severity: critical
deny-licenses: GPL-3.0, AGPL-3.0
# ============================================================================
# Trivy Vulnerability Scanner
# ============================================================================
trivy:
name: Trivy Scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
scan-ref: '.'
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
- name: Upload Trivy scan results
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: 'trivy-results.sarif'
if: always()
# ============================================================================
# Secret Scanning
# ============================================================================
secrets:
name: Secret Scanning
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: TruffleHog scan
uses: trufflesecurity/trufflehog@main
with:
extra_args: --only-verified
# Note: Gitleaks removed - requires paid license as of 2025
# See: https://github.com/gitleaks/gitleaks-action#-announcement
# ============================================================================
# SAST with Semgrep
# ============================================================================
semgrep:
name: Semgrep SAST
runs-on: ubuntu-latest
container:
image: semgrep/semgrep
steps:
- uses: actions/checkout@v4
- name: Run Semgrep
run: |
semgrep ci --sarif --output=semgrep-results.sarif || true
# Create empty sarif if semgrep failed
if [ ! -f semgrep-results.sarif ]; then
echo '{"version":"2.1.0","$schema":"https://json.schemastore.org/sarif-2.1.0.json","runs":[]}' > semgrep-results.sarif
fi
env:
SEMGREP_APP_TOKEN: ${{ secrets.SEMGREP_APP_TOKEN }}
- name: Upload Semgrep results
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: semgrep-results.sarif
if: always()
continue-on-error: true
# ============================================================================
# Quality Gate — fails if any critical security check failed
# ============================================================================
security-gate:
name: Security Gate
runs-on: ubuntu-latest
if: always()
needs: [cargo-audit, cargo-deny, secrets, trivy]
steps:
- name: Check results
run: |
echo "cargo-audit: ${{ needs.cargo-audit.result }}"
echo "cargo-deny: ${{ needs.cargo-deny.result }}"
echo "secrets: ${{ needs.secrets.result }}"
echo "trivy: ${{ needs.trivy.result }}"
if [[ "${{ needs.cargo-audit.result }}" == "failure" ]] || \
[[ "${{ needs.cargo-deny.result }}" == "failure" ]] || \
[[ "${{ needs.secrets.result }}" == "failure" ]]; then
echo "::error::Security gate failed — critical check(s) did not pass"
exit 1
fi