chore: setup nixos runners
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
# Labels the self-hosted NixOS microVM runners register with.
|
||||
self-hosted-runner:
|
||||
labels:
|
||||
- nixos
|
||||
- microvm
|
||||
- audited
|
||||
+55
-77
@@ -12,6 +12,15 @@ on:
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
# Every job runs on the self-hosted NixOS microVM runners, and every `run:`
|
||||
# step inside the flake's `ci` dev shell. Generic-Linux downloads (rustup,
|
||||
# setup-node's node, Playwright's browsers) cannot run on NixOS, so the
|
||||
# toolchain comes from flake.nix, the same one `nix develop` gives locally.
|
||||
# Each step re-enters the shell; after the first, the eval cache makes it cheap.
|
||||
defaults:
|
||||
run:
|
||||
shell: nix develop .#ci --command bash --noprofile --norc -eo pipefail {0}
|
||||
|
||||
jobs:
|
||||
# ---------------------------------------------------------------------------
|
||||
# The one place wasm-pack runs (improvise CI dedup).
|
||||
@@ -35,7 +44,7 @@ jobs:
|
||||
# would serialise a 109s job behind a 126s one for no artifact at all.
|
||||
build:
|
||||
name: Build all bundles
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: [self-hosted, nixos, microvm]
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
# First, because it needs nothing and takes a second: the gate that stops
|
||||
@@ -44,9 +53,10 @@ jobs:
|
||||
# below, so it fails under this job's name rather than another's.
|
||||
- name: The stamp gate refuses what it claims to
|
||||
run: ./scripts/checkers.sh assemble-stamp
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: wasm32-unknown-unknown
|
||||
# rust-cache is a JS action: it runs outside the dev shell, and needs
|
||||
# cargo and rustc on the job's PATH to compute its key.
|
||||
- name: Put the dev shell's toolchain on PATH for actions
|
||||
run: dirname "$(command -v cargo)" >> "$GITHUB_PATH"
|
||||
# Two workspaces, because `harness/opfs-contract` carries an empty
|
||||
# `[workspace]` table and so has its own target dir, which the default
|
||||
# single-workspace configuration never cached (it recompiled its whole
|
||||
@@ -56,34 +66,21 @@ jobs:
|
||||
workspaces: |
|
||||
. -> target
|
||||
harness/opfs-contract -> target
|
||||
# One home for the two pins, so the release capture
|
||||
# (scripts/build-web-release.sh, improvise-oujb) provisions the same
|
||||
# versions rather than a second copy free to go stale. The grep keeps a
|
||||
# comment or a blank line out of $GITHUB_ENV, which takes NAME=VALUE only.
|
||||
- name: Pinned web toolchain versions
|
||||
run: grep -E '^[A-Z_]+=' scripts/web-toolchain-versions.env >> "$GITHUB_ENV"
|
||||
|
||||
# Pinned release binary rather than `cargo install` (a three-minute
|
||||
# source build) or a third-party action. wasm-pack runs its own bundled
|
||||
# `wasm-opt`, which is why improvise-wasm-client's Cargo.toml names
|
||||
# `--enable-bulk-memory`: without it the optimizer rejects the
|
||||
# `memory.copy` LLVM emits regardless.
|
||||
# v0.15.0 is what `nix develop` supplies, and the bundle was built and
|
||||
# measured against it locally (346 KB, 120 KB gzipped). Pinning the same
|
||||
# version is what makes that local run evidence about this one.
|
||||
- name: Install wasm-pack
|
||||
# scripts/web-toolchain-versions.env stays the one home for the pins, so
|
||||
# the release capture (scripts/build-web-release.sh, improvise-oujb)
|
||||
# provisions the same versions. CI no longer installs them — the dev
|
||||
# shell supplies wasm-pack and node — so this checks the shell against
|
||||
# the pins instead: a nixpkgs bump that moves either fails here, by name.
|
||||
# wasm-pack runs its own bundled `wasm-opt`, which is why
|
||||
# improvise-wasm-client's Cargo.toml names `--enable-bulk-memory`.
|
||||
- name: The dev shell supplies the pinned web toolchain
|
||||
run: |
|
||||
set -eu
|
||||
url="https://github.com/rustwasm/wasm-pack/releases/download/${WASM_PACK_VERSION}/wasm-pack-${WASM_PACK_VERSION}-x86_64-unknown-linux-musl.tar.gz"
|
||||
curl -sSfL "$url" | tar -xz --strip-components=1 -C /usr/local/bin \
|
||||
"wasm-pack-${WASM_PACK_VERSION}-x86_64-unknown-linux-musl/wasm-pack"
|
||||
. scripts/web-toolchain-versions.env
|
||||
test "$(wasm-pack --version)" = "wasm-pack ${WASM_PACK_VERSION#v}"
|
||||
test "$(node -p 'process.versions.node.split(".")[0]')" = "$NODE_VERSION"
|
||||
wasm-pack --version
|
||||
|
||||
# Both assemblies below generate the prose site with node. The runner
|
||||
# image ships one, but pinning it is what makes a local run evidence.
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
node --version
|
||||
|
||||
# The same script a developer runs locally, so there is one answer to
|
||||
# "how is the bundle built" rather than two that can drift. It builds all
|
||||
@@ -133,12 +130,11 @@ jobs:
|
||||
|
||||
test:
|
||||
name: Test and lint (host)
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: [self-hosted, nixos, microvm]
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
components: clippy, rustfmt
|
||||
- name: Put the dev shell's toolchain on PATH for actions
|
||||
run: dirname "$(command -v cargo)" >> "$GITHUB_PATH"
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
# NOT `cargo fmt --all`, which reaches only ONE of the two workspace
|
||||
# roots. Exit 2 here is a usage error, never a verdict (improvise-b4ks).
|
||||
@@ -187,12 +183,11 @@ jobs:
|
||||
|
||||
wasm:
|
||||
name: wasm32 check (browser bundle crates)
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: [self-hosted, nixos, microvm]
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: wasm32-unknown-unknown
|
||||
- name: Put the dev shell's toolchain on PATH for actions
|
||||
run: dirname "$(command -v cargo)" >> "$GITHUB_PATH"
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
# Only the crates that go into the browser bundle. The root `improvise`
|
||||
# crate is the terminal binary and depends on crossterm, which does not
|
||||
@@ -229,15 +224,12 @@ jobs:
|
||||
# here is a decision `web/shell.js` or `web/serial.js` got wrong, and
|
||||
# reporting that as "Browser harness" would put it behind an 80 MB browser
|
||||
# download and two wasm-pack builds. It needs neither — `node --test` is in
|
||||
# the runtime, and this job installs nothing at all.
|
||||
# the runtime, which the dev shell supplies; this job installs nothing.
|
||||
js:
|
||||
name: Browser JS unit tests (node --test)
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: [self-hosted, nixos, microvm]
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
# The glob is the SCRIPT's, not the shell's and not node's. Under bash an
|
||||
# unmatched glob survives as a literal, node globs it, matches nothing and
|
||||
# exits 0 having run no test -- so this step gated nothing the moment
|
||||
@@ -252,23 +244,23 @@ jobs:
|
||||
|
||||
kb:
|
||||
name: Knowledge base consistency
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: [self-hosted, nixos, microvm]
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: cachix/install-nix-action@v31
|
||||
# kb.pl is executable knowledge, so it gets checked like code: rules
|
||||
# must reject what they should, domains must close, and functional keys
|
||||
# must not carry conflicting values. See kb_report/0 in the file.
|
||||
# trealla comes from the dev shell, as it does locally.
|
||||
- name: kb_consistent
|
||||
run: |
|
||||
nix shell nixpkgs#trealla --command tpl prolog-sessions/kb.pl \
|
||||
tpl prolog-sessions/kb.pl \
|
||||
-g "(kb_consistent -> halt(0) ; (kb_report, halt(1)))"
|
||||
# scripts/kb is the only thing that writes kb.pl, so its refusals are as
|
||||
# load-bearing as kb_consistent itself. Without this the replacement
|
||||
# writer could regress green -- the review that found the directive
|
||||
# bypass also found that nothing ran this suite.
|
||||
- name: The kb tool refuses what it claims to
|
||||
run: nix shell nixpkgs#trealla --command ./scripts/checkers.sh kb
|
||||
run: ./scripts/checkers.sh kb
|
||||
# Every suite goes through scripts/checkers.sh, which pins a bash >= 5
|
||||
# and scrubs the environment, so the shell and the variables a suite
|
||||
# passes under here are the ones it passes under locally (improvise-f9qf).
|
||||
@@ -301,13 +293,11 @@ jobs:
|
||||
# failed the *Browser harness* job. `-p opfs-contract` scopes it to 1 file.
|
||||
harness-lint:
|
||||
name: Lint the harness crate
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: [self-hosted, nixos, microvm]
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: wasm32-unknown-unknown
|
||||
components: clippy, rustfmt
|
||||
- name: Put the dev shell's toolchain on PATH for actions
|
||||
run: dirname "$(command -v cargo)" >> "$GITHUB_PATH"
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
workspaces: harness/opfs-contract -> target
|
||||
@@ -335,37 +325,25 @@ jobs:
|
||||
browser:
|
||||
name: Browser harness (OPFS contract + shell)
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: [self-hosted, nixos, microvm]
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
- name: Install the harness
|
||||
working-directory: harness
|
||||
run: npm ci
|
||||
# Keyed on the resolved @playwright/test version, so a version bump is a
|
||||
# miss and anything else is a hit. The download was 50s on run
|
||||
# 35535225637 and is pure I/O — nothing about it depends on this commit.
|
||||
- name: Playwright version
|
||||
id: pw
|
||||
# No browser install step: the dev shell points PLAYWRIGHT_BROWSERS_PATH
|
||||
# at nixpkgs' Chromium, Firefox and WebKit, since Playwright's own
|
||||
# downloads cannot run on NixOS. All three, because improvise-xf1's
|
||||
# acceptance criterion names Chrome, Firefox and Safari and
|
||||
# `createSyncAccessHandle` is implemented separately by each engine.
|
||||
# WebKit's OPFS is absent today; the spec skips on a runtime probe.
|
||||
# @playwright/test must equal nixpkgs' playwright-driver version, or it
|
||||
# looks for browser builds that are not there; this says which.
|
||||
- name: Playwright matches the dev shell's browsers
|
||||
working-directory: harness
|
||||
run: echo "v=$(node -p "require('@playwright/test/package.json').version")" >> "$GITHUB_OUTPUT"
|
||||
- uses: actions/cache@v4
|
||||
id: pw-cache
|
||||
with:
|
||||
path: ~/.cache/ms-playwright
|
||||
key: playwright-${{ runner.os }}-${{ steps.pw.outputs.v }}
|
||||
# All three, because improvise-xf1's acceptance criterion names Chrome,
|
||||
# Firefox and Safari and `createSyncAccessHandle` is implemented
|
||||
# separately by each engine. WebKit is installed even though its OPFS is
|
||||
# absent today: the spec skips on a runtime probe, so the day that build
|
||||
# gains OPFS the check starts running without a CI change.
|
||||
# `--with-deps` installs apt packages OUTSIDE the cached directory, so it
|
||||
# runs on a cache hit too; only the browser download is skipped.
|
||||
- name: Install browsers
|
||||
working-directory: harness
|
||||
run: npx playwright install --with-deps chromium firefox webkit
|
||||
run: |
|
||||
npx playwright --version
|
||||
ls "$PLAYWRIGHT_BROWSERS_PATH"
|
||||
# The tree `build` assembled, not one this job rebuilds. Same bytes as
|
||||
# the Pages artifact, modulo the cache-bust token `web/assemble.sh`
|
||||
# stamps — the harness tree is stamped `harness` and the site the commit
|
||||
@@ -434,7 +412,7 @@ jobs:
|
||||
name: Deploy to GitHub Pages
|
||||
needs: [test, wasm, js, browser, harness-lint, kb, build]
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: [self-hosted, nixos, microvm]
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
|
||||
@@ -36,12 +36,47 @@
|
||||
cargoNix = import ./Cargo.nix {
|
||||
inherit nixpkgs pkgs;
|
||||
};
|
||||
# Everything CI runs, and nothing else: `devShells.ci` is exactly this,
|
||||
# and the default shell is this plus editor and release tooling, so a
|
||||
# local `nix develop` runs the toolchain the checks run.
|
||||
ciInputs = [
|
||||
rustToolchain
|
||||
pkgs.pkg-config
|
||||
|
||||
# `scripts/kb` and the CI knowledge-base check both run trealla. It
|
||||
# was reached through `nix shell nixpkgs#trealla` per invocation,
|
||||
# which cost more than the work: the tool's first real use took past
|
||||
# two minutes for a write that takes half a second on PATH.
|
||||
pkgs.trealla
|
||||
|
||||
# `web/build.sh` — and so the Pages job's local dry run — needs this.
|
||||
# The `wasm` CI job only runs `cargo check`, which does not, so the
|
||||
# shell was missing the one tool that turns a passing check into a
|
||||
# loadable page (improvise-d31). Must match WASM_PACK_VERSION in
|
||||
# scripts/web-toolchain-versions.env; CI checks that it does.
|
||||
pkgs.wasm-pack
|
||||
|
||||
# NODE_VERSION's major, same check. The js and browser jobs ran 22
|
||||
# while `build` ran the pinned 24; one shell means one node.
|
||||
pkgs.nodejs_24
|
||||
pkgs.python3
|
||||
pkgs.jq
|
||||
];
|
||||
|
||||
# Playwright's downloaded browsers are generic-Linux builds that cannot
|
||||
# start on NixOS, so nixpkgs' build is used. harness/package.json pins
|
||||
# @playwright/test to this playwright-driver's version: they must match.
|
||||
playwrightEnv = {
|
||||
PLAYWRIGHT_BROWSERS_PATH = "${pkgs.playwright-driver.browsers}";
|
||||
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD = "1";
|
||||
PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS = "true";
|
||||
RUST_BACKTRACE = "1";
|
||||
};
|
||||
in {
|
||||
inherit cargoNix;
|
||||
devShells.default = pkgs.mkShell {
|
||||
nativeBuildInputs = [
|
||||
rustToolchain
|
||||
pkgs.pkg-config
|
||||
devShells.ci = pkgs.mkShell (playwrightEnv // {nativeBuildInputs = ciInputs;});
|
||||
devShells.default = pkgs.mkShell (playwrightEnv // {
|
||||
nativeBuildInputs = ciInputs ++ [
|
||||
pkgs.rust-analyzer
|
||||
crate2nix.packages.${system}.default
|
||||
pkgs.cargo-expand
|
||||
@@ -50,18 +85,6 @@
|
||||
pkgs.universal-ctags
|
||||
beads.packages.${system}.default
|
||||
|
||||
# `scripts/kb` and the CI knowledge-base check both run trealla. It
|
||||
# was reached through `nix shell nixpkgs#trealla` per invocation,
|
||||
# which cost more than the work: the tool's first real use took past
|
||||
# two minutes for a write that takes half a second on PATH.
|
||||
pkgs.trealla
|
||||
|
||||
# `web/build.sh` — and so the Pages job's local dry run — needs this.
|
||||
# The `wasm` CI job only runs `cargo check`, which does not, so the
|
||||
# shell was missing the one tool that turns a passing check into a
|
||||
# loadable page (improvise-d31).
|
||||
pkgs.wasm-pack
|
||||
|
||||
# Demo recording and release tooling
|
||||
pkgs.asciinema
|
||||
pkgs.vhs
|
||||
@@ -69,8 +92,7 @@
|
||||
# nixpkgs cargo-dist installs as "dist"; alias so `cargo dist` works
|
||||
(pkgs.writeShellScriptBin "cargo-dist" ''exec ${pkgs.cargo-dist}/bin/dist "$@"'')
|
||||
];
|
||||
RUST_BACKTRACE = "1";
|
||||
};
|
||||
});
|
||||
|
||||
packages = {
|
||||
improvise = cargoNix.workspaceMembers.improvise.build;
|
||||
|
||||
Generated
+15
-33
@@ -6,70 +6,52 @@
|
||||
"": {
|
||||
"name": "improvise-harness",
|
||||
"devDependencies": {
|
||||
"@playwright/test": "1.56.1"
|
||||
"@playwright/test": "1.63.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@playwright/test": {
|
||||
"version": "1.56.1",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.56.1.tgz",
|
||||
"integrity": "sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==",
|
||||
"version": "1.63.0",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.63.0.tgz",
|
||||
"integrity": "sha512-oxMK4vllB9RK5NQ2l1pq1IfOf2AvnEuj/vYGDj0H2nMtmtZpKtCwt/l00GEO6xjGfpBNAvjovvYdCm50dRQkpQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright": "1.56.1"
|
||||
"playwright": "1.63.0"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright": {
|
||||
"version": "1.56.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.1.tgz",
|
||||
"integrity": "sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==",
|
||||
"version": "1.63.0",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.63.0.tgz",
|
||||
"integrity": "sha512-+7ziBLidS4NaNCdt57SUDT+wYmmd5fmiQejUic/kb+YsYSCPyOOE9sebzMjNmQrsnNpDJqd4WHvV/8lfKfUDUg==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright-core": "1.56.1"
|
||||
"playwright-core": "1.63.0"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "2.3.2"
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright-core": {
|
||||
"version": "1.56.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.1.tgz",
|
||||
"integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==",
|
||||
"version": "1.63.0",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.63.0.tgz",
|
||||
"integrity": "sha512-rYCsBF/M5HjUch52bbtVONEFjv6Xu8sm8h72dNlR5bzIE1fvC/bxgspzkjSfU+MweEMmPM8KJebG6nnyxo5mCg==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"playwright-core": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
"node": ">=20"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,6 @@
|
||||
"test": "playwright test"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "1.56.1"
|
||||
"@playwright/test": "1.63.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,9 +133,15 @@ EOF
|
||||
chmod +x "$work/fakebin/bash"
|
||||
# The runner is invoked through a REAL bash, so the fake one below is only
|
||||
# what its own `command -v bash` probe finds -- not its interpreter.
|
||||
# /usr/bin:/bin carries the utilities the runner itself needs and carries no
|
||||
# nix, so the fake bash is the only candidate and the nix fallback is absent.
|
||||
env PATH="$work/fakebin:/usr/bin:/bin" HOME="$HOME" \
|
||||
# utilbin carries only the utilities the runner itself needs, and no nix, so
|
||||
# the fake bash is the only candidate and the nix fallback is absent. Linked
|
||||
# one by one rather than taking /usr/bin:/bin, which on NixOS hold only `env`
|
||||
# and `sh` -- the runner died on `dirname` there, exit 1 instead of 3.
|
||||
mkdir -p "$work/utilbin"
|
||||
for tool in dirname; do
|
||||
ln -sf "$(command -v "$tool")" "$work/utilbin/$tool"
|
||||
done
|
||||
env PATH="$work/fakebin:$work/utilbin" HOME="$HOME" \
|
||||
"${BASH:-bash}" "$d/checkers.sh" any > "$work/out" 2>&1
|
||||
got=$?
|
||||
[ "$got" = 3 ] && ok "an old bash with no nix is exit 3" \
|
||||
|
||||
Reference in New Issue
Block a user