Skip to content

feat: remote access via Tailscale + HMAC (no SSH)#24

Open
james-s-hedwig[bot] wants to merge 3 commits intomainfrom
swarm/remote-hmac
Open

feat: remote access via Tailscale + HMAC (no SSH)#24
james-s-hedwig[bot] wants to merge 3 commits intomainfrom
swarm/remote-hmac

Conversation

@james-s-hedwig
Copy link
Copy Markdown
Contributor

Summary

Implements a remote access layer so an agent on one machine (Mac Mini) can drive cuad on another (laptop) — no SSH, just Tailscale + HMAC challenge-response over HTTP.

New files

  • RemoteServer.swift (CUADaemonLib) — NWListener HTTP proxy: GET /handshake (nonce, 30s TTL), POST /auth (HMAC-SHA256 verify → session token), POST /rpc (Bearer auth, blocked-app check, method allowlist, proxies to local UDS)
  • RemoteClient.swift (CUACore) — challenge-response client, disk-cached session tokens at ~/.cua/remote-sessions/<name>.json
  • RemoteTests.swift — 20 new tests: HMAC verification, single-use challenges, ±30s replay protection, session TTL, blocked apps, disallowed methods, config decoding. All 344 tests pass.

Modified files

  • CUAConfig.swiftRemoteServerConfig + RemoteTarget types
  • CUA.swiftcua remote setup (generates secret, prints config snippets + Tailscale IP); --remote <target> flag + CUA_REMOTE env var on status, list, snapshot, act, pipe, screenshot
  • main.swift — starts RemoteServer on boot when remote.enabled = true

Test plan

  • swift build -c release passes
  • swift test — all 344 tests pass
  • On laptop: add "remote" block to ~/.cua/config.json, cua daemon restart, verify log shows [remote-server] Listening on port 4567
  • Run cua remote setup to generate secret + print config snippets
  • On Mac Mini: add "remote_targets", run cua --remote james-laptop status
  • Verify snapshot proxies correctly
  • Verify blocked app returns error

Implements a minimal HTTP proxy server (RemoteServer) in cuad that lets
a remote agent drive a local cuad over Tailscale using HMAC
challenge-response authentication — no SSH required.

What's new:
- RemoteServer (CUADaemonLib): GET /handshake → challenge, POST /auth
  → session token (HMAC-SHA256), POST /rpc → proxy to local UDS socket.
  IP-level filtering for "tailscale" / "localhost" / "0.0.0.0" bind modes.
  Single-use challenges, ±30s replay protection, configurable TTL.
- RemoteClient (CUACore): client with HMAC auth flow and disk-cached
  session tokens (~/.cua/remote-sessions/<name>.json) so each CLI
  invocation reuses a valid token without re-authenticating.
- CUAConfig: new RemoteServerConfig and RemoteTarget types loaded from
  ~/.cua/config.json under "remote" and "remote_targets" keys.
- cua remote setup: prints config snippets for both machines with a
  freshly generated secret and the current Tailscale IP.
- --remote <target> flag on status, list, snapshot, act, pipe, screenshot;
  also reads CUA_REMOTE env var.
- 20 new tests covering HMAC generation, challenge expiry, replay
  protection, session TTL, blocked apps, and config decoding.
…air)

Remove 'cua remote setup' (JSON snippet printer). Replace with:
- 'cua remote accept': starts a temporary NWListener-based pairing
  server, generates a short code (e.g. a3f1-9c2b), prints the pair
  command to send to the human, waits for POST /pair, writes
  remote_targets config and exits.
- 'cua remote pair <host> <code>': sends the code to the accept
  server, receives a 32-byte shared HMAC secret, writes remote server
  config to ~/.cua/config.json (merging without clobbering), prompts
  'cua daemon restart'.

Both machines' configs are written automatically — no JSON copy-paste.
Update skills/computer-use/SKILL.md and add docs/REMOTE.md.
All 344 tests pass.
…iles

- Add StreamConfig to CUAConfig (enabled, push_to, secret, flush_interval,
  app_levels, blocked_apps with wildcard "*" default)
- Add EventStreamFilter (CUACore): maps CUAEvent → StreamEvent with level-based
  privacy rules; blocks apps; scrubs AXSecureTextField values from snapshots
- Add EventShipper (CUADaemonLib): subscribes to EventBus, batches StreamEvents,
  authenticates to agent's RemoteServer via HMAC challenge-response, POSTs NDJSON
- Add /stream/push endpoint to RemoteServer: validates Bearer token, parses NDJSON,
  appends events to ~/.cua/streams/<name>/YYYY-MM-DD.jsonl
- Wire EventShipper startup in cuad/main.swift when stream.enabled
- Add `cua stream read <target> [--date] [--app] [--tail] [--json]` CLI command
- Update pairing ceremony: cua remote accept writes remote.secret + remote_targets;
  cua remote pair writes stream config with default app_levels; both print stream URL
- 21 new tests in StreamTests.swift (365 total)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant