Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
39797b5
refactor: cross-platform foundation for macOS support
rgarcia Feb 10, 2026
10836fe
feat: add macOS VM support via Apple Virtualization.framework
rgarcia Feb 10, 2026
3917822
fix: embed vz.entitlements and fix macOS runtime issues
rgarcia Feb 10, 2026
59db909
fix: remove stale disk platform files from rebase
rgarcia Feb 11, 2026
6dcf627
fix: vsock proxy data loss, zombie reaping, and remove vz-shim from i…
rgarcia Feb 11, 2026
570d99c
fix: e2e test config sourcing and missing CLI handling
rgarcia Feb 11, 2026
53ac4ca
fix: remove unused registry-push flag from gen-jwt
rgarcia Feb 11, 2026
a185e2c
fix: remove unnecessary .gitkeep for vz-shim embed dir
rgarcia Feb 11, 2026
a3fc015
feat: add VM lifecycle smoke test to e2e install test
rgarcia Feb 11, 2026
c326356
fix: create vz-shim embed directory in Makefile before copying
rgarcia Feb 11, 2026
732b06c
Fix macOS CLI install missing $SUDO prefix
cursoragent Feb 12, 2026
78c9665
fix: CLI install on macOS and make CLI a hard requirement in e2e
rgarcia Feb 12, 2026
2c9eb67
fix: remove nonexistent 'hypeman images' from e2e test
rgarcia Feb 12, 2026
8c8c3f2
fix: retry hypeman run after async pull in e2e test
rgarcia Feb 12, 2026
42f3dd5
fix: clean up macOS development docs and Makefile comment
rgarcia Feb 12, 2026
af20400
fix: README treats Linux and macOS as equal platforms
rgarcia Feb 12, 2026
5c90036
Address PR review: fix shutdown semantics, reduce timeout, add vz int…
rgarcia Feb 13, 2026
adbc938
fix(vz): fix guest-agent exec format error on instance restart
rgarcia Feb 13, 2026
c58ed0a
Address hiroTamada review nits
rgarcia Feb 13, 2026
6e954ff
fix: respect NetworkEnabled=false in vz shim by not creating NIC when…
cursoragent Feb 14, 2026
cc8413b
Fix StartInstance call to match new signature
rgarcia Feb 14, 2026
34596cd
Fix vz tests: keep VM alive with sleep infinity
rgarcia Feb 14, 2026
4ed925a
Fix e2e test: use nginx:alpine instead of alpine:latest
rgarcia Feb 14, 2026
07550ed
Fix e2e clean slate: remove data dir from previous failed runs
rgarcia Feb 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions .air.darwin.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
root = "."
testdata_dir = "testdata"
tmp_dir = "tmp"

[build]
args_bin = []
bin = "./tmp/main"
# Build for macOS with vz support, then sign with entitlements
# Also builds and signs vz-shim (subprocess that hosts vz VMs)
cmd = "make build-embedded && go build -o ./tmp/vz-shim ./cmd/vz-shim && codesign --sign - --entitlements vz.entitlements --force ./tmp/vz-shim && mkdir -p lib/hypervisor/vz/vz-shim && cp ./tmp/vz-shim lib/hypervisor/vz/vz-shim/vz-shim && go build -tags containers_image_openpgp -o ./tmp/main ./cmd/api && codesign --sign - --entitlements vz.entitlements --force ./tmp/main"
delay = 1000
exclude_dir = ["assets", "tmp", "vendor", "testdata", "bin", "scripts", "data", "kernel"]
exclude_file = []
exclude_regex = ["_test.go"]
exclude_unchanged = false
follow_symlink = false
# No sudo needed on macOS - vz doesn't require root
full_bin = "./tmp/main"
include_dir = []
include_ext = ["go", "tpl", "tmpl", "html", "yaml"]
include_file = []
log = "build-errors.log"
poll = false
poll_interval = 0
post_cmd = []
kill_delay = '1s'
rerun = false
rerun_delay = 500
send_interrupt = true
stop_on_error = false

[color]
app = ""
build = "yellow"
main = "magenta"
runner = "green"
watcher = "cyan"

[log]
main_only = false
time = false

[misc]
clean_on_exit = false

[screen]
clear_on_rebuild = false
keep_scroll = true
122 changes: 122 additions & 0 deletions .env.darwin.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# =============================================================================
# macOS (Darwin) Configuration for Hypeman
# =============================================================================
# Copy this file to .env and customize for your environment.
#
# Key differences from Linux (.env.example):
# - DEFAULT_HYPERVISOR: Use "vz" (Virtualization.framework) instead of cloud-hypervisor/qemu
# - DATA_DIR: Uses macOS conventions (~/Library/Application Support)
# - Network settings: BRIDGE_NAME, SUBNET_CIDR, etc. are IGNORED (vz uses NAT)
# - Rate limiting: Not supported on macOS (no tc/HTB equivalent)
# - GPU passthrough: Not supported on macOS
# =============================================================================

# Required
JWT_SECRET=dev-secret-change-me

# Data directory - use macOS conventions
# Note: ~ expands to $HOME at runtime
DATA_DIR=~/Library/Application Support/hypeman

# Server configuration
PORT=8080

# Logging
LOG_LEVEL=debug

# =============================================================================
# Hypervisor Configuration (IMPORTANT FOR MACOS)
# =============================================================================
# On macOS, use "vz" (Virtualization.framework)
# - "cloud-hypervisor" and "qemu" are NOT supported on macOS
DEFAULT_HYPERVISOR=vz

