The tap repo starts empty: the clone has no Formula/ directory, so
the cp failed. Push HEAD to main explicitly so the tap's branch does
not depend on the runner's init.defaultBranch.
Hosted macOS runners run without nested virtualization: kern
.hv_support is 0 and no binary can boot a VM there, entitlement or
not. The macos job keeps the full compile gate and asserts the probe
reports the known HVF absence with a working engine load, so any
other regression still fails; the boot e2e stays on Linux and real
Macs.
The one-command install edit had replaced the whole macOS section
instead of just the install lines, dropping the from-source sign
snippet; it is back, with the current entitlements path and
libarchive in the brew line. Homebrew's tap-trust gate now leads the
macOS install: dependencies from third-party taps stay refused until
their tap is trusted once, and libkrun ships from its own tap.
Homebrew now refuses formulae from third-party taps unless trusted:
the explicitly requested formula is trusted automatically, but its
dependencies are not, so the install died on libkrunfw. Users hit
the same wall on their first install; the README leads with the
one-time brew trust now.
The tap job matched the literal v0.1.0 url line, so bumping the pin
broke the release render. The pin is now matched generically and
marked in-source as a placeholder the workflow rewrites; the tap
always ships the release tarball with its real sha256.
All consumers live in packaging already: the formula codesigns at
install, and the CI and release workflows codesign the built binary.
The macOS dir held nothing else.
The tap repo is a publish target like the snap store: the release
workflow rewrites the in-repo formula's url/sha256 for the release
tarball and pushes it to homebrew-ecrou. No token, no update — tags
still release.
SPEC records the two macOS facts the code bends around (bare-soname
dlopens needing startup-time DYLD paths; the hypervisor entitlement)
and the packaging decisions; README gains the brew install and the
from-source sign step.
CI runs fmt/clippy/test plus a real alpine boot on a macos-26 runner
with libkrun from the krun tap; the release workflow ships a signed
darwin-arm64 tarball beside the snaps. The formula installs from the
tap, carries the runtime kegs (libkrun, e2fsprogs, libarchive), and
codesigns the binary with the hypervisor entitlement — Hypervisor
.framework grants VM creation only to entitled binaries on current
macOS, the same requirement krunkit's formula signs for.
The engine's dlopen of libkrunfw and mke2fs's of libarchive use bare
sonames, and dyld reads DYLD_FALLBACK_LIBRARY_PATH once, at process
startup — a setenv afterwards is invisible to it. When the variable
is unset and the brew kegs exist, the CLI sets it and execv's itself:
exec restarts dyld, which reads the variable fresh. Library consumers
set the variable before their process starts instead (SPEC.md).
The cache-seeding tests seeded entry names under amd64 but resolved
the request against the host arch, so on an arm64 host the lookup
missed and the tests walked into the network path. Requests now pin
arch, matching the seeded names on any host. The tool gate uses
find_tool: on macOS the e2fsprogs binaries are keg-only, never on
PATH.
mke2fs built against libarchive populates an ext4 from a tarball in
one pass; Homebrew's bottle is not built that way, so when the found
mke2fs cannot take a tarball the builder unpacks the rootfs with the
library's own tar decoder and populates from the directory — slower,
and the run says so. The mkfs child is exec'd fresh, so it reads
DYLD_FALLBACK_LIBRARY_PATH (libarchive's keg) at startup.
The engine is libkrun.1.dylib, dlopen'd from the Homebrew kegs when
the loader's own search fails (bare sonames never reach the brew
prefix); the probe becomes a per-platform hypervisor probe — KVM on
Linux, sysctl + a real hv_vm_create on macOS, so an entitlement
denial (HV_DENIED) names the re-sign fix instead of surfacing as an
opaque krun_start_enter EINVAL. Tool lookup (mke2fs, debugfs) gains
the same keg fallback, and dyld_fallback_dirs() collects the kegs the
bare-soname dlopens (libkrunfw, libarchive) need in
DYLD_FALLBACK_LIBRARY_PATH. The machine child's parent-death contract
moves to a kqueue NOTE_EXIT watcher: macOS has no PR_SET_PDEATHSIG,
and SIGKILL-on-parent-exit is what keeps a killed caller from
stranding a booted machine.