14 Commits
Author SHA1 Message Date
James Stringer 6e8fa70da3 Improve NVIDIA compute compatibility
Fix Windows CUDA and OpenCL adapter identity handling and provision NVIDIA Optical Flow and OptiX runtimes through the existing GPU copy path. Include the new shims in the existing build, signing and packaging pipeline.

Prioritize the Linux WSL library directory so CUDA loads from SSH sessions and background processes.
2026-09-20 21:35:49 -04:00
James Stringer 9d6342f977 Fix viewer mouse capture and keyboard handling 2026-09-08 22:49:37 -04:00
James Stringer a68665db2d Restore static NAT networking and preserve saved VM IPs 2026-09-07 20:20:41 -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 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 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 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 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 5a3494501c Scrub remaining cloud-image/cidata references from comments (comments only)
The cloud-image install flow is gone; reword the last comments that still
referenced it:
  - asb_core.c: "Linux cloud-image creates" -> "Linux ISO creates"
  - disk_util.c: drop the "Ubuntu cloud-image parent ~2.5 GB" rationale
    from vhdx_create_differencing_resized (now describes the generic
    inherit-then-resize behavior)
  - disk_util.h: stage_linux_agent_and_extras doc no longer says "same
    content the cidata builder used to ship"
  - appsandbox-agent.c: "autoinstall lets the user pick" -> "the create-VM
    modal lets the user pick"
2026-05-30 14:49:35 -04:00
James Stringer 52f71115ea Pre-merge cleanup: remove dead cidata/cloud-image flow + fix stale comments
Delete the abandoned cloud-image/cidata Linux install path (zero live
callers — linux_create_thread builds the VHDX directly from the ISO):
  - disk_util.c: drop iso_create_resources_ubuntu, generate_autoinstall_*,
    generate_network_config, generate_ubuntu_setup_sh, find_repo_root +
    copy helpers, the DEAD_ #if0 block, and the entire qcow2/VHD/inflate/
    cloud-image converter incl. ensure_ubuntu_cloud_image_cached
    (4492 -> 2315 lines). Shared helpers kept (create_iso_from_dir,
    remove_staging_dir, unix_password_hash, stage_linux_agent_and_extras).
  - disk_util.h: drop the two now-dead prototypes.

Rename the guest first-boot identifier poc-firstboot -> appsandbox-firstboot
(service/script/marker) in ubuntu_vhdx.c and reword stale "POC gpt.c"/
"f361def"/"old flow"/"subiquity"/"cidata" comment references to describe
the current direct-ISO->VHDX flow.

