fix(work): import hashlib and wire heal subparser into main CLI

This commit is contained in:
operator
2026-10-09 23:13:43 +00:00
parent c3b4b1cd28
commit f75977ca6e
202 changed files with 4185 additions and 4142 deletions
+82 -25
View File
@@ -25,6 +25,58 @@ import approvals
import gravity
def _load(name, relpath):
import importlib.util
spec = importlib.util.spec_from_file_location(name, REPO_ROOT / relpath)
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
return mod
box_ctl = _load("box_ctl_approvaltest", "bin/box-ctl.py")
super_cli = _load("super_cli_approvaltest", "bin/super-cli.py")
class _InProcResult:
"""Minimal CompletedProcess stand-in (returncode/stdout only)."""
def __init__(self, returncode, stdout):
self.returncode = returncode
self.stdout = stdout
def _box_ctl_inproc(*args):
"""In-process box-ctl call (proven pattern from test_box_loop_https).
Real main(argv): identical parsing, dispatch, audit, stdout JSON.
"""
import io
from contextlib import redirect_stdout
buf = io.StringIO()
returncode = 0
with redirect_stdout(buf):
try:
box_ctl.main(["box-ctl.py", *args])
except SystemExit as e:
returncode = e.code if isinstance(e.code, int) else 1
return _InProcResult(returncode, buf.getvalue())
def _super_cli_inproc(*args):
"""In-process super-cli call (main() reads sys.argv; patch it)."""
import io
from contextlib import redirect_stdout
buf = io.StringIO()
returncode = 0
with mock.patch.object(sys, "argv", ["super-cli.py", *args]):
with redirect_stdout(buf):
try:
super_cli.main()
except SystemExit as e:
returncode = e.code if isinstance(e.code, int) else 1
return _InProcResult(returncode, buf.getvalue())
class TestApprovalsModule(unittest.TestCase):
"""Test approvals.py core module functionality."""
@@ -79,8 +131,7 @@ class TestBoxApprovalsCli(unittest.TestCase):
"""Test 'box approvals' and 'box approval' CLI commands."""
def test_box_approvals_check_json(self):
cmd = [sys.executable, str(BIN_DIR / "super-cli.py"), "approvals", "check", "--json"]
r = subprocess.run(cmd, capture_output=True, text=True)
r = _super_cli_inproc("approvals", "check", "--json")
self.assertEqual(r.returncode, 0)
data = json.loads(r.stdout)
self.assertTrue(data.get("ok"))
@@ -88,15 +139,13 @@ class TestBoxApprovalsCli(unittest.TestCase):
self.assertIsInstance(data["approvals"], list)
def test_box_approval_alias(self):
cmd = [sys.executable, str(BIN_DIR / "super-cli.py"), "approval", "--json"]
r = subprocess.run(cmd, capture_output=True, text=True)
r = _super_cli_inproc("approval", "--json")
self.assertEqual(r.returncode, 0)
data = json.loads(r.stdout)
self.assertTrue(data.get("ok"))
def test_box_approvals_auto_json(self):
cmd = [sys.executable, str(BIN_DIR / "super-cli.py"), "approvals", "auto", "--node", "pip", "--json"]
r = subprocess.run(cmd, capture_output=True, text=True)
r = _super_cli_inproc("approvals", "auto", "--node", "pip", "--json")
self.assertEqual(r.returncode, 0)
data = json.loads(r.stdout)
self.assertTrue(data.get("ok"))
@@ -106,16 +155,14 @@ class TestBoxCtlApprovals(unittest.TestCase):
"""Test box-ctl.py allowlisted RPC actions."""
def test_box_ctl_approval_check(self):
cmd = [sys.executable, str(BIN_DIR / "box-ctl.py"), "approval-check"]
r = subprocess.run(cmd, capture_output=True, text=True)
r = _box_ctl_inproc("approval-check")
self.assertEqual(r.returncode, 0)
data = json.loads(r.stdout)
self.assertTrue(data.get("ok"))
self.assertIn("approvals", data)
def test_box_ctl_approval_auto(self):
cmd = [sys.executable, str(BIN_DIR / "box-ctl.py"), "approval-auto", "pip"]
r = subprocess.run(cmd, capture_output=True, text=True)
r = _box_ctl_inproc("approval-auto", "pip")
self.assertEqual(r.returncode, 0)
data = json.loads(r.stdout)
self.assertTrue(data.get("ok"))
@@ -162,6 +209,22 @@ class TestApprovalsReplySafety(unittest.TestCase):
class TestKeyApprovalsAndPasskey(unittest.TestCase):
"""Test key approval workflow and passkey retrieval architecture."""
def test_key_scan_tail_fallback_finds_old_request(self):
# A live request older than the tail cap must still resolve via the
# full-scan fallback (synthetic log; never touches real audit state).
with tempfile.TemporaryDirectory() as td:
p = Path(td) / "box-ctl.jsonl"
old = {"ts": "2026-01-01T00:00:00Z", "action": "key-approval-request",
"type": "key", "name": "dev", "reason": "buried-old-request",
"caller": "t", "expires_at": "2030-01-01T00:00:00Z"}
filler = {"ts": "2026-06-01T00:00:00Z", "action": "noop", "name": "x"}
lines = [json.dumps(old)] + [json.dumps(filler)] * (approvals.KEY_SCAN_TAIL_LINES + 10)
p.write_text("\n".join(lines) + "\n")
with mock.patch.object(approvals, "CTL_LOG", p):
res = approvals.check_node_key_request("dev")
self.assertIsNotNone(res)
self.assertEqual(res.get("reason"), "buried-old-request")
def test_request_and_resolve_key_approval(self):
req = approvals.request_key_approval("dev", reason="UnitTest passkey verification", caller="unit-test")
self.assertTrue(req.get("ok"))
@@ -188,8 +251,7 @@ class TestKeyApprovalsAndPasskey(unittest.TestCase):
self.assertIsNone(cleared)
def test_box_passkey_info_json(self):
cmd = [sys.executable, str(BIN_DIR / "super-cli.py"), "passkey", "--json"]
r = subprocess.run(cmd, capture_output=True, text=True)
r = _super_cli_inproc("passkey", "--json")
self.assertEqual(r.returncode, 0)
data = json.loads(r.stdout)
self.assertTrue(data.get("ok"))
@@ -199,8 +261,7 @@ class TestKeyApprovalsAndPasskey(unittest.TestCase):
self.assertEqual(data["key_location"]["canonical_path"], "/srv/box/passkey.txt")
def test_box_passkey_fetch_json(self):
cmd = [sys.executable, str(BIN_DIR / "super-cli.py"), "passkey", "fetch", "--json"]
r = subprocess.run(cmd, capture_output=True, text=True)
r = _super_cli_inproc("passkey", "fetch", "--json")
self.assertEqual(r.returncode, 0)
data = json.loads(r.stdout)
self.assertIn("operator_pin", data)
@@ -210,8 +271,7 @@ class TestKeyApprovalsAndPasskey(unittest.TestCase):
self.assertIn("operator_command", data)
def test_box_lookup_key(self):
cmd = [sys.executable, str(BIN_DIR / "super-cli.py"), "lookup", "key", "--json"]
r = subprocess.run(cmd, capture_output=True, text=True)
r = _super_cli_inproc("lookup", "key", "--json")
self.assertEqual(r.returncode, 0)
data = json.loads(r.stdout)
self.assertTrue(data.get("ok"))
@@ -219,29 +279,26 @@ class TestKeyApprovalsAndPasskey(unittest.TestCase):
def test_cli_request_key_lifecycle(self):
# 1. Request key
r_req = subprocess.run([
sys.executable, str(BIN_DIR / "super-cli.py"),
r_req = _super_cli_inproc(
"approvals", "request-key", "dev", "--reason", "CLI lifecycle test", "--json"
], capture_output=True, text=True)
)
self.assertEqual(r_req.returncode, 0)
req_data = json.loads(r_req.stdout)
self.assertTrue(req_data.get("ok"))
# 2. Check shows KEY_APPROVAL
r_check = subprocess.run([
sys.executable, str(BIN_DIR / "super-cli.py"),
r_check = _super_cli_inproc(
"approvals", "check", "--node", "dev", "--json"
], capture_output=True, text=True)
)
self.assertEqual(r_check.returncode, 0)
check_data = json.loads(r_check.stdout)
dev_app = next(a for a in check_data["approvals"] if a["node"] == "dev")
self.assertEqual(dev_app["status"], "KEY_APPROVAL")
# 3. Deny key
r_deny = subprocess.run([
sys.executable, str(BIN_DIR / "super-cli.py"),
r_deny = _super_cli_inproc(
"approvals", "deny", "dev", "--json"
], capture_output=True, text=True)
)
self.assertEqual(r_deny.returncode, 0)
deny_data = json.loads(r_deny.stdout)
self.assertTrue(deny_data.get("ok"))