diff --git a/docs/cli/gateway.md b/docs/cli/gateway.md index 25d44eee6..f0832452c 100644 --- a/docs/cli/gateway.md +++ b/docs/cli/gateway.md @@ -124,6 +124,8 @@ clawdbot gateway call logs.tail --params '{"sinceMs": 60000}' Only gateways with Bonjour discovery enabled (default) advertise the beacon. Wide-Area discovery records include (TXT): +- `role` (gateway role hint) +- `transport` (transport hint, e.g. `gateway`) - `gatewayPort` (WebSocket port, usually `18789`) - `sshPort` (SSH port; defaults to `22` if not present) - `tailnetDns` (MagicDNS hostname, when available) diff --git a/docs/gateway/configuration.md b/docs/gateway/configuration.md index b41c18fd1..d5ae37426 100644 --- a/docs/gateway/configuration.md +++ b/docs/gateway/configuration.md @@ -2697,6 +2697,7 @@ Remote client defaults (CLI): - `gateway.remote.url` sets the default Gateway WebSocket URL for CLI calls when `gateway.mode = "remote"`. - `gateway.remote.token` supplies the token for remote calls (leave unset for no auth). - `gateway.remote.password` supplies the password for remote calls (leave unset for no auth). +- `gateway.remote.tlsFingerprint` pins the gateway TLS cert fingerprint (sha256). macOS app behavior: - Clawdbot.app watches `~/.clawdbot/clawdbot.json` and switches modes live when `gateway.mode` or `gateway.remote.url` changes. @@ -2710,7 +2711,8 @@ macOS app behavior: remote: { url: "ws://gateway.tailnet:18789", token: "your-token", - password: "your-password" + password: "your-password", + tlsFingerprint: "sha256:ab12cd34..." } } } diff --git a/docs/gateway/protocol.md b/docs/gateway/protocol.md index cdd6ee5a7..47335ead0 100644 --- a/docs/gateway/protocol.md +++ b/docs/gateway/protocol.md @@ -153,11 +153,22 @@ Nodes declare capability claims at connect time: The Gateway treats these as **claims** and enforces server-side allowlists. +## Presence + +- `system-presence` returns entries keyed by device identity. +- Presence entries include `deviceId`, `roles`, and `scopes` so UIs can show a single row per device + even when it connects as both **operator** and **node**. + ### Node helper methods - Nodes may call `skills.bins` to fetch the current list of skill executables for auto-allow checks. +## Exec approvals + +- When an exec request needs approval, the gateway broadcasts `exec.approval.requested`. +- Operator clients resolve by calling `exec.approval.resolve` (requires `operator.approvals` scope). + ## Versioning - `PROTOCOL_VERSION` lives in `src/gateway/protocol/schema.ts`. @@ -191,7 +202,7 @@ The Gateway treats these as **claims** and enforces server-side allowlists. - TLS is supported for WS connections. - Clients may optionally pin the gateway cert fingerprint (see `gateway.tls` - config and client TLS settings). + config plus `gateway.remote.tlsFingerprint` or CLI `--tls-fingerprint`). ## Scope diff --git a/docs/gateway/remote.md b/docs/gateway/remote.md index 4301ddfde..ebe98d413 100644 --- a/docs/gateway/remote.md +++ b/docs/gateway/remote.md @@ -114,6 +114,7 @@ Short version: **keep the Gateway loopback-only** unless you’re sure you need - **Loopback + SSH/Tailscale Serve** is the safest default (no public exposure). - **Non-loopback binds** (`lan`/`tailnet`/`auto`) must use auth tokens/passwords. - `gateway.remote.token` is **only** for remote CLI calls — it does **not** enable local auth. +- `gateway.remote.tlsFingerprint` pins the remote TLS cert when using `wss://`. - **Tailscale Serve** can authenticate via identity headers when `gateway.auth.allowTailscale: true`. Set it to `false` if you want tokens/passwords instead. - Treat `browser.controlUrl` like an admin API: tailnet-only + token auth. diff --git a/docs/gateway/security.md b/docs/gateway/security.md index 04cb8ba33..269cb33f5 100644 --- a/docs/gateway/security.md +++ b/docs/gateway/security.md @@ -267,6 +267,7 @@ Doctor can generate one for you: `clawdbot doctor --generate-gateway-token`. Note: `gateway.remote.token` is **only** for remote CLI calls; it does not protect local WS access. +Optional: pin remote TLS with `gateway.remote.tlsFingerprint` when using `wss://`. Auth modes: - `gateway.auth.mode: "token"`: shared bearer token (recommended for most setups). diff --git a/docs/refactor/clawnet.md b/docs/refactor/clawnet.md index 09dd026c2..05301b7eb 100644 --- a/docs/refactor/clawnet.md +++ b/docs/refactor/clawnet.md @@ -292,10 +292,10 @@ Same `deviceId` across roles → single “Instance” row: - [x] **Device‑bound auth (PoP):** nonce challenge + signature verify on connect; remove bearer‑only for non‑local. - [x] **Role‑scoped creds:** issue per‑role tokens, rotate, revoke, list; UI/CLI surfaced; audit log entries. - [x] **Scope enforcement:** keep paired scopes in sync on rotation; reject/upgrade flows explicit; tests. -- [ ] **Approvals routing:** gateway‑hosted approvals; operator UI prompt/resolve; node stops prompting. -- [ ] **TLS pinning for WS:** reuse bridge TLS runtime; discovery advertises fingerprint; client validation. -- [ ] **Discovery + allowlist:** WS discovery TXT includes TLS fingerprint + role hints; node commands filtered by server allowlist. -- [ ] **Presence unification:** dedupe deviceId across roles; include role/scope metadata; “single instance row”. +- [x] **Approvals routing:** gateway‑hosted approvals; operator UI prompt/resolve; node stops prompting. +- [x] **TLS pinning for WS:** reuse bridge TLS runtime; discovery advertises fingerprint; client validation. +- [x] **Discovery + allowlist:** WS discovery TXT includes TLS fingerprint + role hints; node commands filtered by server allowlist. +- [x] **Presence unification:** dedupe deviceId across roles; include role/scope metadata; “single instance row”. - [ ] **Docs + examples:** protocol doc, CLI docs, onboarding + security notes; no personal hostnames. - [ ] **Test coverage:** connect auth paths, rotation/revoke, approvals, TLS fingerprint mismatch, presence. diff --git a/docs/tools/exec-approvals.md b/docs/tools/exec-approvals.md index 97a48ae28..369a6a408 100644 --- a/docs/tools/exec-approvals.md +++ b/docs/tools/exec-approvals.md @@ -120,7 +120,11 @@ CLI: `clawdbot approvals` supports gateway or node editing (see [Approvals CLI]( ## Approval flow -When a prompt is required, the companion app displays a confirmation dialog with: +When a prompt is required, the gateway broadcasts `exec.approval.requested` to operator clients. +The Control UI and macOS app resolve it via `exec.approval.resolve`, then the gateway forwards the +approved request to the node host. + +The confirmation dialog includes: - command + args - cwd - agent id