net-kingdom/canon/schemas/custody-record_v0.1.schema.json
tegwick de4c4f84f5
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 3s
Accept root grant ADR and approved OpenBao delivery design
Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a1029d-2c93-7500-a0e0-e3e089668b29
2026-10-03 19:01:13 +02:00

135 lines
5.9 KiB
JSON

{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://policy.coulomb.social/schemas/custody-record/v0.1",
"title": "NetKingdom platform-root custody record v0.1",
"description": "Machine-readable, non-secret form of the platform-root custody record (NK-ADR-0017, status accepted; NK-WP-0045-T02). The record is the single authority for the root grant. Entries are keyed by exact (issuer, subject), never by username. The root grant is relation platform-root-custodian in tenant:platform only; directory membership and IAM claims are projections and cannot ground an entry. Revocation and supersession are recorded custody actions that add a record revision; entries are never deleted. No secret material: token, key, share, recovery-code, password and reset-link fields are rejected everywhere.",
"type": "object",
"additionalProperties": false,
"required": [
"schema_version",
"kind",
"record_id",
"revision",
"updated_at",
"owner_system",
"freshness",
"entries"
],
"propertyNames": { "$ref": "#/$defs/nonSecretName" },
"properties": {
"schema_version": { "const": "0.1" },
"kind": { "const": "netkingdom-custody-record" },
"record_id": {
"description": "Stable identifier of the custody record. Revisions of one record share it.",
"type": "string",
"pattern": "^nk-custody:[a-z0-9][a-z0-9-]{0,62}$"
},
"revision": {
"description": "Monotonic per record: every custody action (grant, revocation, supersession) increments it, so a revocation is distinguishable from a stale read.",
"type": "integer",
"minimum": 1
},
"updated_at": { "type": "string", "format": "date-time" },
"owner_system": { "const": "net-kingdom-custody" },
"freshness": {
"description": "Consumer cache bound. Observations older than this are stale; root-grant-dependent actions re-check and fail closed when the record is unreadable or stale.",
"type": "object",
"additionalProperties": false,
"required": ["max_cache_seconds", "on_unreadable"],
"propertyNames": { "$ref": "#/$defs/nonSecretName" },
"properties": {
"max_cache_seconds": { "type": "integer", "minimum": 0, "maximum": 900 },
"on_unreadable": { "const": "no-grant" }
}
},
"entries": {
"type": "array",
"items": { "$ref": "#/$defs/entry" }
}
},
"$defs": {
"nonSecretName": {
"description": "Field names that would carry secret material are rejected at every level.",
"type": "string",
"not": {
"pattern": "(?i)(token|key|secret|share|recovery|password|passphrase|reset|seed|private|otp|credential)"
}
},
"timestamp": { "type": "string", "format": "date-time" },
"subject": {
"description": "Exact OIDC subject reference. No username, email, group or role is accepted as the key.",
"type": "object",
"additionalProperties": false,
"required": ["issuer", "subject"],
"propertyNames": { "$ref": "#/$defs/nonSecretName" },
"properties": {
"issuer": { "type": "string", "pattern": "^https://[^\\s/]+(/[^\\s]*)?$" },
"subject": { "type": "string", "minLength": 1, "maxLength": 255, "pattern": "^\\S+$" }
}
},
"grant": {
"description": "Membership-envelope mapping from NK-ADR-0017 section 2. Fixed: no other tenant, relation or owner is representable.",
"type": "object",
"additionalProperties": false,
"required": ["scope_type", "scope_id", "relation", "owner_system"],
"propertyNames": { "$ref": "#/$defs/nonSecretName" },
"properties": {
"scope_type": { "const": "tenant" },
"scope_id": { "const": "platform" },
"relation": { "const": "platform-root-custodian" },
"owner_system": { "const": "net-kingdom-custody" }
}
},
"action": {
"description": "A recorded custody action with actor, reason and the record revision it introduced.",
"type": "object",
"additionalProperties": false,
"required": ["at", "actor", "reason", "revision"],
"propertyNames": { "$ref": "#/$defs/nonSecretName" },
"properties": {
"at": { "$ref": "#/$defs/timestamp" },
"actor": { "$ref": "#/$defs/subject" },
"reason": { "type": "string", "minLength": 1, "maxLength": 500 },
"revision": { "type": "integer", "minimum": 1 }
}
},
"evidence": {
"description": "Non-secret pointer to the custody ceremony that grounds the entry. A projection (directory group, IAM claim) is never a basis.",
"type": "object",
"additionalProperties": false,
"required": ["basis", "ref"],
"propertyNames": { "$ref": "#/$defs/nonSecretName" },
"properties": {
"basis": { "const": "custody-ceremony" },
"ref": { "type": "string", "minLength": 1, "maxLength": 300 }
}
},
"supersession": {
"type": "object",
"additionalProperties": false,
"required": ["entry_id", "revision"],
"propertyNames": { "$ref": "#/$defs/nonSecretName" },
"properties": {
"entry_id": { "$ref": "#/$defs/entryId" },
"revision": { "type": "integer", "minimum": 1 }
}
},
"entryId": { "type": "string", "pattern": "^[a-z0-9][a-z0-9-]{0,62}$" },
"entry": {
"type": "object",
"additionalProperties": false,
"required": ["entry_id", "subject", "grant", "evidence", "granted"],
"propertyNames": { "$ref": "#/$defs/nonSecretName" },
"properties": {
"entry_id": { "$ref": "#/$defs/entryId" },
"subject": { "$ref": "#/$defs/subject" },
"grant": { "$ref": "#/$defs/grant" },
"evidence": { "$ref": "#/$defs/evidence" },
"granted": { "$ref": "#/$defs/action" },
"superseded_by": { "$ref": "#/$defs/supersession" },
"revoked": { "$ref": "#/$defs/action" }
},
"not": { "required": ["superseded_by", "revoked"] }
}
}
}