agent-dev-env 0.1.0-canary.2.fbbd044

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +106 -0
  3. package/dist/assets/bridge/bridge.js +202 -0
  4. package/dist/assets/guest/guest-agent-mac.js +586 -0
  5. package/dist/assets/guest/guest-agent-ubuntu.js +481 -0
  6. package/dist/assets/guest/guest-agent-windows.js +466 -0
  7. package/dist/assets/images/mac/CHANGELOG.md +265 -0
  8. package/dist/assets/images/mac/README.md +63 -0
  9. package/dist/assets/images/mac/sandbox.pkr.hcl +468 -0
  10. package/dist/assets/images/mac/vars/sandbox-macos-tahoe.pkrvars.hcl +39 -0
  11. package/dist/assets/images/ubuntu-arm64-vmware/CHANGELOG.md +239 -0
  12. package/dist/assets/images/ubuntu-arm64-vmware/README.md +177 -0
  13. package/dist/assets/images/ubuntu-arm64-vmware/autoinstall/meta-data +2 -0
  14. package/dist/assets/images/ubuntu-arm64-vmware/autoinstall/user-data +34 -0
  15. package/dist/assets/images/ubuntu-arm64-vmware/sandbox.pkr.hcl +776 -0
  16. package/dist/assets/images/ubuntu-arm64-vmware/vars/sandbox-ubuntu-24-04-arm64-vmware.pkrvars.hcl +71 -0
  17. package/dist/assets/images/windows-arm64-qemu/CHANGELOG.md +209 -0
  18. package/dist/assets/images/windows-arm64-qemu/README.md +142 -0
  19. package/dist/assets/images/windows-arm64-qemu/autounattend.xml +325 -0
  20. package/dist/assets/images/windows-arm64-qemu/qemu-with-tpm.sh +170 -0
  21. package/dist/assets/images/windows-arm64-qemu/sandbox.pkr.hcl +1012 -0
  22. package/dist/assets/images/windows-arm64-qemu/vars/sandbox-windows-11-arm64-qemu.pkrvars.hcl +83 -0
  23. package/dist/assets/images/windows-arm64-vmware/CHANGELOG.md +270 -0
  24. package/dist/assets/images/windows-arm64-vmware/README.md +171 -0
  25. package/dist/assets/images/windows-arm64-vmware/autounattend.xml +311 -0
  26. package/dist/assets/images/windows-arm64-vmware/sandbox.pkr.hcl +1036 -0
  27. package/dist/assets/images/windows-arm64-vmware/vars/sandbox-windows-11-arm64-vmware.pkrvars.hcl +83 -0
  28. package/dist/assets/rules/agent-rules-linux.md +68 -0
  29. package/dist/assets/rules/agent-rules.md +71 -0
  30. package/dist/assets/watchdog/watch-build-ocr.swift +40 -0
  31. package/dist/assets/watchdog/watch-build.py +275 -0
  32. package/dist/cli.js +52 -0
  33. package/dist/commands/delete.js +179 -0
  34. package/dist/commands/doctor.js +165 -0
  35. package/dist/commands/list.js +38 -0
  36. package/dist/commands/not-yet.js +15 -0
  37. package/dist/commands/register.js +150 -0
  38. package/dist/commands/run.js +65 -0
  39. package/dist/commands/status.js +142 -0
  40. package/dist/commands/stop.js +186 -0
  41. package/dist/commands/sync.js +98 -0
  42. package/dist/lib/exec.js +250 -0
  43. package/dist/lib/ghcr.js +82 -0
  44. package/dist/lib/git.js +100 -0
  45. package/dist/lib/logger.js +87 -0
  46. package/dist/lib/network.js +63 -0
  47. package/dist/lib/paths.js +116 -0
  48. package/dist/lib/platform.js +87 -0
  49. package/dist/lib/prompt.js +66 -0
  50. package/dist/lib/qemu.js +373 -0
  51. package/dist/lib/regex.js +9 -0
  52. package/dist/lib/ssh.js +230 -0
  53. package/dist/lib/tart.js +210 -0
  54. package/dist/lib/template.js +35 -0
  55. package/dist/lib/vars.js +99 -0
  56. package/dist/lib/vmrun.js +334 -0
  57. package/dist/lifecycle/build-macos.js +23 -0
  58. package/dist/lifecycle/build-qemu.js +204 -0
  59. package/dist/lifecycle/build-shared.js +355 -0
  60. package/dist/lifecycle/build-ubuntu.js +184 -0
  61. package/dist/lifecycle/build-watchdog.js +146 -0
  62. package/dist/lifecycle/build-windows-vmware.js +112 -0
  63. package/dist/lifecycle/build.js +55 -0
  64. package/dist/lifecycle/catalog.js +165 -0
  65. package/dist/lifecycle/deploy.js +161 -0
  66. package/dist/lifecycle/tag.js +77 -0
  67. package/dist/lifecycle/watch-build.js +64 -0
  68. package/dist/runners/bridges.js +156 -0
  69. package/dist/runners/framework.js +66 -0
  70. package/dist/runners/macos-bridges.js +143 -0
  71. package/dist/runners/macos-guest.js +76 -0
  72. package/dist/runners/macos-rules.js +77 -0
  73. package/dist/runners/macos-summary.js +145 -0
  74. package/dist/runners/macos.js +258 -0
  75. package/dist/runners/openchamber.js +60 -0
  76. package/dist/runners/options.js +56 -0
  77. package/dist/runners/qemu-image.js +183 -0
  78. package/dist/runners/rules.js +49 -0
  79. package/dist/runners/ubuntu-bridges.js +154 -0
  80. package/dist/runners/ubuntu-guest.js +136 -0
  81. package/dist/runners/ubuntu-image.js +26 -0
  82. package/dist/runners/ubuntu-rules.js +86 -0
  83. package/dist/runners/ubuntu-shared.js +65 -0
  84. package/dist/runners/ubuntu-summary.js +141 -0
  85. package/dist/runners/ubuntu.js +117 -0
  86. package/dist/runners/vmware-common.js +158 -0
  87. package/dist/runners/vmware-image.js +242 -0
  88. package/dist/runners/windows-autologon.js +119 -0
  89. package/dist/runners/windows-bridges.js +136 -0
  90. package/dist/runners/windows-guest.js +213 -0
  91. package/dist/runners/windows-image.js +23 -0
  92. package/dist/runners/windows-qemu-summary.js +85 -0
  93. package/dist/runners/windows-qemu.js +189 -0
  94. package/dist/runners/windows-shared.js +68 -0
  95. package/dist/runners/windows-summary.js +104 -0
  96. package/dist/runners/windows.js +96 -0
  97. package/dist/settings/common.js +107 -0
  98. package/dist/settings/macos-copy.js +223 -0
  99. package/dist/settings/macos.js +41 -0
  100. package/dist/settings/ubuntu-copy.js +223 -0
  101. package/dist/settings/ubuntu.js +68 -0
  102. package/package.json +52 -0
