diff --git a/Makefile b/Makefile index d980792..5356c57 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,12 @@ -.PHONY: validate validate-resource-contract validate-measurement validate-value-type validate-source-locator validate-sourceos-repo-manifest validate-mesh-action-registry validate-control-plane-examples validate-nlboot-examples validate-lattice-data-governai-examples validate-ops-history-examples validate-runtime-observability-examples validate-interpretability-examples validate-lifecycle-boundary-examples validate-svf-contracts validate-sync-cycle-receipts validate-onboarding-examples validate-runtime-causality-examples validate-agentic-os-examples validate-triparty-examples validate-labor-market-examples validate-supply-chain-risk-examples validate-reasoning-examples validate-mpcc-event-examples validate-knowledge-nugget-examples validate-semantic-action-examples validate-epistemic-kernel-examples validate-ab-update-examples validate-device-service-examples validate-duplicate-schema-ids validate-lawful-dispatch-receipt validate-architectural-building-block validate-measurement +.PHONY: validate validate-resource-contract validate-measurement validate-value-type validate-source-locator validate-sourceos-repo-manifest validate-mesh-action-registry validate-control-plane-examples validate-nlboot-examples validate-lattice-data-governai-examples validate-ops-history-examples validate-runtime-observability-examples validate-interpretability-examples validate-lifecycle-boundary-examples validate-svf-contracts validate-sync-cycle-receipts validate-onboarding-examples validate-runtime-causality-examples validate-agentic-os-examples validate-triparty-examples validate-labor-market-examples validate-supply-chain-risk-examples validate-reasoning-examples validate-mpcc-event-examples validate-knowledge-nugget-examples validate-semantic-action-examples validate-epistemic-kernel-examples validate-ab-update-examples validate-device-service-examples validate-duplicate-schema-ids validate-lawful-dispatch-receipt validate-architectural-building-block validate-agent-passport-examples validate-measurement -validate: validate-control-plane-examples validate-nlboot-examples validate-lattice-data-governai-examples validate-ops-history-examples validate-runtime-observability-examples validate-interpretability-examples validate-lifecycle-boundary-examples validate-svf-contracts validate-sync-cycle-receipts validate-onboarding-examples validate-runtime-causality-examples validate-agentic-os-examples validate-triparty-examples validate-labor-market-examples validate-supply-chain-risk-examples validate-reasoning-examples validate-mpcc-event-examples validate-knowledge-nugget-examples validate-semantic-action-examples validate-epistemic-kernel-examples validate-ab-update-examples validate-device-service-examples validate-duplicate-schema-ids validate-value-type validate-source-locator validate-sourceos-repo-manifest validate-mesh-action-registry validate-lawful-dispatch-receipt validate-architectural-building-block validate-measurement validate-resource-contract +validate: validate-control-plane-examples validate-nlboot-examples validate-lattice-data-governai-examples validate-ops-history-examples validate-runtime-observability-examples validate-interpretability-examples validate-lifecycle-boundary-examples validate-svf-contracts validate-sync-cycle-receipts validate-onboarding-examples validate-runtime-causality-examples validate-agentic-os-examples validate-triparty-examples validate-labor-market-examples validate-supply-chain-risk-examples validate-reasoning-examples validate-mpcc-event-examples validate-knowledge-nugget-examples validate-semantic-action-examples validate-epistemic-kernel-examples validate-ab-update-examples validate-device-service-examples validate-duplicate-schema-ids validate-value-type validate-source-locator validate-sourceos-repo-manifest validate-mesh-action-registry validate-lawful-dispatch-receipt validate-architectural-building-block validate-agent-passport-examples validate-measurement validate-resource-contract @echo "OK: validate" +validate-agent-passport-examples: + python3 -m pip install --user jsonschema >/dev/null + python3 tools/validate_agent_passport_examples.py + validate-source-locator: python3 tools/validate_source_locator.py diff --git a/examples/agent-passport.intelligence-automation.json b/examples/agent-passport.intelligence-automation.json new file mode 100644 index 0000000..d2bbc50 --- /dev/null +++ b/examples/agent-passport.intelligence-automation.json @@ -0,0 +1,16 @@ +{ + "type": "AgentPassport", + "bundle_id": "com.apple.Siri.ActionPredictionNotifications", + "binary_path": "/System/Library/PrivateFrameworks/SiriActionPrediction.framework", + "agent_class": "intelligence_automation", + "is_daemon": true, + "is_apple_signed": true, + "suppress_user_authorization_prompt": false, + "system_bundle": true, + "summarize_previews_permitted": false, + "dnd_intelligent_management_permitted": false, + "autonomous_action_permitted": false, + "interrupt_level": "time_sensitive", + "attested_at": "2026-06-09T14:00:00Z", + "attestation_source": "urn:srcos:agent-machine:attest" +} diff --git a/examples/agent-passport.json b/examples/agent-passport.json new file mode 100644 index 0000000..e39611c --- /dev/null +++ b/examples/agent-passport.json @@ -0,0 +1,14 @@ +{ + "type": "AgentPassport", + "bundle_id": "com.anthropic.claudefordesktop", + "binary_path": "/Applications/Claude.app/Contents/MacOS/Claude", + "agent_class": "third_party", + "is_daemon": false, + "is_apple_signed": false, + "suppress_user_authorization_prompt": false, + "system_bundle": false, + "interrupt_level": "standard", + "capability_exceptions": [], + "attested_at": "2026-06-09T14:00:00Z", + "attestation_source": "urn:srcos:agent-machine:attest" +} diff --git a/examples/agent-passport.system-core.json b/examples/agent-passport.system-core.json new file mode 100644 index 0000000..6104dd9 --- /dev/null +++ b/examples/agent-passport.system-core.json @@ -0,0 +1,13 @@ +{ + "type": "AgentPassport", + "bundle_id": "com.apple.sharingd", + "binary_path": "/usr/libexec/sharingd", + "agent_class": "system_core", + "is_daemon": true, + "is_apple_signed": true, + "suppress_user_authorization_prompt": true, + "system_bundle": true, + "interrupt_level": "critical", + "attested_at": "2026-06-09T14:00:00Z", + "attestation_source": "urn:srcos:agent-machine:attest" +} diff --git a/schemas/AgentPassport.json b/schemas/AgentPassport.json new file mode 100644 index 0000000..309d44a --- /dev/null +++ b/schemas/AgentPassport.json @@ -0,0 +1,180 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/AgentPassport.json", + "title": "AgentPassport", + "description": "Canonical typed classification for an agent or service observed on a SourceOS-managed host. Formalizes the five-class agent model (system_core, intelligence_automation, app_helper, legacy_bridge, third_party) that governs execution authorization, spatial permissions, and intelligence constraints across the SourceOS estate. Complementary to the Agent Plane family (AgentSession/ExecutionDecision/ExecutionSurface), which operate at workflow/session level; AgentPassport is host-level process classification. Canonical instance URN: urn:srcos:agent-passport:. Schema version 1.0.0. Cross-field invariants (documented on the relevant properties) are authoritatively enforced by SHACL in ontogenesis (T1-4); the JSON-Schema-expressible subset is additionally enforced here via the allOf/if-then rules at the end of this schema.", + "type": "object", + "additionalProperties": false, + "required": [ + "bundle_id", + "agent_class", + "is_daemon", + "is_apple_signed", + "suppress_user_authorization_prompt", + "system_bundle", + "interrupt_level" + ], + "properties": { + "type": { + "const": "AgentPassport", + "description": "Object discriminator, matching the repo convention (examples are mapped to their schema by this field). Optional so minimal downstream fixtures remain valid." + }, + "bundle_id": { + "type": "string", + "minLength": 1, + "description": "Stable process identity (e.g. com.anthropic.claudefordesktop). The canonical passport URN is urn:srcos:agent-passport:." + }, + "pid": { + "type": "integer", + "minimum": 0, + "description": "SESSION-SCOPED process id (non-negative). NOT a stable identifier: it is reused across processes and reboots and must never be used for cross-session correlation or authorization." + }, + "binary_path": { + "type": "string", + "description": "Last known binary path on the host." + }, + "agent_class": { + "type": "string", + "enum": [ + "system_core", + "intelligence_automation", + "app_helper", + "legacy_bridge", + "third_party" + ], + "description": "Typed classification. system_core = system-center daemons (highest privilege; the source usernoted ontology tags these as the SYSTEM_CENTER notification-server class). intelligence_automation = proactive/prediction agents, constrained output. app_helper = application background daemons, standard user auth. legacy_bridge = legacy/modern connection bridge services. third_party = unsigned external applications." + }, + "is_daemon": { + "type": "boolean", + "description": "Whether the process runs as a background daemon." + }, + "is_apple_signed": { + "type": "boolean", + "description": "Whether the binary is Apple-signed." + }, + "suppress_user_authorization_prompt": { + "type": "boolean", + "description": "Whether the agent may suppress the user authorization prompt. CONSTRAINT: true is only valid when is_apple_signed is true (enforced below via if/then; SHACL T1-4 is authoritative). third_party/app_helper/legacy_bridge must never set this true (SEAM-002)." + }, + "system_bundle": { + "type": "boolean", + "description": "Whether the agent is part of a system bundle. CONSTRAINT: a third_party agent must not set this true (enforced below via if/then; SHACL T1-4 authoritative)." + }, + "authorized_space_ids": { + "type": "array", + "items": { "type": "integer" }, + "description": "CGSSpace spids the agent may present in." + }, + "authorized_window_ids": { + "type": "array", + "items": { "type": "string" }, + "description": "WAWindow wids the agent may interact with." + }, + "authorized_display_uuids": { + "type": "array", + "items": { "type": "string" }, + "description": "Physical display contexts. Stability is subject to SEAM-008 (displayUUID instability from firmware manipulation); an attestation timestamp is required when this is asserted." + }, + "summarize_previews_permitted": { + "type": "boolean", + "description": "Mirrors the summarizePreviews system flag. Required for the intelligence_automation class (enforced below)." + }, + "dnd_intelligent_management_permitted": { + "type": "boolean", + "description": "Mirrors dndAllowIntelligentManagement. Required for the intelligence_automation class (enforced below)." + }, + "autonomous_action_permitted": { + "type": "boolean", + "description": "Whether the agent may act without a human in the loop. Required for the intelligence_automation class (enforced below)." + }, + "capability_exceptions": { + "type": "array", + "description": "Explicit, scoped capability grants that deviate from the class default.", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["capability", "granted_by", "granted_at", "scope"], + "properties": { + "capability": { "type": "string" }, + "granted_by": { "type": "string" }, + "granted_at": { "type": "string", "format": "date-time" }, + "scope": { "type": "string" }, + "expires": { + "type": ["string", "null"], + "format": "date-time", + "description": "Expiry timestamp, or null for a non-expiring grant." + } + } + } + }, + "interrupt_level": { + "type": "string", + "enum": ["critical", "time_sensitive", "high", "standard", "passive"], + "description": "Notification/interrupt authority level." + }, + "attested_at": { + "type": "string", + "format": "date-time", + "description": "When this passport was attested. Required when spatial authorization (authorized_display_uuids) is asserted (SEAM-008)." + }, + "attestation_source": { + "type": "string", + "description": "The attesting authority (e.g. agent-machine attest subcommand)." + } + }, + "allOf": [ + { + "$comment": "intelligence_automation requires all three intelligence-constraint fields.", + "if": { + "properties": { "agent_class": { "const": "intelligence_automation" } }, + "required": ["agent_class"] + }, + "then": { + "required": [ + "summarize_previews_permitted", + "dnd_intelligent_management_permitted", + "autonomous_action_permitted" + ] + } + }, + { + "$comment": "third_party must not claim system_bundle: true (class elevation).", + "if": { + "properties": { "agent_class": { "const": "third_party" } }, + "required": ["agent_class"] + }, + "then": { + "properties": { "system_bundle": { "const": false } } + } + }, + { + "$comment": "suppress_user_authorization_prompt: true is only valid when is_apple_signed: true.", + "if": { + "properties": { "suppress_user_authorization_prompt": { "const": true } }, + "required": ["suppress_user_authorization_prompt"] + }, + "then": { + "properties": { "is_apple_signed": { "const": true } } + } + }, + { + "$comment": "SEAM-002: third_party, app_helper, and legacy_bridge must never suppress the user authorization prompt, regardless of signing.", + "if": { + "properties": { "agent_class": { "enum": ["third_party", "app_helper", "legacy_bridge"] } }, + "required": ["agent_class"] + }, + "then": { + "properties": { "suppress_user_authorization_prompt": { "const": false } } + } + }, + { + "$comment": "SEAM-008: an attestation timestamp is required whenever spatial display authorization is asserted.", + "if": { + "required": ["authorized_display_uuids"] + }, + "then": { + "required": ["attested_at"] + } + } + ] +} diff --git a/tools/validate_agent_passport_examples.py b/tools/validate_agent_passport_examples.py new file mode 100644 index 0000000..b21669c --- /dev/null +++ b/tools/validate_agent_passport_examples.py @@ -0,0 +1,168 @@ +#!/usr/bin/env python3 +"""Validate AgentPassport: five-class typed host-agent classification (T0-1). + +AgentPassport is the anchor vocabulary object: downstream tranches (ontogenesis +OWL/SHACL, mcp-a2a-zero-trust tiers, synapseiq enrichment, workstation-contracts +fixtures, source-os eBPF) all import urn:srcos:agent-passport:* as a stable +reference. So the invariants that make a classification meaningful are asserted +here BY REJECTION — a validator never observed refusing is indistinguishable +from no validator. + +Positive: every element of examples/agent-passport.json validates, and the +collection covers at least one third_party and one system_core instance. + +Negative (each fed to the SCHEMA as a real document; each MUST be rejected): + R1 third_party with system_bundle: true (class elevation) + R2 suppress_user_authorization_prompt: true while (unsigned suppression) + is_apple_signed: false + R3 intelligence_automation missing an intelligence (unconstrained intel agent) + constraint field + R4 unknown agent_class (not one of the five) (unclassified / anySource) + R5 missing bundle_id (no stable identity) + R6 app_helper/legacy_bridge/third_party suppressing (SEAM-002 class ban) + the auth prompt even when apple-signed +""" + +from __future__ import annotations + +import copy +import json +import sys +from pathlib import Path +from typing import Any + +try: + from jsonschema import Draft202012Validator +except ImportError: # pragma: no cover - dependency is installed by the Makefile target + print("FAIL: jsonschema is not installed; run `python3 -m pip install jsonschema`") + sys.exit(1) + +REPO_ROOT = Path(__file__).resolve().parents[1] +SCHEMA_PATH = REPO_ROOT / "schemas" / "AgentPassport.json" +# One object per file, per the repo's example convention (each carries a top-level +# `type` so CI can map it to its schema). Cover multiple classes across files. +EXAMPLE_GLOB = "agent-passport*.json" + +EXPECTED_CLASSES = { + "system_core", + "intelligence_automation", + "app_helper", + "legacy_bridge", + "third_party", +} + + +def load(path: Path) -> Any: + with path.open("r", encoding="utf-8") as handle: + return json.load(handle) + + +def fail(msg: str) -> None: + print(f"FAIL: {msg}") + sys.exit(1) + + +def main() -> int: + schema = load(SCHEMA_PATH) + Draft202012Validator.check_schema(schema) + validator = Draft202012Validator(schema) + + # agent_class enum must contain exactly the five canonical values. Access + # defensively so a malformed schema yields a clear FAIL, not a traceback. + enum_list = ( + schema.get("properties", {}).get("agent_class", {}).get("enum") + if isinstance(schema, dict) + else None + ) + if not isinstance(enum_list, list): + fail("schema is missing properties.agent_class.enum") + if set(enum_list) != EXPECTED_CLASSES: + fail(f"agent_class enum must be exactly the five classes, got {sorted(set(enum_list))}") + + example_paths = sorted((REPO_ROOT / "examples").glob(EXAMPLE_GLOB)) + if not example_paths: + fail(f"no example files matched examples/{EXAMPLE_GLOB}") + + # Positive: every example object validates. + seen_classes = set() + for path in example_paths: + passport = load(path) + if not isinstance(passport, dict): + fail(f"{path.name}: each example must be a single AgentPassport object") + errors = sorted(validator.iter_errors(passport), key=lambda e: list(e.path)) + if errors: + lines = [f"{path.name} ({passport.get('bundle_id', '?')}) failed validation:"] + for e in errors: + loc = ".".join(str(p) for p in e.path) or "" + lines.append(f" - {loc}: {e.message}") + fail("\n".join(lines)) + seen_classes.add(passport.get("agent_class")) + + # Coverage: at least one third_party and one system_core instance. + for required_class in ("third_party", "system_core"): + if required_class not in seen_classes: + fail(f"examples must cover at least one {required_class} instance") + + # Negative: each bad document MUST be rejected. A valid base to mutate: + base = { + "bundle_id": "com.example.app", + "agent_class": "app_helper", + "is_daemon": False, + "is_apple_signed": True, + "suppress_user_authorization_prompt": False, + "system_bundle": False, + "interrupt_level": "standard", + } + + def must_reject(label: str, doc: dict[str, Any]) -> None: + if validator.is_valid(doc): + fail(f"{label}: document was ACCEPTED but must be rejected: {json.dumps(doc)}") + + # R1: third_party cannot claim system_bundle: true. + r1 = copy.deepcopy(base) + r1["agent_class"] = "third_party" + r1["system_bundle"] = True + must_reject("R1 third_party+system_bundle", r1) + + # R2: suppression requires apple-signed. + r2 = copy.deepcopy(base) + r2["suppress_user_authorization_prompt"] = True + r2["is_apple_signed"] = False + must_reject("R2 unsigned suppression", r2) + + # R3: intelligence_automation must carry all three constraint fields. + r3 = copy.deepcopy(base) + r3["agent_class"] = "intelligence_automation" + r3["summarize_previews_permitted"] = False + r3["dnd_intelligent_management_permitted"] = False + # autonomous_action_permitted intentionally omitted + must_reject("R3 intel missing constraint", r3) + + # R4: unknown class (anySource is not a valid class). + r4 = copy.deepcopy(base) + r4["agent_class"] = "anySource" + must_reject("R4 unknown class", r4) + + # R5: no stable identity. + r5 = copy.deepcopy(base) + del r5["bundle_id"] + must_reject("R5 missing bundle_id", r5) + + # R6: SEAM-002 — app_helper/legacy_bridge/third_party cannot suppress the + # auth prompt even when apple-signed. + r6 = copy.deepcopy(base) + r6["agent_class"] = "app_helper" + r6["is_apple_signed"] = True + r6["suppress_user_authorization_prompt"] = True + must_reject("R6 SEAM-002 class suppression", r6) + + print( + f"OK: AgentPassport schema valid; {len(example_paths)} example passports validated " + f"(classes: {', '.join(sorted(c for c in seen_classes if c))}); " + f"6 rejection invariants enforced (R1-R6)" + ) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main())