diff --git a/schemas/aep/aep-record.schema.json b/schemas/aep/aep-record.schema.json index 99f458d..1ad1dd1 100644 --- a/schemas/aep/aep-record.schema.json +++ b/schemas/aep/aep-record.schema.json @@ -4,28 +4,76 @@ "title": "AEPRecord", "description": "Agent Evidence Protocol record — runtime action evidence and run provenance. Canonical source for wasmagent-js, wasmagent-proxy, trace-pipeline, wasmagent-train-replay, and open-agent-audit.", "type": "object", - "required": ["schema_version", "run_id", "created_at_ms"], + "required": [ + "schema_version", + "run_id", + "created_at_ms" + ], "properties": { - "schema_version": { "type": "string", "enum": ["aep/v0.1", "aep/v0.2", "aep/v0.3"] }, - "run_id": { "type": "string" }, - "trace_id": { "type": "string" }, - "parent_trace_id": { "type": ["string", "null"] }, - "repo_commit": { "type": "string" }, - "runtime_version": { "type": "string" }, - "model_provider": { "type": "string" }, - "model_id": { "type": "string" }, - "policy_bundle_digest": { "type": "string" }, - "tool_manifest_digest": { "type": "string" }, - "mcp_server_card_digest": { "type": ["string", "null"] }, + "schema_version": { + "type": "string", + "enum": [ + "aep/v0.1", + "aep/v0.2", + "aep/v0.3" + ] + }, + "run_id": { + "type": "string" + }, + "trace_id": { + "type": "string" + }, + "parent_trace_id": { + "type": [ + "string", + "null" + ] + }, + "repo_commit": { + "type": "string" + }, + "runtime_version": { + "type": "string" + }, + "model_provider": { + "type": "string" + }, + "model_id": { + "type": "string" + }, + "policy_bundle_digest": { + "type": "string" + }, + "tool_manifest_digest": { + "type": "string" + }, + "mcp_server_card_digest": { + "type": [ + "string", + "null" + ] + }, "input_refs": { "type": "array", "items": { "type": "object", - "required": ["uri"], + "required": [ + "uri" + ], "properties": { - "uri": { "type": "string" }, - "digest": { "type": "string" }, - "taint_labels": { "type": "array", "items": { "type": "string" } } + "uri": { + "type": "string" + }, + "digest": { + "type": "string" + }, + "taint_labels": { + "type": "array", + "items": { + "type": "string" + } + } } } }, @@ -33,11 +81,19 @@ "type": "array", "items": { "type": "object", - "required": ["uri"], + "required": [ + "uri" + ], "properties": { - "uri": { "type": "string" }, - "digest": { "type": "string" }, - "redaction_profile": { "type": "string" } + "uri": { + "type": "string" + }, + "digest": { + "type": "string" + }, + "redaction_profile": { + "type": "string" + } } } }, @@ -45,13 +101,34 @@ "type": "array", "items": { "type": "object", - "required": ["capability", "subject", "resource", "decision"], + "required": [ + "capability", + "subject", + "resource", + "decision" + ], "properties": { - "capability": { "type": "string" }, - "subject": { "type": "string" }, - "resource": { "type": "string" }, - "decision": { "type": "string", "enum": ["allow", "deny", "ask_user", "dry_run"] }, - "reason_code": { "type": "string" } + "capability": { + "type": "string" + }, + "subject": { + "type": "string" + }, + "resource": { + "type": "string" + }, + "decision": { + "type": "string", + "enum": [ + "allow", + "deny", + "ask_user", + "dry_run" + ] + }, + "reason_code": { + "type": "string" + } } } }, @@ -59,27 +136,85 @@ "type": "array", "items": { "type": "object", - "required": ["action_id", "tool_name", "state_changing", "timestamp_ms"], + "required": [ + "action_id", + "tool_name", + "state_changing", + "timestamp_ms" + ], "properties": { - "action_id": { "type": "string" }, - "tool_name": { "type": "string" }, - "state_changing": { "type": "boolean" }, - "precondition_digest": { "type": "string" }, - "result_digest": { "type": "string" }, - "evidence_refs": { "type": "array", "items": { "type": "string" } }, - "timestamp_ms": { "type": "number" }, - "parent_action_id": { "type": "string" }, - "causal_chain_id": { "type": "string" }, - "tool_descriptor_digest": { "type": "string" }, - "server_card_digest": { "type": "string" }, - "scope_lease_id": { "type": "string" }, - "approval_context_hash": { "type": "string" }, - "input_taint_labels": { "type": "array", "items": { "type": "string" } }, - "output_taint_labels": { "type": "array", "items": { "type": "string" } }, - "memory_read_refs": { "type": "array", "items": { "type": "string" } }, - "memory_write_refs": { "type": "array", "items": { "type": "string" } }, - "pre_state_digest": { "type": "string" }, - "post_state_digest": { "type": "string" } + "action_id": { + "type": "string" + }, + "tool_name": { + "type": "string" + }, + "state_changing": { + "type": "boolean" + }, + "precondition_digest": { + "type": "string" + }, + "result_digest": { + "type": "string" + }, + "evidence_refs": { + "type": "array", + "items": { + "type": "string" + } + }, + "timestamp_ms": { + "type": "number" + }, + "parent_action_id": { + "type": "string" + }, + "causal_chain_id": { + "type": "string" + }, + "tool_descriptor_digest": { + "type": "string" + }, + "server_card_digest": { + "type": "string" + }, + "scope_lease_id": { + "type": "string" + }, + "approval_context_hash": { + "type": "string" + }, + "input_taint_labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "output_taint_labels": { + "type": "array", + "items": { + "type": "string" + } + }, + "memory_read_refs": { + "type": "array", + "items": { + "type": "string" + } + }, + "memory_write_refs": { + "type": "array", + "items": { + "type": "string" + } + }, + "pre_state_digest": { + "type": "string" + }, + "post_state_digest": { + "type": "string" + } } } }, @@ -87,12 +222,26 @@ "type": "array", "items": { "type": "object", - "required": ["verifier_id", "passed"], + "required": [ + "verifier_id", + "passed" + ], "properties": { - "verifier_id": { "type": "string" }, - "passed": { "type": "boolean" }, - "score": { "type": "number" }, - "claim_ids": { "type": "array", "items": { "type": "string" } } + "verifier_id": { + "type": "string" + }, + "passed": { + "type": "boolean" + }, + "score": { + "type": "number" + }, + "claim_ids": { + "type": "array", + "items": { + "type": "string" + } + } } } }, @@ -102,64 +251,117 @@ "properties": { "token_budget": { "type": "object", - "required": ["spent"], + "required": [ + "spent" + ], "properties": { - "limit": { "type": "number" }, - "spent": { "type": "number" } + "limit": { + "type": "number" + }, + "spent": { + "type": "number" + } } }, "latency_budget": { "type": "object", - "required": ["actual_ms"], + "required": [ + "actual_ms" + ], "properties": { - "limit_ms": { "type": "number" }, - "actual_ms": { "type": "number" } + "limit_ms": { + "type": "number" + }, + "actual_ms": { + "type": "number" + } } }, "tool_budget": { "type": "object", - "required": ["spent"], + "required": [ + "spent" + ], "properties": { - "limit": { "type": "number" }, - "spent": { "type": "number" } + "limit": { + "type": "number" + }, + "spent": { + "type": "number" + } } }, "risk_budget": { "type": "object", - "required": ["spent"], + "required": [ + "spent" + ], "properties": { - "limit": { "type": "number" }, - "spent": { "type": "number" } + "limit": { + "type": "number" + }, + "spent": { + "type": "number" + } } }, "retry_budget": { "type": "object", - "required": ["spent"], + "required": [ + "spent" + ], "properties": { - "limit": { "type": "number" }, - "spent": { "type": "number" } + "limit": { + "type": "number" + }, + "spent": { + "type": "number" + } } }, "human_approval_budget": { "type": "object", - "required": ["spent"], + "required": [ + "spent" + ], "properties": { - "limit": { "type": "number" }, - "spent": { "type": "number" } + "limit": { + "type": "number" + }, + "spent": { + "type": "number" + } } } } }, - "created_at_ms": { "type": "number" }, + "created_at_ms": { + "type": "number" + }, "run_context": { "type": "object", "properties": { - "agent_id": { "type": "string" }, - "agent_version": { "type": "string" }, - "subagent_id": { "type": "string" }, - "delegation_chain": { "type": "array", "items": { "type": "string" } }, - "environment_digest": { "type": "string" }, - "dependency_lock_digest": { "type": "string" } + "agent_id": { + "type": "string" + }, + "agent_version": { + "type": "string" + }, + "subagent_id": { + "type": "string" + }, + "delegation_chain": { + "type": "array", + "items": { + "type": "string" + } + }, + "environment_digest": { + "type": "string" + }, + "dependency_lock_digest": { + "type": "string" + } } }, "user_id": { @@ -172,41 +374,177 @@ }, "side_effect_class": { "type": "string", - "enum": ["read", "mutate-local", "mutate-external", "network-egress", "unknown"], + "enum": [ + "read", + "mutate-local", + "mutate-external", + "network-egress", + "unknown" + ], "description": "Per-record side-effect classification (additive, aep/v0.3+). Shares one vocabulary with run_side_effect_class_max; reconciles wasmagent-js and trace-pipeline forks." }, "run_side_effect_class_max": { "type": "string", - "enum": ["read", "mutate-local", "mutate-external", "network-egress", "unknown"], + "enum": [ + "read", + "mutate-local", + "mutate-external", + "network-egress", + "unknown" + ], "description": "Per-run aggregate: the highest side-effect class observed across the whole run (additive, aep/v0.3+). Shares the side_effect_class vocabulary." }, "recording_mode": { "type": "string", - "enum": ["full", "delta", "validation"], + "enum": [ + "full", + "delta", + "validation" + ], "description": "How this run's evidence was captured (additive, aep/v0.3+)." }, "argument_drift": { "type": "object", "description": "Detected drift between an action's declared arguments and the arguments used at runtime (additive, aep/v0.3+).", "properties": { - "tool_name": { "type": "string" }, - "declared_digest": { "type": "string" }, - "actual_digest": { "type": "string" }, - "diff_summary": { "type": "string" }, - "drifted_args": { "type": "array", "items": { "type": "string" } } + "tool_name": { + "type": "string" + }, + "declared_digest": { + "type": "string" + }, + "actual_digest": { + "type": "string" + }, + "diff_summary": { + "type": "string" + }, + "drifted_args": { + "type": "array", + "items": { + "type": "string" + } + } }, "additionalProperties": true }, "signature": { "type": "object", "description": "Optional tamper-evident signature. Stays OPTIONAL in aep/v0.3; tightening it to required is a breaking change (CONTRACT-CHANGE-PROCESS.md section 3) that needs an org RFC before it can land - do not silently add it to the 'required' array.", - "required": ["alg", "key_id", "sig"], + "required": [ + "alg", + "key_id", + "sig" + ], "properties": { - "alg": { "type": "string" }, - "key_id": { "type": "string" }, - "sig": { "type": "string" }, - "bundle": { "type": "object" }, - "transparency_log_ref": { "type": "string" } + "alg": { + "type": "string" + }, + "key_id": { + "type": "string" + }, + "sig": { + "type": "string" + }, + "bundle": { + "type": "object" + }, + "transparency_log_ref": { + "type": "string" + } + } + }, + "run_artifacts": { + "type": "array", + "description": "Artifacts produced or consumed during this run. Completed artifacts are cryptographically locked via LockedArtifact constraints.", + "items": { + "type": "object", + "required": [ + "artifact_id", + "class", + "state" + ], + "properties": { + "artifact_id": { + "type": "string", + "description": "Unique artifact identifier within this run." + }, + "class": { + "type": "string", + "description": "Artifact class (e.g. file, pr, issue, test-report, model-output)." + }, + "state": { + "type": "string", + "enum": [ + "pending", + "generating", + "generated", + "building", + "testing", + "completed", + "failed", + "skipped", + "cancelled" + ], + "description": "Lifecycle state of the artifact." + }, + "depends_on": { + "type": "array", + "items": { + "type": "string" + }, + "description": "artifact_ids this artifact depends on (DAG edges)." + }, + "output_hash": { + "type": "string" + }, + "output_uri": { + "type": "string", + "format": "uri" + }, + "size_bytes": { + "type": "integer", + "minimum": 0 + } + }, + "allOf": [ + { + "if": { + "properties": { + "state": { + "const": "completed" + } + }, + "required": [ + "state" + ] + }, + "then": { + "$ref": "#/$defs/LockedArtifact" + } + } + ] + } + } + }, + "$defs": { + "LockedArtifact": { + "type": "object", + "required": [ + "output_hash", + "output_uri" + ], + "description": "Enforced only when an artifact state transitions to completed. Provides cryptographic pinning of the produced artifact.", + "properties": { + "output_hash": { + "type": "string", + "description": "SHA-256 or other digest of the artifact content." + }, + "output_uri": { + "type": "string", + "format": "uri", + "description": "Canonical URI where the artifact can be retrieved." + } } } } diff --git a/schemas/agentbom/agentbom.schema.json b/schemas/agentbom/agentbom.schema.json index 5b4e5a4..a8a7b25 100644 --- a/schemas/agentbom/agentbom.schema.json +++ b/schemas/agentbom/agentbom.schema.json @@ -2,7 +2,7 @@ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://wasmagent.dev/schemas/agentbom/v0.1.schema.json", "title": "AgentBOM", - "description": "Agent Bill of Materials v0.1 \u2014 shipped specification schema", + "description": "Agent Bill of Materials v0.1 — shipped specification schema", "type": "object", "required": [ "agentbom_version", @@ -198,7 +198,14 @@ "granted_scopes": { "type": "array", "items": { - "type": "string" + "type": "string", + "pattern": "^[a-z0-9.-]+:[a-zA-Z0-9.*_/-]+$", + "examples": [ + "network.egress:registry.npmjs.org", + "network.egress:*.github.com", + "filesystem.write:/tmp/workspace", + "tool.call:bash" + ] }, "description": "All granted permission scopes" }, @@ -398,7 +405,7 @@ }, "workflow_layer": { "type": "array", - "description": "Action pathway definitions \u2014 workflows, pipelines, and decision sequences that define how the agent executes tasks", + "description": "Action pathway definitions — workflows, pipelines, and decision sequences that define how the agent executes tasks", "items": { "type": "object", "required": [ @@ -478,7 +485,7 @@ "agent_collaboration": { "type": "object", "additionalProperties": false, - "description": "Multi-agent collaboration topology \u2014 peer agents, delegation boundaries, and shared resource access patterns", + "description": "Multi-agent collaboration topology — peer agents, delegation boundaries, and shared resource access patterns", "properties": { "peer_agents": { "type": "array", @@ -639,7 +646,7 @@ "distribution": { "type": "object", "additionalProperties": false, - "description": "Artifact lifecycle management \u2014 registry location, publication metadata, deprecation, and supersession", + "description": "Artifact lifecycle management — registry location, publication metadata, deprecation, and supersession", "properties": { "registry_uri": { "type": "string", @@ -700,6 +707,46 @@ "description": "Attestation timestamp in ISO 8601 format" } } + }, + "extensions": { + "type": "object", + "description": "CRD-like extension mechanism. An extension with critical=true MUST cause the consumer to abort if the namespace is unrecognised, preventing silent security downgrades.", + "patternProperties": { + "^[a-z0-9.-]+$": { + "type": "object", + "required": [ + "critical" + ], + "properties": { + "critical": { + "type": "boolean", + "default": false, + "description": "If true and the namespace is unrecognised, the consumer MUST abort execution." + }, + "config": { + "type": "object", + "description": "Extension-specific configuration payload." + } + }, + "additionalProperties": false + } + }, + "examples": [ + { + "wasmagent.audit": { + "critical": true, + "config": { + "require_trust_passport": true + } + }, + "ui.theme.hint": { + "critical": false, + "config": { + "primary_color": "#3b82f6" + } + } + } + ] } } } diff --git a/schemas/index.json b/schemas/index.json index 2bc43b1..1cf0a83 100644 --- a/schemas/index.json +++ b/schemas/index.json @@ -1,7 +1,7 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", "protocol": "AEP", - "description": "Registry of canonical WasmAgent protocol schemas \u2014 the single source of truth for every cross-repository contract. Downstream repos consume via @wasmagent/protocol (npm) and wasmagent-protocol (PyPI). Covers: AEP, compliance, AgentBOM, MCP Posture, Trust Passport.", + "description": "Registry of canonical WasmAgent protocol schemas — the single source of truth for every cross-repository contract. Downstream repos consume via @wasmagent/protocol (npm) and wasmagent-protocol (PyPI). Covers: AEP, compliance, AgentBOM, MCP Posture, Trust Passport.", "canonical_host": "https://wasmagent.dev/schemas/", "schemas": [ { @@ -21,7 +21,7 @@ "wasmagent-train-replay", "open-agent-audit" ], - "summary": "Runtime action evidence and run provenance record \u2014 the core Agent Evidence Protocol contract." + "summary": "Runtime action evidence and run provenance record — the core Agent Evidence Protocol contract. Includes LockedArtifact DAG artifact tracking (run_artifacts)." }, { "id": "evidence-envelope", @@ -39,7 +39,7 @@ "trace-pipeline", "open-agent-audit" ], - "summary": "Shared envelope base for all AEP evidence records \u2014 schema_version, trace_id, created_at_ms, and optional signature." + "summary": "Shared envelope base for all AEP evidence records — schema_version, trace_id, created_at_ms, and optional signature." }, { "id": "constraint-ir", @@ -55,7 +55,7 @@ "wasmagent-js", "trace-pipeline" ], - "summary": "Typed, repairable, prioritised constraint \u2014 superset of @wasmagent/core Criterion." + "summary": "Typed, repairable, prioritised constraint — superset of @wasmagent/core Criterion." }, { "id": "constraint-violation", @@ -142,7 +142,7 @@ "title": "AgentBOM", "path": "schemas/agentbom/agentbom.schema.json", "canonical_id": "https://wasmagent.dev/schemas/agentbom/v0.1.schema.json", - "version": "agentbom/v0.1", + "version": "agentbom/v0.2", "stability": "evolving", "owners": [ "agent-trust-infra" @@ -151,7 +151,7 @@ "agent-trust-infra", "open-agent-audit" ], - "summary": "Agent Bill of Materials \u2014 machine-readable agent identity, capabilities, and trust metadata." + "summary": "Agent Bill of Materials — machine-readable agent identity, capabilities, trust metadata, critical extension gate, and permission namespace scopes." }, { "id": "mcp-posture", @@ -167,7 +167,7 @@ "agent-trust-infra", "open-agent-audit" ], - "summary": "MCP Posture \u2014 tool surface, permission grants, and risk signals for MCP servers." + "summary": "MCP Posture — tool surface, permission grants, and risk signals for MCP servers." }, { "id": "trust-passport", @@ -183,7 +183,7 @@ "agent-trust-infra", "open-agent-audit" ], - "summary": "Trust Passport \u2014 signed, expiring, verifiable trust-state artifact for AI agents." + "summary": "Trust Passport — signed, expiring, verifiable trust-state artifact for AI agents." } ] } diff --git a/tests/fixtures/invalid/aep-record/completed-artifact-missing-lock.json b/tests/fixtures/invalid/aep-record/completed-artifact-missing-lock.json new file mode 100644 index 0000000..c3b09b3 --- /dev/null +++ b/tests/fixtures/invalid/aep-record/completed-artifact-missing-lock.json @@ -0,0 +1,12 @@ +{ + "schema_version": "aep/v0.3", + "run_id": "run-002", + "created_at_ms": 1700000000000, + "run_artifacts": [ + { + "artifact_id": "art-pr-99", + "class": "pr", + "state": "completed" + } + ] +} diff --git a/tests/fixtures/invalid/agentbom/bad-permission-scope.json b/tests/fixtures/invalid/agentbom/bad-permission-scope.json new file mode 100644 index 0000000..8c935b6 --- /dev/null +++ b/tests/fixtures/invalid/agentbom/bad-permission-scope.json @@ -0,0 +1,16 @@ +{ + "agentbom_version": "0.1", + "identity": { + "agent_id": "a1", + "agent_name": "Test", + "generated_at": "2026-01-01T00:00:00Z" + }, + "attestation": { + "generator": "test-tool" + }, + "permission_layer": { + "granted_scopes": [ + "*" + ] + } +} diff --git a/tests/fixtures/invalid/agentbom/extension-missing-critical.json b/tests/fixtures/invalid/agentbom/extension-missing-critical.json new file mode 100644 index 0000000..a28a88e --- /dev/null +++ b/tests/fixtures/invalid/agentbom/extension-missing-critical.json @@ -0,0 +1,18 @@ +{ + "agentbom_version": "0.1", + "identity": { + "agent_id": "a1", + "agent_name": "Test", + "generated_at": "2026-01-01T00:00:00Z" + }, + "attestation": { + "generator": "test-tool" + }, + "extensions": { + "wasmagent.audit": { + "config": { + "require_trust_passport": true + } + } + } +} diff --git a/tests/fixtures/valid/aep-record/with-locked-artifacts.json b/tests/fixtures/valid/aep-record/with-locked-artifacts.json new file mode 100644 index 0000000..838e93b --- /dev/null +++ b/tests/fixtures/valid/aep-record/with-locked-artifacts.json @@ -0,0 +1,29 @@ +{ + "schema_version": "aep/v0.3", + "run_id": "run-001", + "created_at_ms": 1700000000000, + "run_artifacts": [ + { + "artifact_id": "art-pr-42", + "class": "pr", + "state": "completed", + "output_hash": "sha256:abc123", + "output_uri": "https://github.com/WasmAgent/wasmagent/pull/42" + }, + { + "artifact_id": "art-test-report", + "class": "test-report", + "state": "completed", + "depends_on": [ + "art-pr-42" + ], + "output_hash": "sha256:def456", + "output_uri": "https://ci.example.com/reports/run-001" + }, + { + "artifact_id": "art-draft", + "class": "file", + "state": "generating" + } + ] +} diff --git a/tests/fixtures/valid/agentbom/with-extension-gate.json b/tests/fixtures/valid/agentbom/with-extension-gate.json new file mode 100644 index 0000000..d72dc81 --- /dev/null +++ b/tests/fixtures/valid/agentbom/with-extension-gate.json @@ -0,0 +1,32 @@ +{ + "agentbom_version": "0.1", + "identity": { + "agent_id": "a1", + "agent_name": "Test", + "generated_at": "2026-01-01T00:00:00Z" + }, + "attestation": { + "generator": "test-tool" + }, + "extensions": { + "wasmagent.audit": { + "critical": true, + "config": { + "require_trust_passport": true + } + }, + "ui.theme.hint": { + "critical": false, + "config": { + "primary_color": "#3b82f6" + } + } + }, + "permission_layer": { + "granted_scopes": [ + "network.egress:registry.npmjs.org", + "filesystem.write:/tmp/workspace", + "tool.call:bash" + ] + } +}