# =============================================================================
# Network Configuration (DIFFERENT ON MACOS)
# =============================================================================
# On macOS with vz, network is handled automatically via NAT:
# - VMs get IP addresses from 192.168.64.0/24 via DHCP
# - No TAP devices, bridges, or iptables needed
# - The following settings are IGNORED on macOS:
# BRIDGE_NAME, SUBNET_CIDR, SUBNET_GATEWAY, UPLINK_INTERFACE

# DNS Server for VMs (used by guest for resolution)
DNS_SERVER=8.8.8.8

# =============================================================================
# Caddy / Ingress Configuration
# =============================================================================
CADDY_LISTEN_ADDRESS=0.0.0.0
CADDY_ADMIN_ADDRESS=127.0.0.1
CADDY_ADMIN_PORT=2019
# Note: 5353 is used by mDNSResponder (Bonjour) on macOS, using 5354 instead
INTERNAL_DNS_PORT=5354
CADDY_STOP_ON_SHUTDOWN=false

# =============================================================================
# Build System Configuration
# =============================================================================
# For builds on macOS with vz, the registry URL needs to be accessible from
# NAT VMs. Since vz uses 192.168.64.0/24 for NAT, the host is at 192.168.64.1.
#
# IMPORTANT: "host.docker.internal" does NOT work in vz VMs - that's a Docker
# Desktop-specific hostname. Use the NAT gateway IP instead.
#
# Registry URL (the host's hypeman API, accessible from VMs)
REGISTRY_URL=192.168.64.1:8080
# Use HTTP (not HTTPS) since hypeman's internal registry uses plaintext
REGISTRY_INSECURE=true

BUILDER_IMAGE=hypeman/builder:latest
MAX_CONCURRENT_SOURCE_BUILDS=2
BUILD_TIMEOUT=600

# =============================================================================
# Resource Limits (same as Linux)
# =============================================================================
# Per-instance limits
MAX_VCPUS_PER_INSTANCE=4
MAX_MEMORY_PER_INSTANCE=8GB

# Aggregate limits (0 or empty = unlimited)
# MAX_TOTAL_VOLUME_STORAGE=

# =============================================================================
# OpenTelemetry (optional, same as Linux)
# =============================================================================
# OTEL_ENABLED=false
# OTEL_ENDPOINT=127.0.0.1:4317
# OTEL_SERVICE_NAME=hypeman
# OTEL_INSECURE=true
# ENV=dev

# =============================================================================
# TLS / ACME Configuration (same as Linux)
# =============================================================================
# ACME_EMAIL=admin@example.com
# ACME_DNS_PROVIDER=cloudflare
# TLS_ALLOWED_DOMAINS=*.example.com
# CLOUDFLARE_API_TOKEN=

# =============================================================================
# macOS Limitations
# =============================================================================
# The following features are NOT AVAILABLE on macOS:
#
# 1. GPU Passthrough (VFIO, mdev)
# - GPU_PROFILE_CACHE_TTL is ignored
# - Device registration/binding will fail
#
# 2. Network Rate Limiting
# - UPLOAD_BURST_MULTIPLIER, DOWNLOAD_BURST_MULTIPLIER are ignored
# - No tc/HTB equivalent on macOS
#
# 3. CPU/Memory Hotplug
# - Resize operations not supported
#
# 4. Disk I/O Limiting
# - DISK_IO_LIMIT, OVERSUB_DISK_IO are ignored
#
# 5. Snapshots (requires macOS 14+ on Apple Silicon)
# - SaveMachineStateToPath/RestoreMachineStateFromURL require macOS 14+
# - Only supported on ARM64 (Apple Silicon) Macs
61 changes: 61 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,64 @@ jobs:
TLS_TEST_DOMAIN: "test.hypeman-development.com"
TLS_ALLOWED_DOMAINS: '*.hypeman-development.com'
run: make test

test-darwin:
runs-on: [self-hosted, macos, arm64]
concurrency:
group: macos-ci-test-${{ github.ref }}
cancel-in-progress: true
env:
DATA_DIR: /tmp/hypeman-ci-${{ github.run_id }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v6
with:
go-version: '1.25'
cache: false
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: Install dependencies
run: |
brew list e2fsprogs &>/dev/null || brew install e2fsprogs
brew list erofs-utils &>/dev/null || brew install erofs-utils
go mod download
- name: Create run-scoped data directory
run: mkdir -p "$DATA_DIR"
- name: Generate OpenAPI code
run: make oapi-generate
- name: Build
run: make build
- name: Run tests
env:
DEFAULT_HYPERVISOR: vz
JWT_SECRET: ci-test-secret
run: make test
- name: Cleanup
if: always()
run: |
pkill -f "vz-shim.*$DATA_DIR" || true
rm -rf "$DATA_DIR"
make clean

e2e-install:
runs-on: [self-hosted, macos, arm64]
needs: test-darwin
concurrency:
group: macos-ci-e2e-${{ github.ref }}
cancel-in-progress: true
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v6
with:
go-version: '1.25'
cache: false
- name: Install dependencies
run: brew list caddy &>/dev/null || brew install caddy
- name: Run E2E install test
run: bash scripts/e2e-install-test.sh
- name: Cleanup on failure
if: failure()
run: bash scripts/uninstall.sh || true
Loading