Apply P16: approvals are !approve/!deny replies in the approval's thread; no reactions

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-24 01:54:50 -07:00
co-authored by Claude Opus 5.5
parent 3088dcc201
commit 1c2695d21d
3 changed files with 6 additions and 6 deletions
+1 -1
View File
@@ -72,7 +72,7 @@ Separate binaries in one Cargo workspace. Each role holds as little authority as
them), runs each approved tool call in a fresh rootless container, and writes a hash-chained them), runs each approved tool call in a fresh rootless container, and writes a hash-chained
JSONL audit log. JSONL audit log.
- `gatewayd` is the Mattermost channel. Outbound only, no listening port; approvals arrive as - `gatewayd` is the Mattermost channel. Outbound only, no listening port; approvals arrive as
replies or reactions over the WebSocket. `!approve`/`!deny` replies over the WebSocket.
- `inferproxy` is a ~100-line byte forwarder from a Unix socket to the shared `llama-server` - `inferproxy` is a ~100-line byte forwarder from a Unix socket to the shared `llama-server`
router on the host. It is required, because `loopd` has no network. router on the host. It is required, because `loopd` has no network.
- `proto` holds shared types. `toolkit` holds tool container entrypoints. - `proto` holds shared types. `toolkit` holds tool container entrypoints.
+2 -3
View File
@@ -92,9 +92,8 @@ Later changes to the brief:
| 2026-09-18 | P14, State: the list gained `broker/sessions/<id>.json`, each session's taint and untrusted flag, written only by `brokerd`. | The M3a spec keeps this state in files the list did not name. It can be rebuilt from the audit log's `result` records, so the audit log stays the record of truth. Owner: a plain file also makes debugging easier. | | 2026-09-18 | P14, State: the list gained `broker/sessions/<id>.json`, each session's taint and untrusted flag, written only by `brokerd`. | The M3a spec keeps this state in files the list did not name. It can be rebuilt from the audit log's `result` records, so the audit log stays the record of truth. Owner: a plain file also makes debugging easier. |
| 2026-09-22 | P13, Authority contract 4: tool containers run from one image built from source by Nix and named by digest; nothing is pulled at call time. | Approved with the M3 design (2026-09-18); applied when the M3b spec came to rely on it. A pull at call time would be unlisted egress. | | 2026-09-22 | P13, Authority contract 4: tool containers run from one image built from source by Nix and named by digest; nothing is pulled at call time. | Approved with the M3 design (2026-09-18); applied when the M3b spec came to rely on it. A pull at call time would be unlisted egress. |
| 2026-09-23 | P15, State, the secrets line: three `SecretStore` backends chosen per secret (a systemd credential by default, an environment variable, an owner-only file), the last two in plaintext and for portability, a file secret warning at startup. | Owner's decision and approval, 2026-09-23 (M4a). The brief's "no plaintext secrets on disk" did not allow the file backend. | | 2026-09-23 | P15, State, the secrets line: three `SecretStore` backends chosen per secret (a systemd credential by default, an environment variable, an owner-only file), the last two in plaintext and for portability, a file secret warning at startup. | Owner's decision and approval, 2026-09-23 (M4a). The brief's "no plaintext secrets on disk" did not allow the file backend. |
| 2026-09-24 | P16, Network isolation 3: approvals are commands (`!approve`, `!deny`) replied in the approval's thread; emoji reactions are not used. | Owner's decision and approval, 2026-09-24; M4b spec `docs/specs/2026-09-24-m4b-approvals.md`. |
## Proposed changes to the design brief ## Proposed changes to the design brief
| # | Change | Reason | None pending.
|---|---|---|
| P16 | Network isolation 3: "v0 approvals use replies or emoji reactions" becomes "approvals are commands (`!approve`, `!deny`) replied in the approval's thread". The rest of the item stands: they arrive over the Mattermost WebSocket, so no callback URL is needed. | Owner's decision of 2026-09-24: reactions are not used. |
+3 -2
View File
@@ -64,8 +64,9 @@ ordinary outbound networking can reach the whole tailnet and the internet as the
2. `inferproxy` is a forwarder of about 100 lines: one Unix socket in, one fixed upstream out. The 2. `inferproxy` is a forwarder of about 100 lines: one Unix socket in, one fixed upstream out. The
upstream is the shared router's TCP listener on the host. It is required: `loopd` has no upstream is the shared router's TCP listener on the host. It is required: `loopd` has no
network, and the router stays on TCP for its other clients. network, and the router stays on TCP for its other clients.
3. `gatewayd` has outbound network only. It opens no listening TCP port. v0 approvals use replies 3. `gatewayd` has outbound network only. It opens no listening TCP port. Approvals are commands
or emoji reactions, which arrive over the Mattermost WebSocket, so no callback URL is needed. (`!approve`, `!deny`) replied in the approval's thread, which arrive over the Mattermost
WebSocket, so no callback URL is needed.
4. Tool containers get no network unless the grant names hosts. Granted network access goes through 4. Tool containers get no network unless the grant names hosts. Granted network access goes through
an allowlisting egress proxy that `brokerd` configures per call. an allowlisting egress proxy that `brokerd` configures per call.
5. Tailnet ACLs (kept in `deploy/`) limit the host's node to `llama-server` and Mattermost, plus 5. Tailnet ACLs (kept in `deploy/`) limit the host's node to `llama-server` and Mattermost, plus