Files
box/docs/BOX-APPROVALS-HTTPS.md
operator 0065d11e97 feat(supervision): add choice watcher daemon, HTTPS spec docs, and test suites
- bin/muse_choice_watcher.py + systemd/muse-choices-reconcile.*: automatic choice answering and timer reconciliation
- bin/digest.py: fleet log and health summarization
- docs/BOX-*-HTTPS.md: comprehensive HTTPS execution contracts and API documentation
- docs/MUSE-CHOICES-POLICY.md & docs/SUPERVISION-SPEC.md: autonomous execution specs
- tests/test_*.py: unit test suites for HTTPS API, choice watcher, fleet heal, and swarm pruning
2026-10-07 00:25:46 +00:00

4.0 KiB

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:

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):

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.