diff --git a/DESIGN-WINDOWS.md b/DESIGN-WINDOWS.md new file mode 100644 index 0000000..1bac02b --- /dev/null +++ b/DESIGN-WINDOWS.md @@ -0,0 +1,263 @@ +# theta-agent on Windows — design + +Status: **planning / design draft**. Companion to `DESIGN.md`, which describes the +Linux-first agent. This document covers bringing the agent to Windows as a first-class +platform, optimized for **air-gapped** deployment: everything the host needs ships in +one installer, and nothing on the target machine requires internet access. + +## 1. Goals + +1. **Parity, not a port.** Every capability Linux has, Windows has too: telemetry, + remote operations (reboot/shutdown, service control, desktop control, arbitrary + commands, logs, IAM, self-update), LDAP-backed directory logins, secrets, and a + WireGuard mesh client. The capability matrix and Ed25519 signature model from + `DESIGN.md` apply unchanged; only the executors change. +2. **One installer, fully offline.** A single Inno Setup `.exe` installs everything the + Windows host needs — agent service, tray, credential provider, WireGuard client, + runtime dependencies. No downloads at install time and no internet calls at runtime. +3. **Single outbound connection preserved.** The agent still dials one persistent WSS + connection to the SSO. No inbound ports, no firewall rules. +4. **The SSO holds all resources.** The Windows installer, loose binaries, and the + self-update feed are served from the SSO, mirroring the existing + `/resources/theta-agent/...` tree. + +## 2. Current Windows compatibility status + +The agent already compiles, runs, and enrolls on Windows. Validated against a live SSO +(`sso.suite.vm42.us`): + +- `go build` for `windows/amd64` succeeds; the agent enrolls via join key, persists its + issued token + the SSO's Ed25519 public key to `agent.yml`, and streams discovery / + telemetry over WSS. +- Unix-domain sockets work on Windows (Go ≥ 1.18, needs Win10 1803+); the LDAP byte-pump + and tray IPC both bind and accept connections under the per-user temp dir. +- Two unit tests assert POSIX `0600` modes that Windows does not implement; they are the + only failures and are not runtime defects (`go test` gate must be made Windows-aware). + +### Changes already merged + +- **Tray IPC socket paths are platform-aware.** Linux keeps `/run/theta/tray.sock` + + `/tmp/theta-tray.sock`; Windows uses a Unix socket under the per-user temp dir + (`tray_ipc.go`). The tray companion dials the same path. +- **The tray no longer exits on Windows.** The `DISPLAY`/`WAYLAND_DISPLAY` graphical + session guard is now non-Windows only (`cmd/theta-agent-tray/main.go`). + +## 3. Process & services layout + +| Component | Runs as | Purpose | +| :--- | :--- | :--- | +| `theta-agent` | Windows service (SYSTEM, auto-start) | WSS to SSO, command dispatch, telemetry, LDAP byte-pump, loopback `/bind`, IAM, WG control | +| `theta-agent-tray` | Per-user, logon autostart | Status icon, enrollment dialog, VPN control, auto-VPN | +| `theta-agent-helper` (new) | Per-interactive-session, spawned by the service | Desktop controls that cannot run from session 0 | +| OpenCredential CP DLL | Loaded by `LogonUI.exe` (Winlogon) | LDAP-backed Windows logon | +| `WireGuardTunnel$` | Service installed by WireGuard client | Mesh tunnel | + +The service is the lynchpin: it is up before any user session, which is what lets the +credential provider validate logins at Ctrl+Alt+Del. + +## 4. Remote operations (full parity) + +Command dispatch, capability gating, and Ed25519 verification in `websocket.go` are +platform-neutral. A `executor_windows.go` (plus a small `executor_linux.go` containing +today's Linux mapping) selects the underlying implementation. + +| Command | Linux (today) | Windows | +| :--- | :--- | :--- | +| `reboot` | `reboot` | `shutdown.exe /r /t 0` | +| `shutdown` | `shutdown -h now` / `poweroff` | `shutdown.exe /s /t 0` | +| `service_restart` | `systemctl restart ` | `sc.exe stop/start ` (allowed-list unchanged) | +| `systemd_action` | `systemctl ` | `sc.exe `; `status` → `sc.exe query` | +| `arbitrary_bash` | `bash -c