diff --git a/asyncapi.agent-plane.patch.identity.yaml b/asyncapi.agent-plane.patch.identity.yaml new file mode 100644 index 0000000..b312761 --- /dev/null +++ b/asyncapi.agent-plane.patch.identity.yaml @@ -0,0 +1,35 @@ +channels: + srcos.v2.identity.packet.requested: + publish: + message: + $ref: '#/components/messages/ValidatorPacketMessage' + + srcos.v2.identity.packet.signed: + publish: + message: + $ref: '#/components/messages/ValidatorReceiptMessage' + + srcos.v2.identity.post.issued: + publish: + message: + $ref: '#/components/messages/ProofOfSelfTokenMessage' + + srcos.v2.identity.post.renewed: + publish: + message: + $ref: '#/components/messages/ProofOfSelfTokenMessage' + + srcos.v2.identity.post.revoked: + publish: + message: + $ref: '#/components/messages/RevocationEntryMessage' + + srcos.v2.identity.attestation.drift: + publish: + message: + $ref: '#/components/messages/AttestationEvidenceMessage' + + srcos.v2.identity.recovery.completed: + publish: + message: + $ref: '#/components/messages/RecoveryCeremonyMessage' diff --git a/docs/adr/ADR-proof-of-self-identity-plane.md b/docs/adr/ADR-proof-of-self-identity-plane.md new file mode 100644 index 0000000..3821e38 --- /dev/null +++ b/docs/adr/ADR-proof-of-self-identity-plane.md @@ -0,0 +1,17 @@ +# ADR — Proof-of-Self Identity Plane + +## Status +Accepted + +## Context +SourceOS requires a first-class identity plane for local issuance, validator-backed trust, recovery, revocation, and attestation-bound proof artifacts. + +## Decision +We add a Proof-of-Self identity family to `sourceos-spec` as typed contracts and additive agent-plane patches. +The runtime lives in a separate implementation repo and is not embedded into the substrate, integration spine, or optional commons. + +## Consequences +- Identity objects become machine-verifiable and transport-neutral. +- Issuance, revocation, and recovery become receipt-bearing and event-emitting. +- Local operation remains possible without `socios`. +- `agentos-spine` integrates but does not absorb the runtime. diff --git a/examples/attestationevidence.json b/examples/attestationevidence.json new file mode 100644 index 0000000..67870df --- /dev/null +++ b/examples/attestationevidence.json @@ -0,0 +1,11 @@ +{ + "id": "urn:srcos:attestation:demo-001", + "type": "AttestationEvidence", + "specVersion": "2.1.0", + "capturedAt": "2026-04-14T12:00:00Z", + "deviceRef": "urn:srcos:device:demo", + "nonce": "nonce-demo", + "evidenceKind": "bundle", + "status": "captured", + "pcrs": {} +} diff --git a/examples/genesisattestationdocument.json b/examples/genesisattestationdocument.json new file mode 100644 index 0000000..c768ce7 --- /dev/null +++ b/examples/genesisattestationdocument.json @@ -0,0 +1,16 @@ +{ + "id": "urn:srcos:genesis-attestation:demo-001", + "type": "GenesisAttestationDocument", + "specVersion": "2.1.0", + "subjectRef": "urn:srcos:subject:demo", + "issuedAt": "2026-04-14T12:00:00Z", + "aad": "pos-validator", + "nonce": "nonce-demo", + "bundleHash": "abc123", + "status": "complete", + "attestationEvidenceRefs": [], + "livenessProfileRef": null, + "validatorPacketRefs": [], + "validatorReceiptRefs": [], + "quorumPolicyRef": null +} diff --git a/examples/proofofselftoken.json b/examples/proofofselftoken.json new file mode 100644 index 0000000..30248c7 --- /dev/null +++ b/examples/proofofselftoken.json @@ -0,0 +1,21 @@ +{ + "id": "urn:srcos:proof-of-self:demo-post-001", + "type": "ProofOfSelfToken", + "specVersion": "2.1.0", + "subjectRef": "urn:srcos:subject:demo", + "issuedAt": "2026-04-14T12:00:00Z", + "expiresAt": "2027-04-14T12:00:00Z", + "state": "active", + "gadRef": "urn:srcos:genesis-attestation:demo-001", + "validatorReceiptRefs": [ + "urn:srcos:validator-receipt:v1", + "urn:srcos:validator-receipt:v2", + "urn:srcos:validator-receipt:v3" + ], + "trustRootRefs": [ + "urn:srcos:validator-trust-root:root-001" + ], + "binding": {}, + "revocationStatus": {}, + "transportHints": {} +} diff --git a/openapi.agent-plane.patch.identity.yaml b/openapi.agent-plane.patch.identity.yaml new file mode 100644 index 0000000..ca90a42 --- /dev/null +++ b/openapi.agent-plane.patch.identity.yaml @@ -0,0 +1,98 @@ +paths: + /v2/identity/genesis-packets: + post: + summary: Create a validator packet for genesis or renewal + operationId: createIdentityGenesisPacket + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ValidatorPacket' + responses: + '201': + description: ValidatorPacket created + + /v2/identity/validator-receipts: + post: + summary: Submit a validator receipt + operationId: submitIdentityValidatorReceipt + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ValidatorReceipt' + responses: + '201': + description: ValidatorReceipt accepted + + /v2/identity/posts: + post: + summary: Issue a Proof-of-Self token + operationId: issueProofOfSelfToken + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ProofOfSelfToken' + responses: + '201': + description: ProofOfSelfToken issued + + /v2/identity/recoveries: + post: + summary: Record a recovery ceremony + operationId: recordRecoveryCeremony + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/RecoveryCeremony' + responses: + '201': + description: RecoveryCeremony recorded + + /v2/identity/revocations: + post: + summary: Append a revocation entry + operationId: appendRevocationEntry + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/RevocationEntry' + responses: + '201': + description: RevocationEntry appended + + /v2/identity/attestations: + post: + summary: Record attestation evidence + operationId: recordAttestationEvidence + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/AttestationEvidence' + responses: + '201': + description: AttestationEvidence recorded + + /v2/identity/quorum-policies: + post: + summary: Create or update an identity quorum policy + operationId: upsertIdentityQuorumPolicy + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/IdentityQuorumPolicy' + responses: + '201': + description: IdentityQuorumPolicy stored diff --git a/schemas/AttestationEvidence.json b/schemas/AttestationEvidence.json new file mode 100644 index 0000000..297df94 --- /dev/null +++ b/schemas/AttestationEvidence.json @@ -0,0 +1,104 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/AttestationEvidence.json", + "title": "AttestationEvidence", + "description": "Measured-boot and host-attestation evidence for a SourceOS workstation or edge node.", + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "type", + "specVersion", + "capturedAt", + "deviceRef", + "nonce", + "evidenceKind", + "status" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^urn:srcos:attestation:[A-Za-z0-9._~-]+$" + }, + "type": { + "const": "AttestationEvidence" + }, + "specVersion": { + "type": "string" + }, + "capturedAt": { + "type": "string", + "format": "date-time" + }, + "deviceRef": { + "type": "string" + }, + "nonce": { + "type": "string" + }, + "evidenceKind": { + "type": "string", + "enum": [ + "tpm_quote", + "ima_runtime", + "secure_boot", + "firmware", + "bundle" + ] + }, + "status": { + "type": "string", + "enum": [ + "captured", + "validated", + "failed", + "stale" + ] + }, + "pcrs": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "tpmQuote": { + "type": [ + "string", + "null" + ] + }, + "imaAggregate": { + "type": [ + "string", + "null" + ] + }, + "secureBootState": { + "type": [ + "string", + "null" + ] + }, + "firmwareHash": { + "type": [ + "string", + "null" + ] + }, + "collector": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + } + } + }, + "diagnostics": { + "type": "object" + } + } +} diff --git a/schemas/GenesisAttestationDocument.json b/schemas/GenesisAttestationDocument.json new file mode 100644 index 0000000..f19057c --- /dev/null +++ b/schemas/GenesisAttestationDocument.json @@ -0,0 +1,75 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/GenesisAttestationDocument.json", + "title": "GenesisAttestationDocument", + "description": "Canonical genesis ceremony record for initial Proof-of-Self issuance.", + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "type", + "specVersion", + "subjectRef", + "issuedAt", + "aad", + "nonce", + "bundleHash", + "status" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^urn:srcos:genesis-attestation:[A-Za-z0-9._~-]+$" + }, + "type": { + "const": "GenesisAttestationDocument" + }, + "specVersion": { + "type": "string" + }, + "subjectRef": { + "type": "string" + }, + "issuedAt": { + "type": "string", + "format": "date-time" + }, + "aad": { + "type": "string" + }, + "nonce": { + "type": "string" + }, + "bundleHash": { + "type": "string" + }, + "status": { + "type": "string", + "enum": [ + "draft", + "collecting", + "complete", + "superseded", + "failed" + ] + }, + "attestationEvidenceRefs": { + "type": "array", + "items": {"type": "string"} + }, + "livenessProfileRef": { + "type": ["string", "null"] + }, + "validatorPacketRefs": { + "type": "array", + "items": {"type": "string"} + }, + "validatorReceiptRefs": { + "type": "array", + "items": {"type": "string"} + }, + "quorumPolicyRef": { + "type": ["string", "null"] + } + } +} diff --git a/schemas/IdentityQuorumPolicy.json b/schemas/IdentityQuorumPolicy.json new file mode 100644 index 0000000..4462799 --- /dev/null +++ b/schemas/IdentityQuorumPolicy.json @@ -0,0 +1,72 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/IdentityQuorumPolicy.json", + "title": "IdentityQuorumPolicy", + "description": "Threshold and validator-weight policy for genesis, renewal, recovery, and suspension.", + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "type", + "specVersion", + "minHumanValidators", + "genesisThreshold", + "renewalThreshold", + "recoveryThreshold" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^urn:srcos:identity-quorum-policy:[A-Za-z0-9._~-]+$" + }, + "type": { + "const": "IdentityQuorumPolicy" + }, + "specVersion": { + "type": "string" + }, + "minHumanValidators": { + "type": "integer", + "minimum": 1 + }, + "genesisThreshold": { + "type": "number", + "minimum": 0 + }, + "renewalThreshold": { + "type": "number", + "minimum": 0 + }, + "recoveryThreshold": { + "type": "number", + "minimum": 0 + }, + "sharedNonceRequired": { + "type": "boolean", + "default": true + }, + "inPersonRequired": { + "type": "boolean", + "default": true + }, + "timeoutSeconds": { + "type": "integer", + "minimum": 0 + }, + "validatorWeights": { + "type": "object", + "additionalProperties": { + "type": "number", + "minimum": 0 + } + }, + "overrideMode": { + "type": "string", + "enum": [ + "none", + "manual", + "emergency" + ] + } + } +} diff --git a/schemas/LivenessProfile.json b/schemas/LivenessProfile.json new file mode 100644 index 0000000..90a66d7 --- /dev/null +++ b/schemas/LivenessProfile.json @@ -0,0 +1,73 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/LivenessProfile.json", + "title": "LivenessProfile", + "description": "Liveness challenge policy and calibration output for Proof-of-Self verification.", + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "type", + "specVersion", + "mode", + "threshold", + "saltPolicy", + "antiReplayWindowSec" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^urn:srcos:liveness-profile:[A-Za-z0-9._~-]+$" + }, + "type": { + "const": "LivenessProfile" + }, + "specVersion": { + "type": "string" + }, + "mode": { + "type": "string", + "enum": [ + "face", + "voice", + "gesture", + "face_voice", + "voice_gesture", + "face_voice_gesture" + ] + }, + "threshold": { + "type": "integer", + "minimum": 0 + }, + "saltPolicy": { + "type": "string", + "enum": [ + "fixed", + "rotating", + "per-issuance" + ] + }, + "antiReplayWindowSec": { + "type": "integer", + "minimum": 0 + }, + "challengeCount": { + "type": "integer", + "minimum": 1 + }, + "eer": { + "type": ["number", "null"] + }, + "far": { + "type": ["number", "null"] + }, + "frr": { + "type": ["number", "null"] + }, + "calibratedAt": { + "type": ["string", "null"], + "format": "date-time" + } + } +} diff --git a/schemas/ProofOfSelfToken.json b/schemas/ProofOfSelfToken.json new file mode 100644 index 0000000..e38c5f1 --- /dev/null +++ b/schemas/ProofOfSelfToken.json @@ -0,0 +1,70 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/ProofOfSelfToken.json", + "title": "ProofOfSelfToken", + "description": "Canonical Proof-of-Self token issued after successful genesis or renewal.", + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "type", + "specVersion", + "subjectRef", + "issuedAt", + "expiresAt", + "state", + "gadRef" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^urn:srcos:proof-of-self:[A-Za-z0-9._~-]+$" + }, + "type": { + "const": "ProofOfSelfToken" + }, + "specVersion": { + "type": "string" + }, + "subjectRef": { + "type": "string" + }, + "issuedAt": { + "type": "string", + "format": "date-time" + }, + "expiresAt": { + "type": "string", + "format": "date-time" + }, + "state": { + "type": "string", + "enum": [ + "active", + "suspended", + "revoked", + "expired" + ] + }, + "gadRef": { + "type": "string" + }, + "validatorReceiptRefs": { + "type": "array", + "items": {"type": "string"} + }, + "trustRootRefs": { + "type": "array", + "items": {"type": "string"} + }, + "binding": { + "type": "object" + }, + "revocationStatus": { + "type": "object" + }, + "transportHints": { + "type": "object" + } + } +} diff --git a/schemas/RecoveryCeremony.json b/schemas/RecoveryCeremony.json new file mode 100644 index 0000000..b45d334 --- /dev/null +++ b/schemas/RecoveryCeremony.json @@ -0,0 +1,74 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/RecoveryCeremony.json", + "title": "RecoveryCeremony", + "description": "Structured record of a Proof-of-Self recovery flow.", + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "type", + "specVersion", + "subjectRef", + "method", + "startedAt", + "status" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^urn:srcos:recovery:[A-Za-z0-9._~-]+$" + }, + "type": { + "const": "RecoveryCeremony" + }, + "specVersion": { + "type": "string" + }, + "subjectRef": { + "type": "string" + }, + "method": { + "type": "string", + "enum": [ + "human_hsm", + "shamir_2of3" + ] + }, + "startedAt": { + "type": "string", + "format": "date-time" + }, + "completedAt": { + "type": ["string", "null"], + "format": "date-time" + }, + "status": { + "type": "string", + "enum": [ + "started", + "validated", + "completed", + "failed", + "revoked_old_token" + ] + }, + "oldTokenRef": { + "type": ["string", "null"] + }, + "newTokenRef": { + "type": ["string", "null"] + }, + "validatorReceiptRefs": { + "type": "array", + "items": {"type": "string"} + }, + "hsmEvidence": { + "type": "object" + }, + "attestationEvidenceRefs": { + "type": "array", + "items": {"type": "string"} + } + } +} diff --git a/schemas/RevocationEntry.json b/schemas/RevocationEntry.json new file mode 100644 index 0000000..a9cb1e3 --- /dev/null +++ b/schemas/RevocationEntry.json @@ -0,0 +1,66 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/RevocationEntry.json", + "title": "RevocationEntry", + "description": "CRL-style revocation or suspension entry for an identity token or trust root.", + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "type", + "specVersion", + "targetRef", + "reasonCode", + "effectiveAt", + "issuerRef" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^urn:srcos:revocation:[A-Za-z0-9._~-]+$" + }, + "type": { + "const": "RevocationEntry" + }, + "specVersion": { + "type": "string" + }, + "targetRef": { + "type": "string" + }, + "reasonCode": { + "type": "string", + "enum": [ + "key_compromise", + "validator_withdrawal", + "device_compromise", + "policy_violation", + "recovery_rotation", + "expired" + ] + }, + "effectiveAt": { + "type": "string", + "format": "date-time" + }, + "issuerRef": { + "type": "string" + }, + "scope": { + "type": "string", + "enum": [ + "token", + "trust_root", + "validator", + "subject" + ] + }, + "evidenceRefs": { + "type": "array", + "items": {"type": "string"} + }, + "notes": { + "type": ["string", "null"] + } + } +} diff --git a/schemas/ValidatorPacket.json b/schemas/ValidatorPacket.json new file mode 100644 index 0000000..77d6216 --- /dev/null +++ b/schemas/ValidatorPacket.json @@ -0,0 +1,68 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/ValidatorPacket.json", + "title": "ValidatorPacket", + "description": "Validator signing request for genesis or renewal.", + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "type", + "specVersion", + "subjectRef", + "requestedAt", + "expiresAt", + "aad", + "payloadHash" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^urn:srcos:validator-packet:[A-Za-z0-9._~-]+$" + }, + "type": { + "const": "ValidatorPacket" + }, + "specVersion": { + "type": "string" + }, + "subjectRef": { + "type": "string" + }, + "requestedAt": { + "type": "string", + "format": "date-time" + }, + "expiresAt": { + "type": "string", + "format": "date-time" + }, + "aad": { + "type": "string" + }, + "payloadHash": { + "type": "string" + }, + "sigStructureHash": { + "type": ["string", "null"] + }, + "alg": { + "type": "string", + "enum": [ + "EdDSA", + "ES256", + "RS256", + "PS256" + ] + }, + "quorumPolicyRef": { + "type": ["string", "null"] + }, + "attestationSummary": { + "type": "object" + }, + "livenessSummary": { + "type": "object" + } + } +} diff --git a/schemas/ValidatorReceipt.json b/schemas/ValidatorReceipt.json new file mode 100644 index 0000000..4ecd221 --- /dev/null +++ b/schemas/ValidatorReceipt.json @@ -0,0 +1,63 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/ValidatorReceipt.json", + "title": "ValidatorReceipt", + "description": "Signed validator response to a ValidatorPacket.", + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "type", + "specVersion", + "packetRef", + "validatorRef", + "receivedAt", + "status" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^urn:srcos:validator-receipt:[A-Za-z0-9._~-]+$" + }, + "type": { + "const": "ValidatorReceipt" + }, + "specVersion": { + "type": "string" + }, + "packetRef": { + "type": "string" + }, + "validatorRef": { + "type": "string" + }, + "receivedAt": { + "type": "string", + "format": "date-time" + }, + "status": { + "type": "string", + "enum": [ + "approved", + "denied", + "expired", + "invalid" + ] + }, + "coseEnvelopeRef": { + "type": ["string", "null"] + }, + "receiptHash": { + "type": ["string", "null"] + }, + "trustRootRef": { + "type": ["string", "null"] + }, + "decision": { + "type": "string" + }, + "notes": { + "type": ["string", "null"] + } + } +} diff --git a/schemas/ValidatorTrustRoot.json b/schemas/ValidatorTrustRoot.json new file mode 100644 index 0000000..aeb9ac2 --- /dev/null +++ b/schemas/ValidatorTrustRoot.json @@ -0,0 +1,72 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/ValidatorTrustRoot.json", + "title": "ValidatorTrustRoot", + "description": "Trust-root entry for validator identity resolution and verification.", + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "type", + "specVersion", + "kind", + "status", + "kid" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^urn:srcos:validator-trust-root:[A-Za-z0-9._~-]+$" + }, + "type": { + "const": "ValidatorTrustRoot" + }, + "specVersion": { + "type": "string" + }, + "kind": { + "type": "string", + "enum": [ + "spki", + "x509", + "ssh", + "cose" + ] + }, + "status": { + "type": "string", + "enum": [ + "active", + "suspended", + "retired" + ] + }, + "kid": { + "type": "string" + }, + "spkiSha256": { + "type": ["string", "null"] + }, + "x5tS256": { + "type": ["string", "null"] + }, + "pem": { + "type": ["string", "null"] + }, + "x5chain": { + "type": "array", + "items": {"type": "string"} + }, + "validFrom": { + "type": ["string", "null"], + "format": "date-time" + }, + "validTo": { + "type": ["string", "null"], + "format": "date-time" + }, + "issuer": { + "type": ["string", "null"] + } + } +}