diff --git a/.claude/rules/adding-options.md b/.claude/rules/adding-options.md index 9021097..4198bca 100644 --- a/.claude/rules/adding-options.md +++ b/.claude/rules/adding-options.md @@ -1,9 +1,9 @@ --- paths: - "options.go" - - "propolis.go" + - "microvm.go" - "runner/config.go" - - "runner/cmd/propolis-runner/main.go" + - "runner/cmd/go-microvm-runner/main.go" --- # Adding a New Option @@ -11,5 +11,5 @@ paths: 1. Add the field to the `config` struct in `options.go` 2. Set the default in `defaultConfig()` if needed 3. Create a `With*` constructor following the existing pattern in `options.go` -4. Use the field in `propolis.go` (in `Run()`) where appropriate -5. If the option affects the runner, add the field to BOTH `runner.Config` in `runner/config.go` AND the runner's duplicate `Config` struct in `runner/cmd/propolis-runner/main.go` with the same JSON tag +4. Use the field in `microvm.go` (in `Run()`) where appropriate +5. If the option affects the runner, add the field to BOTH `runner.Config` in `runner/config.go` AND the runner's duplicate `Config` struct in `runner/cmd/go-microvm-runner/main.go` with the same JSON tag diff --git a/.claude/rules/preflight-and-hooks.md b/.claude/rules/preflight-and-hooks.md index ee69fe8..df28285 100644 --- a/.claude/rules/preflight-and-hooks.md +++ b/.claude/rules/preflight-and-hooks.md @@ -10,7 +10,7 @@ paths: - Create a function returning `preflight.Check` with Name, Description, Run, and Required fields - See existing checks in `preflight/kvm_linux.go` and `preflight/ports.go` for patterns - Platform-specific checks go in build-tagged files (`//go:build linux` or `//go:build darwin`) -- Register via `propolis.WithPreflightChecks()` or add to `registerPlatformChecks()` for defaults +- Register via `microvm.WithPreflightChecks()` or add to `registerPlatformChecks()` for defaults ## Adding a Network Provider - Implement the `net.Provider` interface (Start, SocketPath, Stop) @@ -22,4 +22,4 @@ paths: - Type: `func(rootfsPath string, cfg *image.OCIConfig) error` - Run before `.krun_config.json` is written and before VM boot - Multiple hooks run in registration order; any error aborts the pipeline -- Register via `propolis.WithRootFSHook()` +- Register via `microvm.WithRootFSHook()` diff --git a/.github/workflows/builder.yaml b/.github/workflows/builder.yaml index 5459331..d4b6d77 100644 --- a/.github/workflows/builder.yaml +++ b/.github/workflows/builder.yaml @@ -20,7 +20,7 @@ permissions: env: REGISTRY: ghcr.io - IMAGE_NAME: stacklok/propolis-builder + IMAGE_NAME: stacklok/go-microvm-builder jobs: build: diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index d5ff8f1..b5ce96f 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -52,14 +52,14 @@ jobs: - name: Upload runtime artifact uses: actions/upload-artifact@v7 with: - name: propolis-runtime-linux-${{ matrix.arch }} - path: dist/propolis-runtime-linux-${{ matrix.arch }}.tar.gz + name: go-microvm-runtime-linux-${{ matrix.arch }} + path: dist/go-microvm-runtime-linux-${{ matrix.arch }}.tar.gz - name: Upload firmware artifact uses: actions/upload-artifact@v7 with: - name: propolis-firmware-linux-${{ matrix.arch }} - path: dist/propolis-firmware-linux-${{ matrix.arch }}.tar.gz + name: go-microvm-firmware-linux-${{ matrix.arch }} + path: dist/go-microvm-firmware-linux-${{ matrix.arch }}.tar.gz build-artifacts-darwin: name: Build macOS (${{ matrix.arch }}) @@ -101,14 +101,14 @@ jobs: - name: Upload runtime artifact uses: actions/upload-artifact@v7 with: - name: propolis-runtime-darwin-${{ matrix.arch }} - path: dist/propolis-runtime-darwin-${{ matrix.arch }}.tar.gz + name: go-microvm-runtime-darwin-${{ matrix.arch }} + path: dist/go-microvm-runtime-darwin-${{ matrix.arch }}.tar.gz - name: Upload firmware artifact uses: actions/upload-artifact@v7 with: - name: propolis-firmware-darwin-${{ matrix.arch }} - path: dist/propolis-firmware-darwin-${{ matrix.arch }}.tar.gz + name: go-microvm-firmware-darwin-${{ matrix.arch }} + path: dist/go-microvm-firmware-darwin-${{ matrix.arch }}.tar.gz create-release: name: Create Release @@ -126,7 +126,7 @@ jobs: - name: Generate checksums run: | - sha256sum propolis-*.tar.gz > sha256sums.txt + sha256sum go-microvm-*.tar.gz > sha256sums.txt - name: Create or update GitHub Release env: @@ -134,10 +134,10 @@ jobs: run: | if gh release view "${{ github.ref_name }}" >/dev/null 2>&1; then gh release upload "${{ github.ref_name }}" --clobber \ - propolis-*.tar.gz sha256sums.txt + go-microvm-*.tar.gz sha256sums.txt else gh release create "${{ github.ref_name }}" --generate-notes \ - propolis-*.tar.gz sha256sums.txt + go-microvm-*.tar.gz sha256sums.txt fi push-oci: @@ -153,12 +153,12 @@ jobs: - name: Download runtime artifact uses: actions/download-artifact@v8 with: - name: propolis-runtime-linux-${{ matrix.arch }} + name: go-microvm-runtime-linux-${{ matrix.arch }} - name: Download firmware artifact uses: actions/download-artifact@v8 with: - name: propolis-firmware-linux-${{ matrix.arch }} + name: go-microvm-firmware-linux-${{ matrix.arch }} - name: Install oras uses: oras-project/setup-oras@v1 @@ -169,15 +169,15 @@ jobs: - name: Push runtime OCI artifact run: | - oras push ghcr.io/stacklok/propolis/runtime:${{ github.ref_name }}-linux-${{ matrix.arch }} \ - --artifact-type application/vnd.stacklok.propolis.runtime \ - propolis-runtime-linux-${{ matrix.arch }}.tar.gz:application/gzip + oras push ghcr.io/stacklok/go-microvm/runtime:${{ github.ref_name }}-linux-${{ matrix.arch }} \ + --artifact-type application/vnd.stacklok.go-microvm.runtime \ + go-microvm-runtime-linux-${{ matrix.arch }}.tar.gz:application/gzip - name: Push firmware OCI artifact run: | - oras push ghcr.io/stacklok/propolis/firmware:${{ github.ref_name }}-linux-${{ matrix.arch }} \ - --artifact-type application/vnd.stacklok.propolis.firmware \ - propolis-firmware-linux-${{ matrix.arch }}.tar.gz:application/gzip + oras push ghcr.io/stacklok/go-microvm/firmware:${{ github.ref_name }}-linux-${{ matrix.arch }} \ + --artifact-type application/vnd.stacklok.go-microvm.firmware \ + go-microvm-firmware-linux-${{ matrix.arch }}.tar.gz:application/gzip push-oci-darwin: name: Push OCI macOS (${{ matrix.arch }}) @@ -191,12 +191,12 @@ jobs: - name: Download runtime artifact uses: actions/download-artifact@v8 with: - name: propolis-runtime-darwin-${{ matrix.arch }} + name: go-microvm-runtime-darwin-${{ matrix.arch }} - name: Download firmware artifact uses: actions/download-artifact@v8 with: - name: propolis-firmware-darwin-${{ matrix.arch }} + name: go-microvm-firmware-darwin-${{ matrix.arch }} - name: Install oras uses: oras-project/setup-oras@v1 @@ -207,12 +207,12 @@ jobs: - name: Push runtime OCI artifact run: | - oras push ghcr.io/stacklok/propolis/runtime:${{ github.ref_name }}-darwin-${{ matrix.arch }} \ - --artifact-type application/vnd.stacklok.propolis.runtime \ - propolis-runtime-darwin-${{ matrix.arch }}.tar.gz:application/gzip + oras push ghcr.io/stacklok/go-microvm/runtime:${{ github.ref_name }}-darwin-${{ matrix.arch }} \ + --artifact-type application/vnd.stacklok.go-microvm.runtime \ + go-microvm-runtime-darwin-${{ matrix.arch }}.tar.gz:application/gzip - name: Push firmware OCI artifact run: | - oras push ghcr.io/stacklok/propolis/firmware:${{ github.ref_name }}-darwin-${{ matrix.arch }} \ - --artifact-type application/vnd.stacklok.propolis.firmware \ - propolis-firmware-darwin-${{ matrix.arch }}.tar.gz:application/gzip + oras push ghcr.io/stacklok/go-microvm/firmware:${{ github.ref_name }}-darwin-${{ matrix.arch }} \ + --artifact-type application/vnd.stacklok.go-microvm.firmware \ + go-microvm-firmware-darwin-${{ matrix.arch }}.tar.gz:application/gzip diff --git a/CLAUDE.md b/CLAUDE.md index e6702ee..612eec7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,7 +1,7 @@ -# propolis +# go-microvm Go library + runner binary for running OCI container images as microVMs via libkrun. -Two-process model: pure-Go library spawns a CGO runner subprocess. Module: `github.com/stacklok/propolis`. +Two-process model: pure-Go library spawns a CGO runner subprocess. Module: `github.com/stacklok/go-microvm`. ## Commands @@ -31,23 +31,23 @@ macOS dev setup: `brew tap slp/krun && brew install libkrun libkrunfw` (see `doc ## Architecture -Entry point: `propolis.go:Run()` orchestrates the full pipeline (preflight, pull, hooks, config, net, spawn, post-boot). Config via functional options in `options.go`. Returns a `*VM` handle (`vm.go`). +Entry point: `microvm.go:Run()` orchestrates the full pipeline (preflight, pull, hooks, config, net, spawn, post-boot). Config via functional options in `options.go`. Returns a `*VM` handle (`vm.go`). -**CGO boundary**: Only `krun/` and `runner/cmd/propolis-runner/` use CGO. Everything else is pure Go. The runner binary is sacrificial -- `krun_start_enter()` never returns, so it runs in a detached subprocess. +**CGO boundary**: Only `krun/` and `runner/cmd/go-microvm-runner/` use CGO. Everything else is pure Go. The runner binary is sacrificial -- `krun_start_enter()` never returns, so it runs in a detached subprocess. **Key subsystems**: `hypervisor/` (Backend abstraction + libkrun impl), `image/` (OCI pull + cache), `runner/` (subprocess spawning), `net/` (Provider interface + firewall + hosted mode + egress policy + topology constants), `guest/` (guest-side boot orchestration, hardening, SSH server), `hooks/` (RootFS hook factories for key injection, file injection), `extract/` (binary bundle caching), `preflight/` (platform checks via build tags), `ssh/` (keygen + client), `state/` (flock-based JSON persistence), `internal/` (pathutil, procutil). ## Things That Will Bite You -- **CGO boundary is strict**: Only `krun/` and `runner/cmd/propolis-runner/` use CGO. Every other package MUST stay `CGO_ENABLED=0`. Never import `krun` from a non-CGO package. -- **Runner config is duplicated**: `runner.Config` in `runner/config.go` and a duplicate `Config` struct in `runner/cmd/propolis-runner/main.go`. When adding a field, update BOTH structs with the same JSON tag, then handle it in `runVM()`. +- **CGO boundary is strict**: Only `krun/` and `runner/cmd/go-microvm-runner/` use CGO. Every other package MUST stay `CGO_ENABLED=0`. Never import `krun` from a non-CGO package. +- **Runner config is duplicated**: `runner.Config` in `runner/config.go` and a duplicate `Config` struct in `runner/cmd/go-microvm-runner/main.go`. When adding a field, update BOTH structs with the same JSON tag, then handle it in `runVM()`. - **`krun_start_enter()` never returns**: It calls `exit()` when the guest shuts down. That's why we need the two-process model -- the runner process is sacrificial. - **Platform build tags**: Preflight checks, resource checks, and some net code use `//go:build linux` or `//go:build darwin`. Each platform goes in a separate file. macOS preflight checks verify `kern.hv_support` sysctl and use `hw.memsize`/`syscall.Statfs` for resources. - **Entitlements required on macOS**: `assets/entitlements.plist` has three entitlements: `com.apple.security.hypervisor`, `com.apple.security.cs.disable-library-validation`, and `com.apple.security.cs.allow-dyld-environment-variables` (needed because the hypervisor entitlement activates hardened runtime, which strips DYLD_* vars). The `task build-dev-darwin` command signs automatically. - **CGO Homebrew paths**: `krun/context.go` CGO directives include `-L/opt/homebrew/lib` and `-L/usr/local/lib` for macOS. The linker ignores nonexistent paths. -- **Tests excluding CGO packages**: When CGO isn't available, exclude krun: `CGO_ENABLED=0 go test $(go list ./... | grep -v krun | grep -v propolis-runner)` +- **Tests excluding CGO packages**: When CGO isn't available, exclude krun: `CGO_ENABLED=0 go test $(go list ./... | grep -v krun | grep -v go-microvm-runner)` - **Functional options pattern**: All public config uses `With*` constructors applying to unexported `config` struct via `optionFunc`. Follow the existing pattern in `options.go` exactly. -- **Backend abstraction**: `WithRunnerPath`, `WithLibDir`, and `WithSpawner` are NOT on the top-level `propolis` package. They live in `hypervisor/libkrun` as backend-specific options. Use `propolis.WithBackend(libkrun.NewBackend(libkrun.WithRunnerPath(...)))`. Similarly, `VM.PID()` is gone; use `VM.ID()` (returns string). +- **Backend abstraction**: `WithRunnerPath`, `WithLibDir`, and `WithSpawner` are NOT on the top-level `microvm` package. They live in `hypervisor/libkrun` as backend-specific options. Use `microvm.WithBackend(libkrun.NewBackend(libkrun.WithRunnerPath(...)))`. Similarly, `VM.PID()` is gone; use `VM.ID()` (returns string). ## Conventions @@ -72,7 +72,7 @@ task test # Full test suite with race detector After modifying CGO-free packages only: ```bash -CGO_ENABLED=0 go vet $(go list ./... | grep -v krun | grep -v propolis-runner) +CGO_ENABLED=0 go vet $(go list ./... | grep -v krun | grep -v go-microvm-runner) ``` When tests fail, fix the implementation, not the tests. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b864100..0e28fc1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,4 +1,4 @@ -# Contributing to propolis +# Contributing to go-microvm ## Prerequisites @@ -60,7 +60,7 @@ Run `task --list` for the full list. Key tasks for development: - **Error wrapping**: `fmt.Errorf("context: %w", err)` - **Table-driven tests** with testify - **Functional options**: follow the `With*` pattern in `options.go` -- **CGO boundary**: only `krun/` and `runner/cmd/propolis-runner/` use CGO. +- **CGO boundary**: only `krun/` and `runner/cmd/go-microvm-runner/` use CGO. Never import `krun` from other packages. ## Commit Guidelines diff --git a/README.md b/README.md index 7f2361b..7ecd187 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,15 @@
- propolis mascot + go-microvm mascot -

propolis

+

go-microvm

Run OCI container images as microVMs with libkrun.

- CI status - Go Reference + CI status + Go Reference License: Apache-2.0 - Go Report Card + Go Report Card

@@ -22,19 +22,19 @@

