Files
box/docs/BOX-APPROVALS-HTTPS.md
T

93 lines
4.0 KiB
Markdown
Raw Normal View History

# Box Approvals over HTTPS (No SSH)
> **Box is the main surface.** All operator work goes through Box (box.muse-dev.online). The web UI, `box` CLI, and agents share the same API endpoints. No UI-only powers.
**Date:** 2026-10-06
**Status:** implemented on bl (`exec-constrained.py` + `box-relay.sh`;
`box-ctl.py` verbs pre-existed, plus fast node validation and
`quality-validate` branches; `approvals.py` untouched)
**Scope:** approval visibility (check) + governed decisions (deny, auto,
one-shot allow). Persistent/forced allow (`--always`/`--force`) stays
SSH-only.
## 1. Why
Agents blocked on browser approvals needed SSH to see fleet approval
state, deny a bad prompt, auto-resolve trusted prompts, or allow a
known-good one. All of this now rides the agent HTTPS path
(`https://exec.muse-dev.online/exec`, signature or Bearer [REDACTED], named-op
allowlist, audit log).
## 2. New ops
| Op | Args | Backend | Access |
|---|---|---|---|
| `approval.check` | `{node?}` (default fleet) | `box-ctl.py approval-check` | read-only, in `DEFAULT_PERMS` |
| `approval.deny` | `{node!, message!, allow_main_chat?}` | `box-ctl.py approval-deny` | known-identities-only |
| `approval.auto` | `{node?}` (default fleet) | `box-ctl.py approval-auto` | known-identities-only |
| `approval.allow` | `{node!, message!, allow_main_chat?}` | `box-ctl.py approval-allow` (one-shot) | known-identities-only |
New `box-relay.sh` client commands:
```bash
box approvals check [node]
box approvals allow <node> --message <text> [--allow-main-chat]
box approvals deny <node> --message <text> [--allow-main-chat]
box approvals auto [node]
```
Raw op calls (signature auth, no token):
```bash
exec-sign.sh approval.check '{}'
exec-sign.sh approval.check '{"node": "646"}'
exec-sign.sh approval.allow '{"node": "646", "message": "trusted deploy script"}'
exec-sign.sh approval.auto '{"node": "opm"}'
```
## 3. What the decisions do
- `approval.allow` clicks Allow **once** on the node's active prompt.
There is deliberately no remote `--always` (persistent site allow)
or `--force`.
- `approval.deny` clicks Deny on the node's active prompt.
- `approval.auto` scans (fleet or one node) and allows only TRUSTED
non-key prompts. Key/passkey approvals are never auto-approved;
they need an explicit allow/deny, which notifies the waiting agent.
- All three are audited with identity + op + node.
## 4. Safety notes (same posture as existing ops)
- **Attribution is mandatory.** The allow/deny flows DM the waiting
agent, historically with an `[operator]` prefix. A remote caller is
an agent, not the operator — so the exec layer **requires** a
non-empty `message` (≤2000 chars, no controls) on both allow and
deny. (`box-ctl.py` still permits omitting `--message` for SSH
callers; the HTTPS layer is the narrower gate.)
- **One-shot only.** The allow argv never carries `--always` or
`--force`; the validators reject those keys. Persistence stays an
SSH-side decision.
- **Sidechat-first.** `allow_main_chat` defaults to false; Main Chat
delivery needs the explicit flag, same as `notify`/`dm.ack`.
- **Fixed argv, validated values.** Nodes must be fleet members (fast
`BAD_NODE` before any CDP probe — `approval-check`/`approval-auto`
gained the same node check allow/deny already had); unknown arg
keys rejected.
- **Timeouts.** Check 180s (fleet CDP scan), auto 300s (scan plus one
click per trusted prompt), allow/deny 120s.
- **Retry-safe reads.** `approval-check` / `approval-list` joined
`IDEMPOTENT_ACTIONS`; all six approval verbs have
`quality-validate` dry-run branches.
## 5. Rollout notes
- Restart `exec-constrained.py` after deploy for the 4 new ops to
appear in `GET /ops` (repo total becomes 83).
- `box-relay.sh` is served from bl (`GET /box`); agents re-fetch to
get the `approvals` group.
- While fleet browsers crash-loop, decision ops fail honestly
(`APPROVAL_FAILED` / CDP errors) instead of hanging; check still
reports per-node state including `UNREACHABLE`.
- Non-goals: deletes, `main-loop` enable/disable, policy writes,
swarm kill/prune — future expansions, same pattern.