Rename RAILIANCE-WP-0017..0021 to RMASTER-WP-* so railiance-master IDs no longer collide with railiance-platform's RAILIANCE-WP series. Hub UUIDs are unchanged.
361 lines
15 KiB
JSON
361 lines
15 KiB
JSON
{
|
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
"$id": "https://railiance.dev/schemas/rapp.schema.json",
|
|
"title": "Railiance rapp declaration",
|
|
"description": "Normative shape for declarations/rapp.yaml in every rapp-* repo. Authored by railiance-master under RMASTER-WP-0021 from the drift survey routed by railiance-platform (RAILIANCE-WP-0015). This schema is normative; docs/repo-family-bootstrap-contract.md cites it rather than restating it.",
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": [
|
|
"kind",
|
|
"repo_family",
|
|
"rapp_id",
|
|
"repo",
|
|
"ownership_repo",
|
|
"contract_version",
|
|
"readiness_state",
|
|
"workload_identity",
|
|
"data_classification",
|
|
"criticality",
|
|
"primary_rail",
|
|
"supported_rails",
|
|
"bound_reefs",
|
|
"runtime_dependencies",
|
|
"composition",
|
|
"rollout_contract",
|
|
"smoke_contract",
|
|
"rollback_contract"
|
|
],
|
|
"properties": {
|
|
"kind": {
|
|
"const": "managed-workload-package",
|
|
"description": "Fixed discriminator. All three live declarations already agree on this value."
|
|
},
|
|
"repo_family": {
|
|
"const": "rapp"
|
|
},
|
|
"rapp_id": {
|
|
"$ref": "#/$defs/rappSlug",
|
|
"description": "Canonical identifier for the rapp. Must equal the repo slug for a single-repo rapp; for a grouped rapp it names the bounded context and need not match any member repo."
|
|
},
|
|
"repo": {
|
|
"$ref": "#/$defs/repoSlug",
|
|
"description": "The rapp-* repo holding this declaration."
|
|
},
|
|
"ownership_repo": {
|
|
"$ref": "#/$defs/repoSlug",
|
|
"description": "The single repo accountable for this workload's lifecycle. Both layer repos (railiance-platform) and application repos (qonto-assistant) are legal values; what the schema requires is exactly one, and that it not be the rapp repo itself. See schemas/README.md for the open question on tightening this."
|
|
},
|
|
"contract_version": {
|
|
"$ref": "#/$defs/semver",
|
|
"description": "Version of this declaration contract. Promoted from rapp-qonto-only to required, matching the rail family, which has carried it consistently in both rails and has not drifted."
|
|
},
|
|
"readiness_state": {
|
|
"enum": ["draft", "declared", "deployed", "verified", "retired"],
|
|
"description": "Lifecycle state of the package. Promoted from rapp-qonto-only to required, matching rail.yaml."
|
|
},
|
|
"workload_identity": {
|
|
"$ref": "#/$defs/workloadIdentity"
|
|
},
|
|
"data_classification": {
|
|
"enum": ["public", "internal", "confidential", "restricted"],
|
|
"description": "Highest classification of data the workload handles. Promoted from rapp-qonto-only to required: a package whose classification is unstated cannot be admitted to a reef on evidence."
|
|
},
|
|
"criticality": {
|
|
"enum": ["low", "medium", "high", "critical"],
|
|
"description": "Operational criticality. Promoted from rapp-qonto-only to required. reef.yaml already carries the same vocabulary."
|
|
},
|
|
"primary_rail": {
|
|
"$ref": "#/$defs/railSlug",
|
|
"description": "The rail this package is deployed on by default. Must appear in supported_rails."
|
|
},
|
|
"supported_rails": {
|
|
"type": "array",
|
|
"minItems": 1,
|
|
"uniqueItems": true,
|
|
"items": { "$ref": "#/$defs/railSlug" }
|
|
},
|
|
"bound_reefs": {
|
|
"type": "array",
|
|
"uniqueItems": true,
|
|
"items": { "$ref": "#/$defs/reefSlug" },
|
|
"description": "Reefs this package is bound to. Added by RMASTER-WP-0021-T04 as the source of reef.yaml bound_rapps. Required so the derivation is always defined: an empty list means the package is declared but not yet placed. The validator inverts this field to produce each reef's bound_rapps."
|
|
},
|
|
"runtime_dependencies": {
|
|
"type": "array",
|
|
"minItems": 1,
|
|
"uniqueItems": true,
|
|
"items": { "type": "string", "minLength": 1 },
|
|
"description": "Capabilities the workload requires at runtime. Free-form strings today; a controlled vocabulary shared with rail.required_substrate_capabilities is deferred, not rejected."
|
|
},
|
|
"composition": { "$ref": "#/$defs/composition" },
|
|
"secret_references": {
|
|
"type": "array",
|
|
"uniqueItems": true,
|
|
"items": { "type": "string", "minLength": 1 },
|
|
"description": "OpenBao paths the workload reads. Paths only — never values. Optional, since not every package holds secrets."
|
|
},
|
|
"consumer_contract": { "$ref": "#/$defs/consumerContract" },
|
|
"consumers": {
|
|
"type": "array",
|
|
"items": { "$ref": "#/$defs/consumer" },
|
|
"description": "Present only where consumer_contract is present."
|
|
},
|
|
"rollout_contract": { "$ref": "#/$defs/rolloutContract" },
|
|
"smoke_contract": { "$ref": "#/$defs/smokeContract" },
|
|
"rollback_contract": { "$ref": "#/$defs/rollbackContract" },
|
|
"source_documents": {
|
|
"type": "array",
|
|
"minItems": 1,
|
|
"items": { "$ref": "#/$defs/sourceDocument" },
|
|
"description": "Documents this declaration was derived from. All three live rapps already carry this consistently."
|
|
}
|
|
},
|
|
"allOf": [
|
|
{
|
|
"description": "primary_rail must be one of supported_rails. Expressed as a validator check rather than in schema, since JSON Schema cannot compare a value against a sibling array; the validator enforces it.",
|
|
"type": "object"
|
|
},
|
|
{
|
|
"description": "consumers requires consumer_contract.",
|
|
"if": { "required": ["consumers"] },
|
|
"then": { "required": ["consumer_contract"] }
|
|
}
|
|
],
|
|
"$defs": {
|
|
"repoSlug": {
|
|
"type": "string",
|
|
"pattern": "^[a-z0-9]+(-[a-z0-9]+)*$",
|
|
"minLength": 2
|
|
},
|
|
"rappSlug": {
|
|
"type": "string",
|
|
"pattern": "^rapp-[a-z0-9]+(-[a-z0-9]+)*$"
|
|
},
|
|
"railSlug": {
|
|
"type": "string",
|
|
"pattern": "^rail-[a-z0-9]+(-[a-z0-9]+)*$"
|
|
},
|
|
"reefSlug": {
|
|
"type": "string",
|
|
"pattern": "^reef-[a-z0-9]+(-[a-z0-9]+)*$"
|
|
},
|
|
"semver": {
|
|
"type": "string",
|
|
"pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)$"
|
|
},
|
|
"notes": {
|
|
"type": "array",
|
|
"items": { "type": "string", "minLength": 1 },
|
|
"description": "Human-readable caveats. Never load-bearing: nothing may depend on parsing a note."
|
|
},
|
|
|
|
"workloadIdentity": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["name", "package_type"],
|
|
"description": "Identity of the WORKLOAD, never of the repo. rapp-qonto currently sets name to the repo slug (rapp-qonto); that is the drift this definition closes. The correct value there is qonto.",
|
|
"properties": {
|
|
"name": {
|
|
"type": "string",
|
|
"pattern": "^[a-z0-9]+(-[a-z0-9]+)*$",
|
|
"not": { "pattern": "^rapp-" },
|
|
"description": "The workload's own name. Must not carry the rapp- prefix: that prefix names a repo, and this field does not name a repo."
|
|
},
|
|
"package_type": {
|
|
"enum": [
|
|
"helm-managed-platform-service",
|
|
"manifest-managed-platform-service",
|
|
"knative-managed-service",
|
|
"grouped-composition"
|
|
],
|
|
"description": "grouped-composition is for rapps whose members carry their own package types."
|
|
},
|
|
"principal": { "type": "string" },
|
|
"service_account": { "type": "string" },
|
|
"tenant": {
|
|
"type": "string",
|
|
"description": "Opaque NetKingdom tenant identifier (tenant:<grouping>:<name>, net-kingdom ADR-0013). A rapp never mints, parses, or authorizes on this."
|
|
},
|
|
"chart": { "type": "string" },
|
|
"chart_version": { "type": "string" },
|
|
"app_version": { "type": "string" },
|
|
"notes": { "$ref": "#/$defs/notes" },
|
|
"note": { "type": "string" }
|
|
}
|
|
},
|
|
|
|
"composition": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["purpose", "member_repos"],
|
|
"description": "What this rapp is composed of. Supersedes the flat members: list from proposal 04c776c4 per amendment f88f938d. A rapp is a composition of first-party repos AND pinned third-party components, serving a stated purpose.",
|
|
"properties": {
|
|
"purpose": {
|
|
"type": "string",
|
|
"minLength": 12,
|
|
"description": "What this coherent workload does. One sentence. This is the bounded-context statement; if it cannot be written without 'and also', the grouping is probably wrong."
|
|
},
|
|
"member_repos": {
|
|
"type": "array",
|
|
"minItems": 1,
|
|
"description": "First-party repos, each sharing rollout and rollback fate with the others. A single-repo rapp declares exactly one member. Grouping is legitimate ONLY where members share rollout and rollback fate; members that can be rolled back independently belong in separate rapps.",
|
|
"items": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["repo", "role", "deployables"],
|
|
"properties": {
|
|
"repo": { "$ref": "#/$defs/repoSlug" },
|
|
"role": {
|
|
"type": "string",
|
|
"minLength": 3,
|
|
"description": "What this repo contributes to the composition."
|
|
},
|
|
"deployables": {
|
|
"type": "array",
|
|
"minItems": 1,
|
|
"uniqueItems": true,
|
|
"items": { "type": "string", "minLength": 1 },
|
|
"description": "Names of the running units this repo contributes. CARDINALITY: a repo may appear in the member_repos of MORE THAN ONE rapp (many-to-many), but each deployable belongs to EXACTLY ONE rapp (one-to-one) — exactly one rapp owns its rollout. The validator's coverage check depends on this asymmetry; see schemas/README.md."
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"upstream_components": {
|
|
"type": "array",
|
|
"description": "Third-party components, pinned. An unpinned upstream is not a composition member, it is a liability.",
|
|
"items": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["name", "source", "version"],
|
|
"properties": {
|
|
"name": { "type": "string", "minLength": 1 },
|
|
"source": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"description": "Chart repo/chart or registry reference."
|
|
},
|
|
"version": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"description": "An exact pin. Ranges and floating tags such as latest are not pins."
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
|
|
"rolloutContract": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["default_mode"],
|
|
"description": "NORMATIVE SHAPE. Resembles rapp-openbao and rapp-postgres for the imperative fields (commands) and rapp-qonto for the gate. default_mode was already common to all three live declarations and is kept.",
|
|
"properties": {
|
|
"default_mode": {
|
|
"type": "string",
|
|
"minLength": 3,
|
|
"description": "How this package is rolled out by default, e.g. helm-upgrade-install, kubectl-server-side-apply, revision-canary."
|
|
},
|
|
"commands": {
|
|
"type": "array",
|
|
"items": { "type": "string", "minLength": 1 },
|
|
"description": "Renamed from supported_commands. The imperative execution path where one exists; absent for packages rolled out declaratively."
|
|
},
|
|
"production_gate": {
|
|
"type": "string",
|
|
"description": "Named gate that must be satisfied before production rollout, e.g. reef-production-approved."
|
|
},
|
|
"notes": { "$ref": "#/$defs/notes" }
|
|
}
|
|
},
|
|
|
|
"smokeContract": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["required"],
|
|
"description": "NORMATIVE SHAPE, taken from rapp-qonto. required: names the OUTCOMES that must hold; commands: is how they are exercised. The platform rapps currently declare only commands, so migrating them means naming their checks — that is real migration cost and it is the point: a command list says what was run, not what must be true.",
|
|
"properties": {
|
|
"required": {
|
|
"type": "array",
|
|
"minItems": 1,
|
|
"uniqueItems": true,
|
|
"items": { "type": "string", "minLength": 1 },
|
|
"description": "Named checks that must pass, e.g. authenticated-activation-from-zero, wrong-tenant-denied."
|
|
},
|
|
"commands": {
|
|
"type": "array",
|
|
"items": { "type": "string", "minLength": 1 },
|
|
"description": "Renamed from supported_commands."
|
|
},
|
|
"notes": { "$ref": "#/$defs/notes" }
|
|
}
|
|
},
|
|
|
|
"rollbackContract": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["order"],
|
|
"description": "NORMATIVE SHAPE, taken from rapp-qonto. order: is the ordered preference of rollback strategies, most-preferred first. The platform rapps currently declare only commands; their order is recoverable from the command sequence they already document.",
|
|
"properties": {
|
|
"order": {
|
|
"type": "array",
|
|
"minItems": 1,
|
|
"items": { "type": "string", "minLength": 1 },
|
|
"description": "Ordered rollback strategies, most preferred first, e.g. previous-verified-knative-revision, temporary-minimum-scale, unavailable."
|
|
},
|
|
"commands": {
|
|
"type": "array",
|
|
"items": { "type": "string", "minLength": 1 },
|
|
"description": "Renamed from supported_commands."
|
|
},
|
|
"fallback": {
|
|
"type": "string",
|
|
"description": "Generalized from rapp-qonto's direct_kubernetes_fallback. Names the exceptional path and its expiry condition."
|
|
},
|
|
"notes": { "$ref": "#/$defs/notes" }
|
|
}
|
|
},
|
|
|
|
"consumerContract": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["boundary_unit", "credential_lane", "credential_type"],
|
|
"description": "Present only on packages that provision isolated units to other services. Schema-defined but optional: today only rapp-postgres carries one, and requiring it everywhere would be false precision.",
|
|
"properties": {
|
|
"boundary_unit": { "type": "string", "minLength": 1 },
|
|
"credential_lane": { "type": "string", "minLength": 1 },
|
|
"credential_type": { "type": "string", "minLength": 1 },
|
|
"tenant_keying_required": { "type": "boolean" },
|
|
"notes": { "$ref": "#/$defs/notes" }
|
|
}
|
|
},
|
|
|
|
"consumer": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["name", "declaration"],
|
|
"properties": {
|
|
"name": { "type": "string", "minLength": 1 },
|
|
"declaration": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"description": "Repo-relative path to the consumer declaration."
|
|
},
|
|
"cost_attribution_key": {
|
|
"type": "string",
|
|
"description": "Ties consumption to the cost evidence contract (fin-hub FIN-WP-0004)."
|
|
}
|
|
}
|
|
},
|
|
|
|
"sourceDocument": {
|
|
"type": "object",
|
|
"additionalProperties": false,
|
|
"required": ["repo", "path"],
|
|
"properties": {
|
|
"repo": { "$ref": "#/$defs/repoSlug" },
|
|
"path": { "type": "string", "minLength": 1 }
|
|
}
|
|
}
|
|
}
|
|
}
|