Stop building a second QEMU and mirroring somebody else's kernel - #3
Merged
Conversation
This repository built a QEMU from a recipe modelled on another project's, against a device list that was byte-for-byte that project's, and carried a Dockerfile.guest-kernel that built nothing at all - it existed to move that project's kernel through a registry and back out, so a machine with no sibling checkout could name one by digest instead of by a relative path into somebody's home directory. That was the plumbing across a repository boundary that spin-machine was created to delete, and this deletes it. Gone: Dockerfile.qemu, hack/qemu-devices.mak, Dockerfile.guest-kernel, hack/guest-kernel.sh, hack/publish-guest-inputs.sh, taskfiles/qemu.yml, the five guest:kernel:* and guest:inputs:* targets, and .github/workflows/qemu.yml. `task machine` puts one machine under _output/ - both qemu-system binaries, qemu-img and the kernel - from a sibling spin-machine checkout or its published release, pinned by version and by SHA-256. The wrapper goes with it, and that is the part worth noticing. qemu:tools extracted the binaries, then computed their library closure inside the image, copied the loader and every .so out, and generated a shell wrapper that invoked that loader - because a dynamically linked QEMU extracted onto a bare runner died with `liburing.so.2: cannot open shared object file`. The release is statically linked, so an extracted tree runs wherever the kernel does and all of that is one `install` now. Two paragraphs of CI comment explaining the problem went too. Verified both ways: from a sibling checkout, and by fetching the real release v20260907.01 with the SHA-256 checked. `task ci` passes, and `task machine` now asserts what it fetched actually runs and that the accelerator split holds - the binary a host runs refuses to emulate, the CI one can. Not verified from here: CI fetching from a private repository. The default GITHUB_TOKEN is scoped to this repository, so the workflow prefers a SPIN_MACHINE_TOKEN secret and says so - `gh release download` failing on permissions reads like a missing tag. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019GHRRFvbnZi5q3KSTvyW5a
The workflow preferred a SPIN_MACHINE_TOKEN secret because the default token is scoped to one repository and spin-machine was private. It is public now, so the default token reads its releases and the fallback, and the paragraph explaining why the failure would read as a missing tag, are both gone. gh still wants a token to run at all, which is the only reason GH_TOKEN is still set. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019GHRRFvbnZi5q3KSTvyW5a
The integration job failed with gh's own advice — "set the GH_TOKEN environment variable" — because `task integration` runs `task release`, which runs `task build`, which fetches the machine, and only the release workflow had been given a token. Every job that reaches the fetch would have needed one, and the ones that did not would have failed the same way: naming gh rather than anything about the machine. spin-machine is public, and a release asset on a public repository has a plain URL that needs no authentication at all. gh needs a token even to read one. So the fetch is curl now, no job carries GH_TOKEN, and there is nothing left to forget. --fail so a 404 is an error instead of a tarball full of HTML, --location because the asset redirects to object storage, --retry because this is the one step that depends on somebody else's network, and the download lands on a .part that is renamed only once it is whole — an interrupted one left in place is a cached tarball every later run would reuse and every later run would reject. Verified by fetching v20260907.01 with no credentials in the environment. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019GHRRFvbnZi5q3KSTvyW5a
…r it Every guest lane died at start-up with qemu-system-x86_64-tcg: failed to find romfile "vgabios-stdvga.bin" which reads like a missing firmware file. It is a device nobody wanted: the demos pass -display none, which only says not to open a window, and q35 still creates a VGA adapter. The QEMU this repository used to build shipped a vgabios for it; the machine's does not, because it has no display adapter compiled in at all. `-vga none` on every demo, which is the right side to fix: the machine ships the firmware its own devices need, and a VGA is not one of them. Reproduced and verified with the exact line the lane runs — without the flag, the romfile error; with it, the kernel boots. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019GHRRFvbnZi5q3KSTvyW5a
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This repository built a QEMU from a recipe modelled on spinbox's, against a device list that was byte-for-byte spinbox's, and carried a
Dockerfile.guest-kernelthat built nothing at all — it existed to move spinbox's kernel through a registry and back out, so a machine with no sibling checkout could name one by digest instead of by a relative path into somebody's home directory.That is the plumbing across a repository boundary that
spin-machinewas created to delete. This deletes it.−1,692 lines.
What goes
…plus the five
guest:kernel:*andguest:inputs:*targets.taskfiles/guest.ymlkeeps the one artefact this repository does build: the initramfs.What arrives
task machineputs one machine under_output/— bothqemu-systembinaries,qemu-imgand the kernel — from a siblingspin-machinecheckout or its published release, pinned by version and SHA-256 (v20260907.01).Both binaries, because the split matters here: the one a host runs must refuse to emulate and CI's must be able to.
task machineasserts that, and that what it fetched actually runs.The wrapper goes with it
This is the part worth noticing.
qemu:toolsextracted the binaries, computed their library closure inside the image, copied the loader and every.soout, and generated a shell wrapper that invoked that loader — because a dynamically linked QEMU extracted onto a bare runner died withliburing.so.2: cannot open shared object file.The release is statically linked, so an extracted tree runs wherever the kernel does. All of that is one
installnow, and two paragraphs of CI comment explaining the problem went with it.Verified
task cipasses.Left for a follow-up
docs/still carries ADR-0021 and ADR-0022, which describe the kernel-mirroring mechanism this PR removes. They should be superseded rather than silently contradicted, and that is a separate change.🤖 Generated with Claude Code
https://claude.ai/code/session_019GHRRFvbnZi5q3KSTvyW5a