Commit Graph
100 Commits
Author SHA1 Message Date
James Stringer 4b43155f47 Clarify native GPU shim and provisioning names 2026-09-12 20:39:40 -04:00
James Stringer 17f7ba07e9 Enable native OpenGL and Vulkan for Windows GPU VMs
Build and stage x64 and x86 NVIDIA shims through the existing solution and deploy them through P9 and the guest agent. Include active AMD runtime packages and prefer native OpenGL and Vulkan on NVIDIA, AMD, and Intel guests.
2026-09-12 19:26:06 -04:00
James Stringer 594d323ffe Bump version to 0.1.5
App Sandbox 0.1.5

### Added

- Choose where VM disks are stored when creating a sandbox on Windows or macOS, including on another drive. Requested in [#12](https://github.com/jamesstringer90/appsandbox/issues/12), [#24](https://github.com/jamesstringer90/appsandbox/issues/24), [#38](https://github.com/jamesstringer90/appsandbox/issues/38), [#68](https://github.com/jamesstringer90/appsandbox/issues/68), and [#71](https://github.com/jamesstringer90/appsandbox/issues/71).
- Automatic mouse capture for games and 3D applications in Windows and Ubuntu VMs.
- Keyboard shortcut capture and audio mute controls in the Windows VM viewer's title bar menu on macOS.

### Fixed

- Improved international keyboard input and fixed keyboard layout setup in newly created Ubuntu VMs. [#76](https://github.com/jamesstringer90/appsandbox/issues/76)
- Fixed host input methods intercepting typing and language-switching shortcuts when keyboard shortcut capture is enabled on Windows. [#116](https://github.com/jamesstringer90/appsandbox/issues/116)
- Fixed incorrect mouse positioning when changing display scaling inside Windows VMs. [#111](https://github.com/jamesstringer90/appsandbox/pull/111)
- Fixed distorted text cursors in the Windows viewer at high DPI scaling settings.
- Fixed copying text from Ubuntu Terminal to the host clipboard.
- Fixed NVIDIA driver-profile errors preventing games such as Counter-Strike 2 from starting. Addresses the NVIDIA profile error in [#73](https://github.com/jamesstringer90/appsandbox/issues/73).
- Fixed Windows installation images being incorrectly detected as English on non-English hosts. [#84](https://github.com/jamesstringer90/appsandbox/issues/84)
- Fixed NAT internet connectivity in Windows VMs with localized network adapter names. [#79](https://github.com/jamesstringer90/appsandbox/issues/79), [#84](https://github.com/jamesstringer90/appsandbox/issues/84)
- Fixed external networking failing after saving adapter names containing non-English characters. [#94](https://github.com/jamesstringer90/appsandbox/issues/94)
- Fixed saved NAT addresses being lost when VMs shut down.
- Fixed Windows VMs created from templates using the template's disk size instead of the size selected during creation.
- Fixed saved snapshots being modified when starting a VM after deleting a branch.
- Fixed snapshot controls remaining visible after all snapshots and branches were deleted.
- Fixed Windows installation getting stuck when the username matches the VM name. [#103](https://github.com/jamesstringer90/appsandbox/pull/103)
- Improved VM creation checks for invalid usernames and missing passwords.
- Fixed VM table columns shifting when switching operating systems in the creation window.
2026-09-09 21:18:10 -04:00
James Stringer 6f8fefe948 VM storage options and fixes for input, networking, and setup
VM storage options and fixes for input, networking, and setup
2026-09-09 21:12:55 -04:00
James Stringer 9d6342f977 Fix viewer mouse capture and keyboard handling 2026-09-08 22:49:37 -04:00
James Stringer 26e0e96a78 Fix Mac builds and sandbox creation validation
Correct the Xcode file reference and CoreGraphics API call. Keep creation actions disabled for invalid configuration and use the v0.1.5 ARM64 guest resource ZIP.
2026-09-07 23:14:56 -04:00
James Stringer 046a7c0e8f Use updated Windows ARM64 payload for Mac VM creation 2026-09-07 21:41:27 -04:00
James Stringer 92c7a350f9 Remove redundant source comments 2026-09-07 20:58:47 -04:00
James Stringer a68665db2d Restore static NAT networking and preserve saved VM IPs 2026-09-07 20:20:41 -04:00
James Stringer fcdef6223c Configure NAT DHCP subnets and remove Windows agent IP setup 2026-09-07 17:44:17 -04:00
James Stringer d8b9be0c66 Fix HCN schema for DHCP network creation 2026-09-07 15:51:06 -04:00
James Stringer c737c292cf Use DHCP for Windows-host NAT networking 2026-09-07 15:44:22 -04:00
James Stringer 4e2493dfbe Fix international keyboard input and Linux clipboard copying 2026-09-07 14:27:27 -04:00
James Stringer 978f52b8f5 Fix VM setup, storage, snapshots, and viewer behavior 2026-09-07 13:02:28 -04:00
James Stringer 72c06267a5 Update VM support and features
Updated macOS and Windows 11 ARM VM support details, clarified GPU acceleration capabilities, and improved headless mode description.
2026-06-30 22:00:29 -04:00
James Stringer 2d9eae869a Bump version to 0.1.4
App Sandbox 0.1.4

- **Windows 11 (ARM64) VMs on macOS.** On an Apple Silicon Mac, App Sandbox can
  now create and run Windows 11 ARM guests -- previously a macOS host could only
  run macOS guests. The Windows guest gets its own display window, keyboard and
  mouse, sound, clipboard (including copying files to and from your Mac),
  one-click SSH, and networking, and is built from a Windows 11 ARM64 ISO you
  provide. It runs on a self-contained virtual-machine engine bundled with the
  app, and the guest agent and drivers are downloaded (code-signed) when you
  create the VM, so no test-signed components ship inside App Sandbox.

- **Non-ASCII usernames and passwords now work when creating a VM through the
  scriptable API.** Characters outside plain ASCII (for example Chinese) arrive
  from the API JSON-escaped; App Sandbox stored the escape sequences literally
  instead of decoding them, so a VM created via the API with such a credential
  would reject the login. They are now decoded correctly. (The desktop app was
  unaffected.)
- **The virtual display now recovers if it gets disabled in the guest.** The
  guest agent kept trying to restart the App Sandbox display driver -- which
  can't re-enable a disabled device -- so the picture never came back; it is now
  re-enabled and recovers.
- Various stability and bug fixes across the Windows and macOS components.

- **Windows VMs on macOS are not GPU-accelerated.**
- **x64 (emulated) apps in ARM Windows VMs don't get the OpenGL fix** -- the Mesa
  driver shipped on ARM is ARM64-only; native ARM64 apps get full GPU OpenGL.
  (carried over from 0.1.2)
- **ARM Linux (Ubuntu 26.04 LTS) guests do not work -- on ARM, Windows is the
  only working guest** (Ubuntu 26.04's arm64 kernel churns BPF JIT memory and
  never reaches the desktop). (carried over from 0.1.2)
2026-06-30 20:57:07 -04:00
James Stringer 77e2b744d6 Windows 11 ARM64 guests on macOS hosts
## Summary

Adds support for running **Windows 11 ARM64 guests on macOS (Apple Silicon) hosts**.
Until now a macOS host ran only macOS guests (Virtualization.framework); this branch boots
Windows guests on a bundled **QEMU + Hypervisor.framework (HVF)** VMM, with an **ivshmem
shared-memory transport** carrying every guest channel — agent control, display (VDD), input,
audio, clipboard, SSH, and 9P — so **no guest networking is required**. The same headless
HTTP/JSON API and GUI now create Windows guests on a Mac, and Windows-on-Windows behaviour
is unchanged.

## How it works

- **Transport** (`tools/transport`): a single guest transport API with two backends — PC
  `AF_HYPERV` (unchanged) and Mac **ivshmem** — over an SPSC ring. `src/backend_mac` maps the
  ivshmem BAR and runs the host side of each channel; the launcher publishes the region
  directory and the guest reads its geometry at boot.
- **Guest driver** (`tools/ivshmem`): an in-house KMDF ivshmem BAR-mapping driver
  (**AppSandboxSHM**, `PCI\VEN_1AF4&DEV_1110`) — no third party — built through the same VS
  pipeline as VDD/VAD and MS-attestation-signed.
- **VMM**: a vendored **QEMU 11.0.1 fork** with `ivshmem-plain` (`vendor/qemu-ivshmem`),
  embedded self-contained in the app bundle (codesigned with the Hypervisor entitlement), with
  the LGPL source mirror for compliance. This is the bulk of the diff (vendored upstream).
- **Disk build / provisioning**: a from-scratch ISO→NTFS disk builder (`tools/iso-patch-mac`)
  applies the install image and stages the payload + answer file. `unattend.xml` / `setup.cmd`
  / `SetupComplete.cmd` are generated by the **shared** `tools/provision/win_provision.c` used
  by both the Windows backend and the Mac host — one generator, no platform fork.

## Guest payload

The Mac host **JIT-downloads** the signed Windows release zip (EV-signed agent EXEs +
**MS-attestation-signed** drivers, incl. AppSandboxSHM), caches it, and pulls the WHQL-signed
**NetKVM** virtio-net driver from a vendored zip (`vendor/virtio-win`). No test-signed Windows
binaries ship in the app bundle.

## Credentials

- The account credential is **obfuscated/hashed in the daemon** for all configs — the
  disk-applier child only ever receives the non-plaintext result, so the plaintext never
  crosses the process boundary. Win-on-Mac generates the base64 `unattend.xml` in-process;
  macOS guests get a salted PBKDF2-SHA512 ShadowHash + kcpassword computed in-process
  (`tools/provision/mac_account_hash.{h,m}`).
- **Non-ASCII (incl. CJK) credentials** are handled correctly: the unattend `<Password>` is
  encoded as true UTF-16LE and the headless SDK's JSON `\uXXXX` escapes are decoded. Verified
  with a 12-character mixed Chinese/English password (`ValidateCredentials` on Windows,
  `dscl -authonly` on macOS).

## Testing

- Full **2× Windows-11 concurrent lifecycle suite green** (4 GB / 4 cores / 64 GB each):
  create → disk build → boot-to-online → SSH key auto-deploy → display open/close →
  edit-while-stopped → shutdown/restart → delete; snapshots correctly return `501` on macOS.
- Guests reach agent-online with the attestation-signed drivers under Secure Boot.
- CJK password authenticated inside both Windows and macOS guests.

## Deploy note

The signed-payload URL points at the **v0.1.4 release** — that release must be published, or a
Windows-on-Mac create fails with "Signed Windows guest payload download failed".
2026-06-30 19:41:10 -04:00
James Stringer e931f24bf7 Remove superseded dev prototypes from the engine and ivshmem tools
win2ntfs.c was the standalone harness that validated the WIM->NTFS apply;
that logic now lives (with real per-file SIDs) in win_disk.c. AppSandboxSHM_producer.c
was the ivshmem bring-up bandwidth POC whose host-side reader (shm-test) is gone;
the production data path is asb_transport over the AppSandboxSHM driver. Neither
file was compiled by any target or included anywhere.
2026-06-30 19:30:52 -04:00
James Stringer 095a4f9ed4 Remove dev-only agent build/deploy scripts added in this branch
build-arm64.cmd and deploy-arm64.cmd were manual dev-VM helpers (cl build
of the guest binaries + hand-copy to C:\Windows\AppSandbox); the production
pipeline builds via msbuild on AppSandbox.sln and never referenced them.
2026-06-30 18:57:27 -04:00
James Stringer 4898c4692f Remove TODO planning docs; complete THIRD-PARTY-NOTICES for the bundled deps
- Delete the TODO/ planning + runbook docs, and fix the four code/README comments
  that pointed at them (asb_transport.c/.h; the tools/ivshmem and vendor/qemu-ivshmem
  READMEs now point at the vendored QEMU directly).
- THIRD-PARTY-NOTICES.md: add the bundled QEMU stack (QEMU GPL-2.0; GLib +
  gettext/libintl LGPL-2.1; PCRE2 BSD; EDK2/TianoCore BSD-2-Clause-Patent) and
  NetKVM (BSD-3) -- shipped/staged by the app but previously absent from the
  top-level notices. The QEMU entry cross-references the bundled
  vendor/qemu-ivshmem/LICENSES/NOTICE.md + WRITTEN_OFFER.txt. A usage audit
  confirmed every listed dependency is still in use, so nothing was removed.
2026-06-30 18:42:49 -04:00
James Stringer dfd6fe475f Win-on-Mac: fix ivshmem AGENT/SSH region overlap and display readiness
Post-review fixes and release prep for the win-on-mac feature.

* asb_shm_layout.h: fix a region-sizing bug -- the AGENT (ch1) slot stride
  (0x20070) exceeded ASB_AGENT_REGION_SIZE (0x20000) by 112 bytes, so the agent
  host->guest ring overran into the adjacent SSH (ch7) region and corrupted its
  slot state under sustained traffic. Enlarge the AGENT region to 0x21000
  (downstream offsets cascade) and add per-region compile-time guards
  (n_slots*stride <= region_size) so this class of overlap fails the build.
  Host/publisher-side only -- the guest reads geometry from the published directory.

* headless.m: GET /display readiness now includes idd_ready for a Windows guest,
  matching the open precondition (asb_core_mac.m) and the Windows host
  (asb_vm_idd_ready). Before, the Mac readiness was running && agent_online only,
  so it could report ready before the VDD was up and a poll-then-open would
  spuriously 409 display_not_ready. macOS guests are unchanged.

* iso-patch-mac.m (stage): wipe the plaintext password buffer on the
  --shadowhash-file read-failure path, matching the sibling --kcpassword-file path.

* iso_patch_mac.m: point the signed Windows guest payload at the v0.1.4 release.

* vm_lifecycle.py: raise the Windows build-stall budget to 3600 s for the
  signal-less first-boot window under concurrent multi-VM load.

* tools/headless-api/README.md: document Windows guests on macOS hosts (platform
  matrix, host-fixed line, requirements heading, osType field).
2026-06-30 18:12:32 -04:00
James Stringer 45530e2e2a Add new image to README.md
Added a new image to the README for better visual representation.
2026-06-30 08:19:28 -04:00
James Stringer 96fbc9ae60 Win-on-Mac: point the signed guest-payload prefetch at the updated release zip
Update ensureSignedWinPayloadZipCached to the new GitHub attachment URL and embed
the attachment id in the cached filename, so changing the URL at the same app
version auto-invalidates the cache instead of serving the stale cached zip.
2026-06-29 21:52:30 -04:00
James Stringer c042b92a21 Agent: enable (not just restart) a disabled VDD to recover it
ensure_vdd_running() detected a disabled AppSandboxVDD and ran `devcon restart`,
which reports success but cannot clear CONFIGFLAG_DISABLED on a device in
CM_PROB_DISABLED -- so the device snapped straight back to disabled and the agent
looped forever (detect disabled -> restart -> still disabled, every 20s). Only
`devcon enable` (DICS_ENABLE) clears the explicit-disable bit.

Now: ENABLE a disabled device; keep RESTART for a stuck-but-enabled ("problem") one.
2026-06-29 21:31:59 -04:00
James Stringer 303b34dab8 Win-on-Mac: encode the guest password in the daemon for all three configs
All three guest configs now obfuscate/hash the account credential in the daemon
and hand the disk-applier child only the non-plaintext result -- the plaintext
never crosses the process boundary, mirroring the Windows-on-Windows model.

  * Win-on-Mac: the daemon generates unattend.xml / setup.cmd / SetupComplete.cmd
    in-process via the shared asb_provision_* (base64 of UTF-16LE(pass+"Password"),
    the same encoder the Windows backend uses) and passes build-windows only
    --prov-dir; the plaintext --pass argv is gone. The child still detects the
    install.wim language and reports LANG:, and the daemon re-generates unattend.xml
    in-process with the detected tag -- the exact mirror of vhdx_create_thread.
  * Mac-on-Mac: the salted PBKDF2-SHA512 ShadowHash + kcpassword are computed in
    the daemon via the new shared tools/provision/mac_account_hash.{h,m}; the stage
    child takes --shadowhash-file / --kcpassword-file. --user-password-file remains
    a direct-CLI fallback.
  * Verified end-to-end on live Windows + macOS guests with a 12-character mixed
    Chinese/English password (ValidateCredentials / dscl -authonly), exercising the
    UTF-16 surrogate path.

Also in this checkpoint of accumulated win-on-mac work:

  * agent: report_idd_status re-runs on the device-check loop (force-on-connect +
    on-change) so display readiness tracks the live, self-healed VDD state instead
    of a single one-shot sample.
  * disk builder (tools/iso-patch-mac/engine): WIM reader gains the install-image
    default-language reader behind the language auto-detect; win_disk locale/apply
    refinements.
  * display + transport: idd_display Metal render + clipboard-reader paths;
    asb_ivshmem_transport slot-reclaim hardening.
  * housekeeping: remove the dev-only transport test harness (tools/transport/test/*);
    update headless-api test scripts; drop changelog-style comments.
2026-06-29 20:50:32 -04:00
James Stringer 4b28e7138d Windows-on-Mac: JIT-only guest payload; remove the bundled test-signed fallback
The Mac host now sources the entire Windows guest payload via JIT download + cache --
no bundled/embedded fallback, so zero test-signed binaries ship in the app.

- iso-patch-mac.m (build-windows): --signed-payload-zip is now required (its extraction
  failing is a hard error, not a fallback); new --netkvm-zip. Extract the signed zip in
  full -- the Windows-built zip uses backslash separators that forward-slash unzip
  include-patterns never match (unzip exits 11 and stages nothing); a full extract makes
  Info-ZIP rewrite them into real resources/ + drivers/. Stage our VDD/VAD/SHM from the
  signed payload and NetKVM from its own zip (best-effort). Drop --payload/--devcon.
- iso_patch_mac.{h,m}: buildWindowsDiskWithISO drops payloadDir/devconExe, takes a
  required signedPayloadZip + optional netkvmZip. Add ensureNetkvmZipCached (pulls the
  vendored netkvm-arm64.zip from the public repo, cached like the IPSW).
- asb_core_mac.m: remove windows_payload_directory()/devcon_exe_path(); the create flow
  fails if the signed payload download fails (JIT-only). NetKVM + OpenSSH best-effort.
- Remove the "Embed agent_win" Xcode phase and git rm tools/agent_win (the test-signed
  EXEs + drivers). The app bundle embeds zero Windows test-signed binaries.

Fixes the staging bug where the backslash zip silently fell back to the bundled
WDKTestCert drivers, which failed DriverStore import (0xE0000243), so the agent never
came online.
2026-06-28 23:09:39 -04:00
James Stringer c66928bfff Vendor NetKVM as a committed JIT zip (vendor/virtio-win)
Store the signed ARM64 NetKVM driver (Red Hat VirtIO Ethernet Adapter, v100.101.104.28500,
WHQL-signed) as vendor/virtio-win/netkvm-arm64.zip so the Mac app JIT-pulls it from the public
repo (raw.githubusercontent.com) and caches it, instead of bundling it. License kept visible
alongside. Redistributed unmodified under BSD 3-Clause.
2026-06-28 22:23:20 -04:00
James Stringer 3cddb072e7 Windows-on-Mac: JIT-download the signed guest payload instead of bundling it
The macOS host now pulls the signed Windows release zip (EV-signed agent EXEs +
MS-attestation-signed drivers, incl. the ivshmem AppSandboxSHM) and stages those
into the guest, instead of the bundled test-signed tools/agent_win payload.

- iso_patch_mac.m: ensureSignedWinPayloadZipCached mirrors ensureOpenSSHMsiCached
  -- a single atomic writeToFile of the release zip to a version-named file under
  the support dir (sibling of VMs/), race-safe by the same single atomic write.
  Returns the cached zip path; the build extracts it.
- iso-patch-mac.m (build-windows): new --signed-payload-zip. When given, the CLI
  selectively unzips resources/appsandbox-*.exe + drivers/* into its own per-build
  temp and prefers them over --payload (so concurrent creates never collide);
  derives binDir/drvDir/devconPath from it. Falls back to --payload on any problem.
  The signed drivers carry no .cer, so SetupComplete's `if exist` certutil steps
  no-op; devcon comes from the zip's drivers/.
- iso_patch_mac.{h,m}: buildWindowsDiskWithISO threads signedPayloadZip and makes
  --payload conditional (a nil bundle can't crash the args array).
- asb_core_mac.m: start_windows_build_flow caches the zip off-main and passes it;
  bundled payload remains the fallback. NetKVM is still not downloaded.

The bundled test-signed payload stays embedded as a fallback for now; dropping the
Xcode "Embed agent_win" phase (to fully remove test-signed binaries from the app)
is a follow-up once the download URL is durable. Mac target not compiled here.
2026-06-28 21:16:30 -04:00
James Stringer 584f0b7cc5 Windows: unify provisioning (R5) + fix UTF-8 username/password handling
Provisioning unification (R5):
- disk_util.c delegates generate_unattend_vhdx / generate_vhdx_setup_cmd /
  generate_vhdx_setupcomplete to the shared tools/provision/win_provision.c, and
  stages AppSandboxSHM + NetKVM (existence-gated) in generate_vhdx_manifest.
- Compile win_provision.c into AppSandboxCore.vcxproj. Win->Win output is
  equivalent (the SHM/NetKVM install steps are if-exist no-ops on a PC host).

UTF-8 / non-ASCII credentials:
- win_provision.c: encode the unattend <Password> as true UTF-16LE (was a UTF-8
  byte zero-extend that corrupted non-ASCII/CJK passwords); ASCII unchanged. Plus
  case-insensitive locale-tag lookup and ComputerName truncation by UTF-8 code
  points (never splitting a multibyte char).
- webview2_bridge.c json_get_string: decode JSON escapes (\uXXXX, \" \ ...) so
  non-ASCII values from the headless SDK (json.dumps/ensure_ascii) are no longer
  stored as literal \uXXXX text. Validated end-to-end: a CJK password now sets
  correctly and Windows authenticates against it.
- disk_util.c wrapper: check the WideCharToMultiByte conversions.

Also included in the working tree:
- Reconcile user-mode .vcxproj platform toolset v145 -> v143 (VS2022).
- WINDOWS_AGENT_BRIEF.md: correct stale driver-name/symbol/devcon references.
2026-06-28 21:16:30 -04:00
James Stringer 842c194e2c Windows-on-Mac: build-integrate the SHM driver, fix provisioning, harden transport/display
- Rename the ivshmem guest driver asb_ivshmem -> AppSandboxSHM everywhere (files, INF
  service/binary/catalog + display strings, device-interface GUID symbol with the GUID
  value preserved, driver source, transport, provisioning, payload, iso-patch stage list).
  QEMU's ivshmem device id and the Mac host transport (asb_ivshmem_transport.*) keep names.
- Build the driver through the VS pipeline like VDD/VAD: AppSandboxSHM.vcxproj (KMDF) +
  Package/AppSandboxSHMPackage.vcxproj (Inf2Cat + TestSign + post-build copy into
  bin\Release[-ARM64]\drivers), registered in AppSandbox.sln; add to submission-config.json
  + make-release.ps1 for MS attestation. INF gets a .10.0...22000 (Win11) TargetOSVersion
  decoration (required by DIRID 13 / PnpLockdown).
- Install the SHM PCI driver with devcon update (not devcon install, which fabricates a
  phantom ROOT devnode on a real PnP hwid) -- same pattern as NetKVM.
- Fix SetupComplete.cmd: a literal (...) in an echo inside a cmd ( ) block desynced cmd's
  paren matcher and silently skipped every driver install; removed it.
- iso-patch: per-build -shadow ISO attach so concurrent VM builds get independent devices.
- Reconcile all user-mode .vcxproj to the v145 (VS 2026) toolset.
- Transport/display: guest liveness beacon + h2g-stall reclaim, zero-copy Metal render of
  the IDD display, clipboard-file paste chown for the root daemon.
- Refresh the committed tools/agent_win payload; update the windows-on-mac integration plan.
2026-06-22 22:38:34 -04:00
James Stringer 0d4897dd6b Windows guest on Mac host via QEMU+HVF + ivshmem transport
Run Windows 11 ARM64 guests on macOS over QEMU+HVF, with an ivshmem
shared-memory transport carrying every guest channel (agent control,
display/VDD, input, audio, clipboard, SSH, 9P) - no guest networking
required.

- tools/transport: one guest transport API, two backends (PC AF_HYPERV,
  Mac ivshmem); SPSC ring with an acquire-barrier fix for SSH integrity
- tools/ivshmem: our own KMDF ivshmem BAR-mapping driver (no third party)
- src/backend_mac: Mac-host ivshmem transport, QEMU VM lifecycle, IDD
  display consumer, agent/SSH proxies, ISO->disk patcher, Windows create
- tools/agent + channel EXEs + tools/vdd: wired to asb_transport
- tools/agent_win: staged guest payload (interim, pending JIT pull)
- vendor/qemu-ivshmem: vendored QEMU 11.0.1 fork (ivshmem-plain) + LGPL
  source mirror for the self-contained app bundle
- tools/sign/make-release.ps1: use the host-native ARM64 MSBuild so the
  WDK driver ApiValidator runs (the x86 validator fails on ARM64)
2026-06-21 18:30:59 -04:00
James Stringer 4b790037ee Describe Headless API
Updated README to clarify headless mode features and API usage.
2026-06-14 09:58:14 -04:00
James Stringer df0e2532e0 Bump version to 0.1.3
### Added
- **Headless mode with a scriptable HTTP/JSON API (Windows + macOS).** Launch
  App Sandbox with `--headless` to run a single-owner background daemon exposing
  a loopback HTTP/JSON API that mirrors the GUI: create, start, shut down, edit,
  and delete VMs; manage snapshots, branches, and templates (Windows); read SSH
  connection info; subscribe to a live event stream; and open or close a VM's
  display window -- all from a script. Ships a dependency-free Python SDK,
  runnable examples, and a cross-platform test suite (bundled in the release
  package under headless-api/, alongside the app). Launching normally (no
  `--headless`) is unchanged.
- **One-click SSH key login.** With the SSH server enabled, the new "Deploy SSH
  key" option installs an App Sandbox key into the guest (Windows, Linux, and
  macOS) so the GUI's SSH button and the SDK connect without a password.

### Fixed
- **Excessive GPU usage while viewing a Windows VM.** The display window was
  redrawing as fast as it could -- presenting ~2,100 frames a second and holding
  the host GPU near 90% even on a static screen. It now redraws only when the
  picture changes (plus a small safety refresh), dropping to the real frame rate
  (~30-60 fps) with no added latency.
- **A graceful shutdown could report a false error.** On a busy guest, a
  shutdown that actually succeeded could surface as a failure; shutdown and
  restart now report success once the request is delivered and confirm it by the
  guest exiting.
- **The headless daemon now cleans up its VMs when it exits**, instead of
  leaving them running with no owner.
- **macOS: text fields no longer autocorrect or autocapitalize** VM names,
  usernames, paths, and snapshot names as you type.
- Various stability and bug fixes across the Windows, macOS, and Linux
  components.

### Known issues
- **Create VMs one at a time.** Creating several at once can race on the
  disk-image build/staging step, causing a build to fail and the VM to be
  removed; create them sequentially.
- **x64 (emulated) apps in ARM Windows VMs don't get the OpenGL fix** -- the
  Mesa driver shipped on ARM is ARM64-only; native ARM64 apps get full GPU
  OpenGL. (carried over from 0.1.2)
- **ARM Linux (Ubuntu 26.04 LTS) guests do not work -- on ARM, Windows is the
  only working guest** (Ubuntu 26.04's arm64 kernel churns BPF JIT memory and
  never reaches the desktop). (carried over from 0.1.2)
2026-06-11 22:03:47 -04:00
James Stringer a800e5d3fa Ship the headless-api SDK alongside the app in release packages
Both release packagers now place a headless-api/ folder next to the app at the
zip root (AppSandbox.exe / AppSandbox.app + headless-api/), so a user who
installs from a release gets the Python SDK, examples, and tests without cloning
the repo. The folder holds asb.py, README.md, examples/ and tests/ -- no tools/
parent, and __pycache__/*.pyc are excluded.

Windows (make-release.ps1): stage the folder into the explicit allowlist just
before zipping, and add it to the required-artifacts tripwire.

macOS (make-release-mac.sh): publish_package stages the already-stapled .app
plus the SDK and archives the staging dir contents (ditto -c -k without
--keepParent) so both land at the zip root; ditto copies the bundle verbatim,
preserving its signature and notarization staple.

The SDK is added only at the final packaging step, after the binaries and
drivers are signed and (macOS) the app is notarized and stapled.
2026-06-11 21:52:14 -04:00
James Stringer 38b1728f7c Use a sentinel fallback for the macOS headless /version
product_version() reads CFBundleShortVersionString, which is stamped from
Directory.Build.props at build time. Change the fallback used when that key is
absent from a real-looking 0.1.2 to 0.0.0, so a missing or failed stamp reports
an obviously-invalid version instead of silently masquerading as a real one.
2026-06-11 21:23:58 -04:00
James Stringer 37d5e66cd4 Derive the headless API version from Directory.Build.props
The Windows headless daemon reported its /version from a hardcoded
ASB_PRODUCT_VER "0.1.2" in headless.c -- a second place to edit each release
that could silently drift from the real build version.

Pass AsbVersionShort (from Directory.Build.props, the single source of truth)
into the C compile as an unquoted ASB_VERSION_SHORT define in
Directory.Build.targets, and stringize it in headless.c, mirroring how
build\version.rc already derives every binary VERSIONINFO. The /version
response now tracks the build with no per-release edit; a fallback keeps a
standalone (no-MSBuild) compile valid.
2026-06-11 21:07:53 -04:00
James Stringer 09adc89df0 Merge --headless API and tests
Summary
Adds a single-owner headless daemon to AppSandbox on both Windows and macOS (Apple silicon), exposing the same Docker-style loopback HTTP/JSON API the GUI drives — so VMs can be created, run, snapshotted, SSH'd into, and have their display window opened/closed entirely from a script. Ships a dependency-free Python SDK, runnable examples, and a self-contained cross-platform regression suite. A normal GUI launch is unaffected (the daemon only runs with --headless).

What's in it
1. Headless daemon (Windows + macOS)

appsandbox.exe --headless (Windows, http.sys) / AppSandbox.app/Contents/MacOS/AppSandbox --headless (macOS, BSD socket) hosts the core for the process lifetime.
host.json discovery file (endpoint + port + per-run bearer token); serialized command loop (one request to completion before the next); SSE /v1/events stream.
Single-owner model: GUI and headless are mutually exclusive (mutex / per-user flock); the daemon owns its VMs and terminates them on exit (fixed an earlier asb_detach bug that orphaned them).
Fail-fast startup: Windows (admin / Win11 build / VirtualMachinePlatform); macOS (min OS / VZVirtualMachine.isSupported / elevation, resolving SUDO_USER so it uses the invoking user's VM registry + restore-image cache).
2. HTTP/JSON API + Python SDK + examples

Endpoints mirror the GUI: create/start/shutdown/stop/edit/delete, snapshots + branches (incl. base branches), templates, sshInfo, events (SSE), and display. Input validation mirrors the GUI's JS guards.
Capability-gated: snapshots/templates are Windows-only (501 + capabilities flags on macOS), so the wire interface matches across hosts.
asb.py resolves host.json / support dir / key path per platform; examples cover list/start/stop/full-lifecycle/SSE/admin.
3. Display open/close (Windows · Linux · macOS)

POST/DELETE/GET /v1/vms/{name}/display + displayOpen on every status object — opens the same view as the GUI's Connect button.
Readiness is a latched agent flag, never a frame-channel probe. Connecting to the guest frame service is becoming its single consumer, so polling it would steal the slot and blank the display. Instead the guest agent reports driver state over the agent channel (idd_status) and the host latches idd_ready: Windows (VDD device "running" via devcon), Linux (Mutter session up). macOS has no frame channel (the VZVirtualMachineView binds the in-process VM framebuffer directly), so readiness is running && agentOnline.
A-gate: only shows a window in a session that can render one (visible window station / console Aqua session), else 409 no_display. Per-VM daemon-owned table; X-close self-teardown + reap; displayOpen read from the live window state.
Validated live on all three. macOS required swapping CFRunLoopRun() → [NSApp run] (Accessory policy) only in a console GUI session; the design's flagged spike (do VZ main-queue dispatches still fire under [NSApp run]?) was confirmed on hardware.
4. SSH key auto-deploy

sshDeployKey (requires sshEnabled): the core generates an AppSandbox ed25519 keypair once; the guest agent writes the public key into authorized_keys (Windows administrators_authorized_keys + ACL; Linux/macOS ~/.ssh) and reports sshState 4. SDK + GUI then log in password-less. The macOS agent deploys on a worker thread so heartbeats aren't blocked during a slow first-boot user lookup.
5. Graceful shutdown → fire-and-forget

vm_agent_send gains a per-command timeout; shutdown/restart return immediately (delivery confirmed by the HCS SystemExited monitor, not the ack). Fixes a false 500 when a busy guest's ack arrived late, and stops the request loop / UI thread blocking during shutdown.
6. GUI polish + fixes

Disable WebView spellcheck/autocorrect/autocapitalize (macOS was mangling VM names/usernames/paths); grey out the disabled "Deploy SSH key" checkbox. vm_agent re-resolves VMs by stable id (no stale pointers).
Validation
Windows: open the instant readiness latches, close + reopen, graceful shutdown + remove — daemon stable throughout.
Linux: validated on fresh VMs (latched idd_status); sequential creates advised (concurrent VHDX prefetch can race).
macOS: display validated live on Apple silicon.
Cross-platform regression suite (tools/headless-api/tests/) runs per-VM lifecycles concurrently, capability-gating mac vs Windows.
2026-06-11 20:48:37 -04:00
James Stringer 70e9c285cb Build the Linux guest agent and driver from main
The Linux guest builds its agent + asb_drm/dxgkrnl source from the GitHub branch the daemon binary was built from; during development the prefetch was pinned to the feature branch. Point it at main so that once this lands, fresh Linux VMs build the guest agent/driver from merged code.
2026-06-11 20:39:09 -04:00
James Stringer 9b9b92f053 Add the display window to the macOS headless daemon; retire the plan docs
Bring macOS to parity with the Windows display feature: open/close/poll the VM's
display window over the API (POST/DELETE/GET /v1/vms/{name}/display, plus
displayOpen on every status object), so a script can show the same view the GUI's
Connect button does. Validated live on Apple silicon.

The GUI already creates the per-VM VZVirtualMachineView window on the Running
transition (gated off under --headless); the daemon now opens it on an explicit
request after two gates:
  - A-gate: asb_mac_have_gui_session() (CGSessionCopyCurrentDictionary /
    kCGSessionOnConsoleKey) -- a daemon with no console Aqua session (launchd /
    SSH) refuses with 409 no_display instead of spawning an invisible window;
  - readiness: running && agent_online. macOS has no frame channel or display
    driver (the view binds the in-process VM framebuffer directly), so there is
    nothing to probe -- unlike the Windows/Linux idd_status latch.
New core API asb_mac_open_display / asb_mac_close_display (asb_core_mac.m); new
codes BACKEND_ERR_NO_DISPLAY / BACKEND_ERR_NOT_READY (asb_types.h).

run_headless swaps the bare CFRunLoopRun() for [NSApp run] (Accessory policy)
ONLY in a console GUI session -- the window needs the window server; otherwise it
keeps the bare CFRunLoop so the daemon still runs headless over SSH/launchd. Both
loops drain the main dispatch queue, so every VZ op and the SIGINT/SIGTERM sources
are unaffected; cleanup_and_exit exit()s directly, so no quit-path change. The
spike the design flagged as unverifiable without a Mac was confirmed here: VZ
main-queue dispatches still fire under [NSApp run], and windows open, take focus,
and deliver windowWillClose:.

Close tracking avoids a mid-close use-after-free: VzDisplayWindow gains a
userClosed flag set in windowWillClose:; displayOpen reads display && !userClosed,
and open_display reaps a self-(X)-closed window on the next request (off the WM
close stack), mirroring the Windows reap. showDisplay also calls
activateIgnoringOtherApps: so the Accessory daemon's window comes to the front.

tests: vm_lifecycle.py now runs the display open/close check on macOS too (it
self-skips on 409 no_display or a Linux guest whose agent predates idd_status).
README documents the macOS display support (matrix row, the console-session
A-gate, and the running && agentOnline readiness).

Remove tools/headless-api/PLAN.md and display-plan.md: these were the design /
decision logs for the headless port and the display feature, both now shipped and
validated. Their dangling references in README.md and headless.m comments are
cleaned up in the same change.
2026-06-11 20:27:52 -04:00
James Stringer 7ed54b1fc4 Document edit() and snap_take() stopped-only preconditions in the SDK
edit() honors ramMb/cpuCores/gpuMode/networkMode on a stopped VM (name is fixed at create, other keys ignored; 409 if running); snap_take() requires the VM stopped (409 vm_running).
2026-06-11 20:08:47 -04:00
James Stringer 82c5bd7507 Mark Linux display validated in the plan; advise sequential VM creates
display-plan.md: the Linux display half is now implemented and validated (confirmed on fresh Linux VMs built from the pushed branch, where the agent's idd_status latches readiness and the display opens).

README.md: note that VMs should be created sequentially -- concurrent creates can race on the VHDX-build prefetch/staging and a build may fail (iso-patch.exe exit 1) and be removed.
2026-06-11 18:59:16 -04:00
James Stringer 889ccbc3a1 Implement headless display open/close with agent-reported readiness
Add POST/DELETE/GET /vms/{name}/display plus the open_display/close_display/display_status/display_ready SDK methods, so a script can open and close a VM's display window like the GUI's Connect button.

Readiness is a latched flag, not a frame-channel probe: connecting to the guest frame service is itself becoming the display's single consumer, so polling it would steal the slot and blank the display. The guest agent reports the display driver state over the agent channel (idd_status) and the host latches it as idd_ready; asb_vm_idd_ready = running && agent_online && idd_ready. The Linux agent reports idd_status:ok once the user session is up (Mutter compositing).

The display window is daemon-owned (per-VM table keyed by unique_id), gated on a visible window station, and self-tears-down on the X button; displayOpen is read from the live window state, so it is honest however the window closed.
2026-06-11 18:14:13 -04:00
James Stringer b95913dc1c Add headless display-open design plan
tools/headless-api/display-plan.md: design for opening/closing a VM display window
through the headless API (POST/DELETE /v1/vms/{name}/display). Windows is implementable
(vm_display_idd_create is self-contained); macOS is design-only and unvalidated (it
swaps the daemon run loop to AppKit and needs a Mac to verify). Access model: bearer
token for auth + a runtime "can this session render a window" gate; no loopback/peer
detection.
2026-06-10 22:30:34 -04:00
James Stringer 4d03b89b3e Make agent-mediated graceful shutdown fire-and-forget
vm_agent_send gains a per-command timeout; shutdown/restart pass 0 (fire-and-forget):
queue the command for the connection thread and return immediately instead of waiting
for the agent's "ok". The guest agent replies then powers itself off, so on a busy
guest (mid-setup) the ack can arrive after any fixed wait -- which previously turned a
slow ack into a false failure (hcs_stop_vm -> 0x80070032 -> HTTP 500) even though the
shutdown was delivered and the guest exited gracefully. Delivery is now confirmed by
the HCS SystemExited monitor, not the ack.

This also stops the single-threaded http.sys request loop (and the GUI UI thread) from
blocking during a shutdown -- asb_vm_shutdown returns promptly for every caller.
ping/idd_connect keep their bounded waits.

Verified: the create-from-template graceful shutdown that returned 500 now returns 202;
the full parallel regression is green apart from a pre-existing first-Windows-shutdown
flake under concurrent load (unrelated to this change).
2026-06-10 22:30:34 -04:00
James Stringer 929ad69f89 Make the headless SDK and test suite cross-platform; update docs
asb.py: resolve the support directory, daemon launch hint, and SSH key path per
platform (%ProgramData%\AppSandbox on Windows, ~/Library/Application Support/
AppSandbox on macOS) so the same SDK drives either daemon from its host.json.

tests: the suite is now capability-gated and runs on either host. helpers.py
adds IS_MAC, the per-platform VM/disk paths, the macOS IPSW location, a key-auth
login helper (chmod on mac), and wait_progress -- a stall-based wait that watches
the VM's reported progress/status instead of a fixed deadline, so a slow install
or IPSW download doesn't false-fail. run_all.py launches the macOS suite as two
concurrent VMs (one downloading a fresh IPSW, one from cache) sized 4096 MB / 2
cores / 64 GB, with a leftover sweep and IPSW housekeeping. The lifecycle and
host/validation tests assert 501 for snapshots/templates on macOS and run the
Windows-only template build only where supported.

docs: README gains a platform-support matrix (which guest OSes and host features
each platform supports) and the macOS sudo/SUDO_USER launch model alongside the
Windows instructions. PLAN.md records the macOS port, the Windows
cleanup-on-exit fix, the guest-agent threading fix, and the startup fail-fast /
GUI polish.
2026-06-10 19:00:04 -04:00
James Stringer 3b14889dd8 Disable spellcheck/autocorrect and grey out disabled checkboxes in the GUI
On macOS the WebView was autocorrecting and autocapitalising VM names,
usernames, paths, and snapshot names as they were typed. There is no clean
public WKWebView toggle, so disable it in the markup: spellcheck="false" on
<body> (inherits to all descendants) plus the WebKit autocorrect="off" /
autocapitalize="off" extensions on the body and the free-text inputs (vm-name,
image-path, admin-user, modal-input). These attributes are inert on Windows, so
the shared web assets behave the same there.

style.css greys a disabled checkbox and its label (opacity, default cursor, via
:has()) so the "Deploy SSH key" option reads as unavailable until "SSH Server"
is enabled.
2026-06-10 19:00:04 -04:00
James Stringer f8d5c3bb06 Clean up VMs when the Windows daemon exits; harden SSH key deploy
The Windows daemon called asb_detach() on exit, which left its VMs running with
no owner -- an architecture bug, since the daemon is meant to own the VMs it
starts. Switch the exit (and the failure paths) to asb_cleanup() so the daemon
terminates its VMs when it goes away, matching the intended single-owner model.
A second instance now fails cleanly via cli_fail.

asb_core.c: a create-from-template now copies ssh_deploy_key/ssh_pubkey onto the
instance so a templated VM still deploys the key; ssh_key_deployed is reset on
stop/exit; ensure_appsandbox_ssh_key checks ssh-keygen's exit code and deletes a
partial key; load_vm_list uses a truncating copy. vm_agent.c re-resolves the VM
by stable id each iteration so it never stashes a stale pointer.
2026-06-10 19:00:04 -04:00
James Stringer 73e8a253ed Deploy the SSH key off the accept loop in the macOS guest agent
The macOS guest agent ran ssh_deploy_key inline on its single command socket.
On a cold first boot the find_primary_user lookup (getpwent/OpenDirectory) can
take several seconds, during which the agent could not service heartbeats or
replies and the host would tear the connection down -- the key deploy reported
as failed even though it eventually succeeded.

Run the deploy on a detached worker thread (spawn_deploy_key) so the accept loop
keeps responding. send_line takes a mutex so a worker's reply can't interleave
its bytes with the loop's writes on the shared socket, and a connection
generation counter (g_conn_gen, bumped on every connection start/end) lets a
worker tell its connection is gone -- and the fd possibly reused by a new client
-- and suppress a stale write via send_line_gen. deploy_ssh_key now returns
failure (reports ssh_key_failed) when the chown of authorized_keys fails instead
of falsely reporting success.
2026-06-10 18:34:41 -04:00
James Stringer 910fd5db2b Add macOS headless daemon and wire up the core for it
Port the --headless daemon to macOS so the same loopback HTTP/JSON API the
Windows build exposes is available on Apple silicon, driving macOS guests via
Virtualization.framework. AppSandbox.app/Contents/MacOS/AppSandbox --headless
starts a single-owner daemon (CFRunLoop, no NSApplication/window server) that
hosts AppSandboxCore for the process lifetime; a normal GUI launch passes no
args and is unaffected.

src/app_mac/headless.m/.h: BSD-socket loopback listener, bearer-token auth, a
host.json discovery file, an SSE event stream, and the serialized command loop
(one request runs to completion before the next). Validation mirrors the GUI;
snapshots/templates return 501 (capabilities.snapshots/templates = false) so the
HTTP interface matches Windows while gating the unsupported features. Startup
fail-fast checks the minimum macOS version (LSMinimumSystemVersion) and
VZVirtualMachine.isSupported, requires elevation, and -- because creation stages
the guest disk as root -- resolves SUDO_USER so it reads the invoking user's VM
registry and restore-image cache and hands created files back to that user. The
daemon owns its VMs: exit cleans them up rather than leaving them running.

main.m routes --headless to run_headless and otherwise takes the same per-user
flock the daemon uses, so GUI and headless are mutually exclusive. The backend
gains a g_headless flag (asb_mac_set_headless): the display window, clipboard,
and audio (vz_vm_set_no_audio -- host-mic capture would block on a TCC prompt no
daemon can show) are gated off headless. vm_dir.m resolves the VM root from
SUDO_USER under sudo; iso_patch_mac.m skips the AuthorizationExecuteWithPrivileges
prompt when already root. asb_core_mac auto-starts a VM once install completes
(polling until the disk image is no longer attached, to avoid the create/boot
race) so macOS matches the Windows auto-start behaviour. ui.m reports
sshDeployKey/sshKeyDeployed and the GUI SSH terminal logs in with the deployed
key. Adds Virtualization.framework to the app target link and headless.m to its
sources.
2026-06-10 18:34:31 -04:00
James Stringer 4087baa4bf Add headless --headless daemon, HTTP/JSON API + Python SDK, and SSH key deploy
Headless mode: `appsandbox.exe --headless` runs a single-owner daemon that hosts
the core over a loopback HTTP/JSON API (http.sys) with a host.json discovery
file. A dependency-free Python SDK, examples, and a self-contained regression
suite live under tools/headless-api/ (PLAN.md = design rationale).

The API mirrors the GUI: create/start/shutdown/stop/delete/edit, snapshots and
branches (incl. base branches via the new asb_snap_base_branch_count), templates,
sshInfo, an SSE /v1/events stream, GUI-mirrored input validation, a startup
fail-fast (admin / Win11 build / VirtualMachinePlatform), and a single-instance
mutex shared with the GUI so only one of GUI/headless runs at a time.

SSH key deploy: sshDeployKey (requires sshEnabled) has the core generate an
AppSandbox ed25519 keypair once and the guest agent write the public key into
authorized_keys -- Windows administrators_authorized_keys (+ ACL), Linux/macOS
~/.ssh -- reporting a new ssh_key_deployed status (sshState 4). The GUI SSH
button and the SDK use the key for password-less login. Verified end-to-end on
Windows.

The Linux guest builds its agent/driver source from this branch's GitHub repo;
asb_core.c points the prefetch at "headless-api" (revert to "main" before merge,
see PLAN.md).
2026-06-09 20:12:18 -04:00
James Stringer ed9286f937 Fix for excessive GPU usage when viewing a VM in Windows
Fix runaway WM_PAINT loop pegging the GPU on the IDD display window
2026-06-08 21:15:13 -04:00
James Stringer ddeda50501 Fix runaway WM_PAINT loop pegging the GPU on the IDD display window
The IDD render child window (AppSandboxIddRender) forwarded WM_PAINT to its
parent along with the input messages. The parent's WM_PAINT handler calls
BeginPaint/EndPaint on the parent, never on the child, so the child's update
region was never validated. Windows therefore re-issued WM_PAINT to the child
on every message-pump idle, driving d3d_render_frame -> Present ~2,100 times a
second and pegging the host GPU 3D engine at ~90% for a trivial full-screen
textured quad (~0.36 ms of GPU work per present; the defect is the present
count, not the per-present cost).

Give the render child its own WM_PAINT case that validates its update region
with BeginPaint/EndPaint and requests a single repaint via WM_IDD_FRAME_READY,
so expose/resize still repaints. Rendering is otherwise push-driven by received
frames plus a dirty-gated 16 ms backstop timer, so no continuous stream is
needed. Present rate drops to the real frame rate (~30-60/s) and the GPU falls
off the ceiling. SyncInterval stays 0, so latency is unchanged (no swap-chain,
flip-model, or vsync changes).

Re-gate the window-title recv= counter in d3d_render_frame on a per-uploaded-
frame flag instead of render_count % 60. With renders no longer running at
~2,100/s, "every 60 renders" updated the title only every 1-2 seconds; gating
on actual uploaded frames keeps it ticking at ~frame rate.
2026-06-08 21:09:21 -04:00
James Stringer 78dbcb0626 Update gpu-test.exe link 2026-06-07 19:05:01 -04:00
James Stringer 5674a4c66d Bump version to 0.1.2
### Added
- **Windows on ARM (ARM64).** App Sandbox now runs on ARM64 Windows PCs and can
  create **ARM Windows 11 VMs with GPU-PV** — paravirtualized GPU acceleration in
  the guest.

### Fixed
- **Hardware OpenGL in Windows VMs.** OpenGL apps in the guest were stuck on
  Windows' GDI Generic software renderer (OpenGL 1.1) — apps needing OpenGL 4.3+
  (e.g. Blender) refused to start. The old approach selected Microsoft's OpenGLOn12
  driver via an AppInit DLL, but Windows disables AppInit DLLs when Secure Boot is
  on — and App Sandbox runs guests with Secure Boot on by default — so it never
  engaged (and even when it did, Windows' opengl32 dropped the GPU driver across the
  virtual GPU's render/display split). App Sandbox now installs the Mesa OpenGL
  driver directly into the guest, taking Windows' broken opengl32 out of the path,
  so apps get real GPU-accelerated OpenGL 4.6 (or software 4.6 with no GPU) — with
  Secure Boot left on.
- **New VMs could fail to start with an odd memory size.** HCS (Windows' Host
  Compute Service) requires VM memory to be a multiple of 2 MB; the suggested
  default (half the host RAM) or a manually entered value could be odd (e.g. 7991 MB)
  and fail to start. RAM is now rounded to an even value in the suggested default,
  the create form, and inline edits.
- **New Sandbox dialog no longer closes by accident.** Selecting text in a field
  and releasing the mouse outside the dialog no longer dismisses it.
- Various stability and bug fixes across the Windows, macOS, and Linux components.

### Known issues
- **x64 (emulated) apps in ARM Windows VMs don't get the OpenGL fix.** The Mesa
  driver shipped on ARM is ARM64-only, so emulated x64 apps fall back to the old
  renderer; native ARM64 apps get full GPU OpenGL.
- **ARM Linux (Ubuntu 26.04 LTS) guests do not work in this release — on ARM,
  Windows is the only guest that works.** Ubuntu 26.04's arm64 kernel constantly
  churns BPF JIT memory, which makes the kernel boot extremely slowly and never
  reach the Ubuntu desktop. On a Qualcomm Snapdragon X1-Plus (ASUS A14) using 25H2,
  the guest never came up and the App Sandbox agent never came online.
2026-06-07 15:25:42 -04:00
James Stringer 266971b311 Fix create-modal RAM 2 MB alignment and backdrop-close
RAM (MB) must be 2 MB-aligned for Hyper-V/HCS, but the smart default (half of a 15982 MB host = 7991) and odd user-entered values were passed through unaligned and failed to boot. Round odd RAM down to even in the default, the create form (gatherConfig + a live field snap), and inline row edits; add step=2 on the field.

Also stop the New Sandbox modal from closing when a press starts inside it (e.g. selecting text in a field) and releases on the backdrop -- only close when the press also started on the backdrop.
2026-06-07 15:17:34 -04:00
James Stringer b1e58a74af Fix create-modal RAM 2 MB alignment and backdrop-close
RAM (MB) must be 2 MB-aligned for Hyper-V/HCS, but the smart default (half of a 15982 MB host = 7991) and odd user-entered values were passed through unaligned and failed to boot. Round odd RAM down to even in the default, the create form (gatherConfig + a live field snap), and inline row edits; add step=2 on the field.

Also stop the New Sandbox modal from closing when a press starts inside it (e.g. selecting text in a field) and releases on the backdrop -- only close when the press also started on the backdrop.
2026-06-07 15:16:25 -04:00
James Stringer 4e08453b4a Fix hardware OpenGL in Windows guests (Mesa standalone opengl32)
Why this is needed
AppSandbox Windows GPU-PV guests had no working hardware OpenGL. The previous
approach — Microsoft's OpenGLOn12 ICD selected via the appsandbox_gl_shim.dll
AppInit_DLLs shim — cannot work in the shipping configuration:

AppInit_DLLs is disabled when Secure Boot is on (Microsoft-documented,
Windows 8+), and release VMs run with Secure Boot on. So the shim never
loads, the UMOPENGLINFO ICD rewrite never happens, and OpenGL silently falls
back to GDI Generic 1.1 — on x64 as well as ARM64. (Any "it worked on
x64" was a test_mode/Secure-Boot-off build.)
Even when the shim does load, Microsoft's opengl32 refuses to bring up a
hardware ICD across the GPU-PV render-only / display-only adapter split: it
loads OpenGLOn12, validates it, hands it the callbacks, then abandons it
before enumerating pixel formats — so apps still land on GDI Generic. (Proven
with an interposing ICD that logs every Drv* call; it fails on both the IddCx
desktop and the Hyper-V Video display, so it is the render/display split, not an
"indirect display" quirk.)
Vulkan (Dozen) and OpenCL (OpenCLOn12) were unaffected because they are
registered as registry ICDs — no AppInit, no opengl32 gate.
Net effect: OpenGL was broken for guest apps (e.g. Blender refused to start:
"A driver with support for OpenGL 4.3 or higher is required.").

The fix
Ship Mesa's standalone opengl32.dll (gallium d3d12 driver + WGL
frontend) system-wide into the guest's System32, so Microsoft's broken
opengl32 is out of the path entirely. Mesa's WGL frontend creates its own
D3D12 device (first DXGI adapter = the projected render GPU, or WARP if none) and
presents via a windowed flip-model swapchain that DWM composites
cross-adapter — the same bridge Vulkan/D3D12 already use.

Result:

Hardware OpenGL 4.6 via D3D12 when a GPU is present (GL_RENDERER: D3D12 (<gpu>), GL_VERSION: 4.6).
WARP software GL 4.6 with no GPU — far better than the old GDI-Generic 1.1
fallback, and it means replacing the system opengl32 never makes an app worse.
Works with Secure Boot ON — plain DLL loading, not AppInit_DLLs.
Not a performance regression: OpenGLOn12 is the same Mesa gallium d3d12
driver. This is the identical renderer with a working entry path (a full
gl*/wgl* DLL instead of the Drv* ICD Microsoft's opengl32 won't drive).
What this PR does
tools/win-mesa-gl/ — vendors the prebuilt Mesa trio (opengl32.dll +
gallium_wgl.dll + z-1.dll) for x64 and arm64 (Mesa 26.1.2, static CRT,
EV-signed), plus build-mesa.cmd, aarch64-cross.txt, sign-mesa.ps1, and
a README. Mirrors tools/linux/wsl-mesa/ (same upstream Mesa; only the build
target/options differ).
AppSandbox.vcxproj — stages the build's-arch trio into
resources\win-mesa-gl\ per-config (alongside the existing WebView2Loader copy).
src/backend_win/asb_core.c — prepare_gl_layers_share() stages the trio
into the AppSandbox.GlLayers Plan 9 share.
tools/agent/agent.c — gl_provision() deploys the trio into the guest's
System32 (take ownership, rename the in-use opengl32 aside, copy ours in;
re-applied every boot so it self-heals if servicing/SFC restores Microsoft's),
and keeps the dxil.dll staging + Khronos OpenCL/Vulkan ICD registrations.
Removes the appsandbox_gl_shim project (AppSandbox.sln, tools/gl-shim/).
.gitignore un-ignores the vendored binaries; SIGNING.md notes the trio is
pre-signed (the build skips re-signing already-EV-signed files).
OpenCL, Vulkan, and dxil.dll are unchanged.

Verification
Builds clean on Release|x64 and Release|ARM64.
In-guest: GL_RENDERER: D3D12 (<gpu>), GL_VERSION: 4.6 (hardware), or
D3D12 (Microsoft Basic Render Driver) 4.6 (WARP, no GPU) — including on a
Secure-Boot-ON VM, which the old shim could never satisfy.
Known limitation
On ARM64 the deployed opengl32 is pure-ARM64, so x64 apps emulated on ARM64
(which load opengl32 from System32 via ARM64X) are not served — that would
need an ARM64X Mesa build (future work). Native ARM64 apps and all x64-on-x64
apps are covered.
2026-06-07 14:01:35 -04:00
James Stringer 1060c2ac5b Add Mesa standalone opengl32 for Windows guest OpenGL
Deploy Mesa's standalone opengl32 trio (opengl32.dll + gallium_wgl.dll + z-1.dll,
the gallium d3d12 driver + WGL frontend) system-wide into Windows GPU-PV guests,
so apps get hardware OpenGL 4.6 via D3D12 (WARP software 4.6 when there is no GPU).
OpenCL (OpenCLOn12), Vulkan (Dozen) and dxil.dll are unchanged.

- tools/win-mesa-gl: vendored prebuilt trio for x64 + arm64 (Mesa 26.1.2,
  EV-signed) plus build-mesa.cmd, aarch64-cross.txt, sign-mesa.ps1, and README.
- AppSandbox.vcxproj: stage the build's-arch trio into resources\win-mesa-gl
  per-config, alongside the WebView2Loader copy.
- asb_core.c: prepare_gl_layers_share stages the trio into the AppSandbox.GlLayers
  Plan 9 share.
- agent.c: gl_provision deploys the trio into the guest's System32 (take ownership,
  rename the in-use opengl32 aside, copy in; re-applied every boot to self-heal),
  and keeps the dxil.dll staging + Khronos OpenCL/Vulkan ICD registrations.
- Remove the appsandbox_gl_shim project (AppSandbox.sln, tools/gl-shim).
- .gitignore: un-ignore the vendored prebuilt Mesa binaries.
- SIGNING.md: drop the shim; the Mesa trio is pre-signed via sign-mesa.ps1.
2026-06-06 22:06:33 -04:00
James Stringer d7b34f629e Fix gpu-test.zip link
Updated the link for gpu-test.zip in the README.
2026-06-06 18:57:50 -04:00
James Stringer e116f42109 Initial support for Windows ARM
What works:
-Windows 11 ARM64 iso boots up OK, with TPM/Guest Isolation disabled (no vTPM on ARM HCS?) 
-GPU-PV for Windows VMs excluding OpenGL

What doesn't
- Ubuntu 26.04LTS has massive issues booting / can't boot, the kernel runs at an absolute crawl, more cores makes it worse, I think the issue is with kernel or hypervisor, under same settings x64 Ubuntu 26.04LTS boots great on an x64 host.
- Discovered an issue with OpenGL that means I need to refactor my opengl_shim setup, as it's totally wrong... but doesn't block merging of ARM support, need to merge ARM and then move to fixing OpenGL.  Issue also applies to x64.
2026-06-06 16:21:24 -04:00
James Stringer 302a6eb60e Fix formatting and add whitespace in README.md 2026-06-06 11:40:46 -04:00
James Stringer c036bdcdc9 Add GPU-PV driver setup verification instructions
Added instructions for checking GPU-PV driver setup using gpu-test.exe.
2026-06-06 11:39:58 -04:00
James Stringer e5acdaaf8b Add ARM64 support for the Linux guest (iso-patch)
iso-patch builds an arm64 Ubuntu VHDX: the grub/shim/EFI, apt, dxcore and
mesa paths are selected from the build arch at compile time via the new
target_arch.h, and the arm64 serial console is ttyAMA0 (PL011) not ttyS0.
x64 behavior is unchanged. (Windows-on-ARM support landed in the previous
commit.)

Known issue: an arm64 Ubuntu 26.04 LTS guest boots very slowly on this
platform and is not usable in practice yet — Windows is the supported
arm64 guest for now. The 26.04 generic kernel is built
CONFIG_BPF_JIT_ALWAYS_ON (+RODATA_FULL), so systemd's constant BPF churn
JIT-allocs and frees executable memory, and each free issues a broadcast
cross-CPU TLB/cache-maintenance op (TLBI ..IS). arm64 has no Hyper-V
paravirt TLB flush, so the hypervisor traps every one and the cost scales
with vCPU count; the host's experimental Insider Hyper-V services them
slowly. Fewer vCPUs or a stable Hyper-V build mitigate it.

Also trim the previous commit's ARM code comments down to the essential
architectural differences.
2026-06-05 18:42:50 -04:00
James Stringer ffeab19f0a Better readme
Updated README.md to include additional details about App Sandbox, its functionality, and usage tips.
2026-06-05 18:02:50 -04:00
James Stringer 717c5b5148 Add ARM64 (Windows on ARM) support
Build, EV-sign, Microsoft attestation-sign, and package AppSandbox for
Windows on ARM with feature parity to x64 except the vTPM and guest-state
isolation (neither is supported by ARM Windows HCS). Target architecture is
resolved at compile time (ASB_IS_ARM64 in disk_util.h); the supported pairing
is x64 build/host/guest and ARM64 build/host/guest, so one flag drives every
architecture decision. x64 behavior is unchanged throughout.

Runtime:
- hcs_vm.c: omit SecuritySettings (vTPM + GuestStateOnly isolation) on ARM;
  Secure Boot is retained.
- disk_util.c: emit the arch token in every autounattend/unattend
  processorArchitecture attribute; on ARM, bypass the Win11 Setup hardware
  checks via the HKLM\SYSTEM\Setup\LabConfig keys across all VM-creation
  paths; select the arch-correct OpenSSH Server MSI.
- d3dlayers.c / agent.c: resolve, download, and stage the arm64 D3D mapping
  layers for GPU-PV; stage the Vulkan ICD manifest under the arch-neutral
  name dzn_icd.json.

Build and release pipeline:
- AppSandbox.sln: add the missing AppSandboxPackage Release|ARM64 Build.0 so
  the VS GUI actually runs sign+package for the ARM64 config.
- AppSandboxPackage.vcxproj: run make-release.ps1 for Release on x64 or ARM64,
  passing -Platform $(Platform).
- make-release.ps1 / sign-drivers.ps1: -Platform ARM64 selects bin\Release-ARM64,
  the ARM64 attestation profile, and the AppSandbox-<ver>-win-arm64.zip name.
  Sanitize LIB before Add-Type so the .NET Framework C# compiler does not fail
  (CS1668) on the non-existent atlmfc\lib\ARM64 path the VS ARM64 build adds to
  LIB.
- Directory.Build.props: disable ApiValidator only when cross-building ARM64 on
  a non-ARM64 host (the x86 ApiExtractor cannot read ARM64 PEs); Microsoft
  re-runs full API validation on every attestation submission.
- Package.vcxproj: stage the vendored ARM64 devcon.exe into the ARM64 drivers
  output, mirroring the x64 devcon copy.
- vendor/devcon/arm64/devcon.exe: add the vendored ARM64 devcon.exe, un-ignored
  in .gitignore mirroring the existing vendor/webview2/arm64 precedent.
2026-06-04 19:00:27 -04:00
James Stringer 3f4294dab1 Pumping up the readme commit numbers :( 2026-06-03 22:44:25 -04:00
James Stringer e627b3b1e9 Update readme (again) 2026-06-03 22:34:41 -04:00
James Stringer 9f8a93a540 Update readme 2026-06-03 22:33:03 -04:00
James Stringer 4a4e7abb78 Add license info
Add MIT LICENSE and third-party license notices
2026-06-03 21:50:53 -04:00
James Stringer 9f1772ce60 Add MIT LICENSE and third-party license notices
- LICENSE: MIT, Copyright (c) 2026 James Stringer.
- THIRD-PARTY-NOTICES.md: scopes the MIT grant around bundled third-party
  components, documenting each one's license/copyright:
    dxgkrnl (Microsoft WSL2 GPU driver) GPL-2.0; iso-patch/engine/xz 0BSD;
    wsl-mesa prebuilt (Mesa 25.3.6) MIT; WDF SDK, WebView2 SDK, DevCon (Microsoft).
- tools/linux/dxgkrnl/COPYING: verbatim GPL-2.0 text shipped with the GPL'd
  driver source.
- tools/linux/wsl-mesa/prebuilt/MESA-LICENSE.txt: Mesa's headline MIT license,
  shipped next to the prebuilt binary.
- README: license section points to LICENSE + THIRD-PARTY-NOTICES.
- Info.plist: copyright string now names the holder and notes MIT.

The asb_drm Linux kernel module keeps its existing dual (GPL-2.0 OR MIT)
licensing; vendored sources keep their own SPDX headers.
2026-06-03 21:47:02 -04:00
James Stringer 97e9278e1b Repo wide bug scan 2026-06-03 21:04:38 -04:00
James Stringer ca07335749 Remove bug-review changelog (bug_list.md)
The bug-bash review pass is complete; drop the working changelog.
2026-06-03 20:58:30 -04:00
James Stringer 503db33307 Harden iso-patch-mac (ARC over-release, resume-sidecar overflow)
- C8  StageEntry stored ARC __strong NSString members in an NSValue (raw byte
      copy, no retain), so ARC over-released them each loop iteration ->
      double-free/UAF in the privileged stage path; mark __unsafe_unretained
      (the source strings outlive the command via the outer autorelease pool).
- L10 resumeDataFromSidecarAt: `raw.length < 8 + n` overflowed for n near
      UINT64_MAX, bypassing the guard and throwing NSRangeException; compare
      with subtraction (`n > raw.length - 8`).
2026-06-03 20:58:30 -04:00
James Stringer c617d0f374 Fix macOS guest agent bugs (clipboard parsing, symlink paste, child reaping)
- C3  appsandbox-clipboard.m: inbound `format_len` was unbounded, so a
      32-bit `format_len + 1` could wrap to malloc(0) then read/write ~4GB;
      bound it against CLIP_MAX_PAYLOAD and allocate in size_t. Both sites.
- M13 appsandbox-agent.m: mute/unmute (and shutdown) fork+exec children were
      never reaped, accumulating zombies; ignore SIGCHLD so Darwin auto-reaps.
- M19 appsandbox-clipboard.m (guest half): handle the new symlink entry type
      -- recreate links with symlink() instead of treating them as dirs.
2026-06-03 20:58:30 -04:00
James Stringer 31385be53e Fix macOS host backend bugs (clipboard, SSH proxy, agent, install, menu)
- H3  vm_clipboard_mac.m: FORMAT_LIST_V2 `ulen + 8 + 4` 32-bit overflow
      bypassed the bounds check (guest->host ~4GB OOB read); cast to size_t.
- H18/H19/H20 vm_ssh_proxy_mac.m: relay teardown detached-not-joined (UAF),
      double-closed fds, double-detached. Redesigned: relay is the sole fd
      closer (under the owner lock), -stop signals+shutdowns+joins, threads
      stay joinable and are reaped on stop / slot reuse.
- M4  vm_{agent,clipboard,ssh_proxy}_mac.m: vsock fd leaked when the VZ
      connect completion fired after the wait timed out; claim ownership via
      a flag + lock and close the late dup (corrected the timeout test to !=0).
- M1/M2 asb_core_mac.m: roll back the phantom VM when its dir can't be
      created; wipe the admin password on the agent-resources-missing path.
- M3  iso_patch_mac.m: auth keep-alive timer could use g_auth after
      releaseAuthorization freed it; free from a dispatch cancel handler.
- M5  AppDelegate.m: app has no nib, so [NSApp mainMenu] was nil and the
      View -> Event Log / Cmd+L item never installed; build a main menu.
- M19 vm_clipboard_mac.m (host half): preserve symlinks in clipboard file
      copy (new wire entry type) instead of following them -- a symlink to a
      directory made open() succeed but read() return EISDIR, aborting the
      tree mid-stream and hanging the guest. Found via live VM testing.
2026-06-03 20:58:30 -04:00
James Stringer 76332f7fde Update bug-review changelog: Linux fixes + L18 + PNG limitation
Mark the Linux guest-agent fixes (C10/L11/L12/L13) and L18 as applied,
validated and committed; add the L18 folder-flatten finding; and record
the confirmed pre-existing limitation that guest->host clipboard images
only support image/bmp (screenshots are image/png; no decoder).
2026-06-02 23:30:55 -04:00
James Stringer a2a3c0920a Fix Linux guest agent clipboard/display/audio bugs
- C10 appsandbox-clipboard.c: the host->guest INCR accumulator doubled
  accum_cap *before* realloc, so on realloc failure it memcpy'd into the
  un-enlarged buffer (heap overflow). Grow into a temp, commit the cap
  only on a successful realloc, and append only when the buffer has room.
- L11 appsandbox-clipboard.c: reject FORMAT_LIST frames with data_size<4
  before reading the 4-byte count (OOB read; Linux analog of H4/C9).
- L18 appsandbox-clipboard.c: host->guest folder paste flattened — the
  text/uri-list builder listed every nested file and no directory, so the
  file manager pasted the files flat with no folder. List top-level items
  only (a top-level dir contributes its own URI; nested entries none),
  guarded on the dir actually existing.
- L12 appsandbox-display.c: use-after-free reading p->plane_id after
  drmModeFreePlane(p) in cursor_init; log the cached cur->plane_id.
- L13 appsandbox-audio.c: idle silence paced at 10ms < the ~21.3ms packet
  duration, overrunning the host render ring; pace at the true packet
  duration (FRAMES_PER_PACKET * 1000000000 / SAMPLE_RATE).

Built in-VM and validated on a live Ubuntu VM (folder/sub-item paste;
audio/display/clipboard daemons healthy after redeploy).
2026-06-02 23:30:55 -04:00
James Stringer 6d6bda5a36 Add bug-review changelog (bug_list.md)
Records the line-by-line review: each finding with severity/type tags
(implementation-failure vs broken-functionality), which fixes were
applied vs reverted (H24) vs deferred to macOS/Linux hosts, the
not-a-bug exclusions, and the runtime findings surfaced by App Verifier /
full page heap (H21 clipboard socket double-close, H22 DROPFILES heap
overflow, H23 snapshot column no-refresh).
2026-06-02 21:51:53 -04:00
James Stringer e25fedb943 Fix VAD audio driver validation and refcount bugs
- M15 wavminiport.cpp: reject PinId >= WaveDescriptor->PinCount in the
  proposed-format property handler.
- M16 wavstream.cpp: guard divide-by-zero on m_ulDmaMovementRate and
  nAvgBytesPerSec in buffer allocation and presentation-position.
- L14 topology.cpp: set PropertyRequest->ValueSize in both jack
  description GET paths.
- L15 adaptercommon.cpp: balance the adapter instance count on the
  allocation-failure path.
2026-06-02 21:51:42 -04:00
James Stringer 8cda2fe452 Harden iso-patch image parsing and build/cleanup paths
- C1/C2/H7/H8/H9 engine/squashfs.c: validate block_size (non-zero, power
  of two, == 1<<block_log, <= 1 MiB); bound walk_directory to the dir
  stream; bound the inode block_sizes[] list and each per-block write to
  the output buffer.
- C6/H6 engine/ext4.c: cap inodes_per_group at BLOCK_SIZE*8 and size the
  inode table by whole blocks so the bitmap/table buffers can't overrun.
- C7 + M8-sibling iso-patch.c: bound qcow2 l1_size (reject under/oversize,
  avoid 32-bit length overflow) and propagate IStream::Read failures.
- H10/H11 prefetch_build_deps.c: reject an over-long Filename and clamp
  WriteFile lengths derived from snprintf return values.
- L17 prefetch_wsl_deps.c: route download/extract/copy failures through a
  cleanup label that removes the unique temp directory.
- M10/M11 ubuntu_vhdx.c: abort (don't finalize a partial VHDX) when the
  squashfs walk reports errors; stop and join workers if a thread fails
  to start so they can't touch the freed stack-local pipeline.
2026-06-02 21:51:32 -04:00
James Stringer b5919dd155 Fix overflow, conversion, and handle-race bugs in the guest agent
- M14 agent.c: serialize the clipboard helper/reader process globals with
  a critical section; the SCM control-handler and monitor threads could
  otherwise close the same process HANDLE twice.
- L9 agent.c: zero-init and check MultiByteToWideChar for the GPU-copy
  destination path before use.
- C9 appsandbox-clipboard.c: reject a FORMAT_LIST name_len that runs past
  the received buffer.
- M12 appsandbox-displays.c: gate and clamp the snprintf accumulation so
  the resolution list cannot overflow buf.
- C4/C5 p9copy.c: clamp the server-advertised msize to the fixed client
  recv buffer, and validate Rread/Rreaddir count against the received
  payload before using it.
2026-06-02 21:51:19 -04:00
James Stringer 70ab72e8ee Refresh snapshot column when the snapshot tree changes (H23)
web/app.js: renderVmTable's per-row rebuild signature omitted the
snapshot tree, so taking/deleting/renaming a snapshot did not re-run
makeSnapCell (the row only refreshed when edit mode toggled, which is why
clicking edit revealed the new snapshot). Add hasSnapshots, snapCurrent,
snapCurrentBranch and the serialized snapshots/baseBranches to the
signature. These change only on user snapshot actions (a running VM can't
be snapshotted), so the install-progress-tick rebuild-skip optimization
is preserved.
2026-06-02 21:51:07 -04:00
James Stringer 14daec375e Flush queued WebView2 messages once the UI is ready (L1)
ui.c: on the uiReady action, call webview2_flush_queue() so messages
posted before the JS message listener registered (e.g. early ui_log
lines) are delivered instead of silently dropped.
2026-06-02 21:50:51 -04:00
James Stringer b9629afe7f Fix memory-safety, leak, and concurrency bugs in Windows host backend
Bounds / overflow:
- H1/H5 vm_display_idd.c, asb_display.c: bound full-frame and dirty-rect
  copies by the bytes actually received (OOB read on malformed frame).
- H2 vm_display_idd.c: validate cursor shape_data_size vs pitch*height.
- H4/C9 vm_clipboard.c: reject short/oversized FORMAT_LIST frames and a
  name_len that runs past the buffer.
- H22 vm_clipboard.c: DROPFILES wcscpy_s passed MAX_PATH as destsz on a
  tightly-sized buffer, so the secure-CRT tail-fill overran the heap.

Use-after-free / double-close:
- H13 asb_core.c: resolve the VM by stable unique_id under g_cs in the
  build progress/completion paths (g_vms[] compaction left vm_index
  stale); free the orphaned HCS handle if the VM was deleted mid-build.
- H14 vm_agent.c, H21 vm_clipboard.c: claim sockets atomically with
  InterlockedExchangePointer so worker threads and the stop path never
  double-close the same (possibly recycled) handle.
- H15/H16 vm_ssh_proxy.c: shutdown() relay sockets from the stop thread
  instead of closing them, and wait INFINITE (cleanup is bounded) so the
  listener can't run inside a freed proxy.

Leaks / correctness:
- M6/M7 hcs_vm.c: free the HCS result document on failed queries.
- M8 disk_util.c: propagate IStream::Read and WriteFile failures.
- M9/L7 snapshot.c: read/write tree.dat as UTF-8; zero-init the GUID and
  check CoCreateGuid.
- H12 asb_core.c: fix the inverted wait condition in asb_vm_wait_running.
- H17 vm_display_idd.c: on WSAEWOULDBLOCK / partial input send, drop the
  packet or flag reconnect instead of misaligning the stream.
- L3 asb_core.c: bounds-check the snapshot index in the delete-branch log.
- L4/L5 gpu_enum.c: NUL-terminate InfPath; only CoUninitialize when COM
  was actually initialized.
- L6 hcn_network.c: skip entries with OnLinkPrefixLength > 32.
- L8 vmms_cert.c: fall back to "unknown" when GetComputerNameW fails.
2026-06-02 21:50:39 -04:00
James Stringer b56c67bd25 Bump version to 0.1.1
Single edit to the version source of truth (Directory.Build.props:
AsbVersionPatch 0->1). Windows binaries (via build/version.rc) and the macOS
app/framework (via the build-time stamp from Directory.Build.props) both build
as 0.1.1; release zips become AppSandbox-0.1.1-{win-x64,mac-arm64}.zip.
2026-06-01 21:48:24 -04:00
James Stringer e2dd3c4aa5 Single source of truth for binary version
Stamp macOS version from Directory.Build.props at build time
2026-06-01 21:43:32 -04:00
James Stringer 1d0bab6b01 Stamp macOS version from Directory.Build.props at build time
Make Directory.Build.props the single place a version is ever set on macOS,
matching how Windows derives its version from the same file.

- Add a 'Stamp version' Run Script build phase to the AppSandbox and
  AppSandboxCore targets. It runs on every build (Xcode GUI, xcodebuild,
  Archive) and writes CFBundleShortVersionString / CFBundleVersion into the
  built bundle's Info.plist from Directory.Build.props.
- A build phase (not an xcconfig) is used because xcconfig is read before build
  phases run, so a generated xcconfig couldn't version the current build.
- tools/sign/asb-version.sh reads the version; tools/sign/stamp-version.sh is
  the build-phase wrapper. make-release-mac.sh uses asb-version.sh for the zip
  name.
- Remove the committed, generated version.xcconfig and sync-mac-version.sh;
  Local.xcconfig no longer includes version.xcconfig.

A fresh clone builds (ad-hoc or Personal Team, Xcode GUI or CLI) with the
version stamped, and nothing but Directory.Build.props defines it.
2026-06-01 21:42:11 -04:00
James Stringer 6707d0bff6 add OS to release zip file names
Include OS in release zip names
2026-06-01 21:20:05 -04:00
James Stringer dd445c3a5c Include OS in release zip names: AppSandbox-{version}-{os}-{platform}.zip
- Windows (make-release.ps1): add an $OS param (default 'win') used only in the
  zip filename; $Platform is untouched so MSBuild is unaffected. Produces
  AppSandbox-<ver>-win-x64.zip. SIGNING.md updated to match.
- macOS (make-release-mac.sh + mac-release-config.json): name the package
  <productName>-<version>-<os>-<platform>.zip from productName/os/platform plus
  the version derived from Directory.Build.props. Produces
  AppSandbox-<ver>-mac-arm64.zip. SIGNING_MAC.md updated.
2026-06-01 21:18:21 -04:00
James Stringer 038cdcefbd Add signing and packaging scripts for macOS
Add macOS Developer ID signing, notarization, and release tooling
2026-06-01 21:07:34 -04:00
James Stringer a518eea507 Merge remote-tracking branch 'origin/main' into mac-build 2026-06-01 21:06:41 -04:00
James Stringer cb7434f531 Add nested virtualization to Windows HCS config
Enable nested virtualization + WSL2 memory defaults for HCS VMs
2026-06-01 21:05:09 -04:00
James Stringer e2c578e228 Add macOS Developer ID signing, notarization, and release tooling
- xcconfig-based signing: Local.xcconfig (committed) pulls in a git-ignored
  LocalUser.xcconfig for the maintainer's team/Developer ID identity, so the
  public project builds ad-hoc/Personal-Team with no secrets committed.
- Release config in project.pbxproj: Developer ID + hardened runtime +
  secure timestamp + no get-task-allow; arm64; macOS 26 deployment target
  (guest helpers stay 13.0); scheme defaults to Release.
- Version derives from Directory.Build.props via sync-mac-version.sh ->
  version.xcconfig (the same single source of truth Windows uses).
- make-release-mac.sh: build -> verify-sign -> notarize (recursive, covers
  the framework + iso-patch-mac + appsandbox-agent + appsandbox-clipboard) ->
  staple -> Gatekeeper check -> publish a zip-only release_package/.
- Config split mirrors the Windows convention: mac-release-config.json
  (committed, no secrets) + mac-signing.local.json (git-ignored creds).
- tools/sign/SIGNING_MAC.md documents the whole process end to end.
2026-06-01 20:59:29 -04:00
James Stringer 994c5a36c2 Enable nested virtualization + WSL2 memory defaults for HCS VMs
Add ExposeVirtualizationExtensions to the Processor block, gated on host capability via HcsGetServiceProperties (ProcessorCapabilities -> "NestedVirt"), mirroring WSL2. Emitted only when the host advertises nesting support so HcsCreateComputeSystem never fails on ARM64 / older CPUs.

Also adopt WSL2's memory defaults: EnableDeferredCommit and EnableColdDiscardHint alongside the existing AllowOvercommit.
2026-06-01 19:05:36 -04:00
James Stringer 2809831a61 Update README.md 2026-05-31 23:59:47 -04:00
James Stringer 077da11639 Update README.md 2026-05-31 23:59:27 -04:00
James Stringer 54b3f29425 Readme polish 2026-05-31 23:53:21 -04:00
James Stringer 118e69b8ea Signing + Zip bundle creation
Signing and packaging
2026-05-31 22:30:24 -04:00
James Stringer 957bffd386 IDD display: focus an already-open window + add "Show Log" menu item
- Connecting to a VM whose IDD display is already open now brings that
  window to the foreground (via a thread-marshaled WM_IDD_FOCUS) instead
  of just logging "already open".
- The per-display log window is created hidden; a "Show Log" item on the
  window's system menu reveals it on demand (closing it just hides it).
2026-05-31 22:21:09 -04:00
James Stringer c986d092bf Add EV + Microsoft-attestation driver signing and release packaging
YubiKey-gated signing/packaging driven from the VS Release|x64 build:
- make-release.ps1 / sign-drivers.ps1: EV-sign all binaries + driver
  .sys/.dll, submit drivers to Microsoft for attestation in parallel,
  deposit the returned MS-signed drivers into bin\Release\drivers, and
  build a flat AppSandbox-<ver>-x64.zip. Token presence is detected via
  WinSCard + a silent NCrypt key-open, so an unplugged or unrelated card
  never triggers an "insert smart card" dialog; no token => test-sign
  only, no packaging.
- AppSandboxPackage.vcxproj runs it as a post-build step.
- Directory.Build.props/targets + build/version.rc: single-source version
  stamped into every binary and into the driver INFs (StampInf).
- VDD INF: pull WUDFRd via Include/Needs + Win11 decoration to pass
  infverif /h for Partner Center submission.
- Default new Windows VMs to Test Mode off (shipped drivers are MS-signed).
- SIGNING.md documents the git-ignored partner-center.local.json that you
  must create with the Entra API secrets for driver attestation.

Partner Center credentials stay in git-ignored tools/sign/*.local.* files.
2026-05-31 22:21:09 -04:00