From 3aa5fbf6224f150826969069dd7005af4df3682e Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Fri, 22 May 2026 13:29:41 -0400 Subject: [PATCH 1/2] Add AgentRegistryGrant CLI resolution and activation grant-store wiring --- src/agent_machine/cli.py | 106 ++++++++++++++++++++++++++++++++++----- 1 file changed, 93 insertions(+), 13 deletions(-) diff --git a/src/agent_machine/cli.py b/src/agent_machine/cli.py index a1abb88..e353e4a 100644 --- a/src/agent_machine/cli.py +++ b/src/agent_machine/cli.py @@ -220,27 +220,82 @@ def cmd_policy_resolve(args: argparse.Namespace) -> int: 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]]: +def agentpod_workload_default(agentpod: dict[str, Any], key: str) -> str | None: + value = agentpod.get("workload", {}).get(key) + return value if isinstance(value, str) and value else None + + +def resolve_registry_grant_from_args(args: argparse.Namespace, agentpod: dict[str, Any], agent_registry: Any) -> dict[str, Any]: + requested_agent_identity_ref = args.requested_agent_identity_ref or agentpod_workload_default(agentpod, "agentIdentityRef") + session_ref = args.session_ref + if not requested_agent_identity_ref: + raise AssertionError("requested agent identity ref is required; pass --requested-agent-identity-ref or set workload.agentIdentityRef") + if not session_ref: + raise AssertionError("session ref is required when resolving AgentRegistryGrant; pass --session-ref") + requested_scope = agent_registry.requested_scope_from_inputs( + provider_id=args.provider_id, + model_ref=args.model_ref, + tool_refs=args.tool_ref, + storage_scope_ref=args.storage_scope_ref, + evidence_scope_ref=args.evidence_scope_ref, + ) + grants = agent_registry.load_agent_registry_grants(files=args.grant_file, directories=args.grant_dir, root=REPO_ROOT) + return agent_registry.resolve_agent_registry_grant( + grants=grants, + agentpod_id=str(agentpod.get("id")), + requested_agent_identity_ref=requested_agent_identity_ref, + session_ref=session_ref, + agent_machine_id=args.agent_machine_id, + workroom_ref=args.workroom_ref or agentpod_workload_default(agentpod, "workroomRef"), + topic_ref=args.topic_ref or agentpod_workload_default(agentpod, "topicRef"), + grant_id=args.grant_id, + expected_status=args.expected_grant_status, + allow_missing_stub=not args.no_missing_stub, + issued_at=args.issued_at, + requested_scope=requested_scope, + requested_expires_at=args.requested_expires_at, + root=REPO_ROOT, + ) + + +def cmd_registry_resolve(args: argparse.Namespace) -> int: + agent_registry = import_renderer(lambda: __import__("agent_machine.agent_registry", fromlist=["_unused"])) + agentpod = load_json(args.agentpod_json) + grant = resolve_registry_grant_from_args(args, agentpod, agent_registry) + print(json.dumps(grant, indent=2 if args.pretty else None, sort_keys=True)) + return 0 + + +def resolve_activation_policy_and_grant(args: argparse.Namespace, agentpod: dict[str, Any], policy_fabric: Any, agent_registry: Any) -> tuple[dict[str, Any], dict[str, Any]]: policy_json = args.policy_json grant_json = args.grant_json - 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: + policy_resolver_requested = bool(args.policy_file or args.policy_dir or args.policy_id or args.expected_status) + grant_resolver_requested = bool(args.grant_file or args.grant_dir or args.grant_id or args.expected_grant_status) + if grant_json is None and policy_json is not None and policy_resolver_requested and not grant_resolver_requested: grant_json = policy_json policy_json = None - if grant_json is None: - raise AssertionError("grant JSON is required. Use either ` ` or ` --policy-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) + policy = load_json(policy_json) + else: + 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) + + if grant_json is not None: + grant = load_json(grant_json) + elif grant_resolver_requested: + grant = resolve_registry_grant_from_args(args, agentpod, agent_registry) + else: + raise AssertionError("grant JSON is required unless --grant-file/--grant-dir resolver inputs are provided") + return policy, grant 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"])) + agent_registry = import_renderer(lambda: __import__("agent_machine.agent_registry", fromlist=["_unused"])) agentpod = load_json(args.agentpod_json) - policy, grant = resolve_activation_policy_and_grant(args, agentpod, policy_fabric) + policy, grant = resolve_activation_policy_and_grant(args, agentpod, policy_fabric, agent_registry) 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: @@ -283,6 +338,26 @@ def cmd_steer_resolve_artifacts(args: argparse.Namespace) -> int: return 0 +def add_registry_resolver_args(parser: argparse.ArgumentParser) -> None: + parser.add_argument("--grant-file", action="append", type=Path, default=[]) + parser.add_argument("--grant-dir", action="append", type=Path, default=[]) + parser.add_argument("--requested-agent-identity-ref") + parser.add_argument("--session-ref") + parser.add_argument("--agent-machine-id") + parser.add_argument("--workroom-ref") + parser.add_argument("--topic-ref") + parser.add_argument("--grant-id") + parser.add_argument("--expected-grant-status", choices=["missing", "active", "expired", "revoked", "denied", "unknown"]) + parser.add_argument("--no-missing-stub", action="store_true") + parser.add_argument("--provider-id") + parser.add_argument("--model-ref") + parser.add_argument("--tool-ref", action="append", default=[]) + parser.add_argument("--storage-scope-ref") + parser.add_argument("--evidence-scope-ref") + parser.add_argument("--requested-expires-at") + parser.add_argument("--issued-at", default="1970-01-01T00:00:00Z") + + def build_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser(description="Agent Machine Python CLI") subcommands = parser.add_subparsers(dest="command", required=True) @@ -333,6 +408,13 @@ def build_parser() -> argparse.ArgumentParser: policy_resolve.add_argument("--decided-at", default="1970-01-01T00:00:00Z") policy_resolve.add_argument("--pretty", action="store_true") policy_resolve.set_defaults(func=cmd_policy_resolve) + registry = subcommands.add_parser("registry", help="Resolve Agent Registry grant artifacts") + registry_subcommands = registry.add_subparsers(dest="registry_command", required=True) + registry_resolve = registry_subcommands.add_parser("resolve", help="Resolve an AgentRegistryGrant from local files/stores") + registry_resolve.add_argument("agentpod_json", type=Path) + add_registry_resolver_args(registry_resolve) + registry_resolve.add_argument("--pretty", action="store_true") + registry_resolve.set_defaults(func=cmd_registry_resolve) activate = subcommands.add_parser("activate", help="Evaluate activation readiness") activate_subcommands = activate.add_subparsers(dest="activate_command", required=True) activate_evaluate = activate_subcommands.add_parser("evaluate", help="Evaluate AgentPod activation decision") @@ -344,9 +426,7 @@ 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=[]) activate_evaluate.add_argument("--storage-receipt-dir", action="append", type=Path, default=[]) From dfad883b4617f2d5c0e68c44eaa416bfa07ef568 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Fri, 22 May 2026 13:30:31 -0400 Subject: [PATCH 2/2] Validate Python CLI registry resolver and activation grant-store path --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b213b51..dc75bc0 100644 --- a/Makefile +++ b/Makefile @@ -62,6 +62,7 @@ validate-policy-fabric: validate-agent-registry: $(PYTHON) scripts/validate-agent-registry.py $(PYTHON) scripts/resolve-agent-registry-grant.py $(LOCAL_AGENTPOD) --grant-dir $(GRANT_DIR) --grant-id urn:srcos:agent-machine:agent-registry-grant:active-loopback-activation --requested-agent-identity-ref urn:srcos:agent:local-inference-provider --session-ref urn:srcos:session:local-bootstrap --agent-machine-id urn:srcos:agent-machine:m2-asahi-local --pretty >/tmp/agent-machine-registry-resolve-active.json + $(PYCLI) registry resolve $(LOCAL_AGENTPOD) --grant-dir $(GRANT_DIR) --grant-id urn:srcos:agent-machine:agent-registry-grant:active-loopback-activation --session-ref urn:srcos:session:local-bootstrap --agent-machine-id urn:srcos:agent-machine:m2-asahi-local --pretty >/tmp/agent-machine-pycli-registry-resolve-active.json validate-superconscious-runtime-plan: $(PYTHON) scripts/validate-superconscious-runtime-plan.py @@ -71,6 +72,7 @@ validate-activation: $(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 $(PYCLI) activate evaluate $(LOCAL_AGENTPOD) $(FAIL_POLICY) $(FAIL_GRANT) --deployment-receipt-id $(DEPLOYMENT_RECEIPT_ID) --storage-receipt-dir $(RECEIPT_DIR) --decided-at $(DECIDED_AT) --decision-id urn:srcos:agent-machine:activation-decision:local-llama-cpp-fail-closed --pretty >/tmp/agent-machine-pycli-evaluate-activation-fail-closed.json $(PYCLI) activate evaluate $(LOCAL_AGENTPOD) $(READY_GRANT) --policy-dir $(POLICY_DIR) --expected-status allowed --deployment-receipt-id $(DEPLOYMENT_RECEIPT_ID) --agent-machine-id urn:srcos:agent-machine:m2-asahi-local --provider-id urn:srcos:agent-machine:inference-provider:asahi-llama-cpp --storage-receipt-dir $(RECEIPT_DIR) --decided-at $(DECIDED_AT) --decision-id urn:srcos:agent-machine:activation-decision:local-llama-cpp-allowed --pretty >/tmp/agent-machine-pycli-resolved-policy-activation-allowed.json + $(PYCLI) activate evaluate $(LOCAL_AGENTPOD) --policy-dir $(POLICY_DIR) --expected-status allowed --grant-dir $(GRANT_DIR) --grant-id urn:srcos:agent-machine:agent-registry-grant:active-loopback-activation --session-ref urn:srcos:session:local-bootstrap --deployment-receipt-id $(DEPLOYMENT_RECEIPT_ID) --agent-machine-id urn:srcos:agent-machine:m2-asahi-local --provider-id urn:srcos:agent-machine:inference-provider:asahi-llama-cpp --storage-receipt-dir $(RECEIPT_DIR) --decided-at $(DECIDED_AT) --decision-id urn:srcos:agent-machine:activation-decision:local-llama-cpp-allowed --pretty >/tmp/agent-machine-pycli-resolved-policy-grant-activation-allowed.json $(BOOTSTRAP_CLI) activate evaluate $(LOCAL_AGENTPOD) $(READY_POLICY) $(READY_GRANT) --deployment-receipt-id $(DEPLOYMENT_RECEIPT_ID) --storage-receipt-dir $(RECEIPT_DIR) --decided-at $(DECIDED_AT) --decision-id urn:srcos:agent-machine:activation-decision:local-llama-cpp-allowed --pretty >/tmp/agent-machine-bootstrap-evaluate-activation-allowed.json validate-supply-chain: @@ -117,4 +119,4 @@ doctor: $(BOOTSTRAP_CLI) doctor --format json probe: - $(BOOTSTRAP_CLI) probe --format json + $(BOOTSTRAP_CLI) probe --format json \ No newline at end of file