diff --git a/index.d.ts b/index.d.ts index 465117e..036b02e 100644 --- a/index.d.ts +++ b/index.d.ts @@ -31,6 +31,91 @@ export const schemas: Record; */ export function getSchema(id: string): unknown; +// --------------------------------------------------------------------------- +// Canonical event type (the aep-record shape). +// +// `AepRecord` is the typed view of the canonical-event wire contract +// (schemas/v0.1/canonical-event.schema.json). Each field maps 1:1 onto the +// Agent Evidence Protocol record, so consumers get types instead of an opaque +// object. open-agent-audit maps its v0.1 events onto this shape before +// validating them against the aep-record schema. +// --------------------------------------------------------------------------- + +/** Agent identity that produced a canonical event. Maps to AEP run_context. */ +export interface CanonicalEventAgent { + agent_id?: string; + agent_version?: string; + subagent_id?: string; + delegation_chain?: string[]; + [key: string]: unknown; +} + +/** A single state-changing tool action. Maps to an AEP actions[] entry. */ +export interface CanonicalEventAction { + action_id: string; + tool_name: string; + state_changing: boolean; + timestamp_ms: number; + precondition_digest?: string; + result_digest?: string; + parent_action_id?: string; + evidence_refs?: string[]; + [key: string]: unknown; +} + +/** A capability allow/deny decision. Maps to an AEP capability_decisions[] entry. */ +export interface CanonicalEventCapabilityDecision { + capability: string; + subject: string; + resource: string; + decision: 'allow' | 'deny' | 'ask_user' | 'dry_run'; + reason_code?: string; + [key: string]: unknown; +} + +/** A verifier pass/fail result. Maps to an AEP verifier_results[] entry. */ +export interface CanonicalEventVerifierResult { + verifier_id: string; + passed: boolean; + score?: number; + claim_ids?: string[]; + [key: string]: unknown; +} + +/** Tamper-evident signature over the event. Maps to the AEP signature block. */ +export interface CanonicalEventSignature { + alg: string; + key_id: string; + sig: string; + bundle?: Record; + transparency_log_ref?: string; + [key: string]: unknown; +} + +/** + * The canonical event (aep-record) type exported by @wasmagent/protocol. + * Maps onto schemas/v0.1/canonical-event.schema.json and the Agent Evidence + * Protocol record shape. + */ +export interface AepRecord { + schema_version: 'canonical-event/v0.1'; + event_id: string; + event_type: 'action' | 'capability_decision' | 'verifier_result' | 'run_lifecycle' | 'custom'; + run_id: string; + trace_id?: string; + parent_trace_id?: string | null; + created_at_ms: number; + agent?: CanonicalEventAgent; + action?: CanonicalEventAction; + capability_decision?: CanonicalEventCapabilityDecision; + verifier_result?: CanonicalEventVerifierResult; + payload?: Record; + signature?: CanonicalEventSignature; +} + +/** Alias naming the same type after the canonical-event schema. */ +export type CanonicalEvent = AepRecord; + // --------------------------------------------------------------------------- // Cross-repo schema drift detection. // --------------------------------------------------------------------------- diff --git a/schemas/index.json b/schemas/index.json index 2bc43b1..dc567be 100644 --- a/schemas/index.json +++ b/schemas/index.json @@ -41,6 +41,21 @@ ], "summary": "Shared envelope base for all AEP evidence records \u2014 schema_version, trace_id, created_at_ms, and optional signature." }, + { + "id": "canonical-event", + "title": "CanonicalEvent", + "path": "schemas/v0.1/canonical-event.schema.json", + "canonical_id": "https://wasmagent.dev/schemas/v0.1/canonical-event.schema.json", + "version": "canonical-event/v0.1", + "stability": "evolving", + "owners": [ + "wasmagent-protocol" + ], + "consumers": [ + "open-agent-audit" + ], + "summary": "Canonical single-event shape open-agent-audit emits and maps onto an AEP record (aep-record) \u2014 the bridge contract for the open-agent-audit -> aep-record adapter." + }, { "id": "constraint-ir", "title": "ConstraintIR", diff --git a/schemas/v0.1/canonical-event.schema.json b/schemas/v0.1/canonical-event.schema.json new file mode 100644 index 0000000..4157850 --- /dev/null +++ b/schemas/v0.1/canonical-event.schema.json @@ -0,0 +1,127 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://wasmagent.dev/schemas/v0.1/canonical-event.schema.json", + "title": "CanonicalEvent", + "description": "Canonical agent event — the normalized, single-event shape that open-agent-audit emits and maps onto an AEP record (aep-record). Each field has a direct aep-record counterpart: run_id/trace_id/created_at_ms/signature map 1:1; agent -> run_context; action -> actions[]; capability_decision -> capability_decisions[]; verifier_result -> verifier_results[].", + "type": "object", + "required": ["schema_version", "event_id", "event_type", "run_id", "created_at_ms"], + "properties": { + "schema_version": { + "type": "string", + "enum": ["canonical-event/v0.1"], + "description": "Wire version tag for the canonical event envelope." + }, + "event_id": { + "type": "string", + "description": "Stable, unique identifier for this single event within the run." + }, + "event_type": { + "type": "string", + "enum": ["action", "capability_decision", "verifier_result", "run_lifecycle", "custom"], + "description": "Discriminator naming which canonical payload this event carries." + }, + "run_id": { + "type": "string", + "description": "The run this event belongs to. Maps to aep-record.run_id." + }, + "trace_id": { + "type": "string", + "description": "Optional trace/correlation id. Maps to aep-record.trace_id." + }, + "parent_trace_id": { + "type": ["string", "null"], + "description": "Optional parent trace id for nested/delegated runs. Maps to aep-record.parent_trace_id." + }, + "created_at_ms": { + "type": "number", + "description": "Unix-epoch milliseconds at which the event was recorded. Maps to aep-record.created_at_ms." + }, + "agent": { + "$ref": "#/$defs/agent", + "description": "Identity of the agent that produced the event. Maps to aep-record.run_context." + }, + "action": { + "$ref": "#/$defs/action", + "description": "A single tool action. Maps to one entry of aep-record.actions[]." + }, + "capability_decision": { + "$ref": "#/$defs/capabilityDecision", + "description": "A capability allow/deny decision. Maps to one entry of aep-record.capability_decisions[]." + }, + "verifier_result": { + "$ref": "#/$defs/verifierResult", + "description": "A verifier pass/fail result. Maps to one entry of aep-record.verifier_results[]." + }, + "payload": { + "type": "object", + "additionalProperties": true, + "description": "Free-form event-specific payload for event_type 'custom'. Ignored by the open-agent-audit -> aep-record adapter for typed event_types." + }, + "signature": { + "$ref": "#/$defs/signature", + "description": "Optional tamper-evident signature over the event. Maps to aep-record.signature." + } + }, + "$defs": { + "agent": { + "type": "object", + "properties": { + "agent_id": { "type": "string" }, + "agent_version": { "type": "string" }, + "subagent_id": { "type": "string" }, + "delegation_chain": { "type": "array", "items": { "type": "string" } } + }, + "additionalProperties": true + }, + "action": { + "type": "object", + "required": ["action_id", "tool_name", "state_changing", "timestamp_ms"], + "properties": { + "action_id": { "type": "string" }, + "tool_name": { "type": "string" }, + "state_changing": { "type": "boolean" }, + "timestamp_ms": { "type": "number" }, + "precondition_digest": { "type": "string" }, + "result_digest": { "type": "string" }, + "parent_action_id": { "type": "string" }, + "evidence_refs": { "type": "array", "items": { "type": "string" } } + }, + "additionalProperties": true + }, + "capabilityDecision": { + "type": "object", + "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" } + }, + "additionalProperties": true + }, + "verifierResult": { + "type": "object", + "required": ["verifier_id", "passed"], + "properties": { + "verifier_id": { "type": "string" }, + "passed": { "type": "boolean" }, + "score": { "type": "number" }, + "claim_ids": { "type": "array", "items": { "type": "string" } } + }, + "additionalProperties": true + }, + "signature": { + "type": "object", + "required": ["alg", "key_id", "sig"], + "properties": { + "alg": { "type": "string" }, + "key_id": { "type": "string" }, + "sig": { "type": "string" }, + "bundle": { "type": "object" }, + "transparency_log_ref": { "type": "string" } + }, + "additionalProperties": true + } + } +} diff --git a/tests/fixtures/invalid/canonical-event/example.json b/tests/fixtures/invalid/canonical-event/example.json new file mode 100644 index 0000000..4a40fdb --- /dev/null +++ b/tests/fixtures/invalid/canonical-event/example.json @@ -0,0 +1,7 @@ +{ + "schema_version": "canonical-event/v9.9", + "event_id": "evt-bad", + "event_type": "not-a-real-type", + "run_id": "run-abc123", + "created_at_ms": 1737600000000 +} diff --git a/tests/fixtures/valid/canonical-event/example.json b/tests/fixtures/valid/canonical-event/example.json new file mode 100644 index 0000000..7162266 --- /dev/null +++ b/tests/fixtures/valid/canonical-event/example.json @@ -0,0 +1,24 @@ +{ + "schema_version": "canonical-event/v0.1", + "event_id": "evt-001", + "event_type": "action", + "run_id": "run-abc123", + "trace_id": "trace-001", + "created_at_ms": 1737600000000, + "agent": { + "agent_id": "agent-1", + "agent_version": "1.20.0" + }, + "action": { + "action_id": "a1", + "tool_name": "write_file", + "state_changing": true, + "timestamp_ms": 1737600000100, + "result_digest": "sha256:abcd" + }, + "signature": { + "alg": "ed25519", + "key_id": "k1", + "sig": "base64sig==" + } +}