From 8ef20956f5eb1d094e6e6a27cf326c6e122a11c6 Mon Sep 17 00:00:00 2001 From: Claude Bot Date: Fri, 24 Jul 2026 08:44:07 +0800 Subject: [PATCH 1/3] feat(schemas): add AgentBOM, MCP Posture, Trust Passport schemas Migrate all WasmAgent trust-infrastructure schemas into the canonical schema repository, establishing wasmagent-protocol as the single source of truth for all inter-repo contracts. New schemas: - schemas/agentbom/agentbom.schema.json (from agent-trust-infra/specs/agentbom) - schemas/agentbom/agentbom-v0.1.md (spec prose) - schemas/mcp-posture/mcp-posture.schema.json (from agent-trust-infra/specs/mcp-posture) - schemas/mcp-posture/posture-model-v0.1.md - schemas/trust-passport/trust-passport.schema.json (merged from ati + oaa, canonical $id) - schemas/trust-passport/passport-v0.1.md - schemas/trust-passport/rfc-multi-party-negotiation.md All schemas updated to JSON Schema 2020-12 and canonical $id: https://wasmagent.dev/schemas//v.schema.json schemas/index.json now registers all 10 schemas. Conformance tests: 4/4 pass. Architecture: this mirrors opencontainers/image-spec pattern where the spec repo owns all schema contracts; implementations (agent-trust-infra, open-agent-audit) consume from this package rather than keeping local copies. --- schemas/agentbom/agentbom-v0.1.md | 263 +++++++ schemas/agentbom/agentbom.schema.json | 705 ++++++++++++++++++ schemas/index.json | 120 ++- schemas/mcp-posture/mcp-posture.schema.json | 304 ++++++++ schemas/mcp-posture/posture-model-v0.1.md | 130 ++++ schemas/trust-passport/passport-v0.1.md | 123 +++ .../rfc-multi-party-negotiation.md | 553 ++++++++++++++ .../trust-passport/trust-passport.schema.json | 230 ++++++ 8 files changed, 2411 insertions(+), 17 deletions(-) create mode 100644 schemas/agentbom/agentbom-v0.1.md create mode 100644 schemas/agentbom/agentbom.schema.json create mode 100644 schemas/mcp-posture/mcp-posture.schema.json create mode 100644 schemas/mcp-posture/posture-model-v0.1.md create mode 100644 schemas/trust-passport/passport-v0.1.md create mode 100644 schemas/trust-passport/rfc-multi-party-negotiation.md create mode 100644 schemas/trust-passport/trust-passport.schema.json diff --git a/schemas/agentbom/agentbom-v0.1.md b/schemas/agentbom/agentbom-v0.1.md new file mode 100644 index 0000000..b78497c --- /dev/null +++ b/schemas/agentbom/agentbom-v0.1.md @@ -0,0 +1,263 @@ +# AgentBOM v0.1 Specification + +> Status: shipped v0.1 specification. The schema and reference validator are +> published in this repository; implementation maturity remains a research +> preview. + +## What is AgentBOM? + +AgentBOM is a bill of materials for AI agents. + +It describes the deployed composition of an agent, including model dependencies, MCP servers, tool surfaces, prompt references, permission scopes, data access boundaries, evidence references, and known risk signals. + +AgentBOM is not an audit report. It is an input artifact for audit, posture analysis, procurement review, and trust passport issuance. + +## Relationship to existing standards + +### SBOM (CycloneDX, SPDX) + +Software Bill of Materials standards such as CycloneDX and SPDX catalog the libraries, frameworks, and dependencies that make up a software artifact. They answer the question "what components were shipped?" and are essential for vulnerability tracking and supply-chain integrity. + +AgentBOM does not replace an SBOM. Instead, it extends the bill-of-materials concept into the operational layer of an AI agent. Where an SBOM lists static software components, AgentBOM captures **runtime authority surfaces**: which tools the agent can invoke, what permission scopes it holds, which data sources it may access, and what prompts govern its behavior. These dimensions are outside the scope of traditional SBOM formats, which have no fields for tool registrations, permission boundaries, or prompt provenance. + +### AIBOM + +AIBOM (AI Bill of Materials) initiatives focus on model lineage and dataset provenance — tracking which model weights, training data, and fine-tuning steps produced a given AI capability. This is critical for understanding model-level risks such as data poisoning, bias, and license compliance. + +AgentBOM builds on the same bill-of-materials philosophy but shifts focus from the model itself to the **agent wrapper around the model**. An agent that calls a well-documented model can still introduce risk through overly broad tool permissions, unbounded data access, or insufficient prompt guardrails. AgentBOM captures these agent-level concerns — tool registries, permission scopes, prompt hashes, and runtime evidence — that AIBOM alone does not address. + +### OWASP LLM Top 10 + +The OWASP LLM Top 10 catalogs the most critical security risks specific to large language model applications, including prompt injection, excessive agency, and data leakage. It serves as a risk awareness and mitigation guide. + +AgentBOM does not duplicate the OWASP LLM Top 10 taxonomy. Rather, it provides a **structured, machine-readable artifact** that records whether a given agent deployment has mitigations and findings relevant to those risk categories. The `risk_layer` and `tool_layer.risk_signals` fields can reference OWASP LLM Top 10 categories (e.g., `prompt_injection`, `excessive_agency`), enabling automated tooling to check whether a deployment has acknowledged and addressed the applicable risks. + +### What AgentBOM adds + +The following capabilities are not captured by SBOM, AIBOM, or OWASP LLM Top 10 alone: + +- **Tool registry and permissions**: A complete inventory of tools (MCP servers, built-in functions, plugins) alongside the permission scopes each tool requires. +- **Tool skills**: Declared skills or capabilities each tool contributes, enabling capability-based analysis of agent behavior. +- **Prompt provenance**: Cryptographic hashes of system prompts and template references, enabling integrity verification of the instructions governing agent behavior. Version tracking for prompt templates supports change auditing. +- **Permission boundaries**: Declared data access scopes, credential type references, and granted authority — the "blast radius" if the agent behaves unexpectedly. +- **Workflow definitions**: Action pathway definitions describing sequences of steps, tool invocations, and decisions that the agent can execute. +- **Runtime evidence links**: References to AEP (Agent Evidence Protocol) events and evidence hashes that ground the AgentBOM in observed runtime behavior rather than declared intent alone. +- **Composability**: AgentBOM is designed to be diffed between versions, making it suitable for change-review workflows and continuous compliance monitoring. + +### AgentBOM as input to audit + +AgentBOM is an input artifact, not an audit report itself. In a typical audit workflow: + +1. **Generation**: An AgentBOM is produced for each agent deployment, capturing the full composition at a point in time. +2. **Posture analysis**: Tools such as MCP Posture analyze the AgentBOM against policy rules and risk frameworks, producing findings. +3. **Evidence collection**: Runtime evidence (AEP events, invocation logs) is linked into the `evidence_layer`, grounding the static declaration in observed behavior. +4. **Audit review**: Auditors use the AgentBOM alongside posture findings and evidence to assess compliance, identify gaps, and verify mitigations. + +### AgentBOM and the Trust Passport + +The Trust Passport is a downstream artifact that summarizes the trust status of an agent for consumers such as procurement teams and platform operators. AgentBOM feeds into Trust Passport issuance by providing: + +- **Identity and scope**: The agent's declared identity, version, and deployment context from `identity`. +- **Risk posture**: Aggregated risk signals from `risk_layer` and `tool_layer.risk_signals` that determine the passport's risk rating. +- **Evidence integrity**: Cryptographic hashes and AEP references from `evidence_layer` that allow the passport to make attested claims about runtime behavior. + +Together, AgentBOM provides the detailed technical input while the Trust Passport provides the concise, consumer-facing trust summary. + +## Schema structure + +``` +AgentBOM v0.1 +├── identity — agent ID, name, version, deployment context +├── model_layer — model provider, model ID, version, capabilities +├── tool_layer — registered tools, MCP servers, tool permissions, skills +├── prompt_layer — system prompt references, template IDs, prompt version tracking +├── permission_layer — granted scopes, data access boundaries, credential references +├── policy_definitions — governance policies, constraints, and compliance rules +├── evidence_layer — AEP event references, runtime evidence hashes +├── audit_log — structured audit trail entries +├── risk_layer — known risk signals, open findings +├── workflow_layer — action pathway definitions (workflows, pipelines, decision sequences) +└── attestation — generator, timestamp, hash +``` + +## identity + +| Field | Type | Required | Description | +|---|---|---|---| +| `agentbom_version` | string | yes | Always `"0.1"` | +| `agent_id` | string | yes | Unique agent identifier | +| `agent_name` | string | yes | Human-readable name | +| `agent_version` | string | no | Semantic version | +| `deployment_context` | string | no | `development`, `staging`, `production` | +| `generated_at` | ISO 8601 | yes | Generation timestamp | + +## model_layer + +| Field | Type | Required | Description | +|---|---|---|---| +| `provider` | string | yes | Model provider | +| `model_id` | string | yes | Model identifier | +| `model_version` | string | no | Model version or snapshot | +| `capabilities` | string[] | no | Declared capabilities | + +## tool_layer + +Array of tool entries: + +| Field | Type | Required | Description | +|---|---|---|---| +| `tool_id` | string | yes | Unique tool identifier | +| `tool_name` | string | yes | Tool name | +| `source` | string | yes | `mcp`, `builtin`, `plugin` | +| `mcp_server_id` | string | no | MCP server identifier if source is `mcp` | +| `skills` | string[] | no | Skills or capabilities this tool contributes to the agent | +| `permissions` | string[] | no | Permission scopes this tool requires | +| `risk_signals` | string[] | no | Known risk signals for this tool | + +### skills + +The `skills` field lists declarative skills or capabilities that the tool provides to the agent. Unlike `permissions` (which describe what the tool is allowed to do from an access-control perspective), `skills` describe what the tool **can do** from a functional perspective — for example `file_reading`, `code_generation`, `web_search`, `database_query`. Skills enable capability-based filtering, agent composition analysis, and automated discovery of what an agent is functionally capable of. + +## prompt_layer + +| Field | Type | Required | Description | +|---|---|---|---| +| `system_prompt_hash` | string | no | SHA-256 of system prompt | +| `prompt_version` | string | no | Version identifier for the active prompt set | +| `template_ids` | string[] | no | Referenced prompt template IDs | +| `templates` | object[] | no | Versioned prompt template references | + +### prompt_version + +The `prompt_version` field tracks the version of the active prompt configuration as a whole. This enables audit trails to answer which prompt version was active at a given point in time. + +### templates + +Each entry in the `templates` array provides versioned and hashed references to individual prompt templates: + +| Field | Type | Required | Description | +|---|---|---|---| +| `template_id` | string | yes | Prompt template identifier | +| `version` | string | no | Template version (semver or snapshot) | +| `hash` | string | no | SHA-256 hash of the template content | + +The `templates` array supplements the simpler `template_ids` array; both may be present. Consumers preferring minimal syntax can use `template_ids`, while those needing version or integrity information should use `templates`. + +## permission_layer + +| Field | Type | Required | Description | +|---|---|---|---| +| `granted_scopes` | string[] | no | All granted permission scopes | +| `data_access` | string[] | no | Data sources the agent can access | +| `credential_references` | string[] | no | Credential type references (no secrets) | + +## policy_definitions + +Array of policy definition entries: + +| Field | Type | Required | Description | +|---|---|---|---| +| `policy_id` | string | yes | Unique policy identifier | +| `policy_name` | string | yes | Human-readable policy name | +| `policy_type` | string | yes | Policy type or category (e.g., `content_filter`, `rate_limit`, `data_handling`, `compliance`) | +| `version` | string | no | Policy version (semver) | +| `description` | string | no | Description of what the policy governs | +| `rules` | string[] | no | Declarative policy rules or constraint expressions | + +The `policy_definitions` field captures governance policies and compliance rules that constrain or govern the agent's behavior. This is distinct from `permission_layer` (which declares what the agent *can* access) — `policy_definitions` describe the *rules* that govern *how* the agent uses those permissions, such as content filtering policies, rate limits, data handling constraints, and regulatory compliance requirements. Each policy has a type classification enabling automated policy enforcement and compliance checking. + +## evidence_layer + +| Field | Type | Required | Description | +|---|---|---|---| +| `aep_references` | string[] | no | AEP event IDs or hashes | +| `evidence_hashes` | object[] | no | `{type, hash, timestamp}` | + +## audit_log + +Array of audit trail entries: + +| Field | Type | Required | Description | +|---|---|---|---| +| `timestamp` | ISO 8601 | yes | Event timestamp | +| `event_type` | string | yes | Type of audit event (e.g., `tool_call`, `permission_check`, `prompt_injection_attempt`) | +| `actor` | string | yes | Entity that performed the action (user ID, system component, or external service) | +| `resource` | string | no | Target resource identifier affected by the event | +| `outcome` | string | no | `success`, `failure`, or `partial` | +| `details` | object | no | Additional event-specific context and metadata | + +## risk_layer + +Array of risk entries: + +| Field | Type | Required | Description | +|---|---|---|---| +| `risk_id` | string | yes | Unique risk identifier | +| `severity` | string | yes | `critical`, `high`, `medium`, `low`, `info` | +| `category` | string | yes | Risk category | +| `description` | string | yes | Risk description | +| `status` | string | yes | `open`, `mitigated`, `accepted` | + +## workflow_layer + +Array of workflow (action pathway) definitions: + +| Field | Type | Required | Description | +|---|---|---|---| +| `workflow_id` | string | yes | Unique workflow identifier | +| `workflow_name` | string | yes | Human-readable workflow name | +| `description` | string | no | Workflow description | +| `version` | string | no | Workflow definition version (semver) | +| `steps` | object[] | yes | Ordered list of steps in this workflow | + +The `workflow_layer` captures action pathway definitions — the sequences of tool calls, prompts, and decision points that define how the agent executes its tasks. Each workflow is an ordered or dependency-linked set of steps. + +### steps + +Each step in a workflow: + +| Field | Type | Required | Description | +|---|---|---|---| +| `step_id` | string | yes | Unique step identifier within the workflow | +| `action` | string | yes | Action to perform (e.g., tool_id, prompt name, `sub_workflow`, `decision`) | +| `description` | string | no | Step description | +| `input` | string | no | Input reference or template | +| `output` | string | no | Expected output reference | +| `depends_on` | string[] | no | Step IDs this step depends on; empty means no dependency | +| `allowed_tools` | string[] | no | Tool IDs allowed at this step (subset of the agent's registered tools) | + +The `action` field references what to execute: a tool ID from `tool_layer`, a prompt template from `prompt_layer`, a sub-workflow by its `workflow_id`, or a built-in decision primitive. The `depends_on` field expresses ordering constraints: if step B depends on step A, B will not start until A completes. Steps with no dependencies may execute in any order or in parallel, depending on the runtime. + +## attestation + +| Field | Type | Required | Description | +|---|---|---|---| +| `generator` | string | yes | Tool or process that generated this AgentBOM | +| `generator_version` | string | no | Generator version | +| `agentbom_hash` | string | no | SHA-256 of canonical AgentBOM JSON | +| `signature` | string | no | Cryptographic signature of the AgentBOM for verification | +| `timestamp` | ISO 8601 | no | Attestation timestamp | + +## CLI commands + +```bash +agent-trust agentbom validate # Validate against schema +agent-trust agentbom inspect # Human-readable summary +agent-trust agentbom diff # Show changes between two AgentBOMs +``` + +## Extraction criteria + +AgentBOM can be extracted into a standalone specification repository when: + +1. The schema version (`agentbom_version`) has stabilized and no breaking changes + are expected in the short term. +2. External consumers (beyond the WasmAgent ecosystem) adopt the package + independently, or a standardization pathway (e.g., OpenSSF, OWASP CycloneDX + extension) has been initiated — see [`docs/openssf-proposal.md`](../../docs/openssf-proposal.md). +3. The eleven-layer schema has coverage across at least one major regulatory + framework mapping (e.g., EU AI Act Annex IV, ISO/IEC 42001, NIST AI RMF). + +Until extraction, the canonical source is this repository. The JSON schema in +`specs/agentbom/schema.json` and the reference implementation in +`packages/agentbom-core/` are versioned together. diff --git a/schemas/agentbom/agentbom.schema.json b/schemas/agentbom/agentbom.schema.json new file mode 100644 index 0000000..5b4e5a4 --- /dev/null +++ b/schemas/agentbom/agentbom.schema.json @@ -0,0 +1,705 @@ +{ + "$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", + "type": "object", + "required": [ + "agentbom_version", + "identity", + "attestation" + ], + "additionalProperties": false, + "properties": { + "agentbom_version": { + "type": "string", + "enum": [ + "0.1" + ], + "description": "Always \"0.1\"" + }, + "identity": { + "type": "object", + "required": [ + "agent_id", + "agent_name", + "generated_at" + ], + "additionalProperties": false, + "description": "Agent ID, name, version, deployment context", + "properties": { + "agent_id": { + "type": "string", + "description": "Unique agent identifier" + }, + "agent_name": { + "type": "string", + "description": "Human-readable name" + }, + "agent_version": { + "type": "string", + "description": "Semantic version" + }, + "deployment_context": { + "type": "string", + "enum": [ + "development", + "staging", + "production" + ], + "description": "Deployment environment" + }, + "generated_at": { + "type": "string", + "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}:\\d{2})$", + "description": "Generation timestamp in ISO 8601 format" + } + } + }, + "model_layer": { + "type": "object", + "required": [ + "provider", + "model_id" + ], + "additionalProperties": false, + "description": "Model provider, model ID, version, capabilities", + "properties": { + "provider": { + "type": "string", + "description": "Model provider" + }, + "model_id": { + "type": "string", + "description": "Model identifier" + }, + "model_version": { + "type": "string", + "description": "Model version or snapshot" + }, + "capabilities": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Declared capabilities" + } + } + }, + "tool_layer": { + "type": "array", + "description": "Registered tools, MCP servers, tool permissions, skills", + "items": { + "type": "object", + "required": [ + "tool_id", + "tool_name", + "source" + ], + "additionalProperties": false, + "properties": { + "tool_id": { + "type": "string", + "description": "Unique tool identifier" + }, + "tool_name": { + "type": "string", + "description": "Tool name" + }, + "source": { + "type": "string", + "enum": [ + "mcp", + "builtin", + "plugin" + ], + "description": "Tool source type" + }, + "mcp_server_id": { + "type": "string", + "description": "MCP server identifier if source is mcp" + }, + "skills": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Skills or capabilities this tool contributes to the agent" + }, + "permissions": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Permission scopes this tool requires" + }, + "risk_signals": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Known risk signals for this tool" + } + } + } + }, + "prompt_layer": { + "type": "object", + "additionalProperties": false, + "description": "System prompt references, template IDs, prompt version tracking", + "properties": { + "system_prompt_hash": { + "type": "string", + "description": "SHA-256 of system prompt" + }, + "prompt_version": { + "type": "string", + "description": "Version identifier for the active prompt set" + }, + "template_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Referenced prompt template IDs" + }, + "templates": { + "type": "array", + "description": "Versioned prompt template references", + "items": { + "type": "object", + "required": [ + "template_id" + ], + "additionalProperties": false, + "properties": { + "template_id": { + "type": "string", + "description": "Prompt template identifier" + }, + "version": { + "type": "string", + "description": "Template version (semver or snapshot)" + }, + "hash": { + "type": "string", + "description": "SHA-256 hash of the template content" + } + } + } + } + } + }, + "permission_layer": { + "type": "object", + "additionalProperties": false, + "description": "Granted scopes, data access boundaries, credential references", + "properties": { + "granted_scopes": { + "type": "array", + "items": { + "type": "string" + }, + "description": "All granted permission scopes" + }, + "data_access": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Data sources the agent can access" + }, + "credential_references": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Credential type references (no secrets)" + } + } + }, + "policy_definitions": { + "type": "array", + "description": "Governance policies, constraints, and compliance rules that govern agent behavior", + "items": { + "type": "object", + "required": [ + "policy_id", + "policy_name", + "policy_type" + ], + "additionalProperties": false, + "properties": { + "policy_id": { + "type": "string", + "description": "Unique policy identifier" + }, + "policy_name": { + "type": "string", + "description": "Human-readable policy name" + }, + "policy_type": { + "type": "string", + "description": "Policy type or category (e.g., content_filter, rate_limit, data_handling, compliance)" + }, + "version": { + "type": "string", + "description": "Policy version (semver)" + }, + "description": { + "type": "string", + "description": "Description of what the policy governs" + }, + "rules": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Declarative policy rules or constraint expressions" + } + } + } + }, + "evidence_layer": { + "type": "object", + "additionalProperties": false, + "description": "AEP event references, runtime evidence hashes", + "properties": { + "aep_references": { + "type": "array", + "items": { + "type": "string" + }, + "description": "AEP event IDs or hashes" + }, + "evidence_hashes": { + "type": "array", + "description": "Evidence entries with type, hash, and timestamp", + "items": { + "type": "object", + "required": [ + "type", + "hash" + ], + "additionalProperties": false, + "properties": { + "type": { + "type": "string", + "description": "Evidence type" + }, + "hash": { + "type": "string", + "description": "Evidence hash value" + }, + "timestamp": { + "type": "string", + "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}:\\d{2})$", + "description": "Timestamp in ISO 8601 format" + } + } + } + } + } + }, + "audit_log": { + "type": "array", + "description": "Structured audit trail entries", + "items": { + "type": "object", + "required": [ + "timestamp", + "event_type", + "actor" + ], + "additionalProperties": false, + "properties": { + "timestamp": { + "type": "string", + "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}:\\d{2})$", + "description": "Event timestamp in ISO 8601 format" + }, + "event_type": { + "type": "string", + "description": "Type of audit event (e.g., tool_call, permission_check, prompt_injection_attempt)" + }, + "actor": { + "type": "string", + "description": "Entity that performed the action (user ID, system component, or external service)" + }, + "resource": { + "type": "string", + "description": "Target resource identifier affected by the event" + }, + "outcome": { + "type": "string", + "enum": [ + "success", + "failure", + "partial" + ], + "description": "Event outcome status" + }, + "details": { + "type": "object", + "description": "Additional event-specific context and metadata", + "additionalProperties": true + } + } + } + }, + "risk_layer": { + "type": "array", + "description": "Known risk signals, open findings", + "items": { + "type": "object", + "required": [ + "risk_id", + "severity", + "category", + "description", + "status" + ], + "additionalProperties": false, + "properties": { + "risk_id": { + "type": "string", + "description": "Unique risk identifier" + }, + "severity": { + "type": "string", + "enum": [ + "critical", + "high", + "medium", + "low", + "info" + ], + "description": "Risk severity level" + }, + "category": { + "type": "string", + "description": "Risk category" + }, + "description": { + "type": "string", + "description": "Risk description" + }, + "status": { + "type": "string", + "enum": [ + "open", + "mitigated", + "accepted" + ], + "description": "Risk status" + } + } + } + }, + "workflow_layer": { + "type": "array", + "description": "Action pathway definitions \u2014 workflows, pipelines, and decision sequences that define how the agent executes tasks", + "items": { + "type": "object", + "required": [ + "workflow_id", + "workflow_name", + "steps" + ], + "additionalProperties": false, + "properties": { + "workflow_id": { + "type": "string", + "description": "Unique workflow identifier" + }, + "workflow_name": { + "type": "string", + "description": "Human-readable workflow name" + }, + "description": { + "type": "string", + "description": "Workflow description" + }, + "version": { + "type": "string", + "description": "Workflow definition version (semver)" + }, + "steps": { + "type": "array", + "description": "Ordered list of steps in this workflow", + "items": { + "type": "object", + "required": [ + "step_id", + "action" + ], + "additionalProperties": false, + "properties": { + "step_id": { + "type": "string", + "description": "Unique step identifier within the workflow" + }, + "action": { + "type": "string", + "description": "Action to perform (tool_id, prompt, sub_workflow, decision)" + }, + "description": { + "type": "string", + "description": "Step description" + }, + "input": { + "type": "string", + "description": "Input reference or template" + }, + "output": { + "type": "string", + "description": "Expected output reference" + }, + "depends_on": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Step IDs this step depends on" + }, + "allowed_tools": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Tool IDs allowed at this step" + } + } + } + } + } + } + }, + "agent_collaboration": { + "type": "object", + "additionalProperties": false, + "description": "Multi-agent collaboration topology \u2014 peer agents, delegation boundaries, and shared resource access patterns", + "properties": { + "peer_agents": { + "type": "array", + "description": "Known peer agents this agent collaborates with", + "items": { + "type": "object", + "required": [ + "agent_id", + "role" + ], + "additionalProperties": false, + "properties": { + "agent_id": { + "type": "string", + "description": "Unique identifier of the peer agent" + }, + "agent_name": { + "type": "string", + "description": "Human-readable name of the peer agent" + }, + "role": { + "type": "string", + "enum": [ + "supervisor", + "delegate", + "peer", + "subordinate" + ], + "description": "Collaboration role relative to this agent" + }, + "trust_level": { + "type": "string", + "enum": [ + "full", + "restricted", + "minimal", + "none" + ], + "description": "Trust level assigned to this peer agent" + }, + "agentbom_ref": { + "type": "string", + "description": "URI or hash reference to the peer agent's AgentBOM" + } + } + } + }, + "delegation_boundaries": { + "type": "array", + "description": "Rules governing what this agent can delegate to peers and what it accepts from them", + "items": { + "type": "object", + "required": [ + "boundary_id", + "direction", + "constraint_type" + ], + "additionalProperties": false, + "properties": { + "boundary_id": { + "type": "string", + "description": "Unique boundary identifier" + }, + "direction": { + "type": "string", + "enum": [ + "outbound", + "inbound", + "bidirectional" + ], + "description": "Direction of the delegation boundary" + }, + "constraint_type": { + "type": "string", + "description": "Type of constraint (e.g., tool_delegation, data_sharing, permission_propagation)" + }, + "description": { + "type": "string", + "description": "Human-readable description of the boundary rule" + }, + "target_agents": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Agent IDs this boundary applies to (empty means all peers)" + }, + "allowed_actions": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Actions permitted within this boundary" + }, + "max_delegation_depth": { + "type": "integer", + "minimum": 0, + "description": "Maximum depth of transitive delegation (0 = no transitive delegation)" + } + } + } + }, + "shared_resources": { + "type": "array", + "description": "Resources shared across agent collaboration boundaries", + "items": { + "type": "object", + "required": [ + "resource_id", + "resource_type", + "access_pattern" + ], + "additionalProperties": false, + "properties": { + "resource_id": { + "type": "string", + "description": "Unique resource identifier" + }, + "resource_type": { + "type": "string", + "description": "Type of shared resource (e.g., datastore, file_system, api_endpoint, message_queue)" + }, + "access_pattern": { + "type": "string", + "enum": [ + "read_only", + "write_only", + "read_write", + "exclusive" + ], + "description": "Access pattern for the shared resource" + }, + "description": { + "type": "string", + "description": "Description of the shared resource and its purpose" + }, + "accessing_agents": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Agent IDs that access this resource" + }, + "isolation_level": { + "type": "string", + "enum": [ + "shared", + "partitioned", + "isolated" + ], + "description": "Resource isolation level between agents" + } + } + } + } + } + }, + "distribution": { + "type": "object", + "additionalProperties": false, + "description": "Artifact lifecycle management \u2014 registry location, publication metadata, deprecation, and supersession", + "properties": { + "registry_uri": { + "type": "string", + "format": "uri", + "description": "URI of the distribution registry where this artifact is published" + }, + "publication_timestamp": { + "type": "string", + "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}:\\d{2})$", + "description": "Timestamp when the artifact was published to the registry, in ISO 8601 format" + }, + "deprecation_status": { + "type": "string", + "enum": [ + "active", + "deprecated", + "superseded", + "withdrawn" + ], + "description": "Current deprecation status of the artifact in the registry" + }, + "supersedes": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Artifact IDs that this distribution supersedes" + } + } + }, + "attestation": { + "type": "object", + "required": [ + "generator" + ], + "additionalProperties": false, + "description": "Generator, timestamp, hash, signature", + "properties": { + "generator": { + "type": "string", + "description": "Tool or process that generated this AgentBOM" + }, + "generator_version": { + "type": "string", + "description": "Generator version" + }, + "agentbom_hash": { + "type": "string", + "description": "SHA-256 of canonical AgentBOM JSON" + }, + "signature": { + "type": "string", + "description": "Cryptographic signature of the AgentBOM for verification" + }, + "timestamp": { + "type": "string", + "pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}:\\d{2})$", + "description": "Attestation timestamp in ISO 8601 format" + } + } + } + } +} diff --git a/schemas/index.json b/schemas/index.json index 800c5a4..d3a4542 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. This is the single source of truth for every cross-repository contract in the org. Downstream repos consume these via the versioned npm (@wasmagent/protocol) and pip (wasmagent-protocol) packages and MUST NOT keep local copies.", + "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.", "canonical_host": "https://wasmagent.dev/schemas/", "schemas": [ { @@ -11,9 +11,17 @@ "canonical_id": "https://wasmagent.dev/schemas/aep/aep-record.schema.json", "version": "aep/v0.2", "stability": "evolving", - "owners": ["wasmagent-protocol"], - "consumers": ["wasmagent-js", "wasmagent-proxy", "trace-pipeline", "wasmagent-train-replay", "open-agent-audit"], - "summary": "Runtime action evidence and run provenance record — the core Agent Evidence Protocol contract." + "owners": [ + "wasmagent-protocol" + ], + "consumers": [ + "wasmagent-js", + "wasmagent-proxy", + "trace-pipeline", + "wasmagent-train-replay", + "open-agent-audit" + ], + "summary": "Runtime action evidence and run provenance record \u2014 the core Agent Evidence Protocol contract." }, { "id": "constraint-ir", @@ -22,9 +30,14 @@ "canonical_id": "https://wasmagent.dev/schemas/compliance/constraint-ir.schema.json", "version": "compliance/v1", "stability": "evolving", - "owners": ["wasmagent-protocol"], - "consumers": ["wasmagent-js", "trace-pipeline"], - "summary": "Typed, repairable, prioritised constraint — superset of @wasmagent/core Criterion." + "owners": [ + "wasmagent-protocol" + ], + "consumers": [ + "wasmagent-js", + "trace-pipeline" + ], + "summary": "Typed, repairable, prioritised constraint \u2014 superset of @wasmagent/core Criterion." }, { "id": "constraint-violation", @@ -33,8 +46,13 @@ "canonical_id": "https://wasmagent.dev/schemas/compliance/constraint-violation.schema.json", "version": "compliance/v1", "stability": "evolving", - "owners": ["wasmagent-protocol"], - "consumers": ["wasmagent-js", "trace-pipeline"], + "owners": [ + "wasmagent-protocol" + ], + "consumers": [ + "wasmagent-js", + "trace-pipeline" + ], "summary": "A failed constraint plus its location in the artifact." }, { @@ -44,8 +62,13 @@ "canonical_id": "https://wasmagent.dev/schemas/compliance/repair-trace.schema.json", "version": "compliance/v1", "stability": "evolving", - "owners": ["wasmagent-protocol"], - "consumers": ["wasmagent-js", "trace-pipeline"], + "owners": [ + "wasmagent-protocol" + ], + "consumers": [ + "wasmagent-js", + "trace-pipeline" + ], "summary": "Per-round repair record. Supersedes trace-pipeline's repair-trace-entry naming." }, { @@ -55,8 +78,13 @@ "canonical_id": "https://wasmagent.dev/schemas/compliance/task-spec.schema.json", "version": "compliance/v1", "stability": "evolving", - "owners": ["wasmagent-protocol"], - "consumers": ["wasmagent-js", "trace-pipeline"], + "owners": [ + "wasmagent-protocol" + ], + "consumers": [ + "wasmagent-js", + "trace-pipeline" + ], "summary": "Public contract for a compliance run. One TaskSpec -> one run -> one ComplianceEvalRecord." }, { @@ -66,8 +94,13 @@ "canonical_id": "https://wasmagent.dev/schemas/compliance/compliance-eval-record.schema.json", "version": "compliance-eval-record/v1", "stability": "evolving", - "owners": ["wasmagent-protocol"], - "consumers": ["wasmagent-js", "trace-pipeline"], + "owners": [ + "wasmagent-protocol" + ], + "consumers": [ + "wasmagent-js", + "trace-pipeline" + ], "summary": "One record per compliance run." }, { @@ -77,9 +110,62 @@ "canonical_id": "https://wasmagent.dev/schemas/compliance/rollout-wire.schema.json", "version": "rollout-wire/v1", "stability": "evolving", - "owners": ["wasmagent-protocol"], - "consumers": ["wasmagent-js", "trace-pipeline"], + "owners": [ + "wasmagent-protocol" + ], + "consumers": [ + "wasmagent-js", + "trace-pipeline" + ], "summary": "Intermediate JSONL formats in the wasmagent -> evomerge data pipeline (branch/dpo/ppo records)." + }, + { + "id": "agentbom", + "title": "AgentBOM", + "path": "schemas/agentbom/agentbom.schema.json", + "canonical_id": "https://wasmagent.dev/schemas/agentbom/v0.1.schema.json", + "version": "agentbom/v0.1", + "stability": "evolving", + "owners": [ + "agent-trust-infra" + ], + "consumers": [ + "agent-trust-infra", + "open-agent-audit" + ], + "summary": "Agent Bill of Materials \u2014 machine-readable agent identity, capabilities, and trust metadata." + }, + { + "id": "mcp-posture", + "title": "MCPPosture", + "path": "schemas/mcp-posture/mcp-posture.schema.json", + "canonical_id": "https://wasmagent.dev/schemas/mcp-posture/v0.1.schema.json", + "version": "mcp-posture/v0.1", + "stability": "evolving", + "owners": [ + "agent-trust-infra" + ], + "consumers": [ + "agent-trust-infra", + "open-agent-audit" + ], + "summary": "MCP Posture \u2014 tool surface, permission grants, and risk signals for MCP servers." + }, + { + "id": "trust-passport", + "title": "TrustPassport", + "path": "schemas/trust-passport/trust-passport.schema.json", + "canonical_id": "https://wasmagent.dev/schemas/trust-passport/v0.1.schema.json", + "version": "trust-passport/v0.1", + "stability": "evolving", + "owners": [ + "open-agent-audit" + ], + "consumers": [ + "agent-trust-infra", + "open-agent-audit" + ], + "summary": "Trust Passport \u2014 signed, expiring, verifiable trust-state artifact for AI agents." } ] } diff --git a/schemas/mcp-posture/mcp-posture.schema.json b/schemas/mcp-posture/mcp-posture.schema.json new file mode 100644 index 0000000..208811f --- /dev/null +++ b/schemas/mcp-posture/mcp-posture.schema.json @@ -0,0 +1,304 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://wasmagent.dev/schemas/mcp-posture/v0.1.schema.json", + "title": "MCPPosture", + "description": "MCP Posture snapshot v0.1 \u2014 shipped specification schema", + "type": "object", + "required": [ + "posture_version", + "identity", + "servers", + "attestation" + ], + "properties": { + "posture_version": { + "type": "string", + "enum": [ + "0.1" + ] + }, + "protocol_version": { + "type": "string", + "description": "MCP specification version under which this snapshot was captured. Use '2026-07-28' for the stateless/handle-based spec or omit for pre-2026-07-28 deployments.", + "examples": [ + "2026-07-28" + ] + }, + "identity": { + "type": "object", + "required": [ + "snapshot_id", + "agent_id", + "captured_at" + ], + "properties": { + "snapshot_id": { + "type": "string" + }, + "agent_id": { + "type": "string" + }, + "captured_at": { + "type": "string", + "format": "date-time" + }, + "previous_snapshot_id": { + "type": "string" + } + } + }, + "servers": { + "type": "array", + "items": { + "type": "object", + "required": [ + "server_id", + "server_name", + "tools" + ], + "properties": { + "server_id": { + "type": "string" + }, + "server_name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "provenance": { + "type": "string", + "enum": [ + "verified", + "unverified", + "unknown" + ] + }, + "session_model": { + "type": "string", + "enum": [ + "stateful", + "stateless-handle", + "unknown" + ], + "description": "MCP session architecture: stateless-handle = MCP 2026-07-28+ spec; stateful = pre-2026-07-28." + }, + "handle_expiry_policy": { + "type": "string", + "enum": [ + "short-lived", + "long-lived", + "unset" + ], + "description": "Handle expiry policy under stateless-handle session model (MCP 2026-07-28+)." + }, + "tools": { + "type": "array", + "items": { + "type": "object", + "required": [ + "tool_id", + "tool_name" + ], + "properties": { + "tool_id": { + "type": "string" + }, + "tool_name": { + "type": "string" + }, + "permissions": { + "type": "array", + "items": { + "type": "string" + } + }, + "risk_categories": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "ssrf", + "exfiltration", + "command_execution", + "privilege_escalation", + "prompt_injection", + "credential_access", + "supply_chain", + "mcp_header_leakage" + ] + } + }, + "risk_severity": { + "type": "string", + "enum": [ + "critical", + "high", + "medium", + "low", + "info" + ] + } + } + } + } + } + } + }, + "permission_graph": { + "type": "object", + "properties": { + "total_tools": { + "type": "integer" + }, + "total_permissions": { + "type": "integer" + }, + "high_risk_tools": { + "type": "integer" + }, + "permission_scopes": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "risk_summary": { + "type": "array", + "items": { + "type": "object", + "required": [ + "finding_id", + "severity", + "category", + "description" + ], + "properties": { + "finding_id": { + "type": "string" + }, + "severity": { + "type": "string", + "enum": [ + "critical", + "high", + "medium", + "low", + "info" + ] + }, + "category": { + "type": "string", + "enum": [ + "ssrf", + "exfiltration", + "command_execution", + "privilege_escalation", + "prompt_injection", + "credential_access", + "supply_chain", + "mcp_header_leakage" + ] + }, + "description": { + "type": "string" + }, + "tool_id": { + "type": "string" + }, + "owasp_mcp_ref": { + "type": "string" + }, + "owasp_agentic_ref": { + "type": "string", + "description": "Reference to OWASP Agentic Applications Top 10 (2026) entry, e.g. ASI01." + } + } + } + }, + "drift": { + "type": "object", + "properties": { + "servers_added": { + "type": "array", + "items": { + "type": "string" + } + }, + "servers_removed": { + "type": "array", + "items": { + "type": "string" + } + }, + "tools_added": { + "type": "array", + "items": { + "type": "string" + } + }, + "tools_removed": { + "type": "array", + "items": { + "type": "string" + } + }, + "permissions_expanded": { + "type": "array", + "items": { + "type": "string" + } + }, + "permissions_reduced": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "verification_endpoint": { + "type": "string", + "format": "uri", + "description": "Optional URL for real-time posture verification. Must use HTTPS scheme. Supports token-based authentication (Bearer token in Authorization header). Called with POST method; tokens are managed separately by the verification system.", + "pattern": "^https://.+", + "examples": [ + "https://verification.trust.example.com/posture/check" + ] + }, + "attestation": { + "type": "object", + "required": [ + "generator" + ], + "properties": { + "generator": { + "type": "string" + }, + "snapshot_hash": { + "type": "string" + }, + "auth": { + "type": "object", + "description": "OAuth 2.0 / token validation state at capture time (MCP 2026-07-28+ security baseline).", + "properties": { + "audience_bound_token_validated": { + "type": "boolean", + "description": "Whether the token used to capture this posture was validated as audience-bound (required by Microsoft MCP security guidance)." + }, + "pkce_used": { + "type": "boolean", + "description": "Whether PKCE was used in the authorization flow." + }, + "per_client_consent_verified": { + "type": "boolean", + "description": "Whether per-client consent was verified before tool invocation." + } + } + } + } + } + } +} diff --git a/schemas/mcp-posture/posture-model-v0.1.md b/schemas/mcp-posture/posture-model-v0.1.md new file mode 100644 index 0000000..88fe9bf --- /dev/null +++ b/schemas/mcp-posture/posture-model-v0.1.md @@ -0,0 +1,130 @@ +# MCP Posture Model v0.1 + +> Status: shipped v0.1 specification. The schema and reference validator are +> published in this repository; implementation maturity remains a research +> preview. + +## What is MCP Posture? + +MCP Posture Management answers: + +- Which MCP servers is this agent connected to? +- Which tools does each server expose? +- What permissions do those tools require? +- Which tools carry high-risk signals (SSRF, exfiltration, command execution, privilege escalation)? +- Has the permission surface changed since the last snapshot? +- Which findings should flow into audit reports? + +MCP Posture is not a simple scan result. It is a continuous posture state with historical tracking. + +## Posture pipeline + +``` +MCP server discovery + ↓ +Tool and permission classification + ↓ +Risk taxonomy mapping + ↓ +Permission graph + ↓ +Posture snapshot (this schema) + ↓ +Historical posture state (Trustavo) + ↓ +Audit evidence integration +``` + +## Schema structure + +``` +MCPPosture v0.1 +├── posture_version — schema version (always "0.1") +├── protocol_version — MCP spec version (e.g. "2026-07-28"; optional, omit for pre-2026-07-28) +├── identity — snapshot ID, agent ID, timestamp +├── servers — connected MCP servers +│ ├── session_model — "stateful" | "stateless-handle" | "unknown" (MCP 2026-07-28+) +│ ├── handle_expiry_policy — handle lifetime policy (stateless-handle model only) +│ └── tools — tools per server with permissions and risk classification +├── permission_graph — aggregate permission surface +├── risk_summary — taxonomy-mapped risk findings (with owasp_agentic_ref) +├── drift — changes since previous snapshot +└── attestation — generator, snapshot hash, and OAuth validation state + └── auth — audience-bound token, PKCE, per-client consent status +``` + +## MCP 2026-07-28 compatibility notes + +The MCP 2026-07-28 specification introduced a **stateless/handle-based architecture** replacing the previous stateful session model. Key schema additions: + +- distinguishes snapshots taken under the new spec +- records which architecture the server uses +- captures OAuth 2.0 resource server validation state (audience-bound token, PKCE, per-client consent) as required by Microsoft MCP security guidance +- now includes to capture sensitive data accidentally mapped into the new / headers + +## Risk taxonomy + +| Category | Description | OWASP MCP reference | OWASP Agentic ref (2026) | +|---|---|---|---| +| | Server-side request forgery via network tools | MCP-02 | ASI05 | +| | Data exfiltration via output or storage tools | MCP-04 | ASI03 | +| | Arbitrary command or code execution | MCP-01 | ASI02 | +| | Permission scope expansion | MCP-03 | ASI06 | +| | Tool input that can manipulate agent behavior | MCP-05 | ASI01 | +| | Access to secrets or credentials | MCP-06 | ASI03 | +| | Unverified MCP server provenance | MCP-07 | ASI01 | +| | Sensitive data in MCP-Method/MCP-Name headers | — | ASI03 | + +> OWASP Agentic Applications Top 10 (2026) mapping is approximate. ASI01 = Agent Goal Hijack / Tool Poisoning; ASI02 = Unsafe Code Execution; ASI03 = Data Exfiltration; ASI05 = SSRF; ASI06 = Privilege Escalation. + +## CLI commands + +```bash +agent-trust mcp-posture validate # Validate against schema +agent-trust mcp-posture inspect # Human-readable summary +agent-trust mcp-posture diff # Show posture drift +``` + +## Standalone product viability + +MCP Posture is designed to operate as an independent MCP security product. The +package `@wasmagent/mcp-posture-core` ships a schema, validator, inspector, and +diff engine with zero external runtime dependencies — it can be consumed outside +the agent-trust-infra monorepo by any MCP security tooling. + +### What this package owns + +| Capability | Export | Purpose | +|---|---|---| +| Schema validation | `validateMCPPosture()` | Structural conformance check for posture snapshots | +| Human-readable inspection | `inspectMCPPosture()` | Summarize servers, tools, risk findings, and permission surface | +| Drift detection | `diffMCPPosture()` / `formatPostureDiff()` | Compare two posture snapshots and report server, tool, permission, and risk changes | +| Risk taxonomy constants | `RISK_CATEGORIES` | Enum of 8 canonical risk categories for programmatic use | +| Type definitions | `PostureDiff`, `RiskCategory`, `SessionModel`, etc. | TypeScript types for posture data structures | + +### Boundary with downstream packages + +- **Runtime MCP scanning** (server discovery, live traffic analysis) → + [`@wasmagent/mcp-attestation`](https://github.com/WasmAgent/wasmagent-js) in + `wasmagent-js`. This package validates *snapshots*; it does not perform live + scanning. +- **Audit report generation** (framework mapping, evidence pipelining) → + [`open-agent-audit`](https://github.com/WasmAgent/open-agent-audit). Posture + snapshots feed into audit reports but report rendering is downstream. +- **Trust Passport issuance / renewal** → `open-agent-audit` / Trustavo. The + posture snapshot is referenced by a Trust Passport but passport lifecycle is + managed separately. + +### Extraction criteria + +MCP Posture can be extracted into a standalone repository when: + +1. The schema version (`posture_version`) has stabilized and no breaking changes + are expected in the short term. +2. External consumers (beyond the WasmAgent ecosystem) adopt the package + independently. +3. The risk taxonomy has coverage across OWASP Agentic Top 10 (ASI01–ASI10). + +Until extraction, the canonical source is this repository. The JSON schema in +`specs/mcp-posture/schema.json` and the reference implementation in +`packages/mcp-posture-core/` are versioned together. diff --git a/schemas/trust-passport/passport-v0.1.md b/schemas/trust-passport/passport-v0.1.md new file mode 100644 index 0000000..7ac8593 --- /dev/null +++ b/schemas/trust-passport/passport-v0.1.md @@ -0,0 +1,123 @@ +# Trust Passport v0.1 Specification + +> Status: shipped v0.1 specification. The schema and reference validator are +> published in this repository; implementation maturity remains a research +> preview. + +## What is a Trust Passport? + +A Trust Passport is a signed trust-state artifact for an AI agent. + +It summarizes evidence quality, open risks, audit references, validity period, renewal triggers, and revocation state (including revoked timestamp, reason, and revoking authority). + +It supports technical due diligence, procurement review, and internal governance workflows. + +Trust Passport is not a legal certification, security certification, or ISO/EU AI Act compliance attestation. + +## Trust Passport answers + +- When was this agent last audited? +- What is the audit report hash? +- What is the AgentBOM hash? +- Are there open risks? +- What is the evidence quality? +- Which frameworks have selected technical evidence support? +- When does this passport expire? +- What changes trigger renewal? +- Has this passport been revoked? + +## Validity model + +A Trust Passport has a validity period defined at issuance. The default validity period is 90 days. + +### Renewal triggers + +A passport should be renewed when any of the following occur before expiry: + +- AgentBOM changes (new tools, permission changes, model update) +- New high or critical risk finding +- MCP posture drift detected +- Audit report updated +- Deployment context changes + +### Revocation triggers + +A passport is revoked when: + +- Critical security finding is discovered after issuance +- Evidence is found to be falsified +- Agent is decommissioned +- Issuer determines the trust state is no longer valid + +### Expiry vs. revocation + +Expiry and revocation are distinct states with different semantics and consequences: + +| Aspect | Expiry | Revocation | +|--------|---------|------------| +| **Cause** | Natural passage of time beyond `expires_at` | Explicit action due to a trigger event | +| **Reversibility** | Can be resolved by renewing the passport | Irreversible — a new passport must be issued from scratch | +| **Trust signal** | Passport is stale but was never invalid | Passport was valid at issuance but is now untrusted | +| **Recommended action** | Re-evaluate agent state and renew | Investigate the revocation trigger before any new issuance | + +A passport that has both expired **and** been revoked should be treated as revoked — revocation takes precedence as the stronger trust signal. + +### `isExpired()` implementation + +The `isExpired()` function determines whether a passport's validity window has passed. It operates solely on the `validity.expires_at` timestamp and the current system time — it does not check revocation status. + +```typescript +function isExpired(passport: { validity?: { expires_at?: string } }): boolean { + const expiresAt = passport.validity?.expires_at; + if (!expiresAt) return false; + return new Date(expiresAt) < new Date(); +} +``` + +Key behaviors: + +- Returns `false` if `validity` or `expires_at` is missing (defensive — a malformed passport is not expired, merely invalid). +- Compares `expires_at` as an ISO 8601 date-time string against the current wall-clock time. +- Does **not** account for revocation — use a separate `isRevoked()` check (see revocation triggers above) and always check both independently when evaluating overall passport trustworthiness. + +### Trustavo integration (future) + +The Trustavo product (`trustavo.com/passport`) will automate lifecycle management of Trust Passports, including: + +- Automated renewal workflows triggered by AgentBOM or posture drift detection +- Revocation propagation through a distributed status channel +- Configurable validity periods per issuer policy (overriding the 90-day default) + +See [Future product home](#future-product-home) for the planned CLI surface. + +## Schema structure + +``` +TrustPassport v0.1 +├── identity — passport ID, agent ID, issuance context +├── agentbom_ref — hash reference to AgentBOM +├── audit_ref — hash reference to audit report +├── posture_ref — hash reference to MCP posture snapshot +├── evidence_summary — evidence quality and framework mapping +├── risk_summary — open risk count by severity +├── validity — issued_at, expires_at, renewal triggers +├── revocation — revoked flag, revoked_at, revocation_reason, revoking_authority, revocation triggers +└── attestation — issuer, signature +``` + +## CLI commands + +```bash +agent-trust passport validate # Validate against schema +agent-trust passport inspect # Human-readable summary +``` + +## Future product home + +Trust Passport will be productized in `open-agent-audit / Trustavo` at `trustavo.com/passport` once the schema and workflow stabilize. + +Future CLI (in open-agent-audit): +```bash +open-agent-audit passport issue --report audit-report.json --agentbom agentbom.json --out trust-passport.json +open-agent-audit passport verify trust-passport.json +``` diff --git a/schemas/trust-passport/rfc-multi-party-negotiation.md b/schemas/trust-passport/rfc-multi-party-negotiation.md new file mode 100644 index 0000000..d04b376 --- /dev/null +++ b/schemas/trust-passport/rfc-multi-party-negotiation.md @@ -0,0 +1,553 @@ +# RFC 001: Multi-Party Trust Negotiation Protocol + +> **Status:** draft — Milestone 8, Production Readiness & Enterprise Integration. +> **Tracking:** WasmAgent/agent-trust-infra#216. +> **Last updated:** 2026-07-20. + +## 1. Abstract + +This RFC defines a protocol for federated Trust Passport exchange between +organizations. It enables cross-org AI agent deployment through **mutual +attestation** and **policy reconciliation**: two parties each present their +trust state, verify the other's evidence, and agree on shared deployment policy +before an agent is permitted to operate across organizational boundaries. + +The protocol is **message-based** and **asynchronous-friendly** — parties may +exchange messages over any transport (HTTPS, message queue, git-backed channel) +without requiring synchronous handshakes. + +## 2. Motivation + +The Trust Passport v0.1 specification ([passport-v0.1.md](passport-v0.1.md)) +defines a single-issuer trust artifact. An agent operating within one +organization can carry a passport signed by that organization's issuer. However, +real-world deployments increasingly require agents to: + +- **Cross organizational boundaries** — an agent built by Org A needs to access + tools or data hosted by Org B. +- **Present verifiable trust state** — Org B must evaluate Org A's trust + evidence against its own governance policy before granting access. +- **Negotiate policy** — each organization may have different minimum evidence + thresholds, blocked tool categories, or compliance framework requirements. + Deployment proceeds only when both parties' constraints are satisfied. +- **Maintain ongoing assurance** — trust state drifts over time; both parties + need a mechanism to re-evaluate and renegotiate after initial agreement. + +Without a negotiation protocol, federated agent deployment relies on ad-hoc +email-based review, manual evidence collection, and inconsistent policy +application. This RFC standardizes the exchange. + +## 3. Relationship to existing specifications + +| Spec | Role in negotiation | +|---|---| +| **Trust Passport v0.1** ([passport-v0.1.md](passport-v0.1.md), [schema.json](schema.json)) | The artifact being exchanged. Each party presents a signed Trust Passport as the primary evidence. | +| **Compliance Profile v0.1** ([../compliance-profile/schema.json](../compliance-profile/schema.json)) | Defines each party's governance rules. Policy reconciliation computes the intersection of both profiles. | +| **AgentBOM** ([../agentbom/](../agentbom/)) | Referenced by `agentbom_ref` inside the Trust Passport. Provides tool inventory and permission detail for policy evaluation. | +| **MCP Posture** ([../mcp-posture/](../mcp-posture/)) | Referenced by `posture_ref` inside the Trust Passport. Provides MCP attack-surface detail for cross-org deployment decisions. | + +This RFC does **not** modify any existing schema. It defines a new +`NegotiationEnvelope` message format that wraps existing artifacts. + +## 4. Glossary + +| Term | Definition | +|---|---| +| **Initiator** | The organization proposing a cross-org deployment. Sends the first `NegotiationOffer`. | +| **Responder** | The organization evaluating the offer. Accepts, rejects, or counters with modified policy. | +| **NegotiationEnvelope** | The top-level message container carrying one step of a negotiation. | +| **Policy reconciliation** | The process of computing the union of constraints from both parties' compliance profiles. | +| **Deployment agreement** | The final signed artifact confirming both parties accept the reconciled policy and each other's trust evidence. | + +## 5. Protocol overview + +The negotiation follows a three-phase lifecycle: + +``` +Phase 1: DISCOVERY Phase 2: NEGOTIATION Phase 3: AGREEMENT +───────────────── ───────────────── ───────────────── +Initiator Initiator Both parties + │ │ │ + ├─ NegotiationOffer ──────► │ │ + │ (passport + policy) │ │ + │ ├─ NegotiationCounter ─────► │ + │ │ (counter-policy) │ + │ │ │ + │ ├─ NegotiationAccept ──────► │ + │ │ ├─ DeploymentAgreement + │ │ │ (signed by both) + │ │ │ + └─────────────────────────────┴──────────────────────────────┘ +``` + +### Phase 1: Discovery (offer) + +The Initiator sends a `NegotiationOffer` containing: + +- Its own signed Trust Passport (attesting to the agent's trust state). +- Its outgoing deployment policy (what it requires from the Responder). +- A nonce and timestamp for replay protection. + +### Phase 2: Negotiation (counter / accept / reject) + +The Responder evaluates the offer against its own compliance profile. Three +outcomes: + +- **NegotiationAccept** — the Responder's policy is compatible. It attaches + its own Trust Passport and policy, forming a two-sided agreement. +- **NegotiationCounter** — the Responder requires additional constraints. It + proposes a modified policy. The Initiator may accept, counter again, or + reject. The protocol allows up to `max_rounds` (default 5) counter-offers. +- **NegotiationReject** — the Responder cannot reconcile policies. It + includes a human-readable reason and a list of unsatisfied constraints. + +### Phase 3: Agreement + +Both parties sign a `DeploymentAgreement` containing: + +- The reconciled policy (intersection of both parties' constraints). +- Both Trust Passports with their signatures. +- Deployment scope (which tools, data, and environments are permitted). +- Validity period and renewal mechanism. + +## 6. Message format + +### 6.1 NegotiationEnvelope (top-level container) + +Every message in the protocol is a `NegotiationEnvelope`: + +```json +{ + "envelope_version": "0.1", + "message_type": "NegotiationOffer | NegotiationCounter | NegotiationAccept | NegotiationReject", + "negotiation_id": "uuid-v4", + "round": 0, + "timestamp": "2026-07-20T12:00:00Z", + "initiator": { + "org_id": "did:web:org-a.example.com", + "contact": "trust@org-a.example.com" + }, + "responder": { + "org_id": "did:web:org-b.example.com", + "contact": "trust@org-b.example.com" + }, + "payload": { }, + "attestation": { + "issuer": "did:web:org-a.example.com", + "signature": "" + } +} +``` + +| Field | Type | Required | Description | +|---|---|---|---| +| `envelope_version` | string | yes | Protocol version. Must be `"0.1"`. | +| `message_type` | enum | yes | One of the four message types. | +| `negotiation_id` | string (UUIDv4) | yes | Unique identifier for this negotiation session. Stable across all rounds. | +| `round` | integer ≥ 0 | yes | Round number. `0` = offer, `1` = first counter, etc. | +| `timestamp` | ISO 8601 | yes | When this message was created. | +| `initiator` | object | yes | Initiator identity. `org_id` is a DID-style identifier. | +| `responder` | object | yes | Responder identity. May be partially populated in the initial offer. | +| `payload` | object | yes | Message-type-specific payload (see §6.2–6.5). | +| `attestation` | object | yes | Sender's signature over the canonicalized payload. | + +### 6.2 NegotiationOffer payload + +```json +{ + "trust_passport": { }, + "deployment_policy": { + "required_frameworks": ["eu-ai-act-annex-iv", "soc2-2024"], + "min_evidence_quality": "medium", + "max_unmitigated_critical": 0, + "max_unmitigated_high": 2, + "blocked_tool_permissions": ["filesystem:write"], + "allowed_deployment_contexts": ["staging", "production"], + "renewal_interval_days": 90 + }, + "agent_scope": { + "agent_id": "agent-abc-123", + "intended_tools": ["mcp://org-b.example.com/filesystem", "mcp://org-b.example.com/database"], + "intended_environments": ["production"], + "data_classification": ["internal", "confidential"] + }, + "nonce": "random-64-char-hex-string" +} +``` + +| Field | Type | Required | Description | +|---|---|---|---| +| `trust_passport` | TrustPassport v0.1 | yes | Initiator's signed Trust Passport. | +| `deployment_policy` | object | yes | Initiator's policy requirements (minimum evidence, blocked permissions, etc.). | +| `agent_scope` | object | yes | What the agent intends to access at the Responder's organization. | +| `nonce` | string | yes | Cryptographic nonce for replay protection. | + +### 6.3 NegotiationCounter payload + +```json +{ + "counter_policy": { + "required_frameworks": ["eu-ai-act-annex-iv", "soc2-2024", "iso27001-2022"], + "min_evidence_quality": "high", + "max_unmitigated_critical": 0, + "max_unmitigated_high": 1, + "blocked_tool_permissions": ["filesystem:write", "network:external"], + "allowed_deployment_contexts": ["staging"], + "renewal_interval_days": 60 + }, + "trust_passport": { }, + "counter_reason": "Org B requires ISO 27001 mapping and restricts initial deployment to staging" +} +``` + +| Field | Type | Required | Description | +|---|---|---|---| +| `counter_policy` | object | yes | Responder's proposed policy. | +| `trust_passport` | TrustPassport v0.1 | yes | Responder's own Trust Passport (for the Initiator to verify). | +| `counter_reason` | string | no | Human-readable explanation of the counter. | + +### 6.4 NegotiationAccept payload + +```json +{ + "agreed_policy": { + "required_frameworks": ["eu-ai-act-annex-iv", "soc2-2024", "iso27001-2022"], + "min_evidence_quality": "high", + "max_unmitigated_critical": 0, + "max_unmitigated_high": 1, + "blocked_tool_permissions": ["filesystem:write", "network:external"], + "allowed_deployment_contexts": ["staging"], + "renewal_interval_days": 60 + }, + "initiator_passport": { }, + "responder_passport": { }, + "accepted_round": 1 +} +``` + +### 6.5 NegotiationReject payload + +```json +{ + "rejection_reason": "Policy irreconcilable: Org A requires production deployment but Org B mandates staging-only for external agents", + "unsatisfied_constraints": [ + { + "rule": "allowed_deployment_contexts", + "initiator_value": ["staging", "production"], + "responder_value": ["staging"], + "conflict": "no intersection on 'production'" + } + ], + "suggested_alternatives": ["Restrict agent to staging environment", "Org A to grant Org B tool-level attestation exception"] +} +``` + +## 7. Policy reconciliation algorithm + +Given two deployment policies (P_initiator and P_responder), reconciliation +computes P_agreed — the **intersection** of constraints. A constraint is +reconciled as follows: + +### 7.1 Scalar constraints (take the stricter value) + +| Constraint | Reconciliation rule | +|---|---| +| `min_evidence_quality` | Take the higher quality threshold (`high > medium > low > insufficient`). If initiator requires `medium` and responder requires `high`, agreed = `high`. | +| `max_unmitigated_critical` | Take the lower value (strictest). If either party says 0, agreed = 0. | +| `max_unmitigated_high` | Take the lower value. | +| `renewal_interval_days` | Take the shorter interval (more frequent renewal). | + +### 7.2 Set constraints (take the intersection) + +| Constraint | Reconciliation rule | +|---|---| +| `required_frameworks` | Take the **union** — both parties' framework requirements must be met. | +| `blocked_tool_permissions` | Take the **union** — if either party blocks a permission, it is blocked in the agreement. | +| `allowed_deployment_contexts` | Take the **intersection** — only contexts allowed by both parties are permitted. | + +### 7.3 Irreconcilable constraints + +A constraint is irreconcilable when: + +- `allowed_deployment_contexts` intersection is empty. +- `min_evidence_quality` cannot be satisfied by one party's Trust Passport. +- `required_frameworks` includes a framework that one party's Trust Passport does not map to (`coverage: "none"`). + +When any constraint is irreconcilable, the protocol produces a +`NegotiationReject` with the specific unsatisfied constraints listed. + +## 8. Deployment agreement + +After a `NegotiationAccept`, both parties sign a `DeploymentAgreement`: + +```json +{ + "agreement_version": "0.1", + "agreement_id": "uuid-v4", + "negotiation_id": "uuid-v4 (from negotiation)", + "initiator": { + "org_id": "did:web:org-a.example.com", + "passport_hash": "sha256:", + "signature": "" + }, + "responder": { + "org_id": "did:web:org-b.example.com", + "passport_hash": "sha256:", + "signature": "" + }, + "agreed_policy": { }, + "agent_scope": { }, + "validity": { + "agreed_at": "2026-07-20T14:00:00Z", + "expires_at": "2026-09-18T14:00:00Z", + "renewal_trigger": "both passports renewed or policy change" + }, + "status": "active" +} +``` + +### 8.1 Renewal and drift + +The agreement has a validity period tied to the **shorter** of the two Trust +Passport expiry dates. If either passport expires or is revoked, the agreement +becomes `suspended`. Either party may trigger renegotiation by sending a new +`NegotiationOffer` referencing the original `negotiation_id`. + +## 9. Security considerations + +### 9.1 Replay protection + +Every `NegotiationOffer` contains a `nonce`. Responders must track consumed +nonces for a window equal to the negotiation timeout (recommended: 24 hours). + +### 9.2 Signature verification + +All messages carry an `attestation` block with an Ed25519 signature over the +canonicalized payload (JSON with sorted keys, no whitespace). Receivers must: + +1. Verify the signature against the sender's known public key (resolved via + `org_id` DID document). +2. Verify the payload matches the canonical form used for signing. +3. Reject messages with expired timestamps (recommended: 1-hour clock skew). + +### 9.3 Passport freshness + +Negotiation parties should verify that the presented Trust Passport: +- Is not expired (`validity.expires_at` > now). +- Is not revoked (`revocation.revoked` = false). +- Has been issued within the last `renewal_interval_days` of the agreement. + +### 9.4 Minimum disclosure + +The protocol is designed for **minimum disclosure** — a party need only share +its Trust Passport with organizations it is actively negotiating with. The +`agent_scope` field limits what tool and environment access is being requested, +preventing over-broad authorization. + +### 9.5 Transport security + +Messages must be transmitted over TLS 1.3 or equivalent. The protocol itself +does not define a transport; implementers may use HTTPS APIs, SIGNED git commits, +or message queues with server-side encryption. + +## 10. Transport binding (informative) + +The protocol is transport-agnostic. Recommended bindings: + +| Transport | When to use | Notes | +|---|---|---| +| **HTTPS REST** | Synchronous, low-volume negotiations | `POST /negotiation/{negotiation_id}` | +| **Signed git commits** | Auditability-critical workflows | Each message is a commit to a shared negotiation repository | +| **Message queue** | High-throughput, multi-party workflows | Each message is an event on a topic keyed by `negotiation_id` | +| **Email with S/MIME** | Human-in-the-loop workflows | For organizations requiring manual review before acceptance | + +## 11. Extension points + +### 11.1 Multi-party (N-way) negotiation + +This RFC defines the pairwise (two-party) case. N-way negotiation (e.g., +three organizations agreeing on shared agent deployment) is a natural +extension: the reconciliation algorithm generalizes to computing the +intersection of N policies. N-way negotiation is deferred to a future RFC. + +### 11.2 Automated policy agents + +An organization may deploy a policy agent that evaluates incoming offers against +its compliance profile and automatically responds with `NegotiationAccept`, +`NegotiationCounter`, or `NegotiationReject` without human intervention. The +message format supports this — `counter_reason` and `suggested_alternatives` +provide human-readable context when automated decisions need review. + +### 11.3 Revocation propagation + +When a Trust Passport is revoked mid-agreement, the revoking party should +proactively notify the counterparty via a transport-specific mechanism (webhook, +queue message, or signed git commit). The notified party must immediately +suspend the deployment agreement pending re-evaluation. A formal revocation +notification message type is deferred to a future RFC. + +## 12. Worked example + +### Scenario + +Org A (`acme-corp.example.com`) wants to deploy their agent `data-analyst-v3` +to access Org B's (`global-fin.example.com`) financial data API. Both +organizations have Trust Passports and compliance profiles. + +### Step 1: Org A sends NegotiationOffer + +```json +{ + "envelope_version": "0.1", + "message_type": "NegotiationOffer", + "negotiation_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "round": 0, + "timestamp": "2026-07-20T10:00:00Z", + "initiator": { + "org_id": "did:web:acme-corp.example.com", + "contact": "trust@acme-corp.example.com" + }, + "responder": { + "org_id": "did:web:global-fin.example.com" + }, + "payload": { + "trust_passport": { + "passport_version": "0.1", + "identity": { + "passport_id": "tp-acme-2026-007", + "agent_id": "data-analyst-v3", + "agent_name": "Data Analyst v3", + "issuer": "acme-corp.example.com", + "issuance_context": "trustavo" + }, + "evidence_summary": { + "evidence_quality": "high", + "framework_mappings": [ + { "framework": "soc2-2024", "coverage": "selected_technical_evidence" }, + { "framework": "eu-ai-act-annex-iv", "coverage": "partial" } + ] + }, + "risk_summary": { "critical": 0, "high": 1, "medium": 3, "low": 5 }, + "validity": { + "issued_at": "2026-06-01T00:00:00Z", + "expires_at": "2026-08-30T00:00:00Z" + }, + "revocation": { "revoked": false }, + "attestation": { + "issuer": "acme-corp.example.com", + "passport_hash": "sha256:abc123...", + "signature": "" + } + }, + "deployment_policy": { + "required_frameworks": ["soc2-2024"], + "min_evidence_quality": "medium", + "max_unmitigated_critical": 0, + "blocked_tool_permissions": ["filesystem:write"], + "allowed_deployment_contexts": ["staging", "production"], + "renewal_interval_days": 90 + }, + "agent_scope": { + "agent_id": "data-analyst-v3", + "intended_tools": ["mcp://global-fin.example.com/financial-data-api"], + "intended_environments": ["production"], + "data_classification": ["confidential"] + }, + "nonce": "f47ac10b58cc4372a5670e02b2c3d479" + } +} +``` + +### Step 2: Org B responds with NegotiationCounter + +Org B's compliance profile requires ISO 27001 and restricts external agents to +staging initially: + +```json +{ + "envelope_version": "0.1", + "message_type": "NegotiationCounter", + "negotiation_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "round": 1, + "timestamp": "2026-07-20T10:15:00Z", + "initiator": { + "org_id": "did:web:acme-corp.example.com" + }, + "responder": { + "org_id": "did:web:global-fin.example.com", + "contact": "trust@global-fin.example.com" + }, + "payload": { + "counter_policy": { + "required_frameworks": ["soc2-2024", "iso27001-2022"], + "min_evidence_quality": "high", + "max_unmitigated_critical": 0, + "max_unmitigated_high": 1, + "blocked_tool_permissions": ["filesystem:write", "network:external"], + "allowed_deployment_contexts": ["staging"], + "renewal_interval_days": 60 + }, + "trust_passport": { + "passport_version": "0.1", + "identity": { + "passport_id": "tp-gfin-2026-012", + "agent_id": "financial-data-gateway", + "agent_name": "Financial Data Gateway", + "issuer": "global-fin.example.com", + "issuance_context": "trustavo" + }, + "evidence_summary": { + "evidence_quality": "high", + "framework_mappings": [ + { "framework": "iso27001-2022", "coverage": "selected_technical_evidence" }, + { "framework": "soc2-2024", "coverage": "selected_technical_evidence" } + ] + }, + "risk_summary": { "critical": 0, "high": 0, "medium": 2, "low": 4 }, + "validity": { + "issued_at": "2026-05-15T00:00:00Z", + "expires_at": "2026-08-13T00:00:00Z" + }, + "revocation": { "revoked": false }, + "attestation": { + "issuer": "global-fin.example.com", + "passport_hash": "sha256:def456...", + "signature": "" + } + }, + "counter_reason": "Global Financial requires ISO 27001 attestation and initial staging-only deployment for external agents. Production access requires 30-day staging observation period." + } +} +``` + +### Step 3: Org A accepts + +Org A's agent meets the `high` evidence quality threshold and has no +unmitigated critical risks. Org A agrees to staging deployment with a 60-day +renewal cycle. + +### Step 4: Both parties sign DeploymentAgreement + +The agreement locks in the reconciled policy and both passports. It expires on +2026-08-13 (the shorter of the two passport expiry dates). Both parties store +the agreement and begin the staging deployment. + +## 13. Implementation notes + +This RFC is a **specification-layer deliverable**. Reference implementation +belongs in `open-agent-audit` (`@openagentaudit/negotiation`), leveraging: + +- `@wasmagent/aep` for evidence emission and signing. +- `@wasmagent/mcp-attestation` for capability attestation. +- `@wasmagent/mcp-gateway` for policy enforcement at runtime. + +The `trust-passport-core` and `trust-runtime` packages in **this** repository are +frozen and will not be extended. Validators for the `NegotiationEnvelope` +message format should be added to this repository's spec layer once the schema +stabilizes. + +## 14. Revision history + +| Version | Date | Author | Change | +|---|---|---|---| +| 0.1-draft | 2026-07-20 | claude-bot (auto) | Initial draft — Milestone 8 deliverable | diff --git a/schemas/trust-passport/trust-passport.schema.json b/schemas/trust-passport/trust-passport.schema.json new file mode 100644 index 0000000..94685ba --- /dev/null +++ b/schemas/trust-passport/trust-passport.schema.json @@ -0,0 +1,230 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "TrustPassport", + "type": "object", + "required": [ + "passport_version", + "identity", + "validity", + "revocation", + "attestation" + ], + "properties": { + "passport_version": { + "type": "string", + "enum": [ + "0.1" + ] + }, + "identity": { + "type": "object", + "required": [ + "passport_id", + "agent_id", + "issuer" + ], + "properties": { + "passport_id": { + "type": "string" + }, + "agent_id": { + "type": "string" + }, + "agent_name": { + "type": "string" + }, + "issuer": { + "type": "string" + }, + "issuance_context": { + "type": "string", + "enum": [ + "self-issued", + "trustavo" + ] + } + } + }, + "agentbom_ref": { + "type": "object", + "properties": { + "agentbom_id": { + "type": "string" + }, + "agentbom_hash": { + "type": "string" + }, + "captured_at": { + "type": "string", + "format": "date-time" + } + } + }, + "audit_ref": { + "type": "object", + "properties": { + "report_id": { + "type": "string" + }, + "report_hash": { + "type": "string" + }, + "generated_at": { + "type": "string", + "format": "date-time" + } + } + }, + "posture_ref": { + "type": "object", + "properties": { + "snapshot_id": { + "type": "string" + }, + "snapshot_hash": { + "type": "string" + }, + "captured_at": { + "type": "string", + "format": "date-time" + } + } + }, + "evidence_summary": { + "type": "object", + "properties": { + "evidence_quality": { + "type": "string", + "enum": [ + "high", + "medium", + "low", + "insufficient" + ] + }, + "framework_mappings": { + "type": "array", + "items": { + "type": "object", + "required": [ + "framework", + "coverage" + ], + "properties": { + "framework": { + "type": "string" + }, + "coverage": { + "type": "string", + "enum": [ + "selected_technical_evidence", + "partial", + "none" + ] + }, + "note": { + "type": "string" + } + } + } + } + } + }, + "risk_summary": { + "type": "object", + "properties": { + "critical": { + "type": "integer", + "minimum": 0 + }, + "high": { + "type": "integer", + "minimum": 0 + }, + "medium": { + "type": "integer", + "minimum": 0 + }, + "low": { + "type": "integer", + "minimum": 0 + }, + "open_findings": { + "type": "integer", + "minimum": 0 + } + } + }, + "validity": { + "type": "object", + "required": [ + "issued_at", + "expires_at" + ], + "properties": { + "issued_at": { + "type": "string", + "format": "date-time" + }, + "expires_at": { + "type": "string", + "format": "date-time" + }, + "renewal_triggers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "revocation": { + "type": "object", + "properties": { + "revoked": { + "type": "boolean" + }, + "revoked_at": { + "type": "string", + "format": "date-time" + }, + "revocation_reason": { + "type": "string" + }, + "revocation_triggers": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "attestation": { + "type": "object", + "required": [ + "issuer" + ], + "properties": { + "issuer": { + "type": "string" + }, + "signing_method": { + "type": "string", + "enum": [ + "none", + "sigstore", + "ed25519" + ] + }, + "passport_hash": { + "type": "string" + }, + "signature": { + "type": "string" + } + } + } + }, + "$id": "https://wasmagent.dev/schemas/trust-passport/v0.1.schema.json", + "description": "Agent Trust Passport v0.1 \u2014 canonical schema. The authoritative source for this schema is WasmAgent/wasmagent-protocol." +} From 4ba0f7a04c130e798c9622129ac151edeed6b065 Mon Sep 17 00:00:00 2001 From: Claude Bot Date: Fri, 24 Jul 2026 08:59:49 +0800 Subject: [PATCH 2/3] test: add conformance fixtures for agentbom, mcp-posture, trust-passport --- .../invalid/agentbom/missing-version.json | 5 +++++ .../invalid/mcp-posture/missing-version.json | 4 ++++ .../invalid/trust-passport/missing-version.json | 9 +++++++++ tests/fixtures/valid/agentbom/minimal.json | 9 +++++++++ tests/fixtures/valid/mcp-posture/minimal.json | 6 ++++++ .../fixtures/valid/trust-passport/minimal.json | 17 +++++++++++++++++ 6 files changed, 50 insertions(+) create mode 100644 tests/fixtures/invalid/agentbom/missing-version.json create mode 100644 tests/fixtures/invalid/mcp-posture/missing-version.json create mode 100644 tests/fixtures/invalid/trust-passport/missing-version.json create mode 100644 tests/fixtures/valid/agentbom/minimal.json create mode 100644 tests/fixtures/valid/mcp-posture/minimal.json create mode 100644 tests/fixtures/valid/trust-passport/minimal.json diff --git a/tests/fixtures/invalid/agentbom/missing-version.json b/tests/fixtures/invalid/agentbom/missing-version.json new file mode 100644 index 0000000..8a36af6 --- /dev/null +++ b/tests/fixtures/invalid/agentbom/missing-version.json @@ -0,0 +1,5 @@ +{ + "identity": { + "agent_id": "x" + } +} diff --git a/tests/fixtures/invalid/mcp-posture/missing-version.json b/tests/fixtures/invalid/mcp-posture/missing-version.json new file mode 100644 index 0000000..ab16f5b --- /dev/null +++ b/tests/fixtures/invalid/mcp-posture/missing-version.json @@ -0,0 +1,4 @@ +{ + "agent_id": "x", + "scanned_at": "2026-01-01T00:00:00Z" +} diff --git a/tests/fixtures/invalid/trust-passport/missing-version.json b/tests/fixtures/invalid/trust-passport/missing-version.json new file mode 100644 index 0000000..4e13776 --- /dev/null +++ b/tests/fixtures/invalid/trust-passport/missing-version.json @@ -0,0 +1,9 @@ +{ + "identity": { + "agent_id": "x" + }, + "validity": { + "issued_at": "2026-01-01T00:00:00Z", + "expires_at": "2099-12-31T00:00:00Z" + } +} diff --git a/tests/fixtures/valid/agentbom/minimal.json b/tests/fixtures/valid/agentbom/minimal.json new file mode 100644 index 0000000..cf211ff --- /dev/null +++ b/tests/fixtures/valid/agentbom/minimal.json @@ -0,0 +1,9 @@ +{ + "agentbom_version": "0.1", + "identity": { + "agent_id": "test-agent-001", + "agent_name": "Test Agent", + "deployment_context": "development", + "generated_at": "2026-01-01T00:00:00Z" + } +} diff --git a/tests/fixtures/valid/mcp-posture/minimal.json b/tests/fixtures/valid/mcp-posture/minimal.json new file mode 100644 index 0000000..39dd577 --- /dev/null +++ b/tests/fixtures/valid/mcp-posture/minimal.json @@ -0,0 +1,6 @@ +{ + "posture_version": "0.1", + "agent_id": "test-agent-001", + "scanned_at": "2026-01-01T00:00:00Z", + "servers": [] +} diff --git a/tests/fixtures/valid/trust-passport/minimal.json b/tests/fixtures/valid/trust-passport/minimal.json new file mode 100644 index 0000000..59ec7b9 --- /dev/null +++ b/tests/fixtures/valid/trust-passport/minimal.json @@ -0,0 +1,17 @@ +{ + "passport_version": "0.1", + "identity": { + "agent_id": "test-agent-001", + "issued_at": "2026-01-01T00:00:00Z" + }, + "validity": { + "issued_at": "2026-01-01T00:00:00Z", + "expires_at": "2099-12-31T00:00:00Z" + }, + "revocation": { + "revoked": false + }, + "attestation": { + "trust_score": 80 + } +} From 63e05f38e444d5d1b9d866582fd58fce35255d89 Mon Sep 17 00:00:00 2001 From: Claude Bot Date: Fri, 24 Jul 2026 09:06:38 +0800 Subject: [PATCH 3/3] fix(fixtures): add required fields to pass jsonschema validation in CI --- tests/fixtures/valid/agentbom/minimal.json | 8 +++++--- tests/fixtures/valid/mcp-posture/minimal.json | 12 +++++++++--- tests/fixtures/valid/trust-passport/minimal.json | 7 ++++--- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/tests/fixtures/valid/agentbom/minimal.json b/tests/fixtures/valid/agentbom/minimal.json index cf211ff..84a5be4 100644 --- a/tests/fixtures/valid/agentbom/minimal.json +++ b/tests/fixtures/valid/agentbom/minimal.json @@ -1,9 +1,11 @@ { "agentbom_version": "0.1", "identity": { - "agent_id": "test-agent-001", - "agent_name": "Test Agent", - "deployment_context": "development", + "agent_id": "a1", + "agent_name": "Test", "generated_at": "2026-01-01T00:00:00Z" + }, + "attestation": { + "generator": "test-tool" } } diff --git a/tests/fixtures/valid/mcp-posture/minimal.json b/tests/fixtures/valid/mcp-posture/minimal.json index 39dd577..26984be 100644 --- a/tests/fixtures/valid/mcp-posture/minimal.json +++ b/tests/fixtures/valid/mcp-posture/minimal.json @@ -1,6 +1,12 @@ { "posture_version": "0.1", - "agent_id": "test-agent-001", - "scanned_at": "2026-01-01T00:00:00Z", - "servers": [] + "identity": { + "snapshot_id": "snap-001", + "agent_id": "a1", + "captured_at": "2026-01-01T00:00:00Z" + }, + "servers": [], + "attestation": { + "generator": "test-tool" + } } diff --git a/tests/fixtures/valid/trust-passport/minimal.json b/tests/fixtures/valid/trust-passport/minimal.json index 59ec7b9..b763e2e 100644 --- a/tests/fixtures/valid/trust-passport/minimal.json +++ b/tests/fixtures/valid/trust-passport/minimal.json @@ -1,8 +1,9 @@ { "passport_version": "0.1", "identity": { - "agent_id": "test-agent-001", - "issued_at": "2026-01-01T00:00:00Z" + "passport_id": "pp-001", + "agent_id": "a1", + "issuer": "test-issuer" }, "validity": { "issued_at": "2026-01-01T00:00:00Z", @@ -12,6 +13,6 @@ "revoked": false }, "attestation": { - "trust_score": 80 + "issuer": "test-issuer" } }