@@ -0,0 +1,239 @@
1
+ # Changelog
2
+
3
+ All notable changes to the Ubuntu sandbox images (VMware).
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ The image version lives in the image's vars file (`image_version`); every
9
+ release bumps it, adds an entry below, and tags the release commit
10
+ `<platform>-v<version>` (e.g. `ubuntu-arm64-vmware-v1.0.0`). The
11
+ `[Unreleased]` section on top is never removed — changes land there until
12
+ the next release.
13
+
14
+ ## [Unreleased]
15
+
16
+ ### Added
17
+
18
+ - **Host user settings sync into the Ubuntu guest** — the runner now copies
19
+ the host's user settings into the guest like the macOS sandbox does
20
+ (opencode config + auth, OpenCodeReview config, Copilot config + skills,
21
+ VS Code extensions + user config, mcp-compress-router settings, SSH
22
+ dotfiles, `.gitconfig`), once per VM, tracked by a versioned marker
23
+ (`~/.config/agent-dev-env/settings-copied`), with `--no-settings` to skip
24
+ and `agent-dev-env sync` (ubuntu-vmware) to re-sync on demand. The
25
+ shared logic is `settings/ubuntu.ts` + `settings/ubuntu-copy.ts` (ssh2
26
+ transport, host-to-guest path mapping for the VS Code user dir and
27
+ mcp-compress-router, `.gitconfig` rewritten for `/home/admin`,
28
+ OpenChamber restart). See `docs/ubuntu-vmware.md`.
29
+
30
+ ### Changed
31
+
32
+ - Node.js is bumped from 22 to 26 (`node_version = "26"` in the vars
33
+ file): nvm installs Node 26 and sets it as the default.
34
+
35
+ ### Fixed
36
+
37
+ - **The shared host directory no longer fails when the share is
38
+ registered before VMware Tools are up** — `agent-dev-env run`
39
+ (ubuntu-vmware) called `vmrun addSharedFolder` as soon as sshd answered,
40
+ but open-vm-tools can still be starting then: `getGuestIPAddress`/sshd
41
+ were already up while the tools state vmrun needs for the HGFS
42
+ registration was not, so the runner logged `Error: The VMware Tools are
43
+ not running in the virtual machine` and `/mnt/hgfs/work` never appeared
44
+ in the guest. The runner now waits for `vmrun checkToolsState` to report
45
+ `running` (up to 5 min) and retries `addSharedFolder` a few times, then
46
+ warns only if it still failed. A share persisted by a previous run
47
+ (`Error: Already exists`) is treated as success.
48
+ - **Host user settings copy no longer fails on the root-owned `~/.local`** —
49
+ the sync unpack hit `tar: Cannot utime` / `Permission denied` and aborted:
50
+ the image's `install -d -o admin -g admin
51
+ /home/admin/.local/share ...` left the *intermediate* `.local` directory
52
+ root-owned (install only applies `-o/-g` to its operands), so the sandbox
53
+ user could not write into `~/.local` or restore its timestamps during
54
+ `tar -C $HOME` extraction. `install -d` now lists `/home/admin/.local`
55
+ as its own operand, and the runner's settings copy
56
+ (`settings/ubuntu-copy.ts`) chowns `~/.local` back to the
57
+ sandbox user before unpacking (via `sudo -S` with the guest password the
58
+ runner already knows), so existing images are fixed on the next run
59
+ without a rebuild. The copy also strips macOS AppleDouble companions
60
+ (`._*`) and `.DS_Store` from the staged archive and cleans up any `._*`
61
+ junk a previous partial copy left in the guest — the AppleDouble files
62
+ were packed as ordinary files, and one of them (`._share`) is what first
63
+ made the extraction hit the root-owned directory.
64
+ - **mcp-compress-router settings land where the router looks for them** —
65
+ the settings copy mapped the host's
66
+ `~/Library/Application Support/mcp-compress-router/` to
67
+ `~/.config/mcp-compress-router/`, but mcp-compress-router's
68
+ `defaultConfigDir` on Linux is the XDG **data** dir,
69
+ `~/.local/share/mcp-compress-router/` (a different path from macOS and
70
+ Windows), so the synced `mcp.json`/credentials were never picked up.
71
+ The mapping now targets `~/.local/share/mcp-compress-router/` (where
72
+ `mcp.json`/`.jsonc`, `credentials.json`, `tools-cache.json` and `.env`
73
+ all live), the settings version was bumped so already-provisioned
74
+ guests re-copy, and the unpack drops the stale `~/.config` copy.
75
+ - **The build watchdog no longer misses the grub menu** — the Ubuntu build
76
+ can fail with "Timeout waiting for SSH" when the grub autoinstall
77
+ command is never typed: grub's menu countdown is ~20 s wide, but
78
+ `assets/watchdog/watch-build.py` polled once per ~2 min (90 s worker
79
+ timeout + 20 s sleep), so the menu default booted the interactive
80
+ Subiquity installer and the build sat on the installer's proxy screen
81
+ until SSH timed out. The supervisor now fast-polls (3 s interval — the
82
+ worker timeout stays at 90 s, since a kill mid-typing would corrupt the
83
+ grub shell input line) while the autoinstall command is untyped (no
84
+ `.boot-typed` marker), falling back to the old slow cadence once typed
85
+ or after a 4 min cap; the relaying is unchanged. The build flow's
86
+ watchdog stop also kills the supervisor's in-flight `--worker`
87
+ children (they survive a supervisor kill and keep the VNC port open,
88
+ blocking the next build).
89
+
90
+ ## [ubuntu-arm64-vmware-v1.1.0] - 2026-08-25
91
+
92
+ ### Added
93
+
94
+ - **GNOME desktop in the image** — `ubuntu-desktop-minimal` (GNOME Shell +
95
+ GDM3 + core apps) and `open-vm-tools-desktop` (SVGA Xorg driver,
96
+ clipboard, drag-and-drop) are installed by the Packer provisioners, the
97
+ VM boots to `graphical.target`, and GDM3 auto-logs in `admin` — the
98
+ Fusion window opens straight on the desktop (VS Code, Firefox,
99
+ OpenChamber-in-browser). The session runs on Xorg (`WaylandEnable=false`):
100
+ Fusion guests get no GPU acceleration, and the Xorg session works best
101
+ with the open-vm-tools input drivers. Display is
102
+ software-rendered (llvmpipe) — for human interaction, not 3D.
103
+
104
+ ### Changed
105
+
106
+ - The grub kernel command is typed by the **build watchdog**
107
+ (`scripts/watch-build.py` gained a `WATCH_BUILD_BOOT_CMD` mode: grub
108
+ menu/shell detected in the OCR → type the autoinstall command, once per
109
+ build, marker-guarded) instead of the Packer `boot_command` — the
110
+ firmware's No-Media/PXE probe cycle before grub appears is
111
+ variable-length (~20-40 s on Fusion), so packer-side typing fired
112
+ before grub was up and the menu's default entry booted the interactive
113
+ Subiquity installer. A `boot-typed.png` frame is captured after typing
114
+ for debugging.
115
+ - The autoinstall seed is served by a small HTTP server the build wrapper
116
+ starts on a fixed port (`python3 -m http.server 8004` over
117
+ `autoinstall/`; the seed is fetched via
118
+ `ds=nocloud-net;s=http://<vmnet8-host>:8004/`) instead of
119
+ `http_directory` — the plugin's HTTP server uses a random port and does
120
+ not accept an `http_port` override, and the URL must be known when the
121
+ grub command is typed. The vmnet8 host address is read from Fusion's
122
+ DHCP config.
123
+ - `identity.password` in the seed uses a clean crypt salt (the previous
124
+ salt contained '!', not a valid crypt salt character).
125
+
126
+ ### Fixed
127
+
128
+ - The provisioner heredocs used `$$` for shell variables (HCL only
129
+ escapes `$${`; bash expanded `$$` to its PID — observed as `$NVM_DIR`
130
+ set to "4330HOME/.nvm"). They now use plain `$`.
131
+ - `set_vm_display_name` in `scripts/lib/vmware.sh` matched only the
132
+ camelCase `displayName` key, but `vmrun clone` writes lowercase
133
+ `displayname` — the rename then *appended* a second, case-variant key,
134
+ and Fusion refuses a vmx with duplicate keys ("Cannot read the virtual
135
+ machine configuration file"), so the runner's first `vmrun start` failed
136
+ on freshly cloned VMs. It now matches case-insensitively and writes the
137
+ canonical lowercase key, dropping duplicates.
138
+ - The guest-side bridge setup used plain `sudo`, but the runner's SSH
139
+ sessions are deliberately pty-less (raw-stdin uploads depend on it), so
140
+ sudo failed with "a terminal is required". `sudo` now runs with `-S`
141
+ (password from stdin, answered by the runner's expect session, whose
142
+ prompt pattern matches "[sudo] password for ..." too), and
143
+ `guest-setup.sh` writes the profile.d file to a temp path and installs
144
+ it with `sudo -S install` — `sudo -S tee <<EOF` would eat the first
145
+ heredoc line as the password.
146
+ - The base apt list uses the 24.04 `t64` names (`libasound2t64`,
147
+ `libfuse2t64`, `libgtk-3-0t64`) — the plain names have no install
148
+ candidates.
149
+ - Docker plugin installs use the `docker-` prefixed names
150
+ (`docker-compose`, `docker-buildx` — docker only discovers prefixed
151
+ plugin files) and mirror them into the user plugin dirs; the buildx
152
+ URL includes the release's `v` prefix (the tag and asset are
153
+ `v0.36.1`/`buildx-v0.36.1.linux-arm64`).
154
+ - opencode is installed via the official installer script
155
+ (`curl https://opencode.ai/install | bash`) — the npm package
156
+ postinstall mis-selects the arm64-musl binary on glibc systems
157
+ (EBADPLATFORM) — and the XDG dirs (`~/.local/share` and friends) are
158
+ pre-created with correct ownership (opencode's first run hit EACCES).
159
+ - Google Chrome is not part of the image: CfT publishes no linux-arm64
160
+ build (only x86_64 linux64) and Ubuntu's chromium is snap-only; Firefox
161
+ (official linux-aarch64 releases) is the browser.
162
+ - The final verification checks nvm/node/npm, opencode/ocr/openchamber
163
+ and rust through the sandbox user (they live in the user's home, and
164
+ the verification shell runs as root).
165
+ - Removed the invalid `user-data:`/`late-commands` blocks from the seed:
166
+ subiquity's schema rejected them ("Cloud config schema errors ...
167
+ Additional properties are not allowed"), aborting autoinstall —
168
+ despite the seed being served fine. The seed exactly matches the first
169
+ proven build.
170
+
171
+ ## [ubuntu-arm64-vmware-v1.0.0] - 2026-08-25
172
+
173
+ ### Added
174
+
175
+ - **New platform: Ubuntu 24.04 LTS (ARM64) sandbox image for VMware
176
+ Fusion** — `images/ubuntu-arm64-vmware/`:
177
+ - `sandbox.pkr.hcl` — Packer `vmware-iso` template (same Proven
178
+ ARM64 wiring as the Windows VMware image: `guest_os_type
179
+ "arm-ubuntu-64"`, hardware version 20, NVMe disk, vmxnet3 NIC under
180
+ NAT, EFI firmware, headless + VNC on the pinned port 5901). Ubuntu
181
+ Server 24.04 ARM64 is autoinstalled via Subiquity: the installer
182
+ kernel gets `autoinstall ds=nocloud-net;s=http://.../` in the
183
+ `boot_command` and fetches `autoinstall/user-data` +
184
+ `meta-data` from Packer's HTTP server (LVM layout, user
185
+ `admin`/sandbox1, openssh-server, open-vm-tools). Provisioned over
186
+ SSH; the image ships the same toolchain as the other sandboxes
187
+ (apt base toolchain, hash-pinned Go/Rust/nvm Node/GitHub CLI/VS
188
+ Code/Chrome CfT/Firefox/Docker CLI + compose + buildx, npm globals
189
+ opencode/`ocr`/OpenChamber). OpenChamber runs as a systemd **user**
190
+ service (`agent-dev-env-openchamber`, linger enabled) on
191
+ `0.0.0.0:4000`.
192
+ - `vars/sandbox-ubuntu-24-04-arm64-vmware.pkrvars.hcl` — Ubuntu point
193
+ release, ISO SHA256, all pinned toolchain versions + hashes, VM
194
+ resources, credentials, OpenChamber, `image_version`.
195
+ - `build.sh` — platform wrapper: ISO SHA256 verification, `packer
196
+ init` + `packer build` into `build/ubuntu-arm64-vmware/`, VNC build
197
+ watchdog, post-build `vmrun upgradevm` hardware upgrade (shared
198
+ helper, see below). No driver/tools staging from Fusion is needed —
199
+ the vmxnet3 + NVMe drivers are in-box in the Ubuntu kernel
200
+ (verified: `vmxnet3.ko` ships in the base `linux-modules` package)
201
+ and open-vm-tools come from the Ubuntu archive (Fusion ships no
202
+ Linux tools ISO for arm64 guests).
203
+ - `deploy.sh` — platform wrapper: packs the output directory into a
204
+ tar.gz and pushes `ghcr.io/<owner>/<image>:<version>,latest` as an
205
+ OCI artifact via `oras`.
206
+ - `README.md` — build/publish flow, "What's in the image", gotchas.
207
+ - **`scripts/lib/vmware.sh`** — the generic vmrun helpers (vmrun
208
+ resolution, hardware-version upgrade, vmx displayName) factored out of
209
+ `scripts/lib/windows-vmware/lib.sh` (which is now a thin shim sourcing
210
+ it), shared by both VMware platforms.
211
+ - **`scripts/run-ubuntu-vmware-sandbox.sh`** — user-facing runner: picks
212
+ the archive (env override → local build output → GHCR pull via oras),
213
+ extracts the pristine VM + `vmrun clone`s a working VM (one-time
214
+ hardware-version upgrade), boots it (headless or windowed), discovers
215
+ the guest IP via open-vm-tools, and bridges the host's SSH agent and
216
+ Docker engine into the guest — host-side `socat` on TCP 4400/4401
217
+ bound to the vmnet8 address + guest-side systemd user services
218
+ (`scripts/lib/ubuntu-vmware/guest-setup.sh` renders socat relays for
219
+ `/tmp/ssh-agent.sock` and `/tmp/docker.sock` plus the
220
+ `/etc/profile.d` exports, auto-start via linger). Optionally shares a
221
+ host directory (`--work-dir`, HGFS → `/mnt/hgfs/work`), installs the
222
+ sandbox agent rules (`scripts/agent-rules-linux.md`) into the guest's
223
+ opencode + Copilot configs, and verifies OpenChamber.
224
+ - **`scripts/stop-ubuntu-vmware-sandbox.sh` / `delete-ubuntu-vmware-sandbox.sh`** —
225
+ stop the working VM (`vmrun -T fusion stop`, graceful + hard fallback)
226
+ and kill the host bridge listeners; delete the state dir (extracted
227
+ base + working clone + pulled image cache) after a confirmation.
228
+ - **`scripts/agent-rules-linux.md`** — sandbox environment rules for the
229
+ Ubuntu guest (shared-directory path mapping, host Docker engine via
230
+ `/tmp/docker.sock`, published ports at the NAT gateway, SSH agent
231
+ socket).
232
+ - **Docs**: `docs/linux.md` replaces its "not supported yet" placeholder
233
+ with the full Ubuntu VMware sandbox guide; `README.md`,
234
+ `DEVELOPMENT.md` and `AGENTS.md` list the new platform and the
235
+ shared `scripts/lib/vmware.sh` helper.
236
+
237
+ [unreleased]: https://github.com/ameshkov/agent-dev-env/compare/ubuntu-arm64-vmware-v1.1.0...HEAD
238
+ [ubuntu-arm64-vmware-v1.1.0]: https://github.com/ameshkov/agent-dev-env/releases/tag/ubuntu-arm64-vmware-v1.1.0
239
+ [ubuntu-arm64-vmware-v1.0.0]: https://github.com/ameshkov/agent-dev-env/releases/tag/ubuntu-arm64-vmware-v1.0.0
@@ -0,0 +1,177 @@
1
+ # Ubuntu Sandbox Images — VMware
2
+
3
+ Ubuntu 24.04 LTS (ARM64) sandbox VM images built with
4
+ [Packer](https://www.packer.io/) and the
5
+ [VMware plugin](https://github.com/vmware/packer-plugin-vmware)
6
+ (`vmware-iso` builder) on an Apple Silicon Mac. The output is a runnable
7
+ vmx + vmdk VM (built at the vmware-iso hardware level, upgraded post-build
8
+ to the host Fusion's current hardware version — see
9
+ [How to Build](#how-to-build)), packed into a tar.gz for publishing; the
10
+ macOS host runs it under Fusion's `vmrun` CLI. Fusion
11
+ virtualizes ARM64 guests natively; the guest uses **open-vm-tools** from
12
+ the Ubuntu archive (Fusion ships no VMware Tools for arm64 Linux — the
13
+ `isoimages/arm64/` folder contains only `windows.iso`), which provide
14
+ `vmrun getGuestIPAddress`, graceful power operations and HGFS shared
15
+ folders.
16
+
17
+ The sibling images are the macOS
18
+ ([Tart](../mac/README.md)) and Windows 11 ARM64
19
+ ([QEMU](../windows-arm64-qemu/README.md),
20
+ [VMware](../windows-arm64-vmware/README.md)) sandboxes. See
21
+ [docs/ubuntu-vmware.md](../../docs/ubuntu-vmware.md) for the user
22
+ guide (boot it with `npx agent-dev-env run ubuntu-vmware`).
23
+
24
+ ## Prerequisites
25
+
26
+ - Apple Silicon Mac (M-series). Fusion cannot virtualize ARM64 guests on
27
+ Intel, so this image is ARM64-only.
28
+ - [VMware Fusion](https://www.vmware.com/products/desktop-hypervisor/workstation-and-fusion)
29
+ (free for personal use; the Packer plugin requires Fusion 13.6+).
30
+ - [Packer](https://www.packer.io/): `brew install hashicorp/tap/packer`
31
+ (the VMware plugin is installed automatically by `packer init`).
32
+ - The **Ubuntu Server 24.04 ARM64 ISO** — bring your own, ~3 GB:
33
+
34
+ 1. Download the latest point release from
35
+ https://cdimage.ubuntu.com/releases/24.04/release/ — the
36
+ `ubuntu-24.04.x-live-server-arm64.iso` file.
37
+ 2. Copy its SHA256 from the release `SHA256SUMS`
38
+ (https://cdimage.ubuntu.com/releases/24.04/release/SHA256SUMS) into
39
+ `iso_sha256` in the vars file.
40
+ 3. Set `UBUNTU_ISO_PATH` to its absolute path when building.
41
+
42
+ That is all: the guest's vmxnet3 NIC and NVMe disk drivers are in-box in
43
+ the Ubuntu kernel (vmxnet3.ko ships in the base `linux-modules` package),
44
+ and open-vm-tools come from the Ubuntu archive — no driver or tools
45
+ staging from Fusion is needed (unlike the Windows image).
46
+
47
+ ## How to Build
48
+
49
+ ```bash
50
+ # From the repository root
51
+ UBUNTU_ISO_PATH=/path/to/ubuntu-24.04.4-live-server-arm64.iso \
52
+ npx agent-dev-env build sandbox-ubuntu-24-04-arm64-vmware
53
+ ```
54
+
55
+ `agent-dev-env` is the CLI shipped by this repo (see
56
+ [docs/cli.md](../../docs/cli.md)). The ubuntu-vmware build flow:
57
+
58
+ 1. Verifies the host (Apple Silicon), the local ISO (SHA256 against
59
+ `iso_sha256` from the vars file) and the Fusion install (only needed
60
+ for the post-build hardware upgrade).
61
+ 2. Starts the autoinstall seed server (`python3 -m http.server 8004`
62
+ over `autoinstall/`) and runs `packer init` + `packer build`. The
63
+ build is headless with **no `boot_command` typing**: the build
64
+ watchdog (see below) waits for the grub menu/shell in the VNC OCR and
65
+ types the autoinstall kernel line
66
+ (`ds=nocloud-net;s=http://<vmnet8-host>:8004/` — the firmware's
67
+ No-Media/PXE probe cycle before grub appears is variable-length, so
68
+ the plugin's own typing was unreliable). Subiquity fetches the seed:
69
+ LVM over the whole disk, user `admin` (password from the vars file),
70
+ openssh-server, open-vm-tools — then reboots into the installed system
71
+ and is provisioned over SSH.
72
+ 3. Runs the VNC **build watchdog** (bundled `assets/watchdog/`) alongside
73
+ `packer build` (pinned VNC port 5901) to auto-dismiss installer dialogs
74
+ and rescue a boot that lands in the UEFI shell. Needs
75
+ `pip3 install vncdotool` + Xcode command line tools; skipped with a
76
+ warning when missing.
77
+ 4. Upgrades the output VM with `vmrun upgradevm` to the hardware version
78
+ the installed Fusion writes for a new VM (hardware version 20 → 22 on
79
+ Fusion 26). The headless build never shows Fusion's one-time
80
+ "Upgrade this virtual machine?" prompt, but a first GUI start of a
81
+ version-20 VM would; the upgrade also rewrites the vmdk descriptor.
82
+ The runner upgrades its working clone the same way for artifacts built
83
+ by older Fusion versions (see
84
+ [docs/ubuntu-vmware.md](../../docs/ubuntu-vmware.md)).
85
+
86
+ A build takes roughly 30 minutes on an M-series Mac (the Ubuntu installer
87
+ dominates, plus the ~8 min GNOME desktop apt install; Fusion runs the
88
+ guest near-native). Everything per image lives under the CLI's data root:
89
+ `~/Library/Application Support/agent-dev-env/build/ubuntu-vmware/output/`
90
+ (the vmx + vmdk + nvram), plus `packer_cache/`. The macOS/tart images
91
+ build no files and have no such directory.
92
+
93
+ ## What's in the image
94
+
95
+ | Component | Detail |
96
+ | --- | --- |
97
+ | Ubuntu Server 24.04 LTS (ARM64) | Point release from the vars file; LVM over the whole disk |
98
+ | open-vm-tools | From the Ubuntu archive (Fusion ships no Linux tools for arm64); enables `vmrun getGuestIPAddress`, soft power ops, HGFS shared folders |
99
+ | GNOME desktop | `ubuntu-desktop-minimal` + `open-vm-tools-desktop`; boots to `graphical.target`, GDM3 auto-login as `admin`, Xorg session (software-rendered — no GPU accel in a Fusion arm64 guest) |
100
+ | apt toolchain | build-essential (gcc/g++/make), cmake, autoconf, git, curl, wget, jq, ripgrep, vim, tmux, socat, python3 + pip/venv, ruby; browser + X libs for Firefox |
101
+ | Go | `go<version>` tarball from go.dev/dl, hash-pinned; `/usr/local/go` |
102
+ | Rust | Via rustup (arm64 host toolchain), `rust`/`cargo` on PATH |
103
+ | Node.js | Via nvm (major from the vars file, default alias); npm globals in the nvm dir |
104
+ | GitHub CLI | `gh_<version>_linux_arm64.deb`, hash-pinned |
105
+ | Visual Studio Code | `code_<version>_arm64.deb`, hash-pinned; `code` on PATH |
106
+ | Firefox | Official linux-aarch64 release tarball, hash-pinned; `/opt/firefox` (no Chrome: CfT publishes no linux-arm64 build, Ubuntu's chromium is snap-only) |
107
+ | Docker CLI | Client only (`docker` + `docker compose` + `docker buildx`, static aarch64 binaries, hash-pinned); no engine — bridged from the host |
108
+ | OpenCode (`opencode-ai`) | npm global |
109
+ | OpenCodeReview (`ocr`) | npm global (`@alibaba-group/open-code-review`) |
110
+ | OpenChamber web UI | npm global (`@openchamber/web`), systemd **user** service (`agent-dev-env-openchamber`) on `0.0.0.0:4000`, started at boot (`loginctl enable-linger`) |
111
+ | SSH | openssh-server with password auth; `admin`/sandbox1 (see the vars file); Ubuntu's default cloud-init finalization |
112
+ | systemd user services | Linger enabled for `admin`; the guest agent's bridge services and OpenChamber auto-start in the guest |
113
+
114
+ ## Versioning
115
+
116
+ Same convention as the other images: the image version lives in
117
+ `image_version` in the vars file; every release bumps it, adds a
118
+ `CHANGELOG.md` entry, and creates a `ubuntu-arm64-vmware-v<version>` git
119
+ tag via `npx agent-dev-env tag <image>`.
120
+
121
+ ## Running and publishing
122
+
123
+ - Run the sandbox: `npx agent-dev-env run ubuntu-vmware` — extracts
124
+ the archive, clones a working VM with `vmrun`, discovers the guest IP
125
+ via open-vm-tools, and bridges the host's Docker engine and SSH agent
126
+ into the guest (see
127
+ [docs/ubuntu-vmware.md](../../docs/ubuntu-vmware.md)).
128
+ - Publish: `npx agent-dev-env deploy sandbox-ubuntu-24-04-arm64-vmware`
129
+ packs the output directory into `${image_name}.tar.gz` and pushes it to
130
+ `ghcr.io/<owner>/sandbox-ubuntu-24-04-arm64-vmware:<version>` +
131
+ `:latest` as an OCI artifact via `oras` (the CLI packs and pushes
132
+ directly — no platform wrapper — because `tart push` only works for
133
+ Tart VMs). Needs `brew install oras` and a GHCR token with
134
+ `write:packages` (`oras login ghcr.io`).
135
+
136
+ ## Gotchas
137
+
138
+ - **The Ubuntu ISO is not in the repo.** The build fails fast without
139
+ `UBUNTU_ISO_PATH`; the sha256 in the vars file protects against a
140
+ corrupt download. The ISO is ~3 GB.
141
+ - **ARM64 only.** Fusion on Intel can only run x86_64 guests, so this
142
+ image requires Apple Silicon.
143
+ - **Fusion 13.6+ and the VMware plugin v2+.** The template uses
144
+ `github.com/vmware/vmware` (Broadcom's maintained fork); the older
145
+ `github.com/hashicorp/vmware` plugin has different options.
146
+ - **No VMware Tools from Fusion — ever.** Fusion's arm64 `isoimages/`
147
+ folder ships only `windows.iso`; open-vm-tools are the only in-guest
148
+ tools available for arm64 Linux VMs. The image installs them from the
149
+ Ubuntu archive, so their version tracks Ubuntu, not Fusion.
150
+ - **The autoinstall seed comes over the build flow's HTTP server, and the
151
+ grub typing is done by the build watchdog.** The seed is fetched via
152
+ `ds=nocloud-net` from `python3 -m http.server 8004` (`autoinstall/`),
153
+ and the bundled `watch-build.py` types the kernel command when grub
154
+ appears (`WATCH_BUILD_BOOT_CMD`; the firmware's No-Media/PXE probe
155
+ cycle before grub is variable-length, so the plugin's own boot_command
156
+ typing was unreliable and could boot the interactive Subiquity installer
157
+ — a build then hangs waiting for SSH; check the VNC watchdog frames in
158
+ `~/Library/Application Support/agent-dev-env/build/ubuntu-vmware/packer_cache/watchdog/`).
159
+ The watchdog polls every 3 s until the command is typed (grub's menu
160
+ countdown is ~20 s wide — the slow ~2 min-per-frame poll could miss it
161
+ entirely), then relaxes to the slow cadence.
162
+ - **Keep `autoinstall/user-data` in sync with the vars file**: the seed
163
+ bakes the sandbox user (name + crypt hash of `ssh_password`). Change
164
+ the credentials in the vars file *and* the `identity:` block together.
165
+ - **No snapshot in the published image.** `snapshot_name` is deliberately
166
+ unset: the sandbox runner makes a *full* clone as its working VM, and a
167
+ snapshot inside the published archive would only complicate disk
168
+ compaction and re-cloning.
169
+ - **The shared folder is best-effort.** HGFS via `vmhgfs-fuse`
170
+ (`open-vm-tools`) is mounted by the runner at `/mnt/hgfs/work`; a
171
+ missing mount is a warning, not an error (git, OpenChamber UI, and the
172
+ agent bridges do not need it).
173
+ - **The desktop is software-rendered.** A Fusion arm64 guest has no GPU
174
+ acceleration, so GNOME runs on llvmpipe (Xorg session,
175
+ `WaylandEnable=false` in GDM3's custom.conf). It is meant for human
176
+ interaction (VS Code, Firefox, OpenChamber in a browser) — not for 3D
177
+ work; the agents do not use the GUI at all.
@@ -0,0 +1,2 @@
1
+ instance-id: agent-dev-env-ubuntu-vmware
2
+ local-hostname: ubuntu-sandbox
@@ -0,0 +1,34 @@
1
+ #cloud-config
2
+ #
3
+ # Subiquity autoinstall seed for the Ubuntu sandbox image — served by
4
+ # Packer's HTTP server (http_directory, ds=nocloud-net) and fetched by the
5
+ # installer kernel, as configured by the boot_command in
6
+ # sandbox.pkr.hcl.
7
+ #
8
+ # Keep in sync with sandbox.pkr.hcl:
9
+ # - identity.password is the crypt hash of var.ssh_password ("sandbox1"),
10
+ # - identity.username is var.ssh_username ("admin"),
11
+ # - the ssh block enables sshd + password auth for Packer's communicator.
12
+ #
13
+ # Everything else (toolchain, OpenChamber, ...) is installed by the
14
+ # provisioners — this seed only gets a bootable system with SSH + tools
15
+ # (open-vm-tools must be present before the first boot so `vmrun
16
+ # getGuestIPAddress` works immediately in the sandbox runner).
17
+ autoinstall:
18
+ version: 1
19
+ locale: en_US.UTF-8
20
+ keyboard:
21
+ layout: us
22
+ timezone: UTC
23
+ identity:
24
+ hostname: ubuntu-sandbox
25
+ username: admin
26
+ password: "$6$rand0mS4lt$fgNjBzoL2PEvCW.OGnGIH/13sT54EDF3C0SB2WHzcQla4uvGel3BErD87ZhQTW/7eFv.Mtoaenc7t0UzKEh6q0"
27
+ ssh:
28
+ install-server: true
29
+ allow-pw: true
30
+ storage:
31
+ layout:
32
+ name: lvm
33
+ packages:
34
+ - open-vm-tools