# Interactive Windows VM access This directory is an explicitly temporary, manual-recovery path to the Helium Windows fixture desktop. It is for the small class of actions that require an interactive UAC consent dialog. Normal setup, testing, collection, and reset remain `scripts/windows/test-host` plus VirtualBox Guest Control. The helper builds this private path: ```text browser -- HTTPS/self-signed --> nginx + Guacamole containers | private Docker gateway | controller SSH watchdog/tunnel --> Helium 127.0.0.1:3389 --> VirtualBox VRDE --> VM console ``` Only the HTTPS listener can be made public, and that requires an explicit `--bind 0.0.0.0`. The VirtualBox VRDE endpoint stays on Helium loopback and the SSH tunnel binds only to the Docker network gateway; neither is publicly exposed. Guacamole requires the fixture login before it forwards the entered password to the VM. Clipboard, drives, printing, audio, microphone input, GFX, and display-resize extensions are disabled because the fixture's VirtualBox RDP4 server does not handle them reliably. ## Lifecycle Run commands from the repository root. First prepare the disposable VM using a dedicated run ID. This restores the snapshot, starts the VM headlessly, and holds the exclusive fixture lease while the manual action is in progress: ```sh scripts/windows/test-host prepare --run-id interactive-rdp ``` For browser access from another machine, deliberately expose the temporary HTTPS listener and name the host or IP users will enter in the browser: ```sh test/rdp-access/rdp-access up \ --bind 0.0.0.0 \ --public-host x1.example.net ``` The command prompts without echo for the fixture password. It stores only its MD5 verifier in `test/rdp-access/.runtime/config/user-mapping.xml`, mode 600; the plaintext password is not placed in a command line, environment variable, log, or repository file. Browse to the printed `https://.../guacamole/` URL, accept the short-lived self-signed certificate warning, and sign in as `rvboxtest` with the fixture password. For localhost-only use, omit `--bind` and `--public-host`. The default listener is `127.0.0.1:5002`; use a local SSH forward or a browser on the controller. Choose alternate ports with `--http-port` and `--tunnel-port` if either is in use. The VM must already be running. `up` checks the documented VM/snapshot identity but intentionally does not restore, start, stop, or reset the VM. It starts a small host-side watchdog for the SSH master. Before printing the URL, `up` waits until the HTTPS gateway can serve `/guacamole/`; this prevents a browser login from racing Tomcat's Guacamole WAR deployment. The watchdog reconnects after a transient Helium/SSH failure while preserving the same Docker-gateway listener, so an already-open Guacamole session can recover without restarting the containers. Its PID, stop marker, and diagnostic log are kept under the ignored `.runtime/` directory. All fixture-specific values have embedded, working defaults: the `helium-remote` SSH alias, Helium's loopback VRDE endpoint (`127.0.0.1:3389`), `rvboxtest`, the browser listener (`127.0.0.1:5002`), and the private tunnel port (`54001`). They can be overridden without editing tracked files through `RVBOX_TEST_VBOX_HOST`, `RDP_ACCESS_VRDE_HOST`, `RDP_ACCESS_VRDE_PORT`, `RDP_ACCESS_WEB_USER`, `RDP_ACCESS_RDP_USER`, `RDP_ACCESS_BIND`, `RDP_ACCESS_HTTP_PORT`, `RDP_ACCESS_TUNNEL_PORT`, and `RDP_ACCESS_PUBLIC_HOST`. The helper deliberately limits the VRDE host to Helium loopback (`127.0.0.1` or `localhost`) so an override cannot accidentally turn the diagnostic server into a remote target. If `up` is run again while the Compose services are still running, it is idempotent: an existing healthy tunnel is reused, and a missing tunnel is recreated in place. `status` reports a helper-owned tunnel as `private_tunnel=active` and a listener supplied by an external/interactive SSH supervisor as `private_tunnel=active_external`. A missing listener is reported as `private_tunnel=inactive`; inspect `.runtime/tunnel.log` and run `up` again to trigger a bounded reconnect attempt. The XML mapping intentionally uses Guacamole's `${GUAC_PASSWORD}` connection parameter token. Guacamole resolves this to the password entered at web login; it is not a host environment variable and must remain in the template. After the interactive action, close the browser connection and remove the temporary access path before releasing the fixture lease: ```sh test/rdp-access/rdp-access down scripts/windows/test-host reset --run-id interactive-rdp ``` `down` stops containers and the SSH watchdog/master/tunnel but retains the one-day certificate and password verifier for a quick restart. To remove all generated state, including the certificate, verifier, watchdog PID, and tunnel log: ```sh test/rdp-access/rdp-access clean ``` To also reclaim the exact Guacamole and nginx images when they have no container dependency, use: ```sh test/rdp-access/rdp-access clean --images ``` `clean --images` deliberately leaves `alpine:3.20` alone because it may be shared by unrelated containers. Docker will refuse removal if any other container still depends on an image. ## Operational checks and recovery ```sh test/rdp-access/rdp-access status test/rdp-access/rdp-access logs --tail=100 test/rdp-access/rdp-access url ``` If the browser reaches Guacamole but stays on “Waiting for response”, run `status` first. Confirm `private_tunnel=active` (or `active_external`), then check the VM state and the last lines of `.runtime/tunnel.log`. A tunnel can be recreated without losing the Compose stack by running `up` again. This helper already uses `security=rdp` and disables Guacamole's GFX extension, which are required by the fixture's legacy VRDE server. Do not switch the helper to native Windows RDP: `TermService` is intentionally disabled in the baseline. If VRDE remains unusable, stop this helper and use Guest Control for the deterministic portion of the work; record the blocked interactive step in the native test report. The helper requires Docker/Docker Compose, SSH access through the existing `helium-remote` alias, and the fixture password file documented in [`docs/testing-vm.md`](../../docs/testing-vm.md). It does not install host packages, write credentials into Git, or alter VM settings. The tracked files are Docker-only configuration and the controller script; all generated content is ignored beneath `.runtime/`.