Assistant: codex Assistant-Model: gpt-6.1-sol Assistant-Session: 01a1029d-2c93-7500-a0e0-e3e089668b29
135 lines
5.9 KiB
JSON
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"] }
|
|
}
|
|
}
|
|
}
|