-
-
Notifications
You must be signed in to change notification settings - Fork 51
284 lines (236 loc) · 10 KB
/
Copy pathsecurity-audit.yml
File metadata and controls
284 lines (236 loc) · 10 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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
name: Security Audit
on:
schedule:
# minute hour day-of-month month day-of-week
# Run weekly on Sundays at 2 AM UTC
- cron: '0 2 * * 0'
workflow_dispatch:
push:
branches: [ main ]
paths:
- 'package.json'
- 'package-lock.json'
- '.github/workflows/security-audit.yml'
permissions:
contents: read
issues: write
pull-requests: write
statuses: write
jobs:
security-audit:
name: Security Audit
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run npm audit (production dependencies)
id: audit
run: |
echo "Running npm audit on production dependencies..."
# Try to fix vulnerabilities first
npm audit fix || echo "Some vulnerabilities require manual intervention"
# Audit production dependencies only (--omit=dev)
# Dev-only vulnerabilities (eslint, jest, etc.) are tracked separately below
npm audit --omit=dev --audit-level=moderate --json > audit-results.json || true
VULNERABILITIES=$(cat audit-results.json | jq '.metadata.vulnerabilities.total // 0')
echo "vulnerabilities=$VULNERABILITIES" >> $GITHUB_OUTPUT
if [ "$VULNERABILITIES" -gt 0 ]; then
echo "Found $VULNERABILITIES production vulnerabilities"
HIGH_CRITICAL=$(cat audit-results.json | jq '.metadata.vulnerabilities.high + .metadata.vulnerabilities.critical')
if [ "$HIGH_CRITICAL" -gt 0 ]; then
echo "❌ High or critical production vulnerabilities found - requires immediate attention"
npm audit --omit=dev --audit-level=moderate
exit 1
else
echo "⚠️ Only moderate production vulnerabilities found"
echo "✅ Moderate vulnerabilities detected - logging for review"
npm audit --omit=dev --audit-level=moderate || echo "Moderate vulnerabilities logged for monitoring"
fi
else
echo "✅ No production vulnerabilities found"
fi
- name: Run npm audit (all dependencies - informational)
if: always()
run: |
echo "📋 Full audit (including devDependencies) for monitoring:"
npm audit --audit-level=moderate 2>&1 || true
echo ""
echo "ℹ️ Dev dependency vulnerabilities (eslint, jest, etc.) do not affect production."
echo "ℹ️ These are tracked for awareness but do not block deployment."
- name: Check for sensitive files
run: |
echo "Checking for sensitive files in repository..."
# Check for common sensitive file patterns
SENSITIVE_FILES=$(find . -type f \( \
-name "*.env" -o \
-name "*.key" -o \
-name "*.pem" -o \
-name "*.p12" -o \
-name "*.jks" -o \
-name "*.keystore" -o \
-name "*secret*" -o \
-name "*credential*" -o \
-name "*password*" -o \
-name "*.pfx" \
\) ! -path "./node_modules/*" ! -name ".env.example" ! -name "*.md")
if [ -n "$SENSITIVE_FILES" ]; then
echo "❌ Sensitive files found:"
echo "$SENSITIVE_FILES"
exit 1
else
echo "✅ No sensitive files found"
fi
- name: Check environment variable configuration
run: |
echo "Verifying environment variable setup..."
# Check if .env.example exists
if [ ! -f ".env.example" ]; then
echo "❌ .env.example file missing"
exit 1
fi
# Check if .env.local is properly ignored
if [ -f ".env.local" ] && git check-ignore .env.local; then
echo "✅ .env.local is properly ignored"
elif [ -f ".env.local" ]; then
echo "❌ .env.local exists but is not ignored by git"
exit 1
else
echo "✅ No .env.local file found"
fi
- name: Scan for hardcoded secrets
run: |
echo "Scanning for potential hardcoded secrets..."
# Look for potential API keys, tokens, and secrets in code
POTENTIAL_SECRETS=$(grep -r -i \
--include="*.ts" --include="*.tsx" --include="*.js" --include="*.jsx" \
--exclude-dir=node_modules --exclude-dir=.next --exclude-dir=.git \
-E "(api[_-]?key|secret|token|password|credential)" . | \
grep -v "process.env" | \
grep -v "// " | \
grep -v "* " | \
head -10)
if [ -n "$POTENTIAL_SECRETS" ]; then
echo "⚠️ Potential hardcoded secrets found (review manually):"
echo "$POTENTIAL_SECRETS"
else
echo "✅ No obvious hardcoded secrets found"
fi
- name: Check dependency licenses
run: |
echo "Checking dependency licenses..."
npx license-checker --summary || echo "License checker not available, skipping..."
- name: Create security report
if: steps.audit.outputs.vulnerabilities > 0
run: |
echo "Creating security report..."
cat > security-report.md << EOF
# Security Audit Report
**Date:** $(date)
**Commit:** ${{ github.sha }}
**Vulnerabilities Found:** ${{ steps.audit.outputs.vulnerabilities }}
## Audit Results
\`\`\`json
$(cat audit-results.json | jq '.metadata')
\`\`\`
## Recommendations
1. Run \`npm audit fix\` to automatically fix vulnerabilities
2. Review and update dependencies manually if needed
3. Consider using \`npm audit fix --force\` for breaking changes
4. Monitor security advisories for used packages
## Next Steps
- [ ] Review vulnerability details
- [ ] Apply security fixes
- [ ] Test application after fixes
- [ ] Update dependencies to latest secure versions
EOF
- name: Upload security report
if: steps.audit.outputs.vulnerabilities > 0
uses: actions/upload-artifact@v4
with:
name: security-report
path: |
security-report.md
audit-results.json
retention-days: 30
- name: Create issue for vulnerabilities
if: steps.audit.outputs.vulnerabilities > 0 && github.event_name == 'schedule'
uses: actions/github-script@v7
with:
script: |
const vulnerabilities = ${{ steps.audit.outputs.vulnerabilities }};
// Check if there's already an open security issue
const issues = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
labels: 'security,vulnerability',
state: 'open'
});
if (issues.data.length === 0) {
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `🔒 Security Vulnerabilities Detected (${vulnerabilities} found)`,
body: `**Security audit found ${vulnerabilities} vulnerabilities**
**Detected on:** ${new Date().toISOString()}
**Commit:** ${context.sha}
## Action Required
1. Review the security audit results
2. Run \`npm audit\` locally to see details
3. Apply fixes using \`npm audit fix\`
4. Test the application after applying fixes
5. Update this issue with resolution status
## Audit Command
\`\`\`bash
npm audit
npm audit fix
\`\`\`
## Resources
- [npm audit documentation](https://docs.npmjs.com/cli/v8/commands/npm-audit)
- [GitHub Security Advisories](https://github.com/advisories)
- [Node.js Security Working Group](https://github.com/nodejs/security-wg)
**This issue was automatically created by the security audit workflow.**`,
labels: ['security', 'vulnerability', 'automated']
});
}
- name: Update commit status
if: always()
uses: actions/github-script@v7
with:
script: |
const vulnerabilities = ${{ steps.audit.outputs.vulnerabilities || 0 }};
// Read audit results to check severity levels
const fs = require('fs');
let highCriticalCount = 0;
let moderateCount = 0;
try {
const auditData = JSON.parse(fs.readFileSync('audit-results.json', 'utf8'));
highCriticalCount = (auditData.metadata?.vulnerabilities?.high || 0) + (auditData.metadata?.vulnerabilities?.critical || 0);
moderateCount = auditData.metadata?.vulnerabilities?.moderate || 0;
} catch (error) {
console.log('Could not read audit results, assuming no vulnerabilities');
}
// Only fail on high/critical production vulnerabilities
const state = highCriticalCount > 0 ? 'failure' : 'success';
const description = highCriticalCount > 0
? `${highCriticalCount} high/critical production vulnerabilities found`
: moderateCount > 0
? `${moderateCount} moderate production vulnerabilities (acceptable)`
: 'No production vulnerabilities detected';
await github.rest.repos.createCommitStatus({
owner: context.repo.owner,
repo: context.repo.repo,
sha: context.sha,
state: state,
target_url: `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`,
description: description,
context: 'security-audit'
});