-
Notifications
You must be signed in to change notification settings - Fork 0
159 lines (133 loc) · 5.38 KB
/
Copy pathci.yml
File metadata and controls
159 lines (133 loc) · 5.38 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
name: CI
on:
pull_request:
branches: [main]
push:
branches: [main]
jobs:
build-and-test:
name: Build & Test
runs-on: ubuntu-latest
defaults:
run:
working-directory: compliance-firewall-agent
steps:
- uses: actions/checkout@v7
- name: Set up Node.js
uses: actions/setup-node@v7
with:
# Node 22+ is REQUIRED, not a preference: jsdom 30 declares
# engines ^22.22.2 and pulls undici 8 (engines >=22.19.0), and undici 8
# calls node:worker_threads.markAsUncloneable, which does not exist
# before Node 22.19. npm treats engines as advisory, so on Node 20
# `npm ci` still succeeds and every vitest worker then dies at import
# with "webidl.util.markAsUncloneable is not a function" — reported as
# 125 errors / no tests, which looks like a test failure but is a
# runtime-version mismatch. The Proxy job below is already on 22.
node-version: "22.22.2"
cache: "npm"
cache-dependency-path: compliance-firewall-agent/package-lock.json
- name: Install dependencies
run: npm ci
- name: TypeScript check
run: npx tsc --noEmit
- name: Lint
run: npm run lint
# Coverage thresholds live in vitest.config.ts and FAIL this step when
# missed. The repo's previous threshold (70%) sat in a jest.config.js
# that nothing executed — `npm test` is vitest — so it never once ran.
# This replaces `npm test` rather than running alongside it: the same
# suite, with the gate attached.
- name: Run tests with coverage gate
run: npm run test:coverage
- name: Build
run: npm run build
env:
NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL }}
NEXT_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_ANON_KEY }}
proxy-build-and-test:
name: Proxy Build & Test
runs-on: ubuntu-latest
defaults:
run:
working-directory: proxy
steps:
- uses: actions/checkout@v7
- name: Set up Node.js
uses: actions/setup-node@v7
with:
# better-sqlite3@13 requires Node >=22 (its native binding won't load
# on 20 → vitest workers crash). Match the proxy's engines field.
node-version: "22.22.2"
cache: "npm"
cache-dependency-path: proxy/package-lock.json
- name: Install dependencies
run: npm ci
- name: TypeScript check
run: npm run lint
# Coverage thresholds in proxy/vitest.config.ts fail this step when missed.
- name: Run tests with coverage gate
run: npm run test:coverage
- name: Scanner latency benchmark (<10ms p99 contract)
run: npm run bench
- name: Build
run: npm run build
structure-guard:
name: Repo Structure Guard
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Verify repo matches PROJECT-STRUCTURE.md
run: node scripts/verify-structure.mjs
leak-guard:
name: Secret & PII Guard
runs-on: ubuntu-latest
steps:
# Needs the working tree only — the guard scans `git ls-files`, i.e. exactly
# what is published. History scanning is a separate, one-off job (see
# docs/SECURITY-ROTATION.md), not a per-PR gate.
- uses: actions/checkout@v7
- name: Prove the guard still discriminates
run: node scripts/verify-no-leaks.mjs --self-test
- name: Scan tracked files for credentials and personal addresses
run: node scripts/verify-no-leaks.mjs
compliance-guard:
name: Compliance Pattern Guard
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
# Counts the patterns the scanner actually loads, by importing the
# module. The previous guard ran `grep -c "category:"`, which also
# matched the PatternCategory type alias and the DetectionPattern /
# DetectedEntity interface fields — roughly four free hits that no
# detection rule contributes to. It would therefore have passed with
# a dozen real patterns deleted, which is the one thing it exists to
# prevent. Importing ALL_PATTERNS also proves the export name the
# publish-patterns workflow depends on still resolves.
- name: Verify the shipped CUI pattern set has not been degraded
run: |
cd proxy
npm ci --ignore-scripts
npx tsx -e "
import { ALL_PATTERNS } from './patterns/index.ts';
const MIN = 33;
const byCategory = {};
for (const p of ALL_PATTERNS) {
byCategory[p.category] = (byCategory[p.category] ?? 0) + 1;
}
console.log('Patterns loaded:', ALL_PATTERNS.length, byCategory);
if (ALL_PATTERNS.length < MIN) {
console.error(
'BLOCKED: pattern count dropped to ' + ALL_PATTERNS.length +
' (floor is ' + MIN + '). The compliance engine must never be degraded.'
);
process.exit(1);
}
for (const required of ['CUI', 'PHI', 'PII']) {
if (!byCategory[required]) {
console.error('BLOCKED: no ' + required + ' patterns remain.');
process.exit(1);
}
}
console.log('PASS:', ALL_PATTERNS.length, 'patterns verified');
"