Files
CASAN/packages/casan-harness/scripts/python/kernel_cli.py
T

157 lines
4.7 KiB
Python

#!/usr/bin/env python3
"""CLI boundary for shell/native runtimes to consume Assurance Kernel policy."""
from __future__ import annotations
import argparse
import json
import os
import sys
from pathlib import Path
HARNESS_ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(HARNESS_ROOT))
from kernel.adapters import NativeHarnessAdapter # noqa: E402
from kernel.contracts import validate_bundle # noqa: E402
from kernel.policy import ( # noqa: E402
H2GateContext,
evaluate_h2_gate,
evaluate_registry_configuration,
evaluate_risk,
evaluate_trust_capabilities,
)
def _print(payload: object) -> None:
print(json.dumps(payload, sort_keys=True, separators=(",", ":")))
def _read_content(path: str | None) -> str:
if not path:
return ""
with open(path, encoding="utf-8") as handle:
return handle.read()
def _append_jsonl(path: str, payload: object) -> None:
target = Path(path)
target.parent.mkdir(parents=True, exist_ok=True)
data = (json.dumps(payload, sort_keys=True, separators=(",", ":")) + "\n").encode("utf-8")
fd = os.open(str(target), os.O_WRONLY | os.O_CREAT | os.O_APPEND, 0o600)
try:
try:
import fcntl
fcntl.flock(fd, fcntl.LOCK_EX)
except (ImportError, OSError):
pass
os.write(fd, data)
os.fsync(fd)
finally:
os.close(fd)
def cmd_risk(args: argparse.Namespace) -> int:
payload = evaluate_risk(
action=args.action,
tool=args.tool,
resource=args.resource,
command=args.command,
content=_read_content(args.content_file),
actor=args.actor,
environment=args.environment,
)
_print(payload)
return 0
def cmd_registry(args: argparse.Namespace) -> int:
payload = evaluate_registry_configuration(args.mode, args.profile, args.explicit)
if args.evidence_log:
_append_jsonl(args.evidence_log, payload)
_print(payload)
return 0 if payload["valid"] else 2
def cmd_h2(args: argparse.Namespace) -> int:
context = H2GateContext(
mode=args.mode,
actor=args.actor,
action=args.action,
tool=args.tool,
execution_id=args.execution_id,
enforcement_path=args.enforcement_path,
idempotency_key=args.idempotency_key,
timeout_seconds=args.timeout,
)
payload = evaluate_h2_gate(args.gate, context, bash_path=args.bash)
if args.evidence_log:
_append_jsonl(args.evidence_log, payload)
_print(payload)
return 0 if payload["execution_allowed"] else 2
def cmd_trust(_args: argparse.Namespace) -> int:
payload = evaluate_trust_capabilities()
_print(payload)
return 0 if payload["ready"] else 2
def cmd_native(args: argparse.Namespace) -> int:
event = json.load(sys.stdin) if args.event_file == "-" else json.load(open(args.event_file, encoding="utf-8"))
payload = NativeHarnessAdapter().map_execution(event)
errors = validate_bundle(payload)
if errors:
_print({"valid": False, "errors": errors, "bundle": payload})
return 2
_print(payload)
return 0
def parser() -> argparse.ArgumentParser:
root = argparse.ArgumentParser()
sub = root.add_subparsers(dest="command", required=True)
risk = sub.add_parser("risk")
for name in ("action", "tool", "resource", "command", "actor", "environment"):
risk.add_argument(f"--{name}", default="")
risk.add_argument("--content-file")
risk.set_defaults(func=cmd_risk)
registry = sub.add_parser("registry-config")
registry.add_argument("--mode", default="observe")
registry.add_argument("--profile", default="development")
registry.add_argument("--explicit")
registry.add_argument("--evidence-log")
registry.set_defaults(func=cmd_registry)
h2 = sub.add_parser("h2-gate")
h2.add_argument("--gate", required=True)
h2.add_argument("--mode", choices=("observe", "enforce"), required=True)
h2.add_argument("--actor", default="")
h2.add_argument("--action", required=True)
h2.add_argument("--tool", required=True)
h2.add_argument("--execution-id", required=True)
h2.add_argument("--enforcement-path", required=True)
h2.add_argument("--idempotency-key", required=True)
h2.add_argument("--timeout", type=float, default=8.0)
h2.add_argument("--bash", default="bash")
h2.add_argument("--evidence-log")
h2.set_defaults(func=cmd_h2)
trust = sub.add_parser("trust-capabilities")
trust.set_defaults(func=cmd_trust)
native = sub.add_parser("adapt-native")
native.add_argument("event_file")
native.set_defaults(func=cmd_native)
return root
def main() -> int:
args = parser().parse_args()
return int(args.func(args))
if __name__ == "__main__":
raise SystemExit(main())