> [!WARNING] -> **Experimental** -- propolis is under active development. APIs, configuration +> **Experimental** -- go-microvm is under active development. APIs, configuration > formats, and behavior may change without notice between releases. It is not > yet recommended for production use. --- -propolis is a Go library and runner binary that turns any OCI container image +go-microvm is a Go library and runner binary that turns any OCI container image into a lightweight virtual machine. It pulls the image, flattens its layers into a rootfs, configures in-process networking, and boots the result using [libkrun](https://github.com/containers/libkrun) -- all in a single function call. -You would use propolis when you need stronger isolation than containers provide +You would use go-microvm when you need stronger isolation than containers provide but want to keep the OCI image workflow you already have. The library handles image caching, preflight validation, port forwarding, virtio-fs mounts, and process lifecycle so you can focus on what runs inside the VM. @@ -54,7 +54,7 @@ process lifecycle so you can focus on what runs inside the VM. ## Prerequisites -propolis requires hardware virtualization support and a few system packages. +go-microvm requires hardware virtualization support and a few system packages. ### Linux -- Fedora @@ -122,8 +122,8 @@ sudo modprobe kvm kvm_amd # AMD CPUs ### Go Toolchain -propolis requires **Go 1.26** or later. The library packages (everything -except `krun` and `propolis-runner`) do not require CGO and compile with +go-microvm requires **Go 1.26** or later. The library packages (everything +except `krun` and `go-microvm-runner`) do not require CGO and compile with `CGO_ENABLED=0`. The runner binary requires `CGO_ENABLED=1` and `libkrun-devel`. ## Quick Start @@ -135,14 +135,14 @@ import ( "context" "log" - "github.com/stacklok/propolis" + "github.com/stacklok/go-microvm" ) func main() { ctx := context.Background() - vm, err := propolis.Run(ctx, "alpine:latest", - propolis.WithPorts(propolis.PortForward{Host: 8080, Guest: 80}), + vm, err := microvm.Run(ctx, "alpine:latest", + microvm.WithPorts(microvm.PortForward{Host: 8080, Guest: 80}), ) if err != nil { log.Fatal(err) @@ -158,14 +158,14 @@ func main() { } ``` -`propolis.Run` executes the full pipeline: preflight checks, OCI image pull, +`microvm.Run` executes the full pipeline: preflight checks, OCI image pull, layer extraction, rootfs caching, networking setup, subprocess spawn, and post-boot hooks. It returns a `*VM` handle that you use to query status, stop, or remove the VM. ## Advanced Usage -For appliance-style deployments, propolis exposes hooks and overrides at every +For appliance-style deployments, go-microvm exposes hooks and overrides at every stage of the pipeline: ```go @@ -176,41 +176,41 @@ import ( "os" "path/filepath" - "github.com/stacklok/propolis" - "github.com/stacklok/propolis/hypervisor/libkrun" - "github.com/stacklok/propolis/image" - "github.com/stacklok/propolis/preflight" - "github.com/stacklok/propolis/ssh" + "github.com/stacklok/go-microvm" + "github.com/stacklok/go-microvm/hypervisor/libkrun" + "github.com/stacklok/go-microvm/image" + "github.com/stacklok/go-microvm/preflight" + "github.com/stacklok/go-microvm/ssh" ) func main() { ctx := context.Background() - vm, err := propolis.Run(ctx, "my-appliance:latest", - // Name the VM (defaults to "propolis"). - propolis.WithName("my-appliance"), + vm, err := microvm.Run(ctx, "my-appliance:latest", + // Name the VM (defaults to "go-microvm"). + microvm.WithName("my-appliance"), // Configure VM resources. // vCPUs default to 1, memory defaults to 512 MiB. // Stock libkrunfw caps vCPUs at 8. - propolis.WithCPUs(4), - propolis.WithMemory(2048), + microvm.WithCPUs(4), + microvm.WithMemory(2048), // Port forwards from host to guest. - propolis.WithPorts( - propolis.PortForward{Host: 443, Guest: 443}, - propolis.PortForward{Host: 2222, Guest: 22}, + microvm.WithPorts( + microvm.PortForward{Host: 443, Guest: 443}, + microvm.PortForward{Host: 2222, Guest: 22}, ), // Replace the OCI ENTRYPOINT/CMD with a custom init script. // The command is written into /.krun_config.json and executed // by libkrun's built-in init process (PID 1). - propolis.WithInitOverride("/sbin/my-init"), + microvm.WithInitOverride("/sbin/my-init"), // Inject files into the rootfs before boot. // Hooks run after image extraction but before .krun_config.json // is written, so they can modify anything in the filesystem. - propolis.WithRootFSHook(func(rootfs string, cfg *image.OCIConfig) error { + microvm.WithRootFSHook(func(rootfs string, cfg *image.OCIConfig) error { return os.WriteFile( filepath.Join(rootfs, "etc", "my-app.conf"), []byte("key=value\n"), 0o644, @@ -219,31 +219,31 @@ func main() { // Run setup after the VM process is alive. // Common use: wait for SSH, push configuration, run health checks. - propolis.WithPostBoot(func(ctx context.Context, vm *propolis.VM) error { + microvm.WithPostBoot(func(ctx context.Context, vm *microvm.VM) error { keyPath := filepath.Join(vm.DataDir(), "id_ecdsa") sshClient := ssh.NewClient("127.0.0.1", 2222, "root", keyPath) return sshClient.WaitForReady(ctx) }), // Mount a host directory into the guest via virtio-fs. - propolis.WithVirtioFS(propolis.VirtioFSMount{ + microvm.WithVirtioFS(microvm.VirtioFSMount{ Tag: "shared", HostPath: "/srv/data", }), // Use a custom data directory for state, caches, and logs. - // Defaults to ~/.config/propolis or $PROPOLIS_DATA_DIR. - propolis.WithDataDir("/var/lib/my-appliance"), + // Defaults to ~/.config/go-microvm or $GO_MICROVM_DATA_DIR. + microvm.WithDataDir("/var/lib/my-appliance"), // Configure the libkrun backend with a specific runner binary // and library search path. These options are backend-specific. - propolis.WithBackend(libkrun.NewBackend( - libkrun.WithRunnerPath("/usr/local/bin/propolis-runner"), + microvm.WithBackend(libkrun.NewBackend( + libkrun.WithRunnerPath("/usr/local/bin/go-microvm-runner"), libkrun.WithLibDir("/opt/libs"), )), // Add custom preflight checks beyond the built-in defaults // (KVM access, disk space, system resources, port availability). - propolis.WithPreflightChecks( + microvm.WithPreflightChecks( preflight.PortCheck(443, 2222), preflight.Check{ Name: "connectivity", @@ -257,7 +257,7 @@ func main() { ), // Provide a custom image cache location. - propolis.WithImageCache(image.NewCache("/var/cache/propolis")), + microvm.WithImageCache(image.NewCache("/var/cache/go-microvm")), ) if err != nil { panic(err) @@ -280,7 +280,7 @@ func main() { | Option | Description | Default | |--------|-------------|---------| -| `WithName(s)` | VM name for identification | `"propolis"` | +| `WithName(s)` | VM name for identification | `"go-microvm"` | | `WithCPUs(n)` | Virtual CPUs (max 8 with stock libkrunfw, max 255 hard limit) | `1` | | `WithMemory(mib)` | RAM in MiB | `512` | | `WithPorts(...)` | TCP port forwards from host to guest | none | @@ -294,7 +294,7 @@ func main() { | `WithPreflightChecker(c)` | Replace entire preflight checker | platform defaults | | `WithPreflightChecks(...)` | Add custom pre-boot checks | KVM + resources | | `WithVirtioFS(...)` | Host directory mounts via virtio-fs | none | -| `WithDataDir(p)` | State, cache, and log directory | `~/.config/propolis` | +| `WithDataDir(p)` | State, cache, and log directory | `~/.config/go-microvm` | | `WithCleanDataDir()` | Remove existing data dir contents before boot | disabled | | `WithEgressPolicy(p)` | Restrict outbound traffic to allowed DNS hostnames | none | | `WithImageCache(c)` | Custom image cache instance | `$dataDir/cache/` | @@ -306,9 +306,9 @@ func main() { | Package | CGO? | Description | |---------|------|-------------| -| `propolis` (root) | No | Top-level API: `Run()`, `VM` type, functional options, hook types | +| `microvm` (root) | No | Top-level API: `Run()`, `VM` type, functional options, hook types | | `hypervisor` | No | `Backend` and `VMHandle` interfaces, `VMConfig`, `InitConfig` types | -| `hypervisor/libkrun` | No | libkrun backend: spawns propolis-runner subprocess, `WithRunnerPath`/`WithLibDir`/`WithSpawner` | +| `hypervisor/libkrun` | No | libkrun backend: spawns go-microvm-runner subprocess, `WithRunnerPath`/`WithLibDir`/`WithSpawner` | | `image` | No | OCI image pull via `ImageFetcher`, layer flattening, rootfs extraction | | `image/disk` | No | Disk image download with decompression (gzip/bzip2/xz) | | `krun` | **Yes** | CGO bindings to libkrun C API (context, VM config, `StartEnter`) | @@ -321,21 +321,21 @@ func main() { | `net/hosted` | No | Hosted `net.Provider` running VirtualNetwork in caller's process with HTTP services | | `net/topology` | No | Shared network topology constants (subnet, gateway, IPs, MTU) | | `preflight` | No | `Checker` interface, `Check` struct, built-in KVM/HVF and port checks | -| `runner` | No | `Spawner` / `ProcessHandle` interfaces for managing the propolis-runner subprocess | -| `runner/cmd/propolis-runner` | **Yes** | The runner binary (calls `krun.StartEnter`, never returns) | +| `runner` | No | `Spawner` / `ProcessHandle` interfaces for managing the go-microvm-runner subprocess | +| `runner/cmd/go-microvm-runner` | **Yes** | The runner binary (calls `krun.StartEnter`, never returns) | | `ssh` | No | ECDSA key generation and SSH client for guest communication | | `state` | No | flock-based state persistence with atomic JSON writes | | `rootfs` | No | Rootfs cloning with reflink (copy-on-write) support | | `internal/pathutil` | No | Path traversal validation for safe file operations | | `internal/xattr` | No | Extended attribute helpers for `override_stat` ownership mapping | -Only `krun` and `runner/cmd/propolis-runner` require CGO and `libkrun-devel`. +Only `krun` and `runner/cmd/go-microvm-runner` require CGO and `libkrun-devel`. All other packages are pure Go and can be imported and tested with `CGO_ENABLED=0`. ## Build -propolis uses [Task](https://taskfile.dev/) as its build tool. Run +go-microvm uses [Task](https://taskfile.dev/) as its build tool. Run `task --list` for all available commands. | Command | Description | @@ -361,22 +361,22 @@ The library packages do not require CGO and can be validated separately: ```bash # Test pure-Go packages only (no libkrun needed) -CGO_ENABLED=0 go test $(go list ./... | grep -v krun | grep -v propolis-runner) +CGO_ENABLED=0 go test $(go list ./... | grep -v krun | grep -v go-microvm-runner) # Vet pure-Go packages -CGO_ENABLED=0 go vet $(go list ./... | grep -v krun | grep -v propolis-runner) +CGO_ENABLED=0 go vet $(go list ./... | grep -v krun | grep -v go-microvm-runner) ``` ## Architecture -propolis uses a **two-process model**: +go-microvm uses a **two-process model**: ``` +---------------------------+ +---------------------------+ -| Your application | | propolis-runner | -| (links propolis library) | spawn | (CGO binary, links | +| Your application | | go-microvm-runner | +| (links go-microvm lib) | spawn | (CGO binary, links | | |-------->| libkrun) | -| propolis.Run() | JSON | | +| microvm.Run() | JSON | | | | config | 1. Parse Config (argv[1])| | Pure Go, no CGO | | 2. krun.CreateContext() | | | | 3. SetVMConfig, SetRoot | @@ -389,11 +389,11 @@ propolis uses a **two-process model**: +------------------------------------->| this process ``` -1. **Your application** links the propolis library (pure Go, no CGO). It pulls +1. **Your application** links the go-microvm library (pure Go, no CGO). It pulls the OCI image, configures networking, runs preflight checks, and spawns a subprocess. -2. **propolis-runner** is a small CGO binary that receives the VM configuration +2. **go-microvm-runner** is a small CGO binary that receives the VM configuration as JSON in `argv[1]`. It calls libkrun's C API to configure the VM context, then calls `krun_start_enter()` -- which **never returns** on success. The calling process becomes the VM supervisor until the guest shuts down. @@ -417,7 +417,7 @@ Go runtime. | Start networking (in-process vnet) | - Spawn propolis-runner subprocess + Spawn go-microvm-runner subprocess | Runner calls krun_start_enter() | @@ -475,7 +475,7 @@ sandboxed hypervisor like Firecracker. ### Tar Extraction Security -When extracting OCI image layers, propolis applies multiple defenses against +When extracting OCI image layers, go-microvm applies multiple defenses against malicious tar archives: - **Path traversal prevention**: `sanitizeTarPath` rejects absolute paths and @@ -506,13 +506,13 @@ ls -la /dev/kvm # If permission denied: sudo usermod -aG kvm $USER # 2. Check console output for guest-side errors -cat ~/.config/propolis/console.log +cat ~/.config/go-microvm/console.log # 3. Check runner stderr for host-side errors -cat ~/.config/propolis/vm.log +cat ~/.config/go-microvm/vm.log # 4. Verify the runner binary is available -which propolis-runner +which go-microvm-runner # Or check next to your binary ``` @@ -535,8 +535,8 @@ crane pull alpine:latest /tmp/test.tar # Check which process is using a port ss -tlnp | grep ':8080' -# Or use the propolis preflight check directly: -# propolis.WithPreflightChecks(preflight.PortCheck(8080)) +# Or use the go-microvm preflight check directly: +# microvm.WithPreflightChecks(preflight.PortCheck(8080)) ``` ### macOS-Specific Issues diff --git a/Taskfile.yaml b/Taskfile.yaml index 8575634..9b7628f 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -4,7 +4,7 @@ version: '3' vars: - RUNNER_NAME: propolis-runner + RUNNER_NAME: go-microvm-runner VERSION: sh: git describe --tags --always --dirty 2>/dev/null || echo "dev" COMMIT: @@ -12,14 +12,14 @@ vars: BUILD_DATE: sh: date -u +"%Y-%m-%dT%H:%M:%SZ" LDFLAGS: >- - -X github.com/stacklok/propolis/internal/version.Version={{.VERSION}} - -X github.com/stacklok/propolis/internal/version.Commit={{.COMMIT}} - -X github.com/stacklok/propolis/internal/version.BuildDate={{.BUILD_DATE}} + -X github.com/stacklok/go-microvm/internal/version.Version={{.VERSION}} + -X github.com/stacklok/go-microvm/internal/version.Commit={{.COMMIT}} + -X github.com/stacklok/go-microvm/internal/version.BuildDate={{.BUILD_DATE}} HOST_ARCH: sh: uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/' CONTAINER_RUNTIME: sh: command -v podman >/dev/null 2>&1 && echo podman || echo docker - BUILDER_IMAGE: ghcr.io/stacklok/propolis-builder + BUILDER_IMAGE: ghcr.io/stacklok/go-microvm-builder LIBKRUN_VERSION: sh: grep '^LIBKRUN_VERSION=' versions.env | cut -d= -f2 LIBKRUN_MAJOR: @@ -61,7 +61,7 @@ tasks: CGO_ENABLED: "1" cmds: - mkdir -p bin - - go build -ldflags "{{.LDFLAGS}}" -o bin/{{.RUNNER_NAME}} ./runner/cmd/propolis-runner + - go build -ldflags "{{.LDFLAGS}}" -o bin/{{.RUNNER_NAME}} ./runner/cmd/go-microvm-runner sources: - ./**/*.go - go.mod @@ -74,7 +74,7 @@ tasks: platforms: [darwin] cmds: - mkdir -p bin - - CGO_ENABLED=1 go build -ldflags "{{.LDFLAGS}}" -o bin/{{.RUNNER_NAME}} ./runner/cmd/propolis-runner + - CGO_ENABLED=1 go build -ldflags "{{.LDFLAGS}}" -o bin/{{.RUNNER_NAME}} ./runner/cmd/go-microvm-runner # Hypervisor.framework requires entitlements - codesign --entitlements assets/entitlements.plist --force -s - bin/{{.RUNNER_NAME}} @@ -95,7 +95,7 @@ tasks: - install_name_tool -id @loader_path/libepoxy.0.dylib bin/libepoxy.0.dylib - install_name_tool -id @loader_path/libvirglrenderer.1.dylib bin/libvirglrenderer.1.dylib - install_name_tool -id @loader_path/libMoltenVK.dylib bin/libMoltenVK.dylib - # Rewrite propolis-runner → libkrun reference + # Rewrite go-microvm-runner → libkrun reference - >- install_name_tool -change /opt/homebrew/opt/libkrun/lib/libkrun.{{.LIBKRUN_MAJOR}}.dylib @@ -159,7 +159,7 @@ tasks: CGO_ENABLED: "1" cmds: - mkdir -p bin - - go build -race -ldflags "{{.LDFLAGS}}" -o bin/{{.RUNNER_NAME}} ./runner/cmd/propolis-runner + - go build -race -ldflags "{{.LDFLAGS}}" -o bin/{{.RUNNER_NAME}} ./runner/cmd/go-microvm-runner # ============================================================================= # Standard Tasks @@ -173,7 +173,7 @@ tasks: test-nocgo: desc: Run unit tests excluding CGO packages cmds: - - go test -v -race $(go list ./... | grep -v krun | grep -v propolis-runner) + - go test -v -race $(go list ./... | grep -v krun | grep -v go-microvm-runner) test-coverage: desc: Run tests with coverage @@ -208,7 +208,7 @@ tasks: env: CGO_ENABLED: "0" cmds: - - go build $(go list ./... | grep -v krun | grep -v propolis-runner) + - go build $(go list ./... | grep -v krun | grep -v go-microvm-runner) verify: desc: Verify code (fmt, lint, test) @@ -277,7 +277,7 @@ tasks: -e CGO_ENABLED=1 -e GOTOOLCHAIN=auto {{.BUILDER_IMAGE}}:{{.BUILDER_IMAGE_TAG}} - go build -buildvcs=false -ldflags "{{.LDFLAGS}}" -o bin/{{.RUNNER_NAME}} ./runner/cmd/propolis-runner + go build -buildvcs=false -ldflags "{{.LDFLAGS}}" -o bin/{{.RUNNER_NAME}} ./runner/cmd/go-microvm-runner generates: - bin/{{.RUNNER_NAME}} - bin/libkrun.so.1 @@ -294,9 +294,9 @@ tasks: cmds: - mkdir -p dist - | - staging="propolis-runtime-linux-{{.HOST_ARCH}}" + staging="go-microvm-runtime-linux-{{.HOST_ARCH}}" mkdir -p "${staging}" - cp bin/propolis-runner bin/libkrun.so.1 "${staging}/" + cp bin/go-microvm-runner bin/libkrun.so.1 "${staging}/" echo "{{.TAG}}" > "${staging}/VERSION" tar czf "dist/${staging}.tar.gz" "${staging}" rm -rf "${staging}" @@ -308,7 +308,7 @@ tasks: cmds: - mkdir -p dist - | - staging="propolis-firmware-linux-{{.HOST_ARCH}}" + staging="go-microvm-firmware-linux-{{.HOST_ARCH}}" mkdir -p "${staging}" cp bin/libkrunfw.so.5 "${staging}/" echo "{{.TAG}}" > "${staging}/VERSION" @@ -327,9 +327,9 @@ tasks: cmds: - mkdir -p dist - | - staging="propolis-runtime-darwin-{{.HOST_ARCH}}" + staging="go-microvm-runtime-darwin-{{.HOST_ARCH}}" mkdir -p "${staging}" - cp bin/propolis-runner bin/libkrun.{{.LIBKRUN_MAJOR}}.dylib \ + cp bin/go-microvm-runner bin/libkrun.{{.LIBKRUN_MAJOR}}.dylib \ bin/libepoxy.0.dylib bin/libvirglrenderer.1.dylib bin/libMoltenVK.dylib \ "${staging}/" echo "{{.TAG}}" > "${staging}/VERSION" @@ -344,7 +344,7 @@ tasks: cmds: - mkdir -p dist - | - staging="propolis-firmware-darwin-{{.HOST_ARCH}}" + staging="go-microvm-firmware-darwin-{{.HOST_ARCH}}" mkdir -p "${staging}" cp bin/libkrunfw.{{.LIBKRUNFW_MAJOR}}.dylib "${staging}/" echo "{{.TAG}}" > "${staging}/VERSION" @@ -367,11 +367,11 @@ tasks: - mkdir -p bin - >- gh release download {{.RELEASE_TAG}} - --repo stacklok/propolis - --pattern "propolis-runtime-linux-{{.HOST_ARCH}}.tar.gz" + --repo stacklok/go-microvm + --pattern "go-microvm-runtime-linux-{{.HOST_ARCH}}.tar.gz" --dir bin/ --clobber - - tar -xzf bin/propolis-runtime-linux-{{.HOST_ARCH}}.tar.gz -C bin/ --strip-components=1 - - rm -f bin/propolis-runtime-linux-{{.HOST_ARCH}}.tar.gz + - tar -xzf bin/go-microvm-runtime-linux-{{.HOST_ARCH}}.tar.gz -C bin/ --strip-components=1 + - rm -f bin/go-microvm-runtime-linux-{{.HOST_ARCH}}.tar.gz fetch-firmware: desc: Download pre-built firmware tarball from GitHub Release @@ -381,11 +381,11 @@ tasks: - mkdir -p bin - >- gh release download {{.RELEASE_TAG}} - --repo stacklok/propolis - --pattern "propolis-firmware-linux-{{.HOST_ARCH}}.tar.gz" + --repo stacklok/go-microvm + --pattern "go-microvm-firmware-linux-{{.HOST_ARCH}}.tar.gz" --dir bin/ --clobber - - tar -xzf bin/propolis-firmware-linux-{{.HOST_ARCH}}.tar.gz -C bin/ --strip-components=1 - - rm -f bin/propolis-firmware-linux-{{.HOST_ARCH}}.tar.gz + - tar -xzf bin/go-microvm-firmware-linux-{{.HOST_ARCH}}.tar.gz -C bin/ --strip-components=1 + - rm -f bin/go-microvm-firmware-linux-{{.HOST_ARCH}}.tar.gz fetch-runtime-darwin: desc: Download pre-built macOS runtime tarball from GitHub Release @@ -395,11 +395,11 @@ tasks: - mkdir -p bin - >- gh release download {{.RELEASE_TAG}} - --repo stacklok/propolis - --pattern "propolis-runtime-darwin-{{.HOST_ARCH}}.tar.gz" + --repo stacklok/go-microvm + --pattern "go-microvm-runtime-darwin-{{.HOST_ARCH}}.tar.gz" --dir bin/ --clobber - - tar -xzf bin/propolis-runtime-darwin-{{.HOST_ARCH}}.tar.gz -C bin/ --strip-components=1 - - rm -f bin/propolis-runtime-darwin-{{.HOST_ARCH}}.tar.gz + - tar -xzf bin/go-microvm-runtime-darwin-{{.HOST_ARCH}}.tar.gz -C bin/ --strip-components=1 + - rm -f bin/go-microvm-runtime-darwin-{{.HOST_ARCH}}.tar.gz fetch-firmware-darwin: desc: Download pre-built macOS firmware tarball from GitHub Release @@ -409,11 +409,11 @@ tasks: - mkdir -p bin - >- gh release download {{.RELEASE_TAG}} - --repo stacklok/propolis - --pattern "propolis-firmware-darwin-{{.HOST_ARCH}}.tar.gz" + --repo stacklok/go-microvm + --pattern "go-microvm-firmware-darwin-{{.HOST_ARCH}}.tar.gz" --dir bin/ --clobber - - tar -xzf bin/propolis-firmware-darwin-{{.HOST_ARCH}}.tar.gz -C bin/ --strip-components=1 - - rm -f bin/propolis-firmware-darwin-{{.HOST_ARCH}}.tar.gz + - tar -xzf bin/go-microvm-firmware-darwin-{{.HOST_ARCH}}.tar.gz -C bin/ --strip-components=1 + - rm -f bin/go-microvm-firmware-darwin-{{.HOST_ARCH}}.tar.gz fetch-runtime-oci: desc: Pull pre-built runtime OCI artifact from ghcr.io @@ -423,10 +423,10 @@ tasks: - mkdir -p bin - >- oras pull - ghcr.io/stacklok/propolis/runtime:{{.RELEASE_TAG}}-linux-{{.HOST_ARCH}} + ghcr.io/stacklok/go-microvm/runtime:{{.RELEASE_TAG}}-linux-{{.HOST_ARCH}} -o bin/ - - tar -xzf bin/propolis-runtime-linux-{{.HOST_ARCH}}.tar.gz -C bin/ --strip-components=1 - - rm -f bin/propolis-runtime-linux-{{.HOST_ARCH}}.tar.gz + - tar -xzf bin/go-microvm-runtime-linux-{{.HOST_ARCH}}.tar.gz -C bin/ --strip-components=1 + - rm -f bin/go-microvm-runtime-linux-{{.HOST_ARCH}}.tar.gz fetch-firmware-oci: desc: Pull pre-built firmware OCI artifact from ghcr.io @@ -436,7 +436,7 @@ tasks: - mkdir -p bin - >- oras pull - ghcr.io/stacklok/propolis/firmware:{{.RELEASE_TAG}}-linux-{{.HOST_ARCH}} + ghcr.io/stacklok/go-microvm/firmware:{{.RELEASE_TAG}}-linux-{{.HOST_ARCH}} -o bin/ - - tar -xzf bin/propolis-firmware-linux-{{.HOST_ARCH}}.tar.gz -C bin/ --strip-components=1 - - rm -f bin/propolis-firmware-linux-{{.HOST_ARCH}}.tar.gz + - tar -xzf bin/go-microvm-firmware-linux-{{.HOST_ARCH}}.tar.gz -C bin/ --strip-components=1 + - rm -f bin/go-microvm-firmware-linux-{{.HOST_ARCH}}.tar.gz diff --git a/assets/propolis.png b/assets/go-microvm.png similarity index 100% rename from assets/propolis.png rename to assets/go-microvm.png diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 341b773..3823ec3 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -1,6 +1,6 @@ -# propolis Architecture +# go-microvm Architecture -This document describes the internal architecture of propolis: how it turns an +This document describes the internal architecture of go-microvm: how it turns an OCI container image into a running microVM, the two-process model, networking, state management, security measures, and extension points. @@ -26,12 +26,12 @@ success it never returns -- the process becomes the VM supervisor and eventually calls `exit()` when the guest shuts down. This means we cannot call it from a normal Go application without losing the Go runtime entirely. -propolis solves this with two processes: +go-microvm solves this with two processes: ``` +----------------------------------+ +----------------------------------+ -| Your application | | propolis-runner | -| (links propolis library) | | (CGO binary, links libkrun) | +| Your application | | go-microvm-runner | +| (links go-microvm library) | | (CGO binary, links libkrun) | | | | | | 1. Preflight checks | spawn | 1. Parse Config from argv[1] | | 2. Pull & cache OCI image |------>| 2. Validate (rootfs, vCPUs>0) | @@ -39,7 +39,7 @@ propolis solves this with two processes: | 4. Run rootfs hooks | config| 4. SetVMConfig(vCPUs, RAM) | | 5. Write .krun_config.json | | 5. SetRoot(rootfsPath) | | 6. Start networking (if custom)| | 6. Setup networking | -| 7. Spawn propolis-runner | | 7. AddVirtioFS (for each mount) | +| 7. Spawn go-microvm-runner | | 7. AddVirtioFS (for each mount) | | 8. Run post-boot hooks | | 8. SetConsoleOutput(logPath) | | 9. Return *VM handle | | 9. krun_start_enter() | | | | (NEVER RETURNS ON SUCCESS) | @@ -54,7 +54,7 @@ propolis solves this with two processes: ### Library Side (your application) The library is pure Go with no CGO dependency. It performs the following steps -in `propolis.Run()`: +in `microvm.Run()`: 1. **Preflight checks** -- Runs all registered `preflight.Checker` validations. Built-in checks verify KVM/HVF access, disk space, and system resources. @@ -92,7 +92,7 @@ in `propolis.Run()`: 6. **Start VM via backend** -- The `hypervisor.Backend` handles rootfs preparation and VM launch. The default libkrun backend serializes - `runner.Config` as JSON and spawns `propolis-runner` as a detached + `runner.Config` as JSON and spawns `go-microvm-runner` as a detached subprocess (`setsid` for new session). The runner is located by searching: explicit path, system PATH, then next to the calling executable. Custom backends can be provided via `WithBackend()`. @@ -100,9 +100,9 @@ in `propolis.Run()`: 7. **Post-boot hooks** -- Runs caller-provided `PostBootHook` functions. If any hook fails, the VM is stopped and the error is returned. -### Runner Side (propolis-runner) +### Runner Side (go-microvm-runner) -The runner binary (`runner/cmd/propolis-runner/main.go`) is intentionally +The runner binary (`runner/cmd/go-microvm-runner/main.go`) is intentionally minimal. It is a thin translation layer between JSON config and the libkrun C API: @@ -147,7 +147,7 @@ testing or to customize how the runner subprocess is launched. ## Hypervisor Backend Abstraction -The `hypervisor` package defines the `Backend` interface that decouples propolis +The `hypervisor` package defines the `Backend` interface that decouples go-microvm from any specific hypervisor implementation: ```go @@ -169,7 +169,7 @@ type VMHandle interface { The default backend (`hypervisor/libkrun`) implements `Backend` by: 1. **PrepareRootFS**: Writes `/.krun_config.json` to the rootfs from `InitConfig` -2. **Start**: Converts `VMConfig` to `runner.Config`, spawns `propolis-runner` +2. **Start**: Converts `VMConfig` to `runner.Config`, spawns `go-microvm-runner` via the `runner.Spawner` interface, and returns a `processHandle` wrapping the subprocess @@ -177,15 +177,15 @@ The libkrun backend accepts its own options via `libkrun.NewBackend(opts...)`: | Option | Description | |--------|-------------| -| `libkrun.WithRunnerPath(p)` | Path to propolis-runner binary | +| `libkrun.WithRunnerPath(p)` | Path to go-microvm-runner binary | | `libkrun.WithLibDir(d)` | Directory for libkrun/libkrunfw shared libraries | | `libkrun.WithSpawner(s)` | Custom runner subprocess spawner (for testing) | ### Custom Backends To support a different hypervisor, implement `hypervisor.Backend` and pass it -via `propolis.WithBackend()`. The backend handles all hypervisor-specific logic -while propolis handles OCI image management, networking, hooks, and lifecycle. +via `microvm.WithBackend()`. The backend handles all hypervisor-specific logic +while go-microvm handles OCI image management, networking, hooks, and lifecycle. For migration details from the older top-level `WithRunnerPath`/`WithLibDir`/ `WithSpawner` options, see [MIGRATION-BACKEND-ABSTRACTION.md](MIGRATION-BACKEND-ABSTRACTION.md). @@ -268,7 +268,7 @@ Step 9: NETWORKING Custom provider: net.Provider.Start() in caller's process, socket path to runner | Step 10: SPAWN - runner.Spawner.Spawn() --> propolis-runner subprocess + runner.Spawner.Spawn() --> go-microvm-runner subprocess Detached (setsid), stdout/stderr redirected to vm.log | Step 11: POST-BOOT @@ -281,7 +281,7 @@ Step 11: POST-BOOT Images are cached by manifest digest under the data directory: ``` -~/.config/propolis/cache/ +~/.config/go-microvm/cache/ sha256-abc123def456.../ <-- extracted rootfs for this digest sha256-789012345678.../ <-- another cached image ``` @@ -309,14 +309,14 @@ This ensures no partial writes and no corruption from concurrent access. ### Cache Directory -The cache directory defaults to `~/.config/propolis/cache/`. It can be +The cache directory defaults to `~/.config/go-microvm/cache/`. It can be customized via `WithDataDir()` (which sets the cache under `$dataDir/cache/`) or directly via `WithImageCache(image.NewCache("/custom/path"))`. ## .krun_config.json libkrun's built-in init process reads `/.krun_config.json` from the root of -the guest filesystem to determine what program to execute. propolis constructs +the guest filesystem to determine what program to execute. go-microvm constructs this file from the OCI image config with optional overrides. ### Format @@ -352,7 +352,7 @@ This is the same mechanism used by krunvm and podman machine. ## Networking -propolis uses a userspace network stack powered by +go-microvm uses a userspace network stack powered by [gvisor-tap-vsock](https://github.com/containers/gvisor-tap-vsock). All VM traffic flows as Ethernet frames with no kernel networking between host and guest. @@ -443,7 +443,7 @@ type Provider interface { To replace the default runner-side networking with a different backend (e.g., passt, slirp4netns, a custom bridge, or the built-in hosted provider), implement this interface and pass it via -`propolis.WithNetProvider()`. The `SocketPath()` return value is passed to +`microvm.WithNetProvider()`. The `SocketPath()` return value is passed to the runner as the Unix socket path for `krun_add_net_unixstream`. ### Network Topology Constants @@ -464,16 +464,16 @@ these values to ensure a consistent topology. ### Hosted Network Provider The `net/hosted` package implements a `net.Provider` that runs the -VirtualNetwork in the caller's process rather than inside propolis-runner. +VirtualNetwork in the caller's process rather than inside go-microvm-runner. This enables callers to access the VirtualNetwork directly -- for example, to create in-process TCP listeners via gonet that are reachable from the guest VM without opening real host sockets. ```go p := hosted.NewProvider() -vm, err := propolis.Run(ctx, image, - propolis.WithNetProvider(p), - propolis.WithPorts(propolis.PortForward{Host: sshPort, Guest: 22}), +vm, err := microvm.Run(ctx, image, + microvm.WithNetProvider(p), + microvm.WithPorts(microvm.PortForward{Host: sshPort, Guest: 22}), ) // p.VirtualNetwork() is now available for gonet listeners. ``` @@ -487,12 +487,12 @@ before the guest boots and are reachable from inside the VM: ```go p := hosted.NewProvider() p.AddService(hosted.Service{Port: 4483, Handler: myHandler}) -vm, err := propolis.Run(ctx, image, propolis.WithNetProvider(p)) +vm, err := microvm.Run(ctx, image, microvm.WithNetProvider(p)) // Guest can reach http://192.168.127.1:4483/ ``` The hosted provider exposes a Unix socket (`hosted-net.sock` in the data -directory) that propolis-runner connects to. When firewall rules are +directory) that go-microvm-runner connects to. When firewall rules are configured, a `firewall.Relay` is inserted between the runner connection and the VirtualNetwork to filter traffic. The relay is accessible via `Provider.Relay()` for metrics. @@ -500,7 +500,7 @@ and the VirtualNetwork to filter traffic. The relay is accessible via ## Extension Points ``` - propolis.Run() + microvm.Run() | +------------+------------+ | | @@ -540,14 +540,14 @@ and the VirtualNetwork to filter traffic. The relay is accessible via Inject validation before any work begins: ```go -propolis.WithPreflightChecks(check1, check2) +microvm.WithPreflightChecks(check1, check2) ``` ### Rootfs Hooks Modify the extracted filesystem before boot: ```go -propolis.WithRootFSHook(func(rootfs string, cfg *image.OCIConfig) error { +microvm.WithRootFSHook(func(rootfs string, cfg *image.OCIConfig) error { // Write files, install keys, modify configs return nil }) @@ -557,14 +557,14 @@ propolis.WithRootFSHook(func(rootfs string, cfg *image.OCIConfig) error { Replace the OCI ENTRYPOINT/CMD: ```go -propolis.WithInitOverride("/sbin/my-init", "--flag") +microvm.WithInitOverride("/sbin/my-init", "--flag") ``` ### Network Provider Replace the default runner-side networking with a custom provider: ```go -propolis.WithNetProvider(myProvider) +microvm.WithNetProvider(myProvider) ``` The `net/hosted` package provides a built-in hosted provider that runs the @@ -572,7 +572,7 @@ VirtualNetwork in the caller's process: ```go p := hosted.NewProvider() p.AddService(hosted.Service{Port: 4483, Handler: myHandler}) -propolis.WithNetProvider(p) +microvm.WithNetProvider(p) // After Run(), p.VirtualNetwork() is available for gonet listeners. ``` @@ -580,7 +580,7 @@ propolis.WithNetProvider(p) Run logic after the VM process is confirmed alive: ```go -propolis.WithPostBoot(func(ctx context.Context, vm *propolis.VM) error { +microvm.WithPostBoot(func(ctx context.Context, vm *microvm.VM) error { // Wait for SSH, push config, verify health return nil }) @@ -633,8 +633,8 @@ via `slog.Warn` but do not prevent the pipeline from proceeding. Pass checks via `WithPreflightChecks()`: ```go -propolis.Run(ctx, ref, - propolis.WithPreflightChecks( +microvm.Run(ctx, ref, + microvm.WithPreflightChecks( preflight.PortCheck(8080, 2222), preflight.Check{ Name: "my-check", @@ -650,7 +650,7 @@ Custom checks are appended to (not replacing) the built-in platform defaults. To replace the entire preflight checker (e.g., when the caller manages its own): ```go -propolis.WithPreflightChecker(preflight.NewEmpty()) +microvm.WithPreflightChecker(preflight.NewEmpty()) ``` ## Guest-Side Packages @@ -663,7 +663,7 @@ processes to orchestrate guest boot. |---------|---------| | `guest/boot` | Orchestrates the guest boot sequence: mounts, networking, workspace, hardening, environment, SSH, capabilities. Functional options pattern for configuration. | | `guest/mount` | Handles essential filesystem mounts (devtmpfs, sysfs, procfs) and workspace mounts | -| `guest/env` | Loads environment variables from `/.propolis/env.sh` | +| `guest/env` | Loads environment variables from `/.go-microvm/env.sh` | | `guest/netcfg` | Guest-side network configuration (DHCP, routes) | | `guest/harden` | VM kernel hardening: capability dropping (CAP_NET_ADMIN, etc.), CIS benchmark sysctls, `PR_SET_NO_NEW_PRIVS` | | `guest/reaper` | Zombie process reaping (init process duties) | @@ -674,7 +674,7 @@ processes to orchestrate guest boot. | Package | Purpose | |---------|---------| | `hooks` | RootFS hook factories: `InjectAuthorizedKeys`, `InjectFile`, `InjectBinary`, `InjectEnvFile`. Uses `internal/pathutil` for path traversal validation. | -| `extract` | Binary bundle caching with SHA-256 versioning, atomic extraction, and cross-process file locking. Used to cache and extract the propolis-runner binary and libraries. | +| `extract` | Binary bundle caching with SHA-256 versioning, atomic extraction, and cross-process file locking. Used to cache and extract the go-microvm-runner binary and libraries. | | `image/disk` | Streaming disk image download with retry support and decompression (gzip, bzip2, xz). | ## State Management @@ -684,14 +684,14 @@ The `state` package provides persistent VM state with file-based locking. ### Directory Layout ``` -~/.config/propolis/ (or $PROPOLIS_DATA_DIR, or WithDataDir path) - propolis-state.json <-- VM state (atomic JSON) - propolis-state.lock <-- flock for exclusive access +~/.config/go-microvm/ (or $GO_MICROVM_DATA_DIR, or WithDataDir path) + go-microvm-state.json <-- VM state (atomic JSON) + go-microvm-state.lock <-- flock for exclusive access cache/ sha256-abc123.../ <-- cached rootfs by digest sha256-def456.../ console.log <-- guest console output (kernel, init) - vm.log <-- propolis-runner stdout/stderr + vm.log <-- go-microvm-runner stdout/stderr hosted-net.sock <-- networking Unix socket (only with hosted provider) ``` @@ -725,8 +725,8 @@ The `state` package provides persistent VM state with file-based locking. The `state.Manager` provides atomic load-and-lock semantics: -1. `LoadAndLock(ctx)` acquires an exclusive `flock` on `propolis-state.lock` -2. Reads and parses `propolis-state.json` (or returns a default State if the file +1. `LoadAndLock(ctx)` acquires an exclusive `flock` on `go-microvm-state.lock` +2. Reads and parses `go-microvm-state.json` (or returns a default State if the file does not exist) 3. Returns a `LockedState` that holds the lock @@ -757,7 +757,7 @@ for cases where another process may hold the lock temporarily. 1. Marshals the state to JSON with indentation 2. Writes to a temporary file in the same directory (`state-*.json.tmp`) -3. Calls `os.Rename()` to atomically replace `propolis-state.json` +3. Calls `os.Rename()` to atomically replace `go-microvm-state.json` If a crash occurs during write, either the old state remains intact or the new state is fully written -- never a partial file. The `flock` ensures only @@ -807,7 +807,7 @@ safe use in shell commands. The standard post-boot hook pattern uses `WaitForReady`: ```go -propolis.WithPostBoot(func(ctx context.Context, vm *propolis.VM) error { +microvm.WithPostBoot(func(ctx context.Context, vm *microvm.VM) error { client := ssh.NewClient("127.0.0.1", 2222, "root", keyPath) return client.WaitForReady(ctx) }) diff --git a/docs/CI.md b/docs/CI.md index 399b3ae..39f6014 100644 --- a/docs/CI.md +++ b/docs/CI.md @@ -1,6 +1,6 @@ # CI & Release Pipelines -propolis uses three GitHub Actions workflows. They form a dependency chain: +go-microvm uses three GitHub Actions workflows. They form a dependency chain: the **Builder** produces a container image that **CI** and **Release** consume. ## Workflows @@ -34,7 +34,7 @@ setup tools, call task). ### Builder (`builder.yaml`) -Builds the `ghcr.io/stacklok/propolis-builder` container image, which +Builds the `ghcr.io/stacklok/go-microvm-builder` container image, which compiles libkrun and libkrunfw from source. This image provides the CGO toolchain that CI and Release need. @@ -66,7 +66,7 @@ Both architectures (amd64, arm64) build on native runners. **Where artifacts go:** - GitHub Release with checksums -- OCI artifacts pushed to `ghcr.io/stacklok/propolis/{runtime,firmware}` +- OCI artifacts pushed to `ghcr.io/stacklok/go-microvm/{runtime,firmware}` The runtime and firmware are split into separate tarballs because they have different licenses. diff --git a/docs/MACOS.md b/docs/MACOS.md index a758fc6..c6d9dd2 100644 --- a/docs/MACOS.md +++ b/docs/MACOS.md @@ -1,6 +1,6 @@ # macOS Support -propolis supports macOS on Apple Silicon (arm64) using Hypervisor.framework. +go-microvm supports macOS on Apple Silicon (arm64) using Hypervisor.framework. ## Requirements @@ -18,7 +18,7 @@ brew install libkrun libkrunfw ``` This installs the libraries and headers into Homebrew's prefix (`/opt/homebrew` -on Apple Silicon, `/usr/local` on Intel). The CGO directives in propolis +on Apple Silicon, `/usr/local` on Intel). The CGO directives in go-microvm automatically search both paths. ## Key Platform Differences @@ -47,10 +47,10 @@ Three entitlements are required (see `assets/entitlements.plist`): entitlement activates hardened runtime, which silently strips `DYLD_*` variables without this entitlement) -The propolis-runner binary must be signed: +The go-microvm-runner binary must be signed: ```bash -codesign --entitlements assets/entitlements.plist --force -s - bin/propolis-runner +codesign --entitlements assets/entitlements.plist --force -s - bin/go-microvm-runner ``` The `task build-dev-darwin` command handles signing automatically. @@ -58,7 +58,7 @@ The `task build-dev-darwin` command handles signing automatically. ## DYLD_LIBRARY_PATH When using bundled (non-system) libraries, the runner subprocess needs -`DYLD_LIBRARY_PATH` set. propolis handles this automatically via +`DYLD_LIBRARY_PATH` set. go-microvm handles this automatically via `libkrun.WithLibDir()` (passed to `libkrun.NewBackend()`). The hypervisor entitlement activates macOS **hardened runtime**, which silently @@ -69,12 +69,12 @@ to find libkrun, verify the binary is signed with all three entitlements. ## Filesystem Permissions (virtiofs) -On macOS, non-root users cannot `chown` files to arbitrary UIDs. When propolis +On macOS, non-root users cannot `chown` files to arbitrary UIDs. When go-microvm extracts an OCI image, all files end up owned by the host user. libkrun's virtiofs FUSE server performs access checks using host-side ownership, so guest processes running as different UIDs (e.g., root) would get `EACCES` errors. -propolis works around this using the `user.containers.override_stat` extended +go-microvm works around this using the `user.containers.override_stat` extended attribute, which libkrun's virtiofs server reads to report overridden uid/gid/mode to the guest. This is the same mechanism used by podman on macOS. The xattr is set automatically during OCI layer extraction and rootfs cloning @@ -83,7 +83,7 @@ The xattr is set automatically during OCI layer extraction and rootfs cloning ## Guest Networking On macOS, libkrun's Hypervisor.framework backend pre-configures the guest -network interface via DHCP before the custom init process runs. propolis +network interface via DHCP before the custom init process runs. go-microvm handles this transparently by using idempotent network configuration (`AddrReplace`/`RouteReplace` instead of `AddrAdd`/`RouteAdd`), so the init works correctly regardless of whether the interface is already configured. @@ -106,11 +106,11 @@ nested virtualization). EXC_BAD_ACCESS (code=1, address=0x0) ``` -The propolis-runner binary is not signed with the hypervisor entitlement. +The go-microvm-runner binary is not signed with the hypervisor entitlement. Re-sign it: ```bash -codesign --entitlements assets/entitlements.plist --force -s - bin/propolis-runner +codesign --entitlements assets/entitlements.plist --force -s - bin/go-microvm-runner ``` ### DYLD_LIBRARY_PATH issues diff --git a/docs/MIGRATION-BACKEND-ABSTRACTION.md b/docs/MIGRATION-BACKEND-ABSTRACTION.md index 17e9917..ac0513c 100644 --- a/docs/MIGRATION-BACKEND-ABSTRACTION.md +++ b/docs/MIGRATION-BACKEND-ABSTRACTION.md @@ -8,35 +8,35 @@ consumers. | Removed API | Replacement | Affected projects | |---|---|---| -| `propolis.WithRunnerPath(p)` | `libkrun.WithRunnerPath(p)` passed to `libkrun.NewBackend()` | waggle, apiary, toolhive-appliance | -| `propolis.WithLibDir(d)` | `libkrun.WithLibDir(d)` passed to `libkrun.NewBackend()` | waggle, toolhive-appliance | -| `propolis.WithSpawner(s)` | `libkrun.WithSpawner(s)` passed to `libkrun.NewBackend()` | tests only | -| `propolis.VM.PID() int` | `propolis.VM.ID() string` | waggle, toolhive-appliance | +| `microvm.WithRunnerPath(p)` | `libkrun.WithRunnerPath(p)` passed to `libkrun.NewBackend()` | waggle, apiary, toolhive-appliance | +| `microvm.WithLibDir(d)` | `libkrun.WithLibDir(d)` passed to `libkrun.NewBackend()` | waggle, toolhive-appliance | +| `microvm.WithSpawner(s)` | `libkrun.WithSpawner(s)` passed to `libkrun.NewBackend()` | tests only | +| `microvm.VM.PID() int` | `microvm.VM.ID() string` | waggle, toolhive-appliance | ## New Imports ```go -import "github.com/stacklok/propolis/hypervisor/libkrun" +import "github.com/stacklok/go-microvm/hypervisor/libkrun" ``` ## Migration Examples -### waggle (`pkg/infra/vm/propolis.go`) +### waggle (`pkg/infra/vm/microvm.go`) **Before:** ```go if opts.RunnerPath != "" { - propolisOpts = append(propolisOpts, propolis.WithRunnerPath(opts.RunnerPath)) + microvmOpts = append(microvmOpts, microvm.WithRunnerPath(opts.RunnerPath)) } if opts.LibDir != "" { - propolisOpts = append(propolisOpts, propolis.WithLibDir(opts.LibDir)) + microvmOpts = append(microvmOpts, microvm.WithLibDir(opts.LibDir)) } slog.Info("microVM created", "pid", vm.PID()) ``` **After:** ```go -import "github.com/stacklok/propolis/hypervisor/libkrun" +import "github.com/stacklok/go-microvm/hypervisor/libkrun" var backendOpts []libkrun.Option if opts.RunnerPath != "" { @@ -45,7 +45,7 @@ if opts.RunnerPath != "" { if opts.LibDir != "" { backendOpts = append(backendOpts, libkrun.WithLibDir(opts.LibDir)) } -propolisOpts = append(propolisOpts, propolis.WithBackend(libkrun.NewBackend(backendOpts...))) +microvmOpts = append(microvmOpts, microvm.WithBackend(libkrun.NewBackend(backendOpts...))) slog.Info("microVM created", "id", vm.ID()) ``` @@ -54,16 +54,16 @@ slog.Info("microVM created", "id", vm.ID()) **Before:** ```go if r.runnerPath != "" { - opts = append(opts, propolis.WithRunnerPath(r.runnerPath)) + opts = append(opts, microvm.WithRunnerPath(r.runnerPath)) } ``` **After:** ```go -import "github.com/stacklok/propolis/hypervisor/libkrun" +import "github.com/stacklok/go-microvm/hypervisor/libkrun" if r.runnerPath != "" { - opts = append(opts, propolis.WithBackend(libkrun.NewBackend( + opts = append(opts, microvm.WithBackend(libkrun.NewBackend( libkrun.WithRunnerPath(r.runnerPath), ))) } @@ -74,10 +74,10 @@ if r.runnerPath != "" { **Before:** ```go if runnerPath != "" { - propolisOpts = append(propolisOpts, propolis.WithRunnerPath(runnerPath)) + microvmOpts = append(microvmOpts, microvm.WithRunnerPath(runnerPath)) } if libDir != "" { - propolisOpts = append(propolisOpts, propolis.WithLibDir(libDir)) + microvmOpts = append(microvmOpts, microvm.WithLibDir(libDir)) } PID: vmInstance.PID(), go m.reaperLoop(vmInstance.PID()) @@ -87,7 +87,7 @@ go m.reaperLoop(vmInstance.PID()) ```go import ( "strconv" - "github.com/stacklok/propolis/hypervisor/libkrun" + "github.com/stacklok/go-microvm/hypervisor/libkrun" ) var backendOpts []libkrun.Option @@ -97,7 +97,7 @@ if runnerPath != "" { if libDir != "" { backendOpts = append(backendOpts, libkrun.WithLibDir(libDir)) } -propolisOpts = append(propolisOpts, propolis.WithBackend(libkrun.NewBackend(backendOpts...))) +microvmOpts = append(microvmOpts, microvm.WithBackend(libkrun.NewBackend(backendOpts...))) // For PID — parse ID string: id := vmInstance.ID() @@ -110,8 +110,8 @@ pid, _ := strconv.Atoi(id) **Before:** ```go spawner := &mockSpawner{proc: mockProc, err: nil} -opts := []propolis.Option{ - propolis.WithSpawner(spawner), +opts := []microvm.Option{ + microvm.WithSpawner(spawner), } ``` @@ -131,7 +131,7 @@ func (m *mockBackend) Start(_ context.Context, _ hypervisor.VMConfig) (hyperviso return m.handle, m.err } -opts := []propolis.Option{ - propolis.WithBackend(&mockBackend{handle: mockHandle}), +opts := []microvm.Option{ + microvm.WithBackend(&mockBackend{handle: mockHandle}), } ``` diff --git a/docs/NETWORKING.md b/docs/NETWORKING.md index 7a0a4b7..bbb1f8f 100644 --- a/docs/NETWORKING.md +++ b/docs/NETWORKING.md @@ -1,6 +1,6 @@ # Networking and Firewall -This document provides a deep dive into the propolis networking subsystem, +This document provides a deep dive into the go-microvm networking subsystem, including the in-process userspace network stack, wire protocol, firewall architecture, and extension points. @@ -18,7 +18,7 @@ architecture, and extension points. ## Overview -propolis uses a userspace network stack powered by +go-microvm uses a userspace network stack powered by [gvisor-tap-vsock](https://github.com/containers/gvisor-tap-vsock). All VM traffic flows as Ethernet frames with no kernel networking between host and guest, and no separate gvproxy binary is needed. @@ -59,7 +59,7 @@ When no `WithNetProvider()` is set, the runner creates a VirtualNetwork in-process and connects it to libkrun via a socketpair: ``` -+----------------------------------propolis-runner process---------+ ++----------------------------------go-microvm-runner process------+ | | | +----------+ socketpair +-------------------+ Go net | | | libkrun | (fd pair) | VirtualNetwork |----------+ | @@ -375,15 +375,15 @@ Return traffic for allowed connections is automatically permitted via connection tracking. ```go -import "github.com/stacklok/propolis/net/firewall" +import "github.com/stacklok/go-microvm/net/firewall" -vm, err := propolis.Run(ctx, "my-app:latest", - propolis.WithPorts( - propolis.PortForward{Host: 8080, Guest: 80}, - propolis.PortForward{Host: 2222, Guest: 22}, +vm, err := microvm.Run(ctx, "my-app:latest", + microvm.WithPorts( + microvm.PortForward{Host: 8080, Guest: 80}, + microvm.PortForward{Host: 2222, Guest: 22}, ), - propolis.WithFirewallDefaultAction(firewall.Deny), - propolis.WithFirewallRules( + microvm.WithFirewallDefaultAction(firewall.Deny), + microvm.WithFirewallRules( // Egress: allow DNS and HTTPS firewall.Rule{ Direction: firewall.Egress, @@ -417,13 +417,13 @@ vm, err := propolis.Run(ctx, "my-app:latest", ### Allow Specific Ingress Ports Only ```go -vm, err := propolis.Run(ctx, "my-server:latest", - propolis.WithPorts( - propolis.PortForward{Host: 8443, Guest: 443}, - propolis.PortForward{Host: 6443, Guest: 6443}, +vm, err := microvm.Run(ctx, "my-server:latest", + microvm.WithPorts( + microvm.PortForward{Host: 8443, Guest: 443}, + microvm.PortForward{Host: 6443, Guest: 6443}, ), - propolis.WithFirewallDefaultAction(firewall.Deny), - propolis.WithFirewallRules( + microvm.WithFirewallDefaultAction(firewall.Deny), + microvm.WithFirewallRules( // Allow all egress (VM can reach the internet) firewall.Rule{ Direction: firewall.Egress, @@ -458,8 +458,8 @@ When no firewall rules are configured, all traffic passes through unrestricted. This is the default behavior: ```go -vm, err := propolis.Run(ctx, "alpine:latest", - propolis.WithPorts(propolis.PortForward{Host: 8080, Guest: 80}), +vm, err := microvm.Run(ctx, "alpine:latest", + microvm.WithPorts(microvm.PortForward{Host: 8080, Guest: 80}), ) ``` @@ -467,13 +467,13 @@ vm, err := propolis.Run(ctx, "alpine:latest", `WithEgressPolicy()` restricts VM outbound traffic to a set of allowed DNS hostnames. Instead of writing firewall rules for specific IPs (which change -often), you specify hostnames and let propolis handle the rest. +often), you specify hostnames and let go-microvm handle the rest. ```go -vm, err := propolis.Run(ctx, "my-app:latest", - propolis.WithPorts(propolis.PortForward{Host: 8080, Guest: 80}), - propolis.WithEgressPolicy(propolis.EgressPolicy{ - AllowedHosts: []propolis.EgressHost{ +vm, err := microvm.Run(ctx, "my-app:latest", + microvm.WithPorts(microvm.PortForward{Host: 8080, Guest: 80}), + microvm.WithEgressPolicy(microvm.EgressPolicy{ + AllowedHosts: []microvm.EgressHost{ {Name: "api.github.com", Ports: []uint16{443}}, {Name: "*.docker.io"}, {Name: "ntp.ubuntu.com", Ports: []uint16{123}, Protocol: 17}, @@ -555,7 +555,7 @@ To replace the default runner-side networking with an alternative backend 2. `Start()` must block until the Unix socket is ready for connections. 3. The socket must use `SOCK_STREAM` with 4-byte big-endian length-prefixed Ethernet frames (the QEMU transport protocol). -4. Pass your provider via `propolis.WithNetProvider(myProvider)`. +4. Pass your provider via `microvm.WithNetProvider(myProvider)`. The `SocketPath()` return value is passed to the runner as the Unix socket path for `krun_add_net_unixstream`. See `net/hosted/provider.go` for the diff --git a/docs/SECURITY.md b/docs/SECURITY.md index 5a58e70..2dd373f 100644 --- a/docs/SECURITY.md +++ b/docs/SECURITY.md @@ -1,7 +1,7 @@ # Security Model This document describes the security properties, trust boundaries, and -hardening recommendations for propolis. +hardening recommendations for go-microvm. ## Table of Contents @@ -19,14 +19,14 @@ hardening recommendations for propolis. ## Trust Boundaries -propolis has two trust boundaries: +go-microvm has two trust boundaries: ``` Trust boundary 1: KVM/HVF (hardware isolation) | +-------------------------+|+------------------------------------------+ -| Guest VM ||| propolis-runner | +| Guest VM ||| go-microvm-runner | | (untrusted code) ||| +------------------+ +------------------+| | ||| | libkrun VMM | | VirtualNetwork || | Runs user workload ||| | (virtio devices, | | (gvisor-tap-vsock|| @@ -136,9 +136,9 @@ security-sensitive deployments. The collapsed trust boundary (default mode) would matter more if: - **Multiple VMs shared a VirtualNetwork** (multi-tenant): one VM could - sniff or poison another's traffic. propolis does not support this. + sniff or poison another's traffic. go-microvm does not support this. - **The network stack held secrets** (TLS termination, auth tokens): - a guest escape would expose them. propolis port forwards are plain TCP. + a guest escape would expose them. go-microvm port forwards are plain TCP. - **The network stack ran with higher privileges** than the VMM: not the case here, both share the same process and UID. @@ -199,7 +199,7 @@ network stack out of the runner process. This achieves process-level separation without a custom helper binary: ``` -propolis-runner (VMM only) +go-microvm-runner (VMM only) └── Unix socket → hosted provider in caller's process caller's process (network stack) └── hosted.Provider → VirtualNetwork + HTTP services @@ -387,7 +387,7 @@ The egress policy prevents a compromised or untrusted VM from: ## Tar Extraction Defenses -When extracting OCI image layers, propolis applies multiple layers of +When extracting OCI image layers, go-microvm applies multiple layers of defense against malicious tar archives: **Path traversal prevention.** Every tar entry name is cleaned via @@ -418,7 +418,7 @@ are silently skipped. ## Process Identity Verification -When managing VM lifecycle, propolis verifies process identity before +When managing VM lifecycle, go-microvm verifies process identity before sending signals: - `IsAlive()` sends signal 0 to the PID (no-op that verifies the @@ -432,7 +432,7 @@ been reused. ## Host Capabilities (Linux) -When running as a non-root user on Linux, propolis requires `CAP_CHOWN` on the +When running as a non-root user on Linux, go-microvm requires `CAP_CHOWN` on the process to set correct file ownership during OCI image extraction. Without it, all extracted rootfs files are owned by the host user, and the guest sees incorrect ownership — which can cause permission errors for processes running @@ -451,7 +451,7 @@ capsh --addamb=cap_chown -- -c '/path/to/your-binary' ### override_stat xattr (macOS and Linux) -propolis also sets the `user.containers.override_stat` extended attribute on +go-microvm also sets the `user.containers.override_stat` extended attribute on extracted files so that libkrun's virtiofs server reports correct ownership to the guest. This is the same mechanism that podman uses on macOS. @@ -478,11 +478,11 @@ See the `internal/xattr` package for details. ## SSH Client Security The SSH client uses `InsecureIgnoreHostKey()` for host key verification. -This is acceptable because the client only connects to VMs that propolis +This is acceptable because the client only connects to VMs that go-microvm just created -- the guest was booted from an image we pulled and configured, and the connection is over a localhost port forward that is not exposed to the network. -If propolis is used in a scenario where the SSH connection traverses an +If go-microvm is used in a scenario where the SSH connection traverses an untrusted network, host key verification should be implemented by the caller using a custom SSH client rather than the built-in one. diff --git a/docs/TROUBLESHOOTING.md b/docs/TROUBLESHOOTING.md index cf72268..b0fc351 100644 --- a/docs/TROUBLESHOOTING.md +++ b/docs/TROUBLESHOOTING.md @@ -1,6 +1,6 @@ # Troubleshooting -Common issues when using propolis and how to resolve them. +Common issues when using go-microvm and how to resolve them. ## VM Fails to Start @@ -28,28 +28,28 @@ sysctl kern.hv_support ### Code signing required (macOS) -If propolis-runner crashes immediately with `EXC_BAD_ACCESS`, it needs the +If go-microvm-runner crashes immediately with `EXC_BAD_ACCESS`, it needs the hypervisor entitlement. See [docs/MACOS.md](MACOS.md). ## Log Files -propolis writes log files to the data directory -(`~/.config/propolis/` by default, or the path set via `WithDataDir()`): +go-microvm writes log files to the data directory +(`~/.config/go-microvm/` by default, or the path set via `WithDataDir()`): | File | Contents | |------|----------| | `console.log` | Guest console output (kernel messages, init script) | -| `vm.log` | propolis-runner stdout/stderr (libkrun errors) | +| `vm.log` | go-microvm-runner stdout/stderr (libkrun errors) | Networking logs are emitted via `log/slog` and appear in the application's structured logging output rather than a separate file. ```bash # Check for guest-side errors (kernel, init script) -cat ~/.config/propolis/console.log +cat ~/.config/go-microvm/console.log # Check for host-side runner errors -cat ~/.config/propolis/vm.log +cat ~/.config/go-microvm/vm.log ``` ## Port Conflicts @@ -77,17 +77,17 @@ successfully by checking the application's log output for errors from ## Runner Binary Not Found -propolis searches for `propolis-runner` in this order: +go-microvm searches for `go-microvm-runner` in this order: 1. Explicit path via `libkrun.WithRunnerPath()` (passed to `libkrun.NewBackend()`) 2. System `$PATH` 3. Next to the calling executable ```bash # Check if it's in PATH -which propolis-runner +which go-microvm-runner # Build it (requires system libkrun-devel) -cd propolis && task build-dev +cd go-microvm && task build-dev ``` ## Resource Limits @@ -100,7 +100,7 @@ guests to 8 vCPUs. Requesting more will fail at `SetVMConfig()`. ### Memory There is no hard memory limit from libkrun. The practical limit is -available host RAM. propolis defaults to 512 MiB. +available host RAM. go-microvm defaults to 512 MiB. ## Licensing diff --git a/extract/source.go b/extract/source.go index 259d23c..95a4015 100644 --- a/extract/source.go +++ b/extract/source.go @@ -9,9 +9,9 @@ import ( "os" ) -// RunnerBinaryName is the expected filename for the propolis-runner binary +// RunnerBinaryName is the expected filename for the go-microvm-runner binary // within a runtime source directory. -const RunnerBinaryName = "propolis-runner" +const RunnerBinaryName = "go-microvm-runner" // Source resolves a set of files into a directory, using cacheDir for // extraction-based implementations. The context allows caller-implemented @@ -58,7 +58,7 @@ func (s *dirSource) Ensure(_ context.Context, _ string) (string, error) { return s.path, nil } -// RuntimeBundle creates a Source that extracts propolis-runner and libkrun +// RuntimeBundle creates a Source that extracts go-microvm-runner and libkrun // into a versioned cache directory. The runner and libkrun byte slices are // the file contents to extract. The libkrun major soname version is always 1 // because the runner binary is built against a specific libkrun ABI. diff --git a/extract/source_test.go b/extract/source_test.go index 458ffd5..1f5d9a1 100644 --- a/extract/source_test.go +++ b/extract/source_test.go @@ -26,7 +26,7 @@ func TestRuntimeBundle_ExtractsFiles(t *testing.T) { dir, err := src.Ensure(context.Background(), cacheDir) require.NoError(t, err) - // Verify propolis-runner. + // Verify go-microvm-runner. got, err := os.ReadFile(filepath.Join(dir, RunnerBinaryName)) require.NoError(t, err) assert.Equal(t, runnerData, got) diff --git a/go.mod b/go.mod index 1ebb289..ca0d598 100644 --- a/go.mod +++ b/go.mod @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc. // SPDX-License-Identifier: Apache-2.0 -module github.com/stacklok/propolis +module github.com/stacklok/go-microvm go 1.26.0 diff --git a/guest/boot/boot.go b/guest/boot/boot.go index afa480d..217a4de 100644 --- a/guest/boot/boot.go +++ b/guest/boot/boot.go @@ -14,11 +14,11 @@ import ( "golang.org/x/crypto/ssh" - "github.com/stacklok/propolis/guest/env" - "github.com/stacklok/propolis/guest/harden" - "github.com/stacklok/propolis/guest/mount" - "github.com/stacklok/propolis/guest/netcfg" - "github.com/stacklok/propolis/guest/sshd" + "github.com/stacklok/go-microvm/guest/env" + "github.com/stacklok/go-microvm/guest/harden" + "github.com/stacklok/go-microvm/guest/mount" + "github.com/stacklok/go-microvm/guest/netcfg" + "github.com/stacklok/go-microvm/guest/sshd" ) // Run executes the full guest boot sequence and returns a shutdown function diff --git a/guest/boot/options.go b/guest/boot/options.go index 5c83df3..e6c3555 100644 --- a/guest/boot/options.go +++ b/guest/boot/options.go @@ -118,8 +118,8 @@ func WithSSHAgentForwarding(enabled bool) Option { } // WithTmpSize sets the size of the /tmp tmpfs in MiB. Defaults to 256 MiB when -// 0 or not set. The value is read from /etc/propolis-vm.json when provided by -// the host via [github.com/stacklok/propolis.WithTmpSize]. +// 0 or not set. The value is read from /etc/go-microvm.json when provided by +// the host via [github.com/stacklok/go-microvm.WithTmpSize]. func WithTmpSize(mib uint32) Option { return optionFunc(func(c *config) { if mib > 0 { diff --git a/guest/harden/seccomp_test.go b/guest/harden/seccomp_test.go index 5ea6f95..f7e45f3 100644 --- a/guest/harden/seccomp_test.go +++ b/guest/harden/seccomp_test.go @@ -133,7 +133,7 @@ func TestBlockedSyscallsReturnsFourGroups(t *testing.T) { func TestApplySeccompBlocksSyscalls(t *testing.T) { t.Parallel() - if os.Getenv("PROPOLIS_SECCOMP_CHILD") == "1" { + if os.Getenv("GO_MICROVM_SECCOMP_CHILD") == "1" { // Child process: apply filter, probe blocked syscalls, print results. runSeccompChild() return @@ -142,7 +142,7 @@ func TestApplySeccompBlocksSyscalls(t *testing.T) { // Parent process: re-exec ourselves running only this test. //nolint:gosec // Test helper — arguments are not user-controlled. cmd := exec.Command(os.Args[0], "-test.run=^TestApplySeccompBlocksSyscalls$", "-test.v") - cmd.Env = append(os.Environ(), "PROPOLIS_SECCOMP_CHILD=1") + cmd.Env = append(os.Environ(), "GO_MICROVM_SECCOMP_CHILD=1") out, err := cmd.CombinedOutput() output := string(out) diff --git a/guest/netcfg/doc.go b/guest/netcfg/doc.go index ad21e6e..1919981 100644 --- a/guest/netcfg/doc.go +++ b/guest/netcfg/doc.go @@ -4,7 +4,7 @@ //go:build linux // Package netcfg configures guest networking inside a microVM. It brings up -// eth0 with the guest IP from the propolis network topology, adds a default +// eth0 with the guest IP from the go-microvm network topology, adds a default // route via the gateway, and writes /etc/resolv.conf to point at the // gateway's DNS service. package netcfg diff --git a/guest/netcfg/netcfg.go b/guest/netcfg/netcfg.go index cb80990..abe6682 100644 --- a/guest/netcfg/netcfg.go +++ b/guest/netcfg/netcfg.go @@ -13,10 +13,10 @@ import ( "github.com/vishvananda/netlink" - "github.com/stacklok/propolis/net/topology" + "github.com/stacklok/go-microvm/net/topology" ) -// Configure brings up the guest network interface with the standard propolis +// Configure brings up the guest network interface with the standard go-microvm // topology: eth0 gets the guest IP (192.168.127.2/24), a default route via // the gateway (192.168.127.1), and /etc/resolv.conf pointing at the gateway. func Configure(logger *slog.Logger) error { diff --git a/guest/netcfg/netcfg_test.go b/guest/netcfg/netcfg_test.go index a232078..1b5f21d 100644 --- a/guest/netcfg/netcfg_test.go +++ b/guest/netcfg/netcfg_test.go @@ -12,7 +12,7 @@ import ( "github.com/stretchr/testify/assert" - "github.com/stacklok/propolis/net/topology" + "github.com/stacklok/go-microvm/net/topology" ) func TestConfigureRequiresRoot(t *testing.T) { diff --git a/guest/sshd/doc.go b/guest/sshd/doc.go index d66ffa4..c09d4e7 100644 --- a/guest/sshd/doc.go +++ b/guest/sshd/doc.go @@ -7,5 +7,5 @@ // public-key authentication, command execution with PTY support, environment // variable injection, signal forwarding, and window-change handling. The // server is designed to run inside a microVM as the primary remote access -// mechanism, paired with the host-side ssh.Client from the propolis/ssh package. +// mechanism, paired with the host-side ssh.Client from the go-microvm/ssh package. package sshd diff --git a/guest/vmconfig/vmconfig.go b/guest/vmconfig/vmconfig.go index 436d452..644e123 100644 --- a/guest/vmconfig/vmconfig.go +++ b/guest/vmconfig/vmconfig.go @@ -11,7 +11,7 @@ import ( ) // GuestPath is the guest path where the host writes the VM config. -const GuestPath = "/etc/propolis-vm.json" +const GuestPath = "/etc/go-microvm.json" // Config holds settings written by the host and read by the guest init. // Zero values mean "use the built-in default" for each field. @@ -21,7 +21,7 @@ type Config struct { TmpSizeMiB uint32 `json:"tmp_size_mib,omitempty"` } -// Read loads the VM config from /etc/propolis-vm.json. +// Read loads the VM config from /etc/go-microvm.json. // Returns a zero-value Config (all defaults) if the file does not exist, // ensuring backward compatibility with hosts that do not write the file. func Read() (Config, error) { diff --git a/hooks/doc.go b/hooks/doc.go index 95b3963..6e109b5 100644 --- a/hooks/doc.go +++ b/hooks/doc.go @@ -6,5 +6,5 @@ // before VM boot. // // Functions return func(string, *image.OCIConfig) error which is structurally -// identical to propolis.RootFSHook. +// identical to microvm.RootFSHook. package hooks diff --git a/hooks/hooks.go b/hooks/hooks.go index c9ece59..0b85bed 100644 --- a/hooks/hooks.go +++ b/hooks/hooks.go @@ -13,14 +13,14 @@ import ( "sort" "strings" - "github.com/stacklok/propolis/guest/vmconfig" - "github.com/stacklok/propolis/image" - "github.com/stacklok/propolis/internal/pathutil" - "github.com/stacklok/propolis/internal/xattr" + "github.com/stacklok/go-microvm/guest/vmconfig" + "github.com/stacklok/go-microvm/image" + "github.com/stacklok/go-microvm/internal/pathutil" + "github.com/stacklok/go-microvm/internal/xattr" ) // InjectVMConfig returns a RootFSHook that writes the given VM config as JSON -// to /etc/propolis-vm.json inside the rootfs. The guest init reads this file +// to /etc/go-microvm.json inside the rootfs. The guest init reads this file // to configure mounts before the SSH server starts. func InjectVMConfig(cfg vmconfig.Config) func(string, *image.OCIConfig) error { return func(rootfsPath string, _ *image.OCIConfig) error { diff --git a/hooks/hooks_test.go b/hooks/hooks_test.go index 5bf2fac..7e25e69 100644 --- a/hooks/hooks_test.go +++ b/hooks/hooks_test.go @@ -14,7 +14,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/stacklok/propolis/guest/vmconfig" + "github.com/stacklok/go-microvm/guest/vmconfig" ) // chownCall records a single chown invocation. @@ -71,14 +71,14 @@ func TestInjectVMConfig(t *testing.T) { err := hook(rootfs, nil) require.NoError(t, err) - data, err := os.ReadFile(filepath.Join(rootfs, "etc", "propolis-vm.json")) + data, err := os.ReadFile(filepath.Join(rootfs, "etc", "go-microvm.json")) require.NoError(t, err) var got vmconfig.Config require.NoError(t, json.Unmarshal(data, &got)) assert.Equal(t, tt.cfg, got) - info, err := os.Stat(filepath.Join(rootfs, "etc", "propolis-vm.json")) + info, err := os.Stat(filepath.Join(rootfs, "etc", "go-microvm.json")) require.NoError(t, err) assert.Equal(t, os.FileMode(0o644), info.Mode().Perm()) }) diff --git a/hypervisor/libkrun/backend.go b/hypervisor/libkrun/backend.go index 9751d0c..69f3f7b 100644 --- a/hypervisor/libkrun/backend.go +++ b/hypervisor/libkrun/backend.go @@ -9,16 +9,16 @@ import ( "os" "path/filepath" - "github.com/stacklok/propolis/extract" - "github.com/stacklok/propolis/hypervisor" - "github.com/stacklok/propolis/image" - "github.com/stacklok/propolis/runner" + "github.com/stacklok/go-microvm/extract" + "github.com/stacklok/go-microvm/hypervisor" + "github.com/stacklok/go-microvm/image" + "github.com/stacklok/go-microvm/runner" ) // Option configures a libkrun Backend. type Option func(*Backend) -// WithRunnerPath sets the path to the propolis-runner binary. +// WithRunnerPath sets the path to the go-microvm-runner binary. // When empty, the runner is found via $PATH or alongside the calling binary. func WithRunnerPath(p string) Option { return func(b *Backend) { b.runnerPath = p } } @@ -30,7 +30,7 @@ func WithLibDir(d string) Option { return func(b *Backend) { b.libDir = d } } // When nil (default), the standard runner.DefaultSpawner is used. func WithSpawner(s runner.Spawner) Option { return func(b *Backend) { b.spawner = s } } -// WithRuntime sets a Source that provides propolis-runner and libkrun. +// WithRuntime sets a Source that provides go-microvm-runner and libkrun. // Mutually exclusive with WithRunnerPath and WithLibDir. // When using bundle-based sources, WithCacheDir must also be set. func WithRuntime(src extract.Source) Option { return func(b *Backend) { b.runtime = src } } @@ -109,7 +109,7 @@ func (b *Backend) validate() error { return nil } -// Start launches the VM via the propolis-runner subprocess. +// Start launches the VM via the go-microvm-runner subprocess. func (b *Backend) Start(ctx context.Context, cfg hypervisor.VMConfig) (hypervisor.VMHandle, error) { if err := b.validate(); err != nil { return nil, err diff --git a/hypervisor/libkrun/backend_test.go b/hypervisor/libkrun/backend_test.go index c9a3005..aa48e65 100644 --- a/hypervisor/libkrun/backend_test.go +++ b/hypervisor/libkrun/backend_test.go @@ -13,9 +13,9 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/stacklok/propolis/extract" - "github.com/stacklok/propolis/hypervisor" - "github.com/stacklok/propolis/runner" + "github.com/stacklok/go-microvm/extract" + "github.com/stacklok/go-microvm/hypervisor" + "github.com/stacklok/go-microvm/runner" ) func TestBackend_Name(t *testing.T) { @@ -205,7 +205,7 @@ func (m *mockSource) Ensure(_ context.Context, cacheDir string) (string, error) return m.dir, m.err } -// makeRuntimeDir creates a temp directory with a dummy propolis-runner binary. +// makeRuntimeDir creates a temp directory with a dummy go-microvm-runner binary. func makeRuntimeDir(t *testing.T) string { t.Helper() dir := t.TempDir() @@ -387,7 +387,7 @@ func TestBackend_Start_FirmwareEnsureError(t *testing.T) { func TestBackend_Start_RuntimeMissingRunner(t *testing.T) { t.Parallel() - // Dir exists but has no propolis-runner binary. + // Dir exists but has no go-microvm-runner binary. emptyDir := t.TempDir() b := NewBackend( @@ -402,7 +402,7 @@ func TestBackend_Start_RuntimeMissingRunner(t *testing.T) { _, err := b.Start(context.Background(), cfg) require.Error(t, err) - assert.Contains(t, err.Error(), "propolis-runner not found") + assert.Contains(t, err.Error(), "go-microvm-runner not found") } func TestBackend_Options_Sources(t *testing.T) { diff --git a/hypervisor/libkrun/doc.go b/hypervisor/libkrun/doc.go index d97cfca..dca3736 100644 --- a/hypervisor/libkrun/doc.go +++ b/hypervisor/libkrun/doc.go @@ -2,5 +2,5 @@ // SPDX-License-Identifier: Apache-2.0 // Package libkrun implements the hypervisor.Backend interface using -// libkrun via the propolis-runner subprocess. +// libkrun via the go-microvm-runner subprocess. package libkrun diff --git a/hypervisor/libkrun/handle.go b/hypervisor/libkrun/handle.go index 65b83d7..7bc35ee 100644 --- a/hypervisor/libkrun/handle.go +++ b/hypervisor/libkrun/handle.go @@ -7,7 +7,7 @@ import ( "context" "strconv" - "github.com/stacklok/propolis/runner" + "github.com/stacklok/go-microvm/runner" ) // processHandle wraps a runner.ProcessHandle as a hypervisor.VMHandle. diff --git a/image/disk/decompress.go b/image/disk/decompress.go index cadd5fa..6e2304e 100644 --- a/image/disk/decompress.go +++ b/image/disk/decompress.go @@ -16,7 +16,7 @@ import ( "github.com/klauspost/compress/zstd" - "github.com/stacklok/propolis/image" + "github.com/stacklok/go-microvm/image" ) // MaxDecompressedSize is the safety limit for decompression (30 GiB). diff --git a/image/pull.go b/image/pull.go index 7f914dd..572ca66 100644 --- a/image/pull.go +++ b/image/pull.go @@ -20,7 +20,7 @@ import ( "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/mutate" - "github.com/stacklok/propolis/internal/xattr" + "github.com/stacklok/go-microvm/internal/xattr" "golang.org/x/sync/errgroup" ) @@ -100,7 +100,7 @@ func PullWithFetcher(ctx context.Context, imageRef string, cache *Cache, fetcher if cache != nil { tmpDir, err = cache.TempDir() } else { - tmpDir, err = os.MkdirTemp("", "propolis-rootfs-*") + tmpDir, err = os.MkdirTemp("", "go-microvm-rootfs-*") } if err != nil { return nil, fmt.Errorf("create temp dir for rootfs: %w", err) diff --git a/image/tar_security.go b/image/tar_security.go index e6d78c4..8019e0f 100644 --- a/image/tar_security.go +++ b/image/tar_security.go @@ -6,7 +6,7 @@ package image import ( "os" - "github.com/stacklok/propolis/internal/pathutil" + "github.com/stacklok/go-microvm/internal/pathutil" ) // SanitizeTarPath validates and resolves a tar entry path to prevent path diff --git a/internal/pathutil/doc.go b/internal/pathutil/doc.go index 0560ca9..9f54aed 100644 --- a/internal/pathutil/doc.go +++ b/internal/pathutil/doc.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc. // SPDX-License-Identifier: Apache-2.0 -// Package pathutil provides path validation helpers shared across propolis +// Package pathutil provides path validation helpers shared across go-microvm // packages. The primary use case is verifying that a guest-relative path // resolves within a root directory, preventing path traversal attacks via // ".." components or absolute paths. diff --git a/internal/procutil/doc.go b/internal/procutil/doc.go index 625646f..36dfb75 100644 --- a/internal/procutil/doc.go +++ b/internal/procutil/doc.go @@ -2,5 +2,5 @@ // SPDX-License-Identifier: Apache-2.0 // Package procutil provides platform-specific process identity verification -// utilities shared by the propolis library and runner packages. +// utilities shared by the go-microvm library and runner packages. package procutil diff --git a/internal/version/doc.go b/internal/version/doc.go index c106c5e..baa3f16 100644 --- a/internal/version/doc.go +++ b/internal/version/doc.go @@ -4,5 +4,5 @@ // Package version holds build-time version information injected via ldflags. // The variables in this package are set by the linker during build: // -// go build -ldflags "-X github.com/stacklok/propolis/internal/version.Version=..." +// go build -ldflags "-X github.com/stacklok/go-microvm/internal/version.Version=..." package version diff --git a/internal/xattr/doc.go b/internal/xattr/doc.go index 82666de..9d1c27f 100644 --- a/internal/xattr/doc.go +++ b/internal/xattr/doc.go @@ -5,7 +5,7 @@ // attribute on macOS and Linux so that the virtiofs server reports correct // guest-visible ownership and permissions for rootfs files. // -// When propolis extracts an OCI image, the host user ends up owning all +// When go-microvm extracts an OCI image, the host user ends up owning all // files because non-root cannot chown. libkrun's virtiofs server // performs access checks against these host-side attributes, causing // permission denied errors for guest processes running as UIDs that diff --git a/krun/doc.go b/krun/doc.go index 2edf42d..ab9d735 100644 --- a/krun/doc.go +++ b/krun/doc.go @@ -10,8 +10,8 @@ // The bindings are only available when CGO is enabled on Linux or macOS. // Use [IsAvailable] to check at runtime whether libkrun is functional. // -// The primary consumer of this package is the propolis-runner binary -// (runner/cmd/propolis-runner), which is spawned as a subprocess to run VMs. -// The main propolis library does not link against libkrun directly; it +// The primary consumer of this package is the go-microvm-runner binary +// (runner/cmd/go-microvm-runner), which is spawned as a subprocess to run VMs. +// The main go-microvm library does not link against libkrun directly; it // communicates with libkrun through the runner subprocess. package krun diff --git a/propolis.go b/microvm.go similarity index 95% rename from propolis.go rename to microvm.go index a6e26e1..164e19e 100644 --- a/propolis.go +++ b/microvm.go @@ -1,19 +1,19 @@ // SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc. // SPDX-License-Identifier: Apache-2.0 -// Package propolis provides a simple framework for running OCI container images +// Package microvm provides a simple framework for running OCI container images // as microVMs using libkrun. // // The happy path is a single function call: // -// vm, err := propolis.Run(ctx, "alpine:latest", -// propolis.WithPorts(propolis.PortForward{Host: 8080, Guest: 80}), +// vm, err := microvm.Run(ctx, "alpine:latest", +// microvm.WithPorts(microvm.PortForward{Host: 8080, Guest: 80}), // ) // defer vm.Stop(ctx) // // For advanced use cases, every layer is pluggable: custom init scripts, // rootfs hooks, network providers, preflight checks, and post-boot hooks. -package propolis +package microvm import ( "context" @@ -27,15 +27,15 @@ import ( "syscall" "time" - "github.com/stacklok/propolis/guest/vmconfig" - "github.com/stacklok/propolis/hooks" - "github.com/stacklok/propolis/hypervisor" - "github.com/stacklok/propolis/hypervisor/libkrun" - "github.com/stacklok/propolis/image" - "github.com/stacklok/propolis/net/firewall" - "github.com/stacklok/propolis/net/hosted" - rootfspkg "github.com/stacklok/propolis/rootfs" - "github.com/stacklok/propolis/state" + "github.com/stacklok/go-microvm/guest/vmconfig" + "github.com/stacklok/go-microvm/hooks" + "github.com/stacklok/go-microvm/hypervisor" + "github.com/stacklok/go-microvm/hypervisor/libkrun" + "github.com/stacklok/go-microvm/image" + "github.com/stacklok/go-microvm/net/firewall" + "github.com/stacklok/go-microvm/net/hosted" + rootfspkg "github.com/stacklok/go-microvm/rootfs" + "github.com/stacklok/go-microvm/state" ) // Run pulls an OCI image and boots it as a microVM. It is the primary entry diff --git a/propolis_test.go b/microvm_test.go similarity index 98% rename from propolis_test.go rename to microvm_test.go index 6fa019d..d472060 100644 --- a/propolis_test.go +++ b/microvm_test.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc. // SPDX-License-Identifier: Apache-2.0 -package propolis +package microvm import ( "context" @@ -17,12 +17,12 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/stacklok/propolis/hypervisor" - "github.com/stacklok/propolis/image" - "github.com/stacklok/propolis/internal/testutil" - "github.com/stacklok/propolis/net/firewall" - "github.com/stacklok/propolis/preflight" - "github.com/stacklok/propolis/state" + "github.com/stacklok/go-microvm/hypervisor" + "github.com/stacklok/go-microvm/image" + "github.com/stacklok/go-microvm/internal/testutil" + "github.com/stacklok/go-microvm/net/firewall" + "github.com/stacklok/go-microvm/preflight" + "github.com/stacklok/go-microvm/state" ) // --- Pure function tests --- @@ -304,7 +304,7 @@ func TestForceRemoveAll(t *testing.T) { t.Run("no error on nonexistent path", func(t *testing.T) { t.Parallel() - require.NoError(t, forceRemoveAll("/tmp/does-not-exist-propolis-test")) + require.NoError(t, forceRemoveAll("/tmp/does-not-exist-go-microvm-test")) }) } diff --git a/net/doc.go b/net/doc.go index 8e04465..e49189b 100644 --- a/net/doc.go +++ b/net/doc.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc. // SPDX-License-Identifier: Apache-2.0 -// Package net defines the networking abstraction for propolis microVMs. +// Package net defines the networking abstraction for go-microvm microVMs. // // A [Provider] manages the lifecycle of a network backend that connects the // host to the guest VM. The default implementation uses an in-process diff --git a/net/egress/frame.go b/net/egress/frame.go index 53d2c12..47ee014 100644 --- a/net/egress/frame.go +++ b/net/egress/frame.go @@ -7,7 +7,7 @@ import ( "encoding/binary" "fmt" - "github.com/stacklok/propolis/net/firewall" + "github.com/stacklok/go-microvm/net/firewall" ) const ( diff --git a/net/egress/frame_test.go b/net/egress/frame_test.go index 370a103..f5dbdd0 100644 --- a/net/egress/frame_test.go +++ b/net/egress/frame_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/stacklok/propolis/net/firewall" + "github.com/stacklok/go-microvm/net/firewall" ) // buildTestUDPFrame constructs a minimal Ethernet + IPv4 + UDP frame with diff --git a/net/egress/interceptor.go b/net/egress/interceptor.go index 438fe98..0dcef13 100644 --- a/net/egress/interceptor.go +++ b/net/egress/interceptor.go @@ -8,7 +8,7 @@ import ( "net" "time" - "github.com/stacklok/propolis/net/firewall" + "github.com/stacklok/go-microvm/net/firewall" ) const ( diff --git a/net/egress/interceptor_test.go b/net/egress/interceptor_test.go index 41c368d..47b0a2d 100644 --- a/net/egress/interceptor_test.go +++ b/net/egress/interceptor_test.go @@ -12,7 +12,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/stacklok/propolis/net/firewall" + "github.com/stacklok/go-microvm/net/firewall" ) // buildDNSQueryFrame builds a complete Ethernet frame containing a DNS query. diff --git a/net/hosted/doc.go b/net/hosted/doc.go index e266654..dca703c 100644 --- a/net/hosted/doc.go +++ b/net/hosted/doc.go @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 // Package hosted implements a [net.Provider] that runs the gvisor-tap-vsock -// VirtualNetwork in the caller's process rather than inside propolis-runner. +// VirtualNetwork in the caller's process rather than inside go-microvm-runner. // // This enables callers to access the VirtualNetwork directly — for example, // to create in-process TCP listeners via gonet that are reachable from the @@ -11,9 +11,9 @@ // # Usage // // p := hosted.NewProvider() -// vm, err := propolis.Run(ctx, image, -// propolis.WithNetProvider(p), -// propolis.WithPorts(propolis.PortForward{Host: sshPort, Guest: 22}), +// vm, err := microvm.Run(ctx, image, +// microvm.WithNetProvider(p), +// microvm.WithPorts(microvm.PortForward{Host: sshPort, Guest: 22}), // ) // // p.VirtualNetwork() is now available for gonet listeners. // @@ -25,10 +25,10 @@ // // p := hosted.NewProvider() // p.AddService(hosted.Service{Port: 4483, Handler: myHandler}) -// vm, err := propolis.Run(ctx, image, propolis.WithNetProvider(p)) +// vm, err := microvm.Run(ctx, image, microvm.WithNetProvider(p)) // // Guest can reach http://192.168.127.1:4483/ // -// The provider exposes a Unix socket that propolis-runner connects to. Frames +// The provider exposes a Unix socket that go-microvm-runner connects to. Frames // are bridged between the runner connection and the VirtualNetwork's QEMU // transport. When firewall rules are configured, a [firewall.Relay] is // inserted to filter traffic. diff --git a/net/hosted/provider.go b/net/hosted/provider.go index dbaa74c..21430c0 100644 --- a/net/hosted/provider.go +++ b/net/hosted/provider.go @@ -15,17 +15,17 @@ import ( "github.com/containers/gvisor-tap-vsock/pkg/types" "github.com/containers/gvisor-tap-vsock/pkg/virtualnetwork" - "github.com/stacklok/propolis/internal/logbridge" - propnet "github.com/stacklok/propolis/net" - "github.com/stacklok/propolis/net/egress" - "github.com/stacklok/propolis/net/firewall" - "github.com/stacklok/propolis/net/topology" + "github.com/stacklok/go-microvm/internal/logbridge" + propnet "github.com/stacklok/go-microvm/net" + "github.com/stacklok/go-microvm/net/egress" + "github.com/stacklok/go-microvm/net/firewall" + "github.com/stacklok/go-microvm/net/topology" ) const socketName = "hosted-net.sock" // Provider runs a gvisor-tap-vsock VirtualNetwork in the caller's process -// and exposes a Unix socket for propolis-runner to connect to. +// and exposes a Unix socket for go-microvm-runner to connect to. type Provider struct { mu sync.Mutex vn *virtualnetwork.VirtualNetwork @@ -119,7 +119,7 @@ func (p *Provider) Start(ctx context.Context, cfg propnet.Config) error { return nil } -// SocketPath returns the path to the Unix socket for propolis-runner. +// SocketPath returns the path to the Unix socket for go-microvm-runner. func (p *Provider) SocketPath() string { p.mu.Lock() defer p.mu.Unlock() @@ -250,7 +250,7 @@ func (p *Provider) buildEgressRelay(ctx context.Context, cfg propnet.Config) *fi return firewall.NewRelayWithDNSHook(filter, interceptor) } -// acceptLoop accepts connections from propolis-runner and bridges them +// acceptLoop accepts connections from go-microvm-runner and bridges them // to the VirtualNetwork. func (p *Provider) acceptLoop() { defer p.wg.Done() diff --git a/net/hosted/provider_test.go b/net/hosted/provider_test.go index 597c1d8..10382bb 100644 --- a/net/hosted/provider_test.go +++ b/net/hosted/provider_test.go @@ -14,9 +14,9 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/stacklok/propolis/internal/testutil" - propnet "github.com/stacklok/propolis/net" - "github.com/stacklok/propolis/net/firewall" + "github.com/stacklok/go-microvm/internal/testutil" + propnet "github.com/stacklok/go-microvm/net" + "github.com/stacklok/go-microvm/net/firewall" ) // freePort returns a TCP port that is currently available on localhost. diff --git a/net/hosted/service.go b/net/hosted/service.go index 7192158..9127efd 100644 --- a/net/hosted/service.go +++ b/net/hosted/service.go @@ -11,7 +11,7 @@ import ( "net/http" "time" - "github.com/stacklok/propolis/net/topology" + "github.com/stacklok/go-microvm/net/topology" ) // Service describes an HTTP service to expose inside the virtual network. diff --git a/net/hosted/service_test.go b/net/hosted/service_test.go index 497848d..bcbf1ce 100644 --- a/net/hosted/service_test.go +++ b/net/hosted/service_test.go @@ -11,8 +11,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/stacklok/propolis/internal/testutil" - propnet "github.com/stacklok/propolis/net" + "github.com/stacklok/go-microvm/internal/testutil" + propnet "github.com/stacklok/go-microvm/net" ) func TestAddServiceBeforeStart(t *testing.T) { diff --git a/net/provider.go b/net/provider.go index 10abcf4..f2b70e7 100644 --- a/net/provider.go +++ b/net/provider.go @@ -6,7 +6,7 @@ package net import ( "context" - "github.com/stacklok/propolis/net/firewall" + "github.com/stacklok/go-microvm/net/firewall" ) // PortForward describes a TCP port forwarding rule from host to guest. diff --git a/net/topology/doc.go b/net/topology/doc.go index 3c3f625..e646940 100644 --- a/net/topology/doc.go +++ b/net/topology/doc.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc. // SPDX-License-Identifier: Apache-2.0 -// Package topology defines shared network topology constants for propolis +// Package topology defines shared network topology constants for go-microvm // microVMs. These constants describe the virtual network layout used by // gvisor-tap-vsock: subnet, gateway, guest IP, MAC address, and MTU. // diff --git a/net/topology/topology.go b/net/topology/topology.go index e9da13e..07ad405 100644 --- a/net/topology/topology.go +++ b/net/topology/topology.go @@ -3,7 +3,7 @@ package topology -// Network topology constants for the propolis virtual network. +// Network topology constants for the go-microvm virtual network. // These match the gvisor-tap-vsock defaults used by libkrun/krunvm. const ( // Subnet is the CIDR notation for the virtual network subnet. diff --git a/options.go b/options.go index f4c9c8f..e262ec2 100644 --- a/options.go +++ b/options.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc. // SPDX-License-Identifier: Apache-2.0 -package propolis +package microvm import ( "context" @@ -9,11 +9,11 @@ import ( "path/filepath" "syscall" - "github.com/stacklok/propolis/hypervisor" - "github.com/stacklok/propolis/image" - "github.com/stacklok/propolis/net" - "github.com/stacklok/propolis/net/firewall" - "github.com/stacklok/propolis/preflight" + "github.com/stacklok/go-microvm/hypervisor" + "github.com/stacklok/go-microvm/image" + "github.com/stacklok/go-microvm/net" + "github.com/stacklok/go-microvm/net/firewall" + "github.com/stacklok/go-microvm/preflight" ) // Option configures a VM. Use the With* functions to create options. @@ -91,7 +91,7 @@ type config struct { func defaultConfig() *config { dataDir := defaultDataDir() return &config{ - name: "propolis", + name: "microvm", cpus: 1, memory: 512, ports: nil, @@ -113,14 +113,14 @@ func defaultConfig() *config { } func defaultDataDir() string { - if dir := os.Getenv("PROPOLIS_DATA_DIR"); dir != "" { + if dir := os.Getenv("GO_MICROVM_DATA_DIR"); dir != "" { return dir } home, err := os.UserHomeDir() if err != nil { home = "/tmp" } - return filepath.Join(home, ".config", "propolis") + return filepath.Join(home, ".config", "go-microvm") } func (c *config) buildNetConfig() net.Config { @@ -150,7 +150,7 @@ func (c *config) buildNetConfig() net.Config { // --- Option constructors --- -// WithName sets the VM name. Defaults to "propolis". +// WithName sets the VM name. Defaults to "microvm". func WithName(name string) Option { return optionFunc(func(c *config) { c.name = name }) } @@ -215,7 +215,7 @@ func WithFirewallDefaultAction(action firewall.Action) Option { // WithPreflightChecker replaces the entire preflight checker. Use this when // the caller manages its own preflight logic and wants to skip the built-in // defaults (KVM, port availability, disk space). Pass [preflight.NewEmpty]() -// to disable all propolis preflight checks. +// to disable all microvm preflight checks. func WithPreflightChecker(checker preflight.Checker) Option { return optionFunc(func(c *config) { c.preflight = checker }) } @@ -242,7 +242,7 @@ func WithBackend(b hypervisor.Backend) Option { } // WithDataDir sets the base directory for VM state, caches, and logs. -// Defaults to ~/.config/propolis or $PROPOLIS_DATA_DIR. +// Defaults to ~/.config/go-microvm or $GO_MICROVM_DATA_DIR. func WithDataDir(path string) Option { return optionFunc(func(c *config) { c.dataDir = path @@ -303,7 +303,7 @@ func WithLogLevel(level uint32) Option { // Defaults to 256 MiB when 0 or not set. The kernel enforces available // memory as the upper bound; unreasonable values will cause a mount failure // inside the guest. -// The value is written to /etc/propolis-vm.json in the rootfs and read by +// The value is written to /etc/go-microvm.json in the rootfs and read by // the guest init before mounting filesystems. func WithTmpSize(mib uint32) Option { return optionFunc(func(c *config) { c.tmpSizeMiB = mib }) diff --git a/options_test.go b/options_test.go index 5ec00ec..914ac96 100644 --- a/options_test.go +++ b/options_test.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc. // SPDX-License-Identifier: Apache-2.0 -package propolis +package microvm import ( "context" @@ -10,9 +10,9 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/stacklok/propolis/image" - "github.com/stacklok/propolis/net/firewall" - "github.com/stacklok/propolis/preflight" + "github.com/stacklok/go-microvm/image" + "github.com/stacklok/go-microvm/net/firewall" + "github.com/stacklok/go-microvm/preflight" ) func TestDefaultConfig(t *testing.T) { @@ -23,7 +23,7 @@ func TestDefaultConfig(t *testing.T) { assert.Equal(t, uint32(1), cfg.cpus) assert.Equal(t, uint32(512), cfg.memory) - assert.Equal(t, "propolis", cfg.name) + assert.Equal(t, "microvm", cfg.name) assert.NotNil(t, cfg.preflight) assert.Nil(t, cfg.netProvider) // lazy-initialized in Run() when not set by WithNetProvider assert.NotNil(t, cfg.imageCache) diff --git a/preflight/chown_linux.go b/preflight/chown_linux.go index 57af90b..a32f799 100644 --- a/preflight/chown_linux.go +++ b/preflight/chown_linux.go @@ -45,7 +45,7 @@ func (c *chownChecker) check(_ context.Context) error { return fmt.Errorf("process lacks CAP_CHOWN: extracted rootfs files will have incorrect ownership, " + "which may cause permission errors inside the guest; " + - "grant CAP_CHOWN to the propolis process or run as root") + "grant CAP_CHOWN to the go-microvm process or run as root") } // getEffectiveCaps returns the low 32 bits of the effective capability set diff --git a/rootfs/clone.go b/rootfs/clone.go index 348601b..3f801a9 100644 --- a/rootfs/clone.go +++ b/rootfs/clone.go @@ -12,7 +12,7 @@ import ( "path/filepath" "strings" - "github.com/stacklok/propolis/internal/xattr" + "github.com/stacklok/go-microvm/internal/xattr" ) // CloneDir recursively clones srcDir into dstDir using platform-native COW diff --git a/rootfs/clone_test.go b/rootfs/clone_test.go index b2f8aa1..ca9f550 100644 --- a/rootfs/clone_test.go +++ b/rootfs/clone_test.go @@ -11,7 +11,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/stacklok/propolis/rootfs" + "github.com/stacklok/go-microvm/rootfs" ) func TestCloneDir(t *testing.T) { diff --git a/runner/cmd/propolis-runner/main.go b/runner/cmd/go-microvm-runner/main.go similarity index 96% rename from runner/cmd/propolis-runner/main.go rename to runner/cmd/go-microvm-runner/main.go index 4617c1b..3a41d6b 100644 --- a/runner/cmd/propolis-runner/main.go +++ b/runner/cmd/go-microvm-runner/main.go @@ -3,8 +3,8 @@ //go:build (linux || darwin) && cgo -// Package main provides the propolis-runner helper binary. -// This binary is spawned as a subprocess by the propolis framework +// Package main provides the go-microvm-runner helper binary. +// This binary is spawned as a subprocess by the go-microvm framework // to run VMs using libkrun's CGO bindings. // // IMPORTANT: libkrun's krun_start_enter() takes over the calling process @@ -25,9 +25,9 @@ import ( "github.com/containers/gvisor-tap-vsock/pkg/types" "github.com/containers/gvisor-tap-vsock/pkg/virtualnetwork" - "github.com/stacklok/propolis/internal/logbridge" - "github.com/stacklok/propolis/krun" - "github.com/stacklok/propolis/net/topology" + "github.com/stacklok/go-microvm/internal/logbridge" + "github.com/stacklok/go-microvm/krun" + "github.com/stacklok/go-microvm/net/topology" ) // sentinel errors for classifying exit codes. @@ -86,7 +86,7 @@ const ( func main() { if len(os.Args) < 2 { fmt.Fprintf(os.Stderr, "Usage: %s \n", filepath.Base(os.Args[0])) - fmt.Fprintf(os.Stderr, "\nThis is a helper binary for propolis.\n") + fmt.Fprintf(os.Stderr, "\nThis is a helper binary for go-microvm.\n") fmt.Fprintf(os.Stderr, "It should not be run directly.\n") os.Exit(exitConfigError) } diff --git a/runner/config.go b/runner/config.go index ea63c6d..7aa2b86 100644 --- a/runner/config.go +++ b/runner/config.go @@ -11,7 +11,7 @@ type PortForward struct { Guest uint16 `json:"guest"` } -// Config contains the configuration for running a VM via the propolis-runner subprocess. +// Config contains the configuration for running a VM via the go-microvm-runner subprocess. type Config struct { // RootPath is the path to the root filesystem directory (virtiofs). RootPath string `json:"root_path"` @@ -38,7 +38,7 @@ type Config struct { // libraries. The runner subprocess uses this via LD_LIBRARY_PATH. // Not serialized to JSON; set by the caller before spawning. LibDir string `json:"-"` - // RunnerPath is the explicit path to the propolis-runner binary. + // RunnerPath is the explicit path to the go-microvm-runner binary. // Not serialized to JSON; used by Spawn to locate the binary. RunnerPath string `json:"-"` // VMLogPath is the path to the file where runner stdout/stderr is written. diff --git a/runner/config_test.go b/runner/config_test.go index 0e41e05..b164ba9 100644 --- a/runner/config_test.go +++ b/runner/config_test.go @@ -15,7 +15,7 @@ func TestConfig_MarshalUnmarshal_RoundTrip(t *testing.T) { t.Parallel() original := Config{ - RootPath: "/var/lib/propolis/rootfs", + RootPath: "/var/lib/go-microvm/rootfs", NumVCPUs: 4, RAMMiB: 1024, NetSocket: "/tmp/net.sock", @@ -24,7 +24,7 @@ func TestConfig_MarshalUnmarshal_RoundTrip(t *testing.T) { LogLevel: 3, // These should NOT appear in JSON. LibDir: "/usr/local/lib/krun", - RunnerPath: "/usr/bin/propolis-runner", + RunnerPath: "/usr/bin/go-microvm-runner", VMLogPath: "/var/log/vm.log", } diff --git a/runner/process_darwin.go b/runner/process_darwin.go index 4455c70..97d4d92 100644 --- a/runner/process_darwin.go +++ b/runner/process_darwin.go @@ -5,7 +5,7 @@ package runner -import "github.com/stacklok/propolis/internal/procutil" +import "github.com/stacklok/go-microvm/internal/procutil" // isExpectedProcess checks if the process at pid is running the expected binary. // Delegates to the shared implementation in internal/procutil. diff --git a/runner/process_linux.go b/runner/process_linux.go index 52a6400..6cf3d34 100644 --- a/runner/process_linux.go +++ b/runner/process_linux.go @@ -5,7 +5,7 @@ package runner -import "github.com/stacklok/propolis/internal/procutil" +import "github.com/stacklok/go-microvm/internal/procutil" // isExpectedProcess checks if the process at pid is running the expected binary. // Delegates to the shared implementation in internal/procutil. diff --git a/runner/spawn.go b/runner/spawn.go index adba6e8..960e894 100644 --- a/runner/spawn.go +++ b/runner/spawn.go @@ -24,8 +24,8 @@ var ( ) const ( - // runnerBinaryName is the name of the propolis-runner binary. - runnerBinaryName = "propolis-runner" + // runnerBinaryName is the name of the go-microvm-runner binary. + runnerBinaryName = "go-microvm-runner" // stopTimeout is the maximum time to wait for the process to exit after SIGTERM. stopTimeout = 30 * time.Second // stopPollInterval is the interval between process liveness checks during stop. @@ -46,7 +46,7 @@ func newProcessDeps() processDeps { } } -// runnerFinder locates the propolis-runner binary with injectable lookups. +// runnerFinder locates the go-microvm-runner binary with injectable lookups. type runnerFinder struct { stat func(string) (os.FileInfo, error) lookPath func(string) (string, error) @@ -86,13 +86,13 @@ func (p *Process) killTarget() int { return -p.pid } -// Spawn starts the propolis-runner binary as a detached subprocess. +// Spawn starts the go-microvm-runner binary as a detached subprocess. // Deprecated: Use SpawnProcess or DefaultSpawner instead. func Spawn(ctx context.Context, cfg Config) (*Process, error) { return SpawnProcess(ctx, cfg) } -// SpawnProcess starts the propolis-runner binary as a detached subprocess. +// SpawnProcess starts the go-microvm-runner binary as a detached subprocess. // The runner binary receives the VM configuration as a JSON string in argv[1]. // On success, the returned Process can be used to monitor and stop the VM. func SpawnProcess(ctx context.Context, cfg Config) (*Process, error) { @@ -244,7 +244,7 @@ func (p *Process) IsAlive() bool { return true } -// find locates the propolis-runner binary. It checks, in order: +// find locates the go-microvm-runner binary. It checks, in order: // 1. The explicit path provided in cfg.RunnerPath // 2. The system PATH // 3. Next to the current executable diff --git a/state/state.go b/state/state.go index 04ffc7d..3553595 100644 --- a/state/state.go +++ b/state/state.go @@ -26,13 +26,13 @@ const ( stateVersion = 1 // stateFileName is the name of the state JSON file within the data directory. - // Named "propolis-state.json" to avoid collision with the caller's own + // Named "go-microvm-state.json" to avoid collision with the caller's own // state file (e.g. toolhive-appliance's "state.json") when both share // the same dataDir. - stateFileName = "propolis-state.json" + stateFileName = "go-microvm-state.json" // lockFileName is the name of the lock file within the data directory. - lockFileName = "propolis-state.lock" + lockFileName = "go-microvm-state.lock" // retryInterval is the interval between lock acquisition retries. retryInterval = 500 * time.Millisecond diff --git a/vm.go b/vm.go index e4972a5..774a04e 100644 --- a/vm.go +++ b/vm.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc. // SPDX-License-Identifier: Apache-2.0 -package propolis +package microvm import ( "context" @@ -12,9 +12,9 @@ import ( "strings" "time" - "github.com/stacklok/propolis/hypervisor" - "github.com/stacklok/propolis/net" - "github.com/stacklok/propolis/state" + "github.com/stacklok/go-microvm/hypervisor" + "github.com/stacklok/go-microvm/net" + "github.com/stacklok/go-microvm/state" ) // VM represents a running microVM. diff --git a/vm_test.go b/vm_test.go index 968deec..9c0a346 100644 --- a/vm_test.go +++ b/vm_test.go @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc. // SPDX-License-Identifier: Apache-2.0 -package propolis +package microvm import ( "context" @@ -13,8 +13,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/stacklok/propolis/net" - "github.com/stacklok/propolis/state" + "github.com/stacklok/go-microvm/net" + "github.com/stacklok/go-microvm/state" ) // mockVMHandle is a test double for hypervisor.VMHandle.