Fix factually-wrong comments found in a line-by-line audit:
  - asb_core.c: NAT comment claimed DHCP; it's a static IP baked into the
    HCN endpoint + pushed by the agent. SHA-512-crypt / Secure Boot /
    create-path comments reworded off the removed flow.
  - appsandbox-agent.c: gdm UID-range claim (gdm is <1000); netplan
    "renderer detect" actually probes the NetworkManager service.
  - appsandbox-display.c: cursor cadence said 30fps (TARGET_FPS is 60);
    card-selection "connected output" claim corrected (driver-name match).
  - appsandbox-audio.c: wire-proto doc said 16-bit/4-align (it's 32/8);
    snd-aloop subdev comment.

Move the internal IMPLEMENTATION_PLAN.md design doc out of the repo
(it now lives in the gitignored docs/).
2026-05-30 14:36:56 -04:00
James Stringer 45285394d9 Fix capture daemons hanging guest shutdown when IDD is disconnected
appsandbox-display / -audio / -input installed SIGINT/SIGTERM via
signal(), which on glibc carries BSD SA_RESTART semantics. With the
listen socket blocking and no SO_RCVTIMEO, a SIGTERM at poweroff ran
the handler (set g_stop=1) but the kernel auto-restarted the blocking
accept() instead of returning EINTR — so the existing
`if (errno == EINTR) continue;` re-check never fired and the daemon sat
blocked in accept(). systemd then waited the full TimeoutStopSec (~90s)
per unit before SIGKILL, which presented as the VM hanging at shutdown.
Reconnecting the IDD display made accept() return a real connection, the
loop re-evaluated g_stop, and shutdown finally completed — the tell.

Switch all three to sigaction() with sa_flags=0 (no SA_RESTART), exactly
matching appsandbox-agent.c, which already shuts down promptly for this
reason. accept() now returns EINTR on SIGTERM and the loop exits cleanly.
2026-05-30 12:59:02 -04:00
James Stringer 194cadeaa6 NVENC/NVDEC userspace path + nvidia-smi shortcut
- systemd-user environment generator and appsandbox-gpu wrapper both
  append /usr/lib/wsl/lib to LD_LIBRARY_PATH. ldconfig has the .so.1
  entries cached, but the 9P mount is read-only so the unversioned
  symlinks ldconfig wants to create can't be written. dlopen() of
  unversioned names (libcuda.so, libnvidia-encode.so, libnvcuvid.so)
  needs the path on LD_LIBRARY_PATH — without it ffmpeg's h264_nvenc /
  h264_cuvid plugins fail with 'Cannot load libcuda.so.1'.

- setup.sh: symlink /usr/lib/wsl/lib/nvidia-smi to /usr/local/bin so
  the bare command works without env tweaks. Created unconditionally
  because the symlink target is resolved at exec time — the file
  appears under the agent's 9P mount on first boot regardless of when
  the symlink was created.
2026-05-19 22:09:52 -04:00
James Stringer 2309cec029 Add Linux VM support with GPU-PV
Ubuntu 26.04 LTS guest end-to-end:

- cidata-driven autoinstall pipeline (subiquity user-data + nested
  cloud-init bootcmd) in disk_util.c. Static NAT IP, ssh-via-vsock
  marker, serial-debug kernel cmdline injected into ESP grub.cfg by
  iso-patch.exe. Five separate firstboot pipeline fixes get the VM
  to GDM unattended on Hyper-V Gen 2.

- Linux guest stack under tools/linux/:
    - appsandbox-agent  (vsock :1 control + clipboard helper spawn)
    - appsandbox-audio  (snd-aloop -> vsock :4)
    - appsandbox-display (KMS framebuffer capture -> vsock :2)
    - appsandbox-input  (uinput injection <- vsock :3)
    - appsandbox-clipboard (XCB selection bridge <-> vsock :5/:6)
  Helper binaries staged via release/resources/linux/.

- asb_drm DRM module: virtual single-CRTC display sink the host
  captures over vsock. Platform-bus, DRIVER_GEM/MODESET/ATOMIC/RENDER,
  linear shmem framebuffers. asb-evict-simpledrm.service unbinds the
  EFI simple-framebuffer before display-manager so mutter binds
  asb_drm as the sole DRM card.

- dxgkrnl vendored byte-identical from microsoft/WSL2-Linux-Kernel
  linux-msft-wsl-6.18.y with our DKMS/out-of-tree shim (dxgkrnl_compat.h
  + Kbuild + dkms.conf). Autoinstall late-commands dkms-builds against
  every /target/lib/modules/<kver> so kernel-version drift between ISO
  and post-update reboot still leaves a working .ko.

- wsl-mesa custom build (Mesa 25.3 + d3d12 gallium + microsoft-
  experimental dzn Vulkan). Installs to /opt/wsl-mesa parallel to
  Ubuntu's stock Mesa. Prebuilt tarball for ubuntu-26.04-amd64
  shipped under tools/linux/wsl-mesa/prebuilt/ (21 MB).

- Per-VM GPU acceleration policy:
    - /etc/systemd/user-environment-generators/50-appsandbox-gpu
      emits GALLIUM_DRIVER=d3d12 + LD_LIBRARY_PATH + VK_DRIVER_FILES
      into the user@1000 systemd-user environment when /dev/dxg and
      /opt/wsl-mesa are present. Inherited by every app-*.scope a
      .desktop launch creates.
    - /etc/systemd/user/org.gnome.Shell@.service.d/no-gpu.conf
      UnsetEnvironment= strips these for the compositor — mutter
      stays on llvmpipe so asb_drm scanout works (the d3d12 pipe has
      no GBM compatibility with asb_drm).
    - /usr/local/bin/appsandbox-gpu wrapper for terminal-launched
      opt-in GPU acceleration (probes /dev/dxg; no-op on no-GPU VMs).

- Host changes:
    - vm_display_idd.c, vm_clipboard.c, vm_agent.c, vm_ssh_proxy.c,
      asb_display.c: hcs_service_guid(os_type, port) so the same code
      paths reach the per-OS service identifiers (HV_GUID for Windows,
      vsock template for Linux).
    - asb_core.c: linux_create_thread builds an empty VHDX, cidata
      ISO with extras (agent ELFs, dxgkrnl src, asb_drm src, wsl-mesa
      tarball, wsl-deps libs), and boots the desktop ISO + cidata.
    - hcs_vm.c: HostLxssLib Plan9 share appended for Linux VMs;
      VideoMonitor + ComPorts retained for serial debug.
    - gpu_enum.c/h: gpu_append_lxsslib_share helper.
    - vm_clipboard.c file-drop support (CF_HDROP / x-special/gnome-
      copied-files round-trip).
    - vm_display_idd.c: 32-bit S32_LE PCM audio path matches the
      Linux daemon's snd-aloop capture format.

- iso-patch.c gains a patch_ubuntu_esp_grub_for_debug pass that
  rewrites /EFI/ubuntu/grub.cfg via the FAT32 ESP, plus a qcow2->
  vhdx converter with a RFC 1951 DEFLATE inflater for compressed
  cluster handling.

- wsl-deps: Microsoft's libd3d12.so / libd3d12core.so / libdxcore.so
  fetched on demand from the public NuGet feed
  pkgs.dev.azure.com/shine-oss/wsl (no auth). Staged at
  /opt/appsandbox/wsl-deps on the guest and put on /etc/ld.so.conf.d
  rather than /usr/lib/wsl/lib (which is overlaid by the agent's
  9P mount).

UI: web/{app.js,index.html} expose Linux VM creation + GPU selection,
distribution dropdown for cached Ubuntu ISOs, and the ISO picker for
custom images.
2026-05-19 20:21:43 -04:00