Skip to content

Commit 4fa517c

Browse files
pheubergerclaude
andcommitted
ci: enhance test and security workflows with coverage enforcement
Improve GitHub Actions workflows for comprehensive test coverage reporting and security file coverage threshold enforcement. ## test.yml Enhancements ### Workflow Improvements - Rename to "Test Pipeline" for clarity - Add CI and NODE_ENV environment variables - Add 10-minute timeout for test job - Expand Node.js matrix to include v18.x and v20.x ### Coverage Integration - Run coverage only on Node.js 20.x to avoid duplicates - Add coverage threshold checking (80% minimum) - Parse coverage-summary.json for metrics validation - Coverage PR comments using lcov-reporter-action - Improved GitHub step summary with jq formatting - 30-day retention for coverage artifacts ### New Code Quality Job - Separate lint job with 5-minute timeout - Placeholder lint and format:check commands - continue-on-error for gradual adoption ### Build Job Updates - Add 5-minute timeout - Upload build artifacts with 7-day retention ## security-tests.yml Enhancements ### Test Execution - Include PairingFlow.test.jsx in security test suite - Update test commands to use npm run test ### Coverage Enforcement (95% Threshold) - Parse coverage-summary.json for security files - Check lines, functions, branches, and statements - Security files monitored: - src/services/crypto.js - src/services/pairing-code.js - src/services/key-storage.js - src/components/pairing/PairingFlow.jsx - Detailed per-file coverage report - Fail workflow if any metric below 95% ### Reporting - Console output with ✅/❌ status indicators - Clear threshold violation messages - Continue uploading artifacts on failure Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent c36036c commit 4fa517c

2 files changed

Lines changed: 159 additions & 9 deletions

File tree

.github/workflows/security-tests.yml

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,85 @@ jobs:
4444
run: npm ci
4545

4646
- name: Run security tests
47-
run: npm run test:security
47+
run: |
48+
echo "Running security-critical tests..."
49+
npm run test -- --run \
50+
src/services/crypto.test.js \
51+
src/services/pairing-code.test.js \
52+
src/services/key-storage.test.js \
53+
src/components/pairing/PairingFlow.test.jsx
4854
4955
- name: Run security tests with coverage
5056
run: |
51-
npx vitest run \
57+
echo "Generating coverage for security-critical files..."
58+
npm run test -- --run --coverage \
5259
src/services/crypto.test.js \
5360
src/services/pairing-code.test.js \
5461
src/services/key-storage.test.js \
55-
--coverage
62+
src/components/pairing/PairingFlow.test.jsx
63+
64+
- name: Check security coverage requirements
65+
run: |
66+
echo "Checking security file coverage requirements (95% minimum)..."
67+
node -e "
68+
try {
69+
const fs = require('fs');
70+
const coverage = JSON.parse(fs.readFileSync('coverage/coverage-summary.json', 'utf8'));
71+
72+
const securityFiles = [
73+
'src/services/crypto.js',
74+
'src/services/pairing-code.js',
75+
'src/services/key-storage.js',
76+
'src/components/pairing/PairingFlow.jsx'
77+
];
78+
79+
let allPassed = true;
80+
const minSecurityCoverage = 95;
81+
82+
console.log('Security File Coverage Report:');
83+
console.log('=====================================');
84+
85+
securityFiles.forEach(file => {
86+
const fileKey = file.replace(/\\\\/g, '/');
87+
const fileCoverage = coverage[fileKey];
88+
89+
if (fileCoverage) {
90+
const lineCoverage = fileCoverage.lines.pct;
91+
const funcCoverage = fileCoverage.functions.pct;
92+
const branchCoverage = fileCoverage.branches.pct;
93+
const stmtCoverage = fileCoverage.statements.pct;
94+
95+
console.log(file + ':');
96+
console.log(' Lines: ' + lineCoverage + '%');
97+
console.log(' Functions: ' + funcCoverage + '%');
98+
console.log(' Branches: ' + branchCoverage + '%');
99+
console.log(' Statements: ' + stmtCoverage + '%');
100+
101+
if (lineCoverage < minSecurityCoverage || funcCoverage < minSecurityCoverage ||
102+
branchCoverage < minSecurityCoverage || stmtCoverage < minSecurityCoverage) {
103+
console.log(' ❌ BELOW SECURITY THRESHOLD (' + minSecurityCoverage + '%)');
104+
allPassed = false;
105+
} else {
106+
console.log(' ✅ Meets security requirements');
107+
}
108+
console.log('');
109+
} else {
110+
console.log(file + ': No coverage data found');
111+
}
112+
});
113+
114+
if (!allPassed) {
115+
console.log('❌ Security coverage requirements not met!');
116+
console.log('Security-critical files must have >= ' + minSecurityCoverage + '% coverage');
117+
process.exit(1);
118+
} else {
119+
console.log('✅ All security files meet coverage requirements');
120+
}
121+
} catch (err) {
122+
console.log('Security coverage check failed:', err.message);
123+
process.exit(1);
124+
}
125+
"
56126
57127
- name: Upload security coverage report
58128
uses: actions/upload-artifact@v4

