Files
appsandbox/tools/headless-api/tests
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
..

headless-api tests

Self-contained integration tests for the AppSandbox headless daemon. They drive the daemon over its HTTP/JSON API through the asb.py client — no test framework, just stdlib Python. Every test creates the throwaway VMs it needs (named brk-*) and deletes them at the end, so the suite assumes no existing configuration and never touches your VMs, templates, or snapshots. The same suite runs on Windows and macOS hosts; feature differences (snapshots/templates are Windows-only) are gated on version()["capabilities"].

Running

Windows — start the daemon (elevated), point the suite at your install ISOs, then run the harness from this folder's parent:

appsandbox.exe --headless
set ASB_ISO_LINUX=C:\path\to\ubuntu-desktop-amd64.iso
set ASB_ISO_WINDOWS=C:\path\to\Win11_x64.iso
python tests\run_all.py

macOS — start the daemon with sudo (required; it is fully non-interactive and still operates on YOUR user's VM registry + restore-image cache via SUDO_USER), then run the harness:

sudo AppSandbox.app/Contents/MacOS/AppSandbox --headless
python3 tests/run_all.py

ISOs default to this tests/ folder if the env vars are unset. macOS guests install from a restore IPSW: ASB_IPSW_MACOS overrides; by default the suite also tests the download path — it sets any cached restore.ipsw aside and lets the first VM fetch a fresh image from Apple (resumable), while the second VM installs concurrently from the preserved original. A full run builds real guests — it is long (a Windows install + sysprep, or a macOS IPSW download + install, can each take 20–45 min) and uses real disk and bandwidth.

Files

File What it covers
run_all.py Master harness. Sweeps leftover brk-* VMs, runs the static checks once, then one full per-VM lifecycle per spec concurrently (Linux + Windows on a Windows host; two macOS guests on a macOS host — one downloading its IPSW, one installing from the cached image), then the Windows template lifecycle (Windows hosts only). Prints a per-thread summary and a coverage table. This is the entry point.
vm_lifecycle.py The full per-VM sequence, parametrized by a create-spec. Covers create / status / edit / start / graceful shutdown / force-stop / SSE / delete, the during-build guards, SSH key auto-deploy (build with sshDeployKey, assert keyDeployed/sshState 4, then a key-only login), a quick display open/close once online (skipped on macOS hosts, on Linux guests until the updated agent is pushed, and in non-interactive daemon sessions), and — where capabilities.snapshots — snapshots + branches + base branches (asserts 501 on macOS instead).
test_host_and_validation.py No-VM checks: host cores/RAM cross-checked against the exact OS calls the daemon makes (Win32 / sysctl), capability gates, and the create-input-validation rejections matching the GUI's JS guards for the host platform. Builds nothing.
test_windows_template.py Windows-only template lifecycle: create a template (isTemplate), wait for sysprep finalization, create a VM from it, then delete the template. Never runs on macOS (RUN_TEMPLATE = not IS_MAC).
helpers.py Shared helpers: per-platform paths (vm_dir, disk name), destroy_vm (guard-aware teardown), wait_progress (stall-based waiting driven by the daemon's live progress reporting — no fixed deadlines on phases that report progress), and ssh_key_login (key-only BatchMode SSH login).

Notes

  • No arbitrary deadlines on progress-reporting phases. Builds, installs, and IPSW downloads are waited on with helpers.wait_progress: any change in the daemon-reported state/progress/installStatus resets a stall clock, and the wait fails only after 10 minutes of zero observable movement. Fixed timeouts remain only for signal-less single transitions (boot→online, graceful shutdown).
  • Lifecycle discipline mirrors the GUI. Every VM start boots all the way to online (guest agent connected) before the VM is used; the only exceptions are the delete/edit-during-build guards. Every shutdown is the graceful, agent-mediated one — force-stop is exercised in exactly one dedicated test.
  • Guest agent provenance differs per OS. The Windows and macOS guest agents are built locally and staged into the guest at create time, so their key-deploy checks pass with a local build. The Linux agent is compiled inside the guest from the pushed GitHub branch, so its key-deploy checks stay red until the headless-api branch is pushed.
  • Default guest credentials are user / test123.