Add the exposure contract, additive family schema fields, validator checks and fixtures, the reef-railiance exception snapshot, and routed intakes. Enforcement stays in the owning repos.
183 lines
7.3 KiB
JSON
183 lines
7.3 KiB
JSON
{
|
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
"$id": "https://railiance.dev/schemas/reef.schema.json",
|
|
"title": "Railiance reef declaration",
|
|
"description": "Normative shape for declarations/reef.yaml in every reef-* repo. Authored by railiance-master under RMASTER-WP-0021-T04 from the live reef-railiance declaration and docs/reef-substrate-model.md. bound_rapps is a derived projection of rapp.bound_reefs, not a hand-maintained registry.",
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": [
|
|
"kind",
|
|
"reef_id",
|
|
"repo",
|
|
"ownership_repo",
|
|
"substrate_kind",
|
|
"lifecycle_state",
|
|
"criticality",
|
|
"current_members"
|
|
],
|
|
"properties": {
|
|
"kind": {
|
|
"const": "substrate-reef",
|
|
"description": "Fixed discriminator. The live reef already uses this value."
|
|
},
|
|
"reef_id": {
|
|
"$ref": "#/$defs/reefSlug",
|
|
"description": "Canonical identifier for the reef. Must equal the repo slug."
|
|
},
|
|
"repo": {
|
|
"$ref": "#/$defs/repoSlug",
|
|
"description": "The reef-* repo holding this declaration."
|
|
},
|
|
"ownership_repo": {
|
|
"$ref": "#/$defs/repoSlug",
|
|
"description": "The ownership-axis repo accountable for this substrate boundary. The live reef names railiance-infra."
|
|
},
|
|
"substrate_kind": {
|
|
"type": "string",
|
|
"pattern": "^[a-z0-9]+(-[a-z0-9]+)*$",
|
|
"minLength": 3,
|
|
"description": "What kind of substrate this reef is. Known values include server-group (reef-railiance) and object-storage (reef-storage). Kept as a slug rather than a closed enum. A provider-delegated kind (object-storage) does not host a rail: the provider operates the capability. See docs/reef-substrate-model.md."
|
|
},
|
|
"lifecycle_state": {
|
|
"enum": ["planned", "active", "retired"],
|
|
"description": "Lifecycle of the reef as a substrate boundary. Distinct from rail readiness_state and from the per-binding admission states in docs/reef-production-readiness-contract.md (declared/installed/verified/production-approved/deprecated)."
|
|
},
|
|
"criticality": {
|
|
"enum": ["low", "medium", "high", "critical"],
|
|
"description": "Operational criticality of the substrate. Same vocabulary as rapp.yaml. The live reef is high."
|
|
},
|
|
"primary_rail": {
|
|
"$ref": "#/$defs/railSlug",
|
|
"description": "The default rail on this reef, when the reef hosts rails. Omit on a provider-delegated substrate (object-storage): there is no execution contract to host. If present, must also appear in hosted_rails."
|
|
},
|
|
"hosted_rails": {
|
|
"type": "array",
|
|
"minItems": 0,
|
|
"uniqueItems": true,
|
|
"items": { "$ref": "#/$defs/railSlug" },
|
|
"description": "Rails this reef hosts or is prepared to host. Empty or omitted when the reef does not host a rail. Topology, not readiness. See ADR-0006."
|
|
},
|
|
"bound_rapps": {
|
|
"type": "array",
|
|
"uniqueItems": true,
|
|
"items": { "$ref": "#/$defs/rappSlug" },
|
|
"description": "DERIVED. Projection of every rapp declaration whose bound_reefs lists this reef. Optional so a reef may omit the field and let the validator compute it. If present, the validator requires an exact match against that projection. reef-railiance currently hand-lists rapp-qonto only; that list is already stale (rapp-openbao and rapp-postgres are live on the same reef). Migration: either delete the field, or replace it with the derived set once those rapps name this reef."
|
|
},
|
|
"current_members": {
|
|
"type": "array",
|
|
"minItems": 0,
|
|
"uniqueItems": true,
|
|
"items": { "type": "string", "minLength": 1 },
|
|
"description": "Named machines, buckets, or other units that currently compose this reef. Empty is allowed while a planned provider-delegated reef has no purchased members yet. Live compute example: Railiance01."
|
|
},
|
|
"compatibility_notes": {
|
|
"$ref": "#/$defs/notes",
|
|
"description": "Human-readable caveats. Never load-bearing."
|
|
},
|
|
"source_documents": {
|
|
"type": "array",
|
|
"minItems": 1,
|
|
"items": { "$ref": "#/$defs/sourceDocument" }
|
|
},
|
|
"exposure": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["posture"],
|
|
"description": "Host-port and public-DNS surface this reef publishes. Optional; omitted means private (ADR-0008). public is a substrate grant, not reef lifecycle_state. Provider-delegated reefs must not set public.",
|
|
"properties": {
|
|
"posture": {
|
|
"enum": ["private", "operator", "public"],
|
|
"description": "Default if exposure is omitted: private."
|
|
},
|
|
"grants": {
|
|
"type": "array",
|
|
"minItems": 1,
|
|
"items": { "$ref": "#/$defs/exposureGrant" },
|
|
"description": "Substrate grants. Required by schema when posture is public."
|
|
},
|
|
"tunnel": { "$ref": "#/$defs/exposureTunnel" }
|
|
}
|
|
}
|
|
},
|
|
"allOf": [
|
|
{
|
|
"description": "public reef exposure requires at least one substrate grant.",
|
|
"if": {
|
|
"required": ["exposure"],
|
|
"properties": {
|
|
"exposure": {
|
|
"required": ["posture"],
|
|
"properties": { "posture": { "const": "public" } }
|
|
}
|
|
}
|
|
},
|
|
"then": {
|
|
"properties": {
|
|
"exposure": { "required": ["grants"] }
|
|
}
|
|
}
|
|
}
|
|
],
|
|
"$defs": {
|
|
"repoSlug": {
|
|
"type": "string",
|
|
"pattern": "^[a-z0-9]+(-[a-z0-9]+)*$",
|
|
"minLength": 2
|
|
},
|
|
"railSlug": {
|
|
"type": "string",
|
|
"pattern": "^rail-[a-z0-9]+(-[a-z0-9]+)*$"
|
|
},
|
|
"rappSlug": {
|
|
"type": "string",
|
|
"pattern": "^rapp-[a-z0-9]+(-[a-z0-9]+)*$"
|
|
},
|
|
"reefSlug": {
|
|
"type": "string",
|
|
"pattern": "^reef-[a-z0-9]+(-[a-z0-9]+)*$"
|
|
},
|
|
"notes": {
|
|
"type": "array",
|
|
"items": { "type": "string", "minLength": 1 },
|
|
"description": "Human-readable caveats. Never load-bearing: nothing may depend on parsing a note."
|
|
},
|
|
"sourceDocument": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["repo", "path"],
|
|
"properties": {
|
|
"repo": { "$ref": "#/$defs/repoSlug" },
|
|
"path": { "type": "string", "minLength": 1 }
|
|
}
|
|
},
|
|
|
|
"exposureGrant": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["reason", "approved_on", "residual_risk_owner"],
|
|
"description": "Accepted residual risk for a reef host port or public DNS name we publish. Must name a hostname or a port. Port 6443 is rejected by the validator.",
|
|
"properties": {
|
|
"hostname": { "type": "string", "minLength": 1 },
|
|
"port": { "type": "integer", "minimum": 1, "maximum": 65535 },
|
|
"reason": { "type": "string", "minLength": 1 },
|
|
"approved_on": { "type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$" },
|
|
"residual_risk_owner": { "type": "string", "minLength": 1 }
|
|
},
|
|
"anyOf": [
|
|
{ "required": ["hostname"] },
|
|
{ "required": ["port"] }
|
|
]
|
|
},
|
|
|
|
"exposureTunnel": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["name"],
|
|
"description": "Named ops-bridge / SSH path to this reef. Does not change packet posture.",
|
|
"properties": {
|
|
"name": { "type": "string", "minLength": 1 },
|
|
"local_port": { "type": "integer", "minimum": 1, "maximum": 65535 }
|
|
}
|
|
}
|
|
}
|
|
}
|