Repository navigation
371 lines (362 loc) · 19.2 KB
/
Copy pathci.yml
File metadata and controls
371 lines (362 loc) · 19.2 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
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
name: CI
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
permissions:
contents: read
# A newer push to a pull request supersedes the older run. Every push to
# main gets its own group, so a later push never cancels the
# pending run of an earlier one: each pushed commit can be a deploy candidate
# and needs its own full result. A pull request's newer commits do cancel its
# older runs.
concurrency:
group: ci-${{ github.event_name }}-${{ github.event_name == 'push' && github.sha || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
env:
CARGO_TERM_COLOR: never
PYTHONDONTWRITEBYTECODE: 1
jobs:
lint:
if: github.event_name != 'schedule'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
python-version: '3.12'
- name: Install stable Rust and rustfmt
run: |
rustup toolchain install stable --profile minimal --component rustfmt
rustup default stable
- run: cargo fmt --all --check
- name: Check shell scripts
run: |
curl --fail --location --retry 3 https://github.com/koalaman/shellcheck/releases/download/v0.11.0/shellcheck-v0.11.0.linux.x86_64.tar.xz -o "$RUNNER_TEMP/shellcheck.tar.xz"
tar -xJf "$RUNNER_TEMP/shellcheck.tar.xz" -C "$RUNNER_TEMP"
"$RUNNER_TEMP/shellcheck-v0.11.0/shellcheck" --version
"$RUNNER_TEMP/shellcheck-v0.11.0/shellcheck" -x script/*.sh
# These suites use fixture signing and debugger functions, not the real
# codesign, lldb or worker, so they need no Rust build or macOS runner.
- name: Check offline flow rig contracts
run: python3 -m unittest script.tests.flows_rig -v
- name: Check Cargo path dependency boundary
run: |
python3 script/check-path-deps.py
python3 -m unittest script.tests.check_path_deps -v
- name: Check development executable names
run: |
python3 script/check-ckdev-names.py
python3 -m unittest script.tests.check_ckdev_names -v
- name: Check tracked local paths
run: |
python3 script/check-local-paths.py
python3 -m unittest script.tests.check_local_paths -v
- name: Check offline placement cards
run: |
/bin/sh -n script/stage.sh
python3 -m unittest script.tests.stage_card -v
- name: Check worker signing gate and core JSON features
run: python3 -m unittest script.tests.sign_worker script.tests.codemode_manifest -v
checks:
if: github.event_name != 'schedule'
# The worker confines itself on macOS (Seatbelt) and on Linux (seccomp and
# Landlock), so every leg runs the worker packages. Their macOS-only probes
# (codesign, privacy disclaim) are compiled only on macOS. The Linux
# seccomp filter has a separate syscall table per architecture, so Linux
# runs natively on both x86_64 and aarch64. The lint job handles build-free
# checks.
strategy:
fail-fast: false
matrix:
include:
- platform: linux
os: ubuntu-latest
- platform: linux-arm64
os: ubuntu-24.04-arm
- platform: macos
os: macos-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
python-version: '3.12'
- name: Install stable Rust and analysis components
run: |
rustup toolchain install stable --profile minimal --component rustfmt --component clippy
rustup default stable
- &install-nats
name: Install pinned nats-server v2.15.0
uses: ./.github/actions/install-nats-server
- name: Record installed Rust version
id: rust
run: echo "version=$(rustc --version | cut -d ' ' -f 2)" >> "$GITHUB_OUTPUT"
- name: Restore Cargo build cache
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-${{ runner.arch }}-cargo-${{ hashFiles('Cargo.lock') }}-${{ steps.rust.outputs.version }}-checks-main-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-${{ runner.arch }}-cargo-${{ hashFiles('Cargo.lock') }}-${{ steps.rust.outputs.version }}-checks-main-
${{ runner.os }}-${{ runner.arch }}-cargo-${{ hashFiles('Cargo.lock') }}-${{ steps.rust.outputs.version }}-checks-
${{ runner.os }}-${{ runner.arch }}-cargo-${{ hashFiles('Cargo.lock') }}-${{ steps.rust.outputs.version }}-
- &restored-build-size
name: Measure restored build folder
shell: bash
run: du -sk target 2>/dev/null || test ! -d target
- run: cargo clippy --workspace --all-targets -- -D warnings
if: matrix.platform == 'linux'
- run: cargo clippy --workspace --all-targets --features basal-module/rig-kill-hook -- -D warnings
- name: Test portable crates
if: runner.os == 'Linux'
run: cargo test --locked -p basal-proto -p basal-core -p basal-host
# The module feature propagates to basal-host, so portable tests need both
# modes as well. Enable it on the selected host crate without selecting the
# worker-using module. The hook's Linux tests run on x86_64; aarch64
# retains production-mode tests and hook-enabled clippy coverage.
- name: Test portable crates with the rig kill hook
if: matrix.platform == 'linux'
run: cargo test --locked -p basal-proto -p basal-core -p basal-host --features basal-host/rig-kill-hook
# A procfs mounted with hidepid hides the confined worker from its parent,
# and the Linux startup tests then accept a weaker self-reported status.
# GitHub's runners show every process, so require the exact parent-side
# /proc/<pid>/status readback here; the variable has no effect on macOS.
- name: Test confined worker packages
env:
BASAL_REQUIRE_VISIBLE_PROC: ${{ runner.os == 'Linux' && '1' || '' }}
run: cargo test --locked -p basal-worker -p basal-module -p basal-testkit -p basal-rig
- name: Test confined worker packages with the rig kill hook
if: matrix.platform != 'linux-arm64'
env:
BASAL_REQUIRE_VISIBLE_PROC: ${{ runner.os == 'Linux' && '1' || '' }}
run: cargo test --locked -p basal-worker -p basal-module -p basal-testkit -p basal-rig --features basal-module/rig-kill-hook
- &final-build-size
name: Measure final build folder
shell: bash
run: du -sk target
# Cache entries are immutable. Only main publishes a new run-scoped entry;
# PRs read the newest main prefix without consuming cache quota.
- name: Save Cargo build cache
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-${{ runner.arch }}-cargo-${{ hashFiles('Cargo.lock') }}-${{ steps.rust.outputs.version }}-checks-main-${{ github.run_id }}
# Native aarch64 evidence for the Linux seccomp allowlist. The filter has a
# separate aarch64 syscall table, and only a native trace shows which calls
# glibc and the release worker actually make there. The script fails when no
# confined worker was traced or a panic/abort probe misbehaves; its reduced
# traces are uploaded for review against
# crates/basal-worker/sandbox/linux/syscall-admission.md.
aarch64-syscall-trace:
if: github.event_name != 'schedule'
runs-on: ubuntu-24.04-arm
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Install stable Rust and strace
run: |
rustup toolchain install stable --profile minimal
rustup default stable
sudo apt-get update
sudo apt-get install --yes --no-install-recommends strace
- name: Trace the native release worker
run: |
rm -rf crates/basal-worker/sandbox/linux/traces/aarch64
env -u BASAL_WORKER_BIN bash crates/basal-worker/sandbox/linux/trace-native.sh
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
if: always()
with:
name: syscall-trace-aarch64
path: crates/basal-worker/sandbox/linux/traces/aarch64
if-no-files-found: error
minimum-rust:
if: github.event_name != 'schedule'
# Builds every workspace target at the declared minimum Rust version. It
# only compiles, so it needs no macOS: nothing here starts the flow
# worker, whose sandbox exists on macOS.
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Install the declared minimum Rust
run: rustup toolchain install 1.89.0 --profile minimal
- name: Record installed Rust version
id: rust
run: echo "version=$(rustc +1.89.0 --version | cut -d ' ' -f 2)" >> "$GITHUB_OUTPUT"
- name: Restore Cargo build cache
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-${{ runner.arch }}-cargo-${{ hashFiles('Cargo.lock') }}-${{ steps.rust.outputs.version }}-minimum-main-${{ github.run_id }}
restore-keys: |
${{ runner.os }}-${{ runner.arch }}-cargo-${{ hashFiles('Cargo.lock') }}-${{ steps.rust.outputs.version }}-minimum-main-
${{ runner.os }}-${{ runner.arch }}-cargo-${{ hashFiles('Cargo.lock') }}-${{ steps.rust.outputs.version }}-minimum-
${{ runner.os }}-${{ runner.arch }}-cargo-${{ hashFiles('Cargo.lock') }}-${{ steps.rust.outputs.version }}-
- *restored-build-size
- name: Build every target with the declared minimum Rust
run: |
cargo +1.89.0 check --workspace --all-targets --locked
cargo +1.89.0 check --workspace --all-targets --locked --features basal-module/rig-kill-hook
- *final-build-size
- name: Save Cargo build cache
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-${{ runner.arch }}-cargo-${{ hashFiles('Cargo.lock') }}-${{ steps.rust.outputs.version }}-minimum-main-${{ github.run_id }}
# Each Windows image leaves a different set of loader and thread-pool handles
# in the worker, so both must exercise the startup allowlist. Native suites
# also exercise the launcher, worker probes and filesystem/Git guards. Two
# package groups run in parallel per image; logs survive failed gates.
windows-baseline:
if: github.event_name != 'schedule'
strategy:
fail-fast: false
matrix:
os: [windows-latest, windows-2022]
suite: [launch-worker-host, module-core-testkit-rig]
runs-on: ${{ matrix.os }}
timeout-minutes: 120
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- *install-nats
- name: Install stable Rust
run: |
rustup toolchain install stable --profile minimal
rustup default stable
rustc --version
cargo --version
- name: Record installed Rust version
id: rust
run: echo "version=$(rustc --version | cut -d ' ' -f 2)" >> "$GITHUB_OUTPUT"
- name: Restore Cargo build cache
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-${{ runner.arch }}-cargo-${{ hashFiles('Cargo.lock') }}-${{ steps.rust.outputs.version }}-windows-baseline-${{ matrix.os }}-main-${{ github.run_id }}-${{ matrix.suite }}
restore-keys: |
${{ runner.os }}-${{ runner.arch }}-cargo-${{ hashFiles('Cargo.lock') }}-${{ steps.rust.outputs.version }}-windows-baseline-${{ matrix.os }}-main-
${{ runner.os }}-${{ runner.arch }}-cargo-${{ hashFiles('Cargo.lock') }}-${{ steps.rust.outputs.version }}-windows-baseline-${{ matrix.os }}-
- *restored-build-size
- name: Prepare the log directory
run: mkdir -p "$RUNNER_TEMP/windows-baseline"
# The Windows launcher's own tests start real confined children, so
# they can only run here. The deviations feature adds the test-only
# launch variants, one per confinement check. They run first and print
# what the parent read back, so the log shows it even when the
# workspace steps below fail.
- name: Test the Windows launcher with its test variants
if: matrix.suite == 'launch-worker-host'
id: test-launch
timeout-minutes: 20
run: |
cargo test -p basal-launch --locked -- --show-output 2>&1 | tee "$RUNNER_TEMP/windows-baseline/test-basal-launch-production.log"
cargo test -p basal-launch --features deviations --locked -- --show-output 2>&1 | tee "$RUNNER_TEMP/windows-baseline/test-basal-launch.log"
# The worker's tests on their own: its Windows startup checks, its image
# and a real activation, each worker started through the launcher. The
# plain build is the production worker, which must refuse the
# launcher's request to skip a check. The deviations build is a test
# worker that honours that request, for the three checks the parent
# cannot break from outside.
- name: Test the worker on its own
if: matrix.suite == 'launch-worker-host'
id: test-worker
timeout-minutes: 30
run: cargo test -p basal-worker --locked --no-fail-fast -- --show-output 2>&1 | tee "$RUNNER_TEMP/windows-baseline/test-basal-worker.log"
- name: Test the worker with its test variants
if: matrix.suite == 'launch-worker-host'
id: test-worker-deviations
timeout-minutes: 30
run: cargo test -p basal-worker --features deviations --locked --no-fail-fast -- --show-output 2>&1 | tee "$RUNNER_TEMP/windows-baseline/test-basal-worker-deviations.log"
# The module's tests: workers started, supervised and killed through
# the launcher; worker deaths from a confinement fault (an invalid
# handle or access violation) counted apart from other crashes; and
# the store directory and database readable by their owner only.
# basal-core's tests run with them: the module's store and runtime
# are basal-core's.
- name: Test the module and the core
if: matrix.suite == 'module-core-testkit-rig'
id: test-module
timeout-minutes: 40
run: cargo test -p basal-module -p basal-core --locked --no-fail-fast -- --show-output 2>&1 | tee "$RUNNER_TEMP/windows-baseline/test-basal-module.log"
- name: Test the shared test kit on its own
if: matrix.suite == 'module-core-testkit-rig'
id: test-testkit
timeout-minutes: 30
run: cargo test -p basal-testkit --locked --no-fail-fast 2>&1 | tee "$RUNNER_TEMP/windows-baseline/test-basal-testkit.log"
- name: Test the integration rig on its own
if: matrix.suite == 'module-core-testkit-rig'
id: test-rig
timeout-minutes: 30
run: cargo test -p basal-rig --locked --no-fail-fast 2>&1 | tee "$RUNNER_TEMP/windows-baseline/test-basal-rig.log"
- name: Check every workspace target
if: matrix.suite == 'module-core-testkit-rig'
id: check
timeout-minutes: 40
run: cargo check --workspace --all-targets --locked 2>&1 | tee "$RUNNER_TEMP/windows-baseline/check.log"
- name: Check every workspace target, continuing past failed crates
if: failure() && matrix.suite == 'module-core-testkit-rig' && steps.check.outcome == 'failure'
timeout-minutes: 40
run: cargo check --workspace --all-targets --locked --keep-going 2>&1 | tee "$RUNNER_TEMP/windows-baseline/check-keep-going.log"
# The rest of the workspace: every package not already tested by its own
# step above. Testing those again doubled the job's time, and on a slow
# runner pushed this step past its limit.
- name: Test the workspace
if: matrix.suite == 'launch-worker-host'
id: test
timeout-minutes: 40
run: cargo test --workspace --exclude basal-launch --exclude basal-worker --exclude basal-module --exclude basal-core --exclude basal-testkit --exclude basal-rig --locked 2>&1 | tee "$RUNNER_TEMP/windows-baseline/test.log"
- name: Test the workspace, continuing past failed tests
if: failure() && matrix.suite == 'launch-worker-host' && steps.test.outcome == 'failure'
timeout-minutes: 40
run: cargo test --workspace --exclude basal-launch --exclude basal-worker --exclude basal-module --exclude basal-core --exclude basal-testkit --exclude basal-rig --locked --no-fail-fast 2>&1 | tee "$RUNNER_TEMP/windows-baseline/test-no-fail-fast.log"
- *final-build-size
- name: Save Cargo build cache
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-${{ runner.arch }}-cargo-${{ hashFiles('Cargo.lock') }}-${{ steps.rust.outputs.version }}-windows-baseline-${{ matrix.os }}-main-${{ github.run_id }}-${{ matrix.suite }}
- name: Summarize the Windows gates
if: always()
run: |
{
echo "## Windows gates (${{ matrix.os }}, ${{ matrix.suite }}, $(rustc --version))"
echo
echo "- cargo check --workspace --all-targets --locked: ${{ steps.check.outcome }}"
echo "- cargo test --workspace --locked: ${{ steps.test.outcome }}"
echo "- cargo test -p basal-launch --features deviations --locked: ${{ steps.test-launch.outcome }}"
echo "- cargo test -p basal-module -p basal-core --locked --no-fail-fast: ${{ steps.test-module.outcome }}"
echo "- cargo test -p basal-worker --locked: ${{ steps.test-worker.outcome }}"
echo "- cargo test -p basal-worker --features deviations --locked: ${{ steps.test-worker-deviations.outcome }}"
echo "- cargo test -p basal-testkit --locked --no-fail-fast: ${{ steps.test-testkit.outcome }}"
echo "- cargo test -p basal-rig --locked --no-fail-fast: ${{ steps.test-rig.outcome }}"
} >> "$GITHUB_STEP_SUMMARY"
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
if: always()
with:
name: windows-baseline-logs-${{ matrix.os }}-${{ matrix.suite }}
path: ${{ runner.temp }}/windows-baseline
if-no-files-found: error