Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@ coverage.*

# Local Claude Code worktrees, one per in-flight ticket
/.claude/worktrees/

# The shim binary is build output; pkg/vz embeds it from here
/pkg/vz/shim/shard-vz-shim
1 change: 1 addition & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ make build build ./cmd/shard into bin/shard
make build-linux cross-compile for the box (GOOS=linux GOARCH=amd64)
make build-shard-init build ./cmd/shard-init into bin/shard-init (static, CGO_ENABLED=0)
make build-shard-init-linux cross-compile the supervisor for the box
make build-shard-vz-shim build and ad-hoc sign the VM shim into bin/shard-vz-shim (darwin only)
make test unit tests; must stay green on macOS
make test-integration integration tests, on this host; Linux box only, needs root
make itest integration tests for ITEST_PKG, on the devbox
Expand Down
7 changes: 6 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ ARCH ?= arm64
KERNEL_OUT := bin/kernel
KERNEL_IMAGE := packaging-kernel-builder

.PHONY: all build build-linux build-shard-init build-shard-init-linux test test-integration e2e-test vet lint lint-fix fmt fmt-check vuln check clean devbox-sync devbox-test itest e2e devbox-e2e devbox-demo kernel kernel-reproducible
.PHONY: all build build-linux build-shard-init build-shard-init-linux build-shard-vz-shim test test-integration e2e-test vet lint lint-fix fmt fmt-check vuln check clean devbox-sync devbox-test itest e2e devbox-e2e devbox-demo kernel kernel-reproducible

all: check build

Expand All @@ -38,6 +38,11 @@ build-shard-init:
build-shard-init-linux:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o $(SHARD_INIT_BIN)-linux-amd64 ./cmd/shard-init

# The shim holds one Virtualization.framework VM; darwin only, and unsigned it cannot create one.
build-shard-vz-shim:
go build -o bin/shard-vz-shim ./cmd/shard-vz-shim
Comment thread
presmihaylov marked this conversation as resolved.
codesign --sign - --force --entitlements cmd/shard-vz-shim/entitlements.plist bin/shard-vz-shim

test:
go test ./...

Expand Down
8 changes: 8 additions & 0 deletions cmd/shard-vz-shim/entitlements.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.virtualization</key>
<true/>
</dict>
</plist>
86 changes: 86 additions & 0 deletions cmd/shard-vz-shim/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
//go:build darwin

// shard-vz-shim holds one Virtualization.framework VM behind a unix socket, so it outlives the daemon; the shape follows hypeman's cmd/vz-shim/main.go (561e34fd), see NOTICE.
package main

import (
"encoding/json"
"errors"
"flag"
"fmt"
"log"
"os"
"os/signal"
"runtime"
"runtime/debug"
"syscall"

vzfw "github.com/Code-Hex/vz/v3"

"github.com/presmihaylov/shard/pkg/vz"
)

func main() {
if err := run(); err != nil {
fmt.Fprintln(os.Stderr, "shard-vz-shim:", err)
os.Exit(1)
}
}

func run() error {
encoded := flag.String("config", "", "the VM configuration as JSON")
flag.Parse()

var cfg vz.Config
if err := json.Unmarshal([]byte(*encoded), &cfg); err != nil {
return fmt.Errorf("decode -config: %w", err)
}

// The socket is claimed before the boot, so a second shim for the same VM refuses instead of orphaning the first.
listener, err := vz.Listen(cfg.Socket)
if err != nil {
return err
}
machine, err := vz.NewMachine(&cfg)
if err != nil {
return errors.Join(err, listener.Close())
}
if err := machine.Boot(&cfg); err != nil {
return errors.Join(err, listener.Close(), machine.Close())
}

logger := log.New(os.Stderr, "", log.LstdFlags)
served := make(chan error, 1)
go func() { served <- vz.Serve(listener, machine, logger) }()

signals := make(chan os.Signal, 1)
signal.Notify(signals, syscall.SIGTERM, syscall.SIGINT, syscall.SIGUSR1)
changed := machine.Changed()
for {
select {
case sig := <-signals:
// SIGUSR1 forces a collection, so a test can prove the device files outlive one.
if sig == syscall.SIGUSR1 {
runtime.GC()
debug.FreeOSMemory()
logger.Printf("%s: collected", sig)

continue
}
logger.Printf("%s: stopping the vm", sig)
if err := machine.Stop(); err != nil {
return err
}
case state := <-changed:
if state != vzfw.VirtualMachineStateStopped && state != vzfw.VirtualMachineStateError {
continue
}
logger.Printf("vm %s: exiting", vz.State(state.String()))
if err := listener.Close(); err != nil {
return fmt.Errorf("close the shim socket: %w", err)
}

return errors.Join(<-served, machine.Close())
}
}
}
16 changes: 16 additions & 0 deletions cmd/shard-vz-shim/main_other.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//go:build !darwin