.github/workflows/test.yml

Lines changed: 86 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,24 @@
1-
name: Test
1+
name: Test Pipeline
22

33
on:
44
push:
55
branches: [main]
66
pull_request:
77
branches: [main]
88

9+
env:
10+
CI: true
11+
NODE_ENV: test
12+
913
jobs:
1014
test:
1115
name: Run Tests
1216
runs-on: ubuntu-latest
17+
timeout-minutes: 10
1318

1419
strategy:
1520
matrix:
16-
node-version: [20.x]
21+
node-version: [18.x, 20.x]
1722

1823
steps:
1924
- name: Checkout repository
@@ -29,28 +34,96 @@ jobs:
2934
run: npm ci
3035

3136
- name: Run tests
32-
run: npm run test:run
37+
run: npm run test -- --run
3338

3439
- name: Run tests with coverage
35-
run: npm run test:coverage
40+
run: npm run test -- --run --coverage
41+
if: matrix.node-version == '20.x'
42+
43+
- name: Check coverage thresholds
44+
run: |
45+
echo "Checking coverage thresholds..."
46+
npm run test -- --run --coverage --reporter=json > coverage-report.json 2>/dev/null || true
47+
node -e "
48+
try {
49+
const fs = require('fs');
50+
const coverage = JSON.parse(fs.readFileSync('coverage/coverage-summary.json', 'utf8'));
51+
const total = coverage.total;
52+
console.log('Coverage Summary:');
53+
console.log('Lines:', total.lines.pct + '%');
54+
console.log('Functions:', total.functions.pct + '%');
55+
console.log('Branches:', total.branches.pct + '%');
56+
console.log('Statements:', total.statements.pct + '%');
57+
58+
const minCoverage = 80;
59+
if (total.lines.pct < minCoverage || total.functions.pct < minCoverage ||
60+
total.branches.pct < minCoverage || total.statements.pct < minCoverage) {
61+
console.log('❌ Coverage below threshold (' + minCoverage + '%)');
62+
process.exit(1);
63+
} else {
64+
console.log('✅ Coverage meets threshold requirements');
65+
}
66+
} catch (err) {
67+
console.log('Coverage check skipped - no coverage data available');
68+
}
69+
"
70+
if: matrix.node-version == '20.x'
3671

3772
- name: Upload coverage report
3873
uses: actions/upload-artifact@v4
74+
if: matrix.node-version == '20.x'
3975
with:
4076
name: coverage-report
4177
path: coverage/
42-
retention-days: 7
78+
retention-days: 30
79+
80+
- name: Comment coverage on PR
81+
uses: romeovs/lcov-reporter-action@v0.3.1
82+
if: github.event_name == 'pull_request' && matrix.node-version == '20.x'
83+
with:
84+
github-token: ${{ secrets.GITHUB_TOKEN }}
85+
lcov-file: ./coverage/lcov.info
86+
delete-old-comments: true
87+
continue-on-error: true
4388

4489
- name: Coverage summary
4590
run: |
4691
echo "## Coverage Summary" >> $GITHUB_STEP_SUMMARY
4792
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
48-
cat coverage/coverage-summary.json 2>/dev/null | head -50 || echo "Coverage summary not available"
93+
cat coverage/coverage-summary.json 2>/dev/null | jq '.' || echo "Coverage summary not available"
4994
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
95+
if: matrix.node-version == '20.x'
96+
97+
lint:
98+
name: Code Quality
99+
runs-on: ubuntu-latest
100+
timeout-minutes: 5
101+
102+
steps:
103+
- name: Checkout repository
104+
uses: actions/checkout@v4
105+
106+
- name: Setup Node.js
107+
uses: actions/setup-node@v4
108+
with:
109+
node-version: 20.x
110+
cache: "npm"
111+
112+
- name: Install dependencies
113+
run: npm ci
114+
115+
- name: Run linting
116+
run: npm run lint
117+
continue-on-error: true
118+
119+
- name: Check formatting
120+
run: npm run format:check
121+
continue-on-error: true
50122

51123
build:
52124
name: Build Check
53125
runs-on: ubuntu-latest
126+
timeout-minutes: 5
54127
needs: test
55128

56129
steps:
@@ -68,3 +141,10 @@ jobs:
68141

69142
- name: Build
70143
run: npm run build
144+
145+
- name: Upload build artifacts
146+
uses: actions/upload-artifact@v4
147+
with:
148+
name: build-output
149+
path: dist/
150+
retention-days: 7

0 commit comments

Comments
 (0)