Skip to content
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.PHONY: validate validate-json validate-yaml validate-quadlet validate-render validate-evidence validate-governance validate-policy-fabric validate-activation validate-supply-chain validate-release-bundle validate-sourceos-projections validate-package validate-cli validate-formula doctor probe
.PHONY: validate validate-json validate-yaml validate-quadlet validate-render validate-evidence validate-governance validate-policy-fabric validate-agent-registry validate-superconscious-runtime-plan validate-activation validate-supply-chain validate-release-bundle validate-sourceos-projections validate-package validate-cli validate-formula validate-runtime-install-receipts doctor probe

PYTHON ?= python3
Expand All @@ -22,6 +23,7 @@ DECIDED_AT := 2026-05-04T12:51:00Z
PYCLI := PYTHONPATH=src $(PYTHON) -m agent_machine.cli
PYMOD := PYTHONPATH=src $(PYTHON) -m

validate: validate-json validate-yaml validate-quadlet validate-render validate-evidence validate-governance validate-policy-fabric validate-activation validate-supply-chain validate-release-bundle validate-sourceos-projections validate-package validate-cli validate-formula
validate: validate-json validate-yaml validate-quadlet validate-render validate-evidence validate-governance validate-policy-fabric validate-agent-registry validate-superconscious-runtime-plan validate-activation validate-supply-chain validate-release-bundle validate-sourceos-projections validate-package validate-cli validate-formula validate-runtime-install-receipts

validate-json:
Expand Down Expand Up @@ -69,7 +71,6 @@ validate-superconscious-runtime-plan:

validate-superconscious-runtime-plan:
$(PYTHON) scripts/validate-superconscious-runtime-plan.py

validate-activation:
$(PYTHON) scripts/validate-activation.py
$(PYTHON) scripts/evaluate-activation.py $(LOCAL_AGENTPOD) $(READY_POLICY) $(READY_GRANT) --deployment-receipt-id $(DEPLOYMENT_RECEIPT_ID) --storage-receipt-dir examples --decided-at $(DECIDED_AT) --decision-id urn:srcos:agent-machine:activation-decision:local-llama-cpp-allowed --pretty >/tmp/agent-machine-evaluate-activation-allowed.json
Expand Down
1 change: 1 addition & 0 deletions bin/agent-machine
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ Usage:
agent-machine render quadlet <agentpod.json> [--compare <file>]
agent-machine render k8s <agentpod.json> [--compare <file>]
agent-machine policy resolve <agentpod.json> --policy-dir <dir> --deployment-receipt-id <id> [--expected-status allowed]
agent-machine activate evaluate <agentpod.json> [policy.json] <grant.json> --deployment-receipt-id <id> [--policy-dir <dir>] [--storage-receipt-dir <dir>] [--pretty]
agent-machine registry resolve <agentpod.json> --grant-dir <dir> --requested-agent-identity-ref <ref> --session-ref <ref> [--expected-status active]
agent-machine activate evaluate <agentpod.json> [policy.json] <grant.json> --deployment-receipt-id <id> [--policy-dir <dir>] [--storage-receipt-dir <dir>] [--pretty]
agent-machine steer stub-response <request.json> [--status not_configured|noop] [--pretty]
Expand Down
96 changes: 96 additions & 0 deletions src/agent_machine/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,98 @@ def cmd_policy_resolve(args: argparse.Namespace) -> int:
policy_fabric = import_renderer(lambda: __import__("agent_machine.policy_fabric", fromlist=["_unused"]))
agentpod = load_json(args.agentpod_json)
policies = policy_fabric.load_policy_admissions(files=args.policy_file, directories=args.policy_dir, root=REPO_ROOT)
policy = policy_fabric.resolve_policy_admission(
policies=policies,
agentpod_id=str(agentpod.get("id")),
request_type=args.request_type,
deployment_receipt_id=args.deployment_receipt_id,
agent_machine_id=args.agent_machine_id,
provider_id=args.provider_id,
policy_id=args.policy_id,
expected_status=args.expected_status,
allow_missing_stub=not args.no_missing_stub,
decided_at=args.decided_at,
root=REPO_ROOT,
)
if args.pretty:
print(json.dumps(policy, indent=2, sort_keys=True))
else:
print(json.dumps(policy, sort_keys=True, separators=(",", ":")))
return 0


def resolve_activation_policy_and_grant(args: argparse.Namespace, agentpod: dict[str, Any], policy_fabric: Any) -> tuple[dict[str, Any], dict[str, Any]]:
"""Resolve activation policy/grant from explicit files or local policy store."""
policy_json = args.policy_json
grant_json = args.grant_json