// shard-vz-shim holds one Virtualization.framework VM; off a Mac there is nothing to hold.
package main

import (
"fmt"
"os"

"github.com/presmihaylov/shard/pkg/vz"
)

func main() {
fmt.Fprintln(os.Stderr, "shard-vz-shim:", vz.ErrUnsupported)
os.Exit(1)
}
4 changes: 4 additions & 0 deletions docs/provider-vz.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,10 @@ file-handle network device. It ran on 2026-09-19 on a MacBook (M-series, macOS 1
7. **Two VMs per process.** The third VM in one process fails to start, with the same identifier or
distinct ones, restored or cold-booted. Eight VMs over four processes run together.
8. A restore with a fresh machine identifier is refused with `Code=12, invalid argument`.
9. **A restore needs an unlocked login session.** The helper unwraps the saved state with a key from
the Secure Enclave, and a locked screen withholds it: every restore then fails with `Code=12,
permission denied` while a save still succeeds (SHARD-213, macOS 14.6). A headless box that
never locks is fine; the driver test skips when `ioreg` reports the session locked.

Not proved yet, and owned by the tickets that need it: a restore over a virtio-blk disk (SHARD-215),
the vsock streams end to end (SHARD-216), the netstack (SHARD-217), and any of this on macOS 13.
Expand Down
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ require (
)

require (
github.com/Code-Hex/go-infinity-channel v1.0.0 // indirect
github.com/Code-Hex/vz/v3 v3.7.1 // indirect
github.com/Microsoft/go-winio v0.6.3-0.20251027160822-ad3df93bed29 // indirect
github.com/Microsoft/hcsshim v0.15.0-rc.1 // indirect
github.com/containerd/cgroups/v3 v3.1.3 // indirect
Expand All @@ -34,6 +36,7 @@ require (
github.com/pkg/errors v0.9.1 // indirect
github.com/sirupsen/logrus v1.9.4 // indirect
go.opencensus.io v0.24.0 // indirect
golang.org/x/mod v0.38.0 // indirect
golang.org/x/sync v0.22.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20260406210006-6f92a3bedf2d // indirect
google.golang.org/grpc v1.80.0 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Code-Hex/go-infinity-channel v1.0.0 h1:M8BWlfDOxq9or9yvF9+YkceoTkDI1pFAqvnP87Zh0Nw=
github.com/Code-Hex/go-infinity-channel v1.0.0/go.mod h1:5yUVg/Fqao9dAjcpzoQ33WwfdMWmISOrQloDRn3bsvY=
github.com/Code-Hex/vz/v3 v3.7.1 h1:EN1yNiyrbPq+dl388nne2NySo8I94EnPppvqypA65XM=
github.com/Code-Hex/vz/v3 v3.7.1/go.mod h1:1LsW0jqW0r0cQ+IeR4hHbjdqOtSidNCVMWhStMHGho8=
github.com/Microsoft/go-winio v0.6.3-0.20251027160822-ad3df93bed29 h1:0kQAzHq8vLs7Pptv+7TxjdETLf/nIqJpIB4oC6Ba4vY=
github.com/Microsoft/go-winio v0.6.3-0.20251027160822-ad3df93bed29/go.mod h1:ZWa7ssZJT30CCDGJ7fk/2SBTq9BIQrrVjrcss0UW2s0=
github.com/Microsoft/hcsshim v0.15.0-rc.1 h1:FbbwtQmiD+BVHynGkx5S65JkLyhkEiiTP8nrpmg2SZw=
Expand Down
Loading
Loading