approvals: stale-wait cleanup, key-decision notify, TTLs, key/browser isolation
- bin/approvals.py: responded-wait filtering + auto-mark, key-decision sidechat-first notify (notified flag, --message, --allow-main-chat), TTL defaults (input 30m / browser 30m / key 2h), cross-type guard (browser actions cannot resolve key requests), sweep_expired_key_requests; restores check_node_key_request fallback in inspect_node_approvals - bin/box-ctl.py + bin/super-cli.py (approvals hunks only): --message/--allow-main-chat passthrough on allow/deny, clear/clear-all actions, def sidechat routing; restores sys.exit(1) on dismiss failure - bin/fleet-alert-check.sh: TTL-aware state_machine (EXPIRED action), auto-deny expired browser approvals (fail closed), auto-dismiss expired input waits, targeted per-agent DM for input waits - bin/job-dispatch.py + bin/gravity.py: KEY_APPROVAL excluded from auto-approval Reviewed by 5 independent reviewers (all APPROVE/APPROVE WITH NOTES); integration gate GO (17/17 tests). TUI hunks in super-cli.py intentionally excluded.
This commit is contained in:
+27
-10
@@ -58,6 +58,7 @@ NOTIFY_SIDECHATS = {
|
||||
"pip": "pip tasks",
|
||||
"muse": "muse tasks",
|
||||
"dev": "onboarding-dev",
|
||||
"def": "def tasks",
|
||||
}
|
||||
VALID_ON_FAILURE = {"retry", "alert", "ignore"}
|
||||
KNOWN_PLACEHOLDERS = {"job_id", "job_name", "datetime", "date", "last_run"}
|
||||
@@ -989,12 +990,13 @@ def act_approval_check(node=None):
|
||||
out(True, approvals=res)
|
||||
|
||||
|
||||
def act_approval_allow(node, always=False, force=False):
|
||||
def act_approval_allow(node, always=False, force=False, message=None, allow_main_chat=False):
|
||||
audit("approval-allow", node)
|
||||
if node not in VALID_AGENTS:
|
||||
fail("BAD_NODE", f"unknown node: {node}")
|
||||
import approvals
|
||||
res = approvals.allow_node_approval(node, always=always, force=force, caller="box-ctl")
|
||||
res = approvals.allow_node_approval(node, always=always, force=force, caller="box-ctl",
|
||||
message=message, allow_main_chat=allow_main_chat)
|
||||
if res.get("ok"):
|
||||
kw = {k: v for k, v in res.items() if k != "ok"}
|
||||
out(True, **kw)
|
||||
@@ -1002,12 +1004,13 @@ def act_approval_allow(node, always=False, force=False):
|
||||
fail("APPROVAL_FAILED", res.get("error", "approval failed"), res)
|
||||
|
||||
|
||||
def act_approval_deny(node):
|
||||
def act_approval_deny(node, message=None, allow_main_chat=False):
|
||||
audit("approval-deny", node)
|
||||
if node not in VALID_AGENTS:
|
||||
fail("BAD_NODE", f"unknown node: {node}")
|
||||
import approvals
|
||||
res = approvals.deny_node_approval(node, caller="box-ctl")
|
||||
res = approvals.deny_node_approval(node, caller="box-ctl",
|
||||
message=message, allow_main_chat=allow_main_chat)
|
||||
if res.get("ok"):
|
||||
kw = {k: v for k, v in res.items() if k != "ok"}
|
||||
out(True, **kw)
|
||||
@@ -3563,16 +3566,30 @@ def main(argv):
|
||||
act_approval_check(node)
|
||||
elif action in ("approval-allow", "approval-approve"):
|
||||
if not rest:
|
||||
fail("BAD_ARGS", "usage: approval-allow <node> [--always] [--force]")
|
||||
fail("BAD_ARGS", "usage: approval-allow <node> [--always] [--force] [--message TEXT] [--allow-main-chat]")
|
||||
node = rest[0]
|
||||
always = "--always" in rest[1:]
|
||||
force = "--force" in rest[1:]
|
||||
act_approval_allow(node, always=always, force=force)
|
||||
rest_args = rest[1:]
|
||||
always = "--always" in rest_args
|
||||
force = "--force" in rest_args
|
||||
allow_main_chat = "--allow-main-chat" in rest_args
|
||||
message = None
|
||||
if "--message" in rest_args:
|
||||
mi = rest_args.index("--message")
|
||||
if mi + 1 < len(rest_args):
|
||||
message = rest_args[mi + 1]
|
||||
act_approval_allow(node, always=always, force=force, message=message, allow_main_chat=allow_main_chat)
|
||||
elif action == "approval-deny":
|
||||
if not rest:
|
||||
fail("BAD_ARGS", "usage: approval-deny <node>")
|
||||
fail("BAD_ARGS", "usage: approval-deny <node> [--message TEXT] [--allow-main-chat]")
|
||||
node = rest[0]
|
||||
act_approval_deny(node)
|
||||
rest_args = rest[1:]
|
||||
allow_main_chat = "--allow-main-chat" in rest_args
|
||||
message = None
|
||||
if "--message" in rest_args:
|
||||
mi = rest_args.index("--message")
|
||||
if mi + 1 < len(rest_args):
|
||||
message = rest_args[mi + 1]
|
||||
act_approval_deny(node, message=message, allow_main_chat=allow_main_chat)
|
||||
elif action == "approval-auto":
|
||||
node = rest[0] if rest else None
|
||||
act_approval_auto(node)
|
||||
|
||||
Reference in New Issue
Block a user