Capability Passport Revocation v1¶
Source schema: doc/schemas/capability-passport-revocation.v1.schema.json
Signed revocation artifact that invalidates a previously issued capability-passport.v1. Two signing authorities are recognised: the original issuer (sovereign operator who granted the capability) and the subject node (self-revocation by the node whose capability is being withdrawn). The signed_by field discriminates between the two paths. The Seed Directory appends accepted revocations to its append-only revocation log; consumers MUST poll GET /revocations?since= and immediately invalidate any cached passport whose passport_id appears in the log.
Governing Basis¶
doc/project/40-proposals/025-seed-directory-as-capability-catalog.mddoc/project/40-proposals/024-capability-passports-and-network-ledger-delegation.md
Project Lineage¶
Requirements¶
doc/project/50-requirements/requirements-006.mddoc/project/50-requirements/requirements-010.mddoc/project/50-requirements/requirements-011.md
Stories¶
doc/project/30-stories/story-001.mddoc/project/30-stories/story-004.mddoc/project/30-stories/story-006-buyer-node-components.mddoc/project/30-stories/story-006.mddoc/project/30-stories/story-007.md
Fields¶
| Field | Required | Shape | Description |
|---|---|---|---|
schema |
yes |
const: capability-passport-revocation.v1 |
Schema discriminator. MUST be exactly capability-passport-revocation.v1. |
revocation_id |
yes |
string | Stable unique identifier for this revocation record. MUST use the passport-revocation: prefix. |
passport_id |
yes |
string | Identifier of the capability-passport.v1 being revoked. MUST use the passport:capability: prefix and MUST match an existing passport known to the verifying party. |
node_id |
yes |
string | Node whose delegated capability is being revoked. MUST match the node_id in the original passport. |
capability_id |
yes |
string | Bare kebab-case capability identifier being revoked (e.g. network-ledger). MUST match the capability_id in the original passport. |
revoked_at |
yes |
string | RFC 3339 timestamp at which the revocation was declared. The Seed Directory MUST store this timestamp in the revocation log entry. |
signed_by |
yes |
enum: issuer, subject |
Who signed this revocation. issuer — the sovereign operator participant who originally issued the passport (uses issuer/participant_id). subject — the target node revoking its own capability using its node key (no issuer/participant_id; the signer public key is derived from node_id). |
issuer/participant_id |
no |
string | Canonical participant:did:key:z... identifier of the revoking participant. REQUIRED when signed_by == "issuer" and MUST match issuer/participant_id in the original passport. MUST NOT be present when signed_by == "subject". |
reason |
no |
string | Optional human-readable note explaining why the passport was revoked (e.g. operator key rotation, node decommissioned). Not machine-interpreted; informational only. |
signature |
yes |
ref: #/$defs/ed25519Signature |
|
policy_annotations |
no |
object | Optional informational annotations. MUST NOT alter revocation semantics. |
Definitions¶
| Definition | Shape | Description |
|---|---|---|
ed25519Signature |
object | Ed25519 signature over the deterministic canonical JSON of the revocation artifact with the signature field omitted entirely from the signed payload. Object keys are sorted lexicographically; no insignificant whitespace; arrays left in original order. For signed_by == "issuer" the signing key belongs to issuer/participant_id; for signed_by == "subject" the signing key belongs to the node identified by node_id. |
Conditional Rules¶
Rule 1¶
When:
{
"properties": {
"signed_by": {
"const": "issuer"
}
},
"required": [
"signed_by"
]
}
Then:
{
"required": [
"issuer/participant_id"
]
}
Rule 2¶
When:
{
"properties": {
"signed_by": {
"const": "subject"
}
},
"required": [
"signed_by"
]
}
Then:
{
"properties": {
"issuer/participant_id": false
}
}
Field Semantics¶
schema¶
- Required:
yes - Shape: const:
capability-passport-revocation.v1
Schema discriminator. MUST be exactly capability-passport-revocation.v1.
revocation_id¶
- Required:
yes - Shape: string
Stable unique identifier for this revocation record. MUST use the passport-revocation: prefix.
passport_id¶
- Required:
yes - Shape: string
Identifier of the capability-passport.v1 being revoked. MUST use the passport:capability: prefix and MUST match an existing passport known to the verifying party.
node_id¶
- Required:
yes - Shape: string
Node whose delegated capability is being revoked. MUST match the node_id in the original passport.
capability_id¶
- Required:
yes - Shape: string
Bare kebab-case capability identifier being revoked (e.g. network-ledger). MUST match the capability_id in the original passport.
revoked_at¶
- Required:
yes - Shape: string
RFC 3339 timestamp at which the revocation was declared. The Seed Directory MUST store this timestamp in the revocation log entry.
signed_by¶
- Required:
yes - Shape: enum:
issuer,subject
Who signed this revocation. issuer — the sovereign operator participant who originally issued the passport (uses issuer/participant_id). subject — the target node revoking its own capability using its node key (no issuer/participant_id; the signer public key is derived from node_id).
issuer/participant_id¶
- Required:
no - Shape: string
Canonical participant:did:key:z... identifier of the revoking participant. REQUIRED when signed_by == "issuer" and MUST match issuer/participant_id in the original passport. MUST NOT be present when signed_by == "subject".
reason¶
- Required:
no - Shape: string
Optional human-readable note explaining why the passport was revoked (e.g. operator key rotation, node decommissioned). Not machine-interpreted; informational only.
signature¶
- Required:
yes - Shape: ref:
#/$defs/ed25519Signature
policy_annotations¶
- Required:
no - Shape: object
Optional informational annotations. MUST NOT alter revocation semantics.
Definition Semantics¶
$defs.ed25519Signature¶
- Shape: object
Ed25519 signature over the deterministic canonical JSON of the revocation artifact with the signature field omitted entirely from the signed payload. Object keys are sorted lexicographically; no insignificant whitespace; arrays left in original order. For signed_by == "issuer" the signing key belongs to issuer/participant_id; for signed_by == "subject" the signing key belongs to the node identified by node_id.