Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
80f4c94
ci: the guest suite is a pull request's `guest` check, on this tree's…
Japabu Oct 1, 2026
09bda2f
Merge origin/main (#668, #670) into wt/toyos-guestci
Japabu Oct 1, 2026
da7c7c0
issues: the two reds CI's guest check found at main's tree
Japabu Oct 1, 2026
2a0e045
issues: the nested-NMI interleave is green under TCG on a runner too
Japabu Oct 1, 2026
9ad2b97
Merge remote-tracking branch 'origin/main' into wt/toyos-guestci
Japabu Oct 1, 2026
90a989e
Review round 2: only main publishes, CI installs only what a digest a…
Japabu Oct 1, 2026
88b5487
release: the publisher's refusal is tested at the release job's own e…
Japabu Oct 1, 2026
9a39342
release: the tag test moves each builder from its source, so a tag th…
Japabu Oct 1, 2026
1077064
Toolchain stores keep what builds read: a lean LLVM, no hosted rustc …
Japabu Oct 1, 2026
0237a67
A lean compiler build that runs: no codegen test, and rust-objcopy on…
Japabu Oct 1, 2026
9ce37f2
Merge origin/main (#673) into wt/toyos-guestci
Japabu Oct 1, 2026
c156450
issues: the two reds main's guest lanes found stay until main's night…
Japabu Oct 1, 2026
6441727
Toolchain stores are cache entries by the build system's own keys, an…
Japabu Oct 1, 2026
8a219c1
The workflow rules are the reviewer's to read, not gates over the YAML
Japabu Oct 1, 2026
30c53c5
issues: CI no longer installs the published release, so the AArch64 r…
Japabu Oct 1, 2026
6f31d0a
Merge origin/main (#675) into wt/toyos-guestci
Japabu Oct 1, 2026
64d6036
issues: the nested-NMI report is written under the console's register…
Japabu Oct 1, 2026
9e917f1
A key names a submodule by the commit its gitlink records, checked ou…
Japabu Oct 1, 2026
252c49e
The release speaks to GitHub through ureq and packs gzip through flate2
Japabu Oct 1, 2026
ccecfd5
File that a store's build code moves its key only through a RECIPE bu…
Japabu Oct 1, 2026
74ee3fc
Main builds one toolchain key at a time, and a merge group saves only…
Japabu Oct 1, 2026
1a4f3ab
Review round 3's REMOVEs
Japabu Oct 1, 2026
f1ccb0b
Merge origin/main (#677) into wt/toyos-guestci
Japabu Oct 1, 2026
01c1fd6
Merge origin/main (#678, #669) into wt/toyos-guestci
Japabu Oct 2, 2026
2f48926
Merge origin/main (#650, #653) into wt/toyos-guestci
Japabu Oct 2, 2026
62999d9
The nightly's release is skipped off main, and a toolchain job that w…
Japabu Oct 2, 2026
404df2c
File the two compromises the toolchain job keeps, and close the two k…
Japabu Oct 2, 2026
42a823b
Review round 4's REMOVE: compile_error_at's doc is its first line
Japabu Oct 2, 2026
7f2721a
Merge origin/main (#643, #664, #679, #659) into wt/toyos-guestci
Japabu Oct 2, 2026
cb19bca
The build system's HTTP agent is rustls on ring
Japabu Oct 2, 2026
585e6ea
A landing on main during a nightly is not that nightly's failure
Japabu Oct 2, 2026
3f59d1c
Two kernel issues no longer call the KVM guests the nightly's
Japabu Oct 2, 2026
482d487
The landing test takes the landing that moves the SDK first
Japabu Oct 2, 2026
68dc21c
ring is the provider the tree takes, not yet its only one
Japabu Oct 2, 2026
bf9983a
The release decision's two weaknesses are filed
Japabu Oct 2, 2026
e99547a
Two more issues no longer call the EPYC guests the nightly's
Japabu Oct 2, 2026
281602b
The TLS stage says which builds compile no ring
Japabu Oct 2, 2026
a305253
The capture issue names the KVM runners, and the unrequired guest che…
Japabu Oct 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions .claude/agents/reviewer.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,10 @@ if it meets the bar above; otherwise it is a NOTE.
saying what it is; a new cargo feature or `cfg` arm of one, or an arm a changed `src/clippy.rs`
shape stops building, that no shape in `src/clippy.rs` lints; an `issues/` file added, changed
or deleted against `issues/README.md`.
- **Caches.** No gate reads these; a diff that breaks one is a BLOCKER. Each cache has one
writer, a nightly.yml job, and no workflow uses the combined `actions/cache`, which saves too;
the host cache's is nightly's `host`, and its one reader ci.yml's `host`, on the same
`runs-on`, both caching `src/cicache.rs`'s `PATHS` with its `DRIVER` as their
- **Caches.** No gate reads these; a diff that breaks one is a BLOCKER. No workflow uses the
combined `actions/cache`, which saves too. The host cache has one writer, nightly's `host`,
and one reader, ci.yml's `host`, on the same `runs-on`, both caching `src/cicache.rs`'s
`PATHS` with its `DRIVER` as their
`CARGO_TARGET_DIR`, the one variable an `env:` gives either: an `ImageOS` or `ImageVersion`
set there outlives an image move. The reader's `restore-keys` is the writer's `key` up to its
run id. A job that names the host cache runs `actions/checkout`, its cache step and
Expand All @@ -89,6 +89,13 @@ if it meets the bar above; otherwise it is a NOTE.
skips only a draft, and nightly's `host` has no `if:` of its own, a skipped job being a green
check. No `continue-on-error`, `shell:`, `defaults:` or cargo `runner` reaches them.
nightly.yml's `on:` is one daily `schedule` and `workflow_dispatch`.
- **Workflows.** A BLOCKER each:
- Only main's runs save a cache entry other refs restore: GitHub's cache scoping is every entry's provenance.
- `nightly.yml`'s `release` is the only job granted `contents: write`.
- No workflow runs on `pull_request_target`, `workflow_run`, `issue_comment` or any other trigger that runs code other than main's on main's ref.
- No workflow or job declares `cache-mode: write` or `write-only`.
- `guest / suite` has no job-level `if:`, and a job that calls it runs whatever `toolchain` concluded: a skipped required check reads as green.
- A job that saves a cache entry runs only `cargo run -- --ci <job>`.
- **Growth.** Every line is a responsibility, not an asset. State the branch's net lines
(`git diff --shortstat origin/main...<head>`), production and tests apart. Production code that
grows needs a reason you accept; a branch that could delete more than it adds and does not goes
Expand Down
4 changes: 2 additions & 2 deletions .github/qemu-version
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
# build system's prerequisite check. The version decides test outcomes — 8.2.2
# and 11.0.3 were measured disagreeing about the same tree — so this is a
# declaration the guest image is held to, never a fact read off it. The image
# digest in nightly.yml is chosen to satisfy this line; changing either is a
# deliberate act: it says the instrument moved.
# digest is chosen to satisfy this line; changing either is a deliberate act:
# it says the instrument moved.
11.1.1
22 changes: 19 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
name: ci

# A pull request and the merge queue: the host tests, and no guest.
# nightly.yml boots the guests.

on:
pull_request:
branches: [main]
Expand All @@ -13,6 +10,10 @@ concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

# No job here writes: a toolchain release is main's publisher's alone.
permissions:
contents: read

jobs:
host:
if: github.event_name == 'merge_group' || github.event.pull_request.draft == false
Expand Down Expand Up @@ -42,3 +43,18 @@ jobs:
restore-keys: host-sealed-${{ runner.os }}-${{ runner.arch }}-

- run: cargo run -- --ci host

toolchain:
if: github.event_name == 'merge_group' || github.event.pull_request.draft == false
uses: ./.github/workflows/toolchain.yml

# A required check that is skipped reads as green, so this runs whatever
# `toolchain` concluded.
guest:
needs: toolchain
if: ${{ !cancelled() && (github.event_name == 'merge_group' || github.event.pull_request.draft == false) }}
uses: ./.github/workflows/guest.yml
with:
kvm: true
sysroot-key: ${{ needs.toolchain.outputs.sysroot-key }}
sysroot-path: ${{ needs.toolchain.outputs.sysroot-path }}
74 changes: 74 additions & 0 deletions .github/workflows/guest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
name: guest

on:
workflow_call:
inputs:
# Without it every guest is emulated: the only lane that decodes the paths
# a KVM host's CPU never does.
kvm:
type: boolean
required: true
sysroot-key:
type: string
required: true
sysroot-path:
type: string
required: true

jobs:
suite:
runs-on: ubuntu-24.04
# A wedge guard, not a budget.
timeout-minutes: 60
# The digest is the instrument's one pin: a dated image names the snapshot
# archive it was built from, and `deps` installs QEMU from that archive.
# The node ships `crw-rw---- root:kvm` and root opens it.
container:
image: debian:sid-20260918@sha256:a2aa46262453eba3f464d8b1c7a8c31db85eb15af180ae34dd400615d7208547
options: ${{ inputs.kvm && '--device=/dev/kvm' || '' }}
steps:
# Before the checkout, which wants git. Three attempts, because the
# archive is fixed and the network to it is not.
- name: deps
run: |
snap=$(sed -n 's|^# \(http://snapshot\.debian\.org/archive/debian/[0-9]*T[0-9]*Z\)$|\1|p' \
/etc/apt/sources.list.d/debian.sources)
test -n "$snap"
echo "deb $snap sid main" > /etc/apt/sources.list
rm /etc/apt/sources.list.d/debian.sources
# `zstd`: what the sysroot's restore unpacks the toolchain job's entry with.
for attempt in 1 2 3; do
apt-get -o Acquire::Check-Valid-Until=false update -qq > /tmp/apt.log 2>&1 \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y -qq git curl ca-certificates \
zstd build-essential qemu-system-x86 ovmf-generic qemu-system-arm \
qemu-efi-aarch64 >> /tmp/apt.log 2>&1 \
&& break
[ "$attempt" = 3 ] && { cat /tmp/apt.log; exit 1; }
sleep 20
done
# `actions/checkout` sets this only in a config it discards.
git config --global --add safe.directory "$GITHUB_WORKSPACE"
curl --proto '=https' --tlsv1.2 -sSf -o "$RUNNER_TEMP/rustup-init.sh" https://sh.rustup.rs
sh "$RUNNER_TEMP/rustup-init.sh" -y --profile minimal --default-toolchain stable
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"

- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0

- uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: ${{ inputs.sysroot-path }}
key: ${{ inputs.sysroot-key }}
fail-on-cache-miss: true

- run: cargo run -- --ci guest

# Every boot's 16550 log: what a guest that died early still leaves.
- name: serial logs
if: failure()
continue-on-error: true
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: serial-${{ github.job }}
path: target/red-run-serial/**/uart-*.log
if-no-files-found: warn
retention-days: 7
143 changes: 28 additions & 115 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
name: nightly

# Everything that boots a guest, the host gate again to write the cache the
# merge queue restores, and portability.
# Every job's logic is `cargo run -- --ci <job>` (src/ci.rs); this file says
# where each one runs.

Expand All @@ -10,11 +8,13 @@ on:
- cron: '0 3 * * *'
workflow_dispatch:

# Never cancelled: `build` may be an hour into a bootstrap.
concurrency:
group: nightly-${{ github.ref }}
cancel-in-progress: false

permissions:
contents: read

jobs:
# The host cache's writer restores nothing, and `seal` is green only once
# src/cicache.rs has sealed the tree the save stores.
Expand Down Expand Up @@ -48,126 +48,38 @@ jobs:
bootloader/target
key: host-sealed-${{ runner.os }}-${{ runner.arch }}-${{ github.run_id }}

# Publishes this tree's toolchain if nobody has, and on main moves the SDK
# alias onto it. Bare `ubuntu-24.04`, not a container: its glibc is the
# release's floor.
build:
toolchain:
uses: ./.github/workflows/toolchain.yml

# Skipped off main, where the driver refuses it by name.
release:
needs: toolchain
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-24.04
timeout-minutes: 350
timeout-minutes: 30
permissions:
contents: write
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
with:
fetch-depth: 0

- name: disk, QEMU and CMake
run: |
sudo rm -rf /usr/local/lib/android /usr/share/dotnet /opt/ghc \
/usr/local/share/boost /usr/local/.ghcup
sudo apt-get update -qq
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq qemu-system-x86 zstd \
cmake=3.28.3-1build7
- uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: ${{ needs.toolchain.outputs.sysroot-path }}
key: ${{ needs.toolchain.outputs.sysroot-key }}
fail-on-cache-miss: true

- env:
GH_TOKEN: ${{ github.token }}
run: cargo run -- --ci toolchain
run: cargo run -- --ci release

guest:
needs: build
runs-on: ubuntu-24.04
# A wedge guard, not a budget.
timeout-minutes: 60
# The digest is the instrument's one pin: a dated image names the snapshot
# archive it was built from, and `deps` installs QEMU from that archive.
# The node ships `crw-rw---- root:kvm` and root opens it.
container: &kvm
image: &image debian:sid-20260918@sha256:a2aa46262453eba3f464d8b1c7a8c31db85eb15af180ae34dd400615d7208547
options: --device=/dev/kvm
env:
GH_TOKEN: ${{ github.token }}
steps:
# Before the checkout, which wants git. Three attempts, because the
# archive is fixed and the network to it is not.
- &deps
name: deps
run: |
snap=$(sed -n 's|^# \(http://snapshot\.debian\.org/archive/debian/[0-9]*T[0-9]*Z\)$|\1|p' \
/etc/apt/sources.list.d/debian.sources)
test -n "$snap"
echo "deb $snap sid main" > /etc/apt/sources.list
rm /etc/apt/sources.list.d/debian.sources
for attempt in 1 2 3; do
apt-get -o Acquire::Check-Valid-Until=false update -qq > /tmp/apt.log 2>&1 \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y -qq git curl ca-certificates \
zstd build-essential qemu-system-x86 ovmf-generic qemu-system-arm \
qemu-efi-aarch64 >> /tmp/apt.log 2>&1 \
&& break
[ "$attempt" = 3 ] && { cat /tmp/apt.log; exit 1; }
sleep 20
done
# `actions/checkout` sets this only in a config it discards.
git config --global --add safe.directory "$GITHUB_WORKSPACE"
curl --proto '=https' --tlsv1.2 -sSf -o "$RUNNER_TEMP/rustup-init.sh" https://sh.rustup.rs
sh "$RUNNER_TEMP/rustup-init.sh" -y --profile minimal --default-toolchain stable
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"

- &checkout
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0

- &guest-cache
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: &guest-paths |
~/.cargo/registry/index
~/.cargo/registry/cache
~/.cargo/git/db
target
kernel/target
bootloader/target
userland/target
tests/target
tests/toyos-rust-tests/*/target
key: guest-${{ github.run_id }}
restore-keys: guest-

- run: cargo run -- --ci guest

# Every boot's 16550 log: what a guest that died early still leaves.
- &serial
name: serial logs
if: failure()
continue-on-error: true
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: serial-${{ github.job }}
path: target/red-run-serial/**/uart-*.log
if-no-files-found: warn
retention-days: 7

# The guest suite again with no `/dev/kvm`, so the only lane that decodes the
# paths a KVM host's CPU never does; and the guest cache's one writer, since
# what it builds does not depend on the accelerator.
tcg:
needs: build
runs-on: ubuntu-24.04
timeout-minutes: 60
container:
image: *image
env:
GH_TOKEN: ${{ github.token }}
steps:
- *deps
- *checkout
- *guest-cache
- run: cargo run -- --ci guest
# After the test: what is worth keeping is a tree that built and booted.
- if: github.ref == 'refs/heads/main'
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: *guest-paths
key: guest-${{ github.run_id }}
- *serial
needs: toolchain
if: ${{ !cancelled() }}
uses: ./.github/workflows/guest.yml
with:
kvm: false
sysroot-key: ${{ needs.toolchain.outputs.sysroot-key }}
sysroot-path: ${{ needs.toolchain.outputs.sysroot-path }}

# `cargo run -- --build-only` from a fresh machine. `sid` as it stands,
# image and archive both, and no cache — a fresh machine is the premise.
Expand All @@ -192,9 +104,10 @@ jobs:
sh "$RUNNER_TEMP/rustup-init.sh" -y --profile minimal --default-toolchain stable
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"

- *checkout
- &checkout
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0

- run: env -u GITHUB_ACTIONS -u CI cargo run -- --build-only
- run: cargo run -- --build-only

portability-macos:
runs-on: macos-latest
Expand All @@ -208,6 +121,6 @@ jobs:
curl --proto '=https' --tlsv1.2 -sSf -o "$RUNNER_TEMP/rustup-init.sh" https://sh.rustup.rs
sh "$RUNNER_TEMP/rustup-init.sh" -y --profile minimal --default-toolchain stable
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
- run: env -u GITHUB_ACTIONS -u CI cargo run -- --build-only
- run: cargo run -- --build-only
# The host suite's macOS arms run here alone: `ci.yml`'s `host` is Linux.
- run: cargo run -- --ci host
16 changes: 10 additions & 6 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,6 @@ on:
branches: [main]
workflow_dispatch: {}

# Never two publishers, and never cancel one: a cancelled `cargo publish` may
# have already taken the version.
concurrency:
group: publish
cancel-in-progress: false

permissions:
contents: read
# crates.io trusted publishing: the job trades its OIDC token for a
Expand All @@ -25,6 +19,11 @@ jobs:
publish:
runs-on: ubuntu-latest
timeout-minutes: 30
# Never two publishers, and never cancel one: a cancelled `cargo publish`
# may have already taken the version.
concurrency:
group: publish
cancel-in-progress: false
steps:
# No submodules: `cargo publish` walks the repository's vcs state, and an
# initialised but empty `rust/` breaks that walk.
Expand All @@ -36,3 +35,8 @@ jobs:
- env:
CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
run: cargo run -- --ci publish

toolchain:
permissions:
contents: read
uses: ./.github/workflows/toolchain.yml
Loading
Loading