-
Notifications
You must be signed in to change notification settings - Fork 0
252 lines (227 loc) · 9.04 KB
/
Copy pathci.yml
File metadata and controls
252 lines (227 loc) · 9.04 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
name: CI
on:
push:
branches: [main]
pull_request:
schedule:
# Weekly, Mondays 04:00 UTC — exercises the live public TSAs.
- cron: "0 4 * * 1"
workflow_dispatch:
# A superseded run on a branch is cancelled; main is never cancelled so the
# record of what passed on main stays complete.
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
permissions:
contents: read
env:
# Anchoring against live public TSAs is not done on every CI run; the log
# tamper suite uses recorded RFC 3161 fixtures. The tsa-live job below runs
# the network path on a schedule, so an outage at freetsa.org cannot redden
# an unrelated pull request.
ZW_TSA_MODE: fixtures
jobs:
build-and-test:
name: build + tests (node ${{ matrix.node }})
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
node: ["20", "22"]
steps:
- uses: actions/checkout@v4
- name: Install SoftHSM2 (real PKCS#11 provider)
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends softhsm2 opensc
# The module path differs across distributions; resolve it once
# rather than letting the tests guess from a hardcoded list.
MODULE=$(find /usr/lib -name 'libsofthsm2.so' 2>/dev/null | head -1)
test -n "$MODULE" || { echo "libsofthsm2.so not found"; exit 1; }
echo "ZW_PKCS11_MODULE=$MODULE" >> "$GITHUB_ENV"
echo "ZW_SOFTHSM2_UTIL=$(command -v softhsm2-util)" >> "$GITHUB_ENV"
softhsm2-util --version
# No version pin: pnpm/action-setup reads packageManager from
# package.json. Specifying both is an error when they disagree, which
# is exactly how this broke before.
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm build
- name: Unit, property, integration and drill tests
# SoftHSM2 is installed above, so the PKCS#11 suite must RUN, not skip.
env:
ZW_REQUIRE_PKCS11: "1"
run: pnpm test
coverage:
name: coverage gate (crypto, log, release, generation)
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Install SoftHSM2
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends softhsm2
MODULE=$(find /usr/lib -name 'libsofthsm2.so' 2>/dev/null | head -1)
echo "ZW_PKCS11_MODULE=$MODULE" >> "$GITHUB_ENV"
echo "ZW_SOFTHSM2_UTIL=$(command -v softhsm2-util)" >> "$GITHUB_ENV"
# No version pin: pnpm/action-setup reads packageManager from
# package.json. Specifying both is an error when they disagree, which
# is exactly how this broke before.
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm build
- name: Enforce >=90% line coverage on critical paths
env:
ZW_REQUIRE_PKCS11: "1"
run: pnpm coverage
pilot:
name: acceptance rehearsal
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
# No version pin: pnpm/action-setup reads packageManager from
# package.json. Specifying both is an error when they disagree, which
# is exactly how this broke before.
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm build
- name: Pilot, 3 centres x 60 candidates (offline)
run: pnpm pilot --offline --candidates 60 --rederive 8
cups:
name: IPP against real CUPS
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Install and configure CUPS
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends cups cups-pdf cups-filters
# Keep output inside /var/spool/cups-pdf: cups-pdf is confined by
# AppArmor on Ubuntu and cannot write to an arbitrary path. UserUMask
# 0000 makes the finished PDFs world-readable so the unprivileged
# test process can inspect them.
sudo tee /etc/cups/cups-pdf.conf >/dev/null <<'CONF'
Out /var/spool/cups-pdf
AnonDirName /var/spool/cups-pdf/ANONYMOUS
AnonUser nobody
UserUMask 0000
Cleanup 0
CONF
sudo systemctl restart cups
# Wait for the scheduler rather than sleeping a fixed interval.
for _ in $(seq 1 60); do
lpstat -r >/dev/null 2>&1 && break
sleep 0.5
done
lpstat -r
# -m everywhere drives IPP Everywhere and needs a real network
# device; cups-pdf is a local backend and needs its own PPD. Find it
# rather than guessing a path that differs across releases.
PPD=$(find /usr/share/ppd /usr/share/cups/model -name 'CUPS-PDF*.ppd*' 2>/dev/null | head -1)
echo "cups-pdf PPD: ${PPD:-<none found>}"
if [ -n "$PPD" ]; then
sudo lpadmin -p zw-test -E -v cups-pdf:/ -P "$PPD"
else
sudo lpadmin -p zw-test -E -v cups-pdf:/ -m drv:///sample.drv/generic.ppd
fi
sudo cupsenable zw-test
sudo cupsaccept zw-test
# Fail loudly here rather than letting the test report a confusing
# downstream error: no queue means the job below proves nothing.
lpstat -p zw-test || { echo "queue zw-test was not created"; exit 1; }
# cups-pdf creates its per-user output directories on first print,
# mode 0700. Warm it up once so those directories exist, then open
# them for reading — otherwise the test can print successfully and
# still be unable to see what it produced.
echo "warmup" | lp -d zw-test
for _ in $(seq 1 40); do
[ -n "$(sudo find /var/spool/cups-pdf -name '*.pdf' 2>/dev/null)" ] && break
sleep 0.5
done
sudo chmod -R a+rX /var/spool/cups-pdf
sudo find /var/spool/cups-pdf -name '*.pdf' -delete
echo "cups-pdf output tree:"; ls -la /var/spool/cups-pdf
# No version pin: pnpm/action-setup reads packageManager from
# package.json. Specifying both is an error when they disagree, which
# is exactly how this broke before.
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm build
- name: Print real papers through CUPS
env:
ZW_CUPS_URL: http://127.0.0.1:631/printers/zw-test
ZW_CUPS_OUTPUT_DIR: /var/spool/cups-pdf
# Must RUN, not skip: a missing server fails the job.
ZW_REQUIRE_CUPS: "1"
run: pnpm --filter @zw/centre exec vitest run test/cups.test.ts
- name: CUPS error log on failure
if: failure()
run: sudo tail -100 /var/log/cups/error_log || true
deploy-artifacts:
name: deploy artifacts
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Validate YAML
run: |
python3 - <<'PY'
import yaml
for f in [
"deploy/ansible/site.yml",
"deploy/ansible/inventory.example.yml",
"deploy/pilot/docker-compose.yml",
".github/workflows/ci.yml",
]:
list(yaml.safe_load_all(open(f)))
print(f"{f}: OK")
PY
- name: Shellcheck
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends shellcheck
shellcheck deploy/docker/entrypoint.sh \
deploy/pilot/cups/start-cups.sh \
deploy/pilot/run-pilot.sh
- name: Build the container image
run: docker build -f deploy/docker/Dockerfile -t zero-window:ci .
tsa-live:
name: live TSA anchoring
# Third-party services with no SLA: scheduled and manual only, so an
# outage at freetsa.org means this job needs attention rather than an
# unrelated pull request being blocked.
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
# No version pin: pnpm/action-setup reads packageManager from
# package.json. Specifying both is an error when they disagree, which
# is exactly how this broke before.
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm build
- name: Anchor against FreeTSA and DigiCert
env:
ZW_TSA_MODE: live
run: pnpm --filter @zw/log test
- name: Full pilot with live anchoring
run: pnpm pilot --candidates 40 --rederive 6