# Backward-compatible shorthand:
# agent-machine activate evaluate <agentpod.json> <grant.json> --policy-dir examples ...
# argparse first assigns the single optional positional to policy_json, so we
# reinterpret it as grant_json when a policy store/resolver option is present.
resolver_requested = bool(args.policy_file or args.policy_dir or args.policy_id or args.expected_status)
if grant_json is None and policy_json is not None and resolver_requested:
grant_json = policy_json
policy_json = None

if grant_json is None:
raise AssertionError(
"grant JSON is required. Use either `<agentpod> <policy.json> <grant.json>` "
"or `<agentpod> <grant.json> --policy-dir <dir>`"
)

if policy_json is not None:
return load_json(policy_json), load_json(grant_json)

policies = policy_fabric.load_policy_admissions(
files=args.policy_file,
directories=args.policy_dir,
root=REPO_ROOT,
)
policy = policy_fabric.resolve_policy_admission(
policies=policies,
agentpod_id=str(agentpod.get("id")),
request_type="activation",
deployment_receipt_id=args.deployment_receipt_id,
agent_machine_id=args.agent_machine_id,
provider_id=args.provider_id,
policy_id=args.policy_id,
expected_status=args.expected_status,
allow_missing_stub=not args.no_missing_stub,
decided_at=args.decided_at,
root=REPO_ROOT,
)
return policy, load_json(grant_json)


def cmd_activate_evaluate(args: argparse.Namespace) -> int:
activation = import_renderer(lambda: __import__("agent_machine.activation", fromlist=["_unused"]))
policy_fabric = import_renderer(lambda: __import__("agent_machine.policy_fabric", fromlist=["_unused"]))
agentpod = load_json(args.agentpod_json)
policy, grant = resolve_activation_policy_and_grant(args, agentpod, policy_fabric)
storage_receipts = activation.load_storage_receipts(
files=args.storage_receipt_file,
directories=args.storage_receipt_dir,
)
storage_receipt_refs = list(args.storage_receipt_ref or [])
if not storage_receipt_refs and storage_receipts:
storage_receipt_refs = [str(receipt.get("id")) for receipt in storage_receipts]
decision = activation.evaluate_activation(
agentpod=agentpod,
policy=policy,
grant=grant,
deployment_receipt_id=args.deployment_receipt_id,
storage_receipt_refs=storage_receipt_refs,
storage_receipts=storage_receipts if storage_receipts else None,
decided_at=args.decided_at,
decision_id=args.decision_id,
root=REPO_ROOT,
)
activation.validate_activation_decision_payload(decision, REPO_ROOT)
if args.pretty:
print(json.dumps(decision, indent=2, sort_keys=True))
else:
print(json.dumps(decision, sort_keys=True, separators=(",", ":")))
policy = policy_fabric.resolve_policy_admission(policies=policies, agentpod_id=str(agentpod.get("id")), request_type=args.request_type, deployment_receipt_id=args.deployment_receipt_id, agent_machine_id=args.agent_machine_id, provider_id=args.provider_id, policy_id=args.policy_id, expected_status=args.expected_status, allow_missing_stub=not args.no_missing_stub, decided_at=args.decided_at, root=REPO_ROOT)
print(json.dumps(policy, indent=2 if args.pretty else None, sort_keys=True))
return 0
Expand Down Expand Up @@ -394,6 +486,7 @@ def build_parser() -> argparse.ArgumentParser:
render_k8s.add_argument("agentpod_json", type=Path)
render_k8s.add_argument("--compare", type=Path)
render_k8s.set_defaults(func=cmd_render_k8s)

policy = subcommands.add_parser("policy", help="Resolve Policy Fabric admission artifacts")
policy_subcommands = policy.add_subparsers(dest="policy_command", required=True)
policy_resolve = policy_subcommands.add_parser("resolve", help="Resolve a PolicyAdmission from local files/stores")
Expand Down Expand Up @@ -428,6 +521,9 @@ def build_parser() -> argparse.ArgumentParser:
activate_evaluate.add_argument("--policy-dir", action="append", type=Path, default=[])
activate_evaluate.add_argument("--policy-id")
activate_evaluate.add_argument("--expected-status", choices=["missing", "allowed", "denied", "not-required", "unknown"])
activate_evaluate.add_argument("--no-missing-stub", action="store_true")
activate_evaluate.add_argument("--agent-machine-id")
activate_evaluate.add_argument("--provider-id")
add_registry_resolver_args(activate_evaluate)
activate_evaluate.add_argument("--storage-receipt-ref", action="append", default=[])
activate_evaluate.add_argument("--storage-receipt-file", action="append", type=Path, default=[])
Expand Down
Loading