feat: implement RMASTER-WP-0023 private-by-default exposure

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.
This commit is contained in:
codex 2026-08-15 20:08:37 +02:00
parent 6301798fab
commit 4a664533d3
24 changed files with 998 additions and 13 deletions

View file

@ -0,0 +1,12 @@
kind: execution-rail
rail_id: rail-kubernetes
repo: rail-kubernetes
ownership_repo: railiance-cluster
contract_version: 1.0.0
composition_kind: base
execution_architecture: kubernetes
readiness_state: verified
required_substrate_capabilities:
- kubernetes-api
supported_rollout_modes:
- stage1-run

View file

@ -0,0 +1,37 @@
kind: managed-workload-package
repo_family: rapp
rapp_id: rapp-nogrant
repo: rapp-nogrant
ownership_repo: railiance-platform
contract_version: 1.0.0
readiness_state: declared
workload_identity:
name: nogrant
package_type: helm-managed-platform-service
data_classification: internal
criticality: medium
primary_rail: rail-kubernetes
supported_rails:
- rail-kubernetes
bound_reefs:
- reef-example
runtime_dependencies:
- kubernetes-api
composition:
purpose: Fixture rapp used to exercise exposure validation.
member_repos:
- repo: rapp-nogrant
role: package
deployables:
- nogrant
rollout_contract:
default_mode: helm-upgrade-install
smoke_contract:
required:
- example-status-ok
rollback_contract:
order:
- helm-rollback
exposure:
posture: public
binding_admission: production-approved

View file

@ -0,0 +1,42 @@
kind: managed-workload-package
repo_family: rapp
rapp_id: rapp-unapproved
repo: rapp-unapproved
ownership_repo: railiance-platform
contract_version: 1.0.0
readiness_state: declared
workload_identity:
name: unapproved
package_type: helm-managed-platform-service
data_classification: internal
criticality: medium
primary_rail: rail-kubernetes
supported_rails:
- rail-kubernetes
bound_reefs:
- reef-example
runtime_dependencies:
- kubernetes-api
composition:
purpose: Fixture rapp used to exercise exposure validation.
member_repos:
- repo: rapp-unapproved
role: package
deployables:
- unapproved
rollout_contract:
default_mode: helm-upgrade-install
smoke_contract:
required:
- example-status-ok
rollback_contract:
order:
- helm-rollback
exposure:
posture: public
binding_admission: verified
grant:
hostname: unapproved.example
reason: should fail
approved_on: "2026-08-15"
residual_risk_owner: railiance-platform

View file

@ -0,0 +1,42 @@
kind: managed-workload-package
repo_family: rapp
rapp_id: rapp-wrongreef
repo: rapp-wrongreef
ownership_repo: railiance-platform
contract_version: 1.0.0
readiness_state: declared
workload_identity:
name: wrongreef
package_type: helm-managed-platform-service
data_classification: internal
criticality: medium
primary_rail: rail-kubernetes
supported_rails:
- rail-kubernetes
bound_reefs:
- reef-closed
runtime_dependencies:
- kubernetes-api
composition:
purpose: Fixture rapp used to exercise exposure validation.
member_repos:
- repo: rapp-wrongreef
role: package
deployables:
- wrongreef
rollout_contract:
default_mode: helm-upgrade-install
smoke_contract:
required:
- example-status-ok
rollback_contract:
order:
- helm-rollback
exposure:
posture: public
binding_admission: production-approved
grant:
hostname: closed.example
reason: reef has no public surface
approved_on: "2026-08-15"
residual_risk_owner: railiance-platform

View file

@ -0,0 +1,12 @@
kind: substrate-reef
reef_id: reef-closed
repo: reef-closed
ownership_repo: railiance-infra
substrate_kind: server-group
lifecycle_state: active
criticality: high
primary_rail: rail-kubernetes
hosted_rails:
- rail-kubernetes
current_members:
- Closed01

View file

@ -0,0 +1,20 @@
kind: substrate-reef
reef_id: reef-example
repo: reef-example
ownership_repo: railiance-infra
substrate_kind: server-group
lifecycle_state: active
criticality: high
primary_rail: rail-kubernetes
hosted_rails:
- rail-kubernetes
current_members:
- Example01
exposure:
posture: public
grants:
- hostname: example.coulomb.social
port: 443
reason: fixture public DNS surface
approved_on: "2026-08-15"
residual_risk_owner: railiance-infra

View file

@ -0,0 +1,19 @@
kind: substrate-reef
reef_id: reef-k3s
repo: reef-k3s
ownership_repo: railiance-infra
substrate_kind: server-group
lifecycle_state: active
criticality: high
primary_rail: rail-kubernetes
hosted_rails:
- rail-kubernetes
current_members:
- K3s01
exposure:
posture: public
grants:
- port: 6443
reason: must be rejected
approved_on: "2026-08-15"
residual_risk_owner: railiance-infra

View file

@ -0,0 +1,15 @@
kind: substrate-reef
reef_id: reef-storage-example
repo: reef-storage-example
ownership_repo: railiance-platform
substrate_kind: object-storage
lifecycle_state: planned
criticality: high
current_members: []
exposure:
posture: public
grants:
- hostname: s3.example
reason: provider API is not a listener we open
approved_on: "2026-08-15"
residual_risk_owner: railiance-platform

View file

@ -0,0 +1,8 @@
{
"source": "fixture",
"captured_at": "2026-08-15T00:00:00Z",
"reef": "reef-example",
"deployables": [
{"name": "example", "namespace": "example", "kind": "helm-release"}
]
}

View file

@ -0,0 +1,21 @@
kind: execution-rail
rail_id: rail-knative
repo: rail-knative
ownership_repo: railiance-cluster
contract_version: 1.0.0
composition_kind: derived
base_rail: rail-kubernetes
base_rail_contract: 1.0.0
execution_architecture: knative-serving-on-kubernetes
readiness_state: verified
required_substrate_capabilities:
- kubernetes-api
- knative-serving
supported_rollout_modes:
- revision-canary
inherited_semantics:
- workload-identity
overridden_semantics:
- request-activation
compatibility_constraints:
- rail-kubernetes contract must equal 1.0.0

View file

@ -0,0 +1,12 @@
kind: execution-rail
rail_id: rail-kubernetes
repo: rail-kubernetes
ownership_repo: railiance-cluster
contract_version: 1.0.0
composition_kind: base
execution_architecture: kubernetes
readiness_state: verified
required_substrate_capabilities:
- kubernetes-api
supported_rollout_modes:
- stage1-run

View file

@ -0,0 +1,42 @@
kind: managed-workload-package
repo_family: rapp
rapp_id: rapp-example
repo: rapp-example
ownership_repo: railiance-platform
contract_version: 1.0.0
readiness_state: declared
workload_identity:
name: example
package_type: helm-managed-platform-service
data_classification: internal
criticality: medium
primary_rail: rail-kubernetes
supported_rails:
- rail-kubernetes
bound_reefs:
- reef-example
runtime_dependencies:
- kubernetes-api
composition:
purpose: Fixture rapp used to exercise exposure validation.
member_repos:
- repo: rapp-example
role: package
deployables:
- example
rollout_contract:
default_mode: helm-upgrade-install
smoke_contract:
required:
- example-status-ok
rollback_contract:
order:
- helm-rollback
exposure:
posture: public
binding_admission: production-approved
grant:
hostname: example.coulomb.social
reason: fixture public rapp
approved_on: "2026-08-15"
residual_risk_owner: railiance-platform

View file

@ -0,0 +1,21 @@
kind: substrate-reef
reef_id: reef-example
repo: reef-example
ownership_repo: railiance-infra
substrate_kind: server-group
lifecycle_state: active
criticality: high
primary_rail: rail-kubernetes
hosted_rails:
- rail-kubernetes
- rail-knative
current_members:
- Example01
exposure:
posture: public
grants:
- hostname: example.coulomb.social
port: 443
reason: fixture public DNS surface
approved_on: "2026-08-15"
residual_risk_owner: railiance-infra

View file

@ -11,8 +11,11 @@ checks, in this order:
2. sibling-field constraints JSON Schema cannot express
3. declared member repos, named rails, and named reefs resolve on disk
4. reef bound_rapps matches the projection of rapp.bound_reefs
5. a deployable name belongs to at most one rapp
6. if --inventory is given, every live deployable belongs to exactly one rapp
5. exposure posture rules from ADR-0008 (public needs a grant and
approved binding; rapp public needs a public reef surface; 6443 is
never grantable; provider-delegated reefs cannot be public)
6. a deployable name belongs to at most one rapp
7. if --inventory is given, every live deployable belongs to exactly one rapp
This repo does not query a cluster. Live coverage consumes an inventory
file produced by an implementation repo (RMASTER-WP-0021-T06).
@ -53,6 +56,7 @@ DECL_BY_PREFIX = {
}
FLOATING_PIN = re.compile(r"^(latest|[\^~*]|.*\*|.*x$)", re.IGNORECASE)
SLUG = re.compile(r"^[a-z0-9]+(-[a-z0-9]+)*$")
FORBIDDEN_PUBLIC_PORTS = {6443}
@dataclass
@ -260,6 +264,119 @@ def check_resolution(loaded: Loaded, present: set[str], root: Path, report: Repo
need(f"hosted_rails[{i}]", rail)
def exposure_block(doc: dict[str, Any]) -> dict[str, Any] | None:
block = doc.get("exposure")
return block if isinstance(block, dict) else None
def posture_of(doc: dict[str, Any]) -> str:
block = exposure_block(doc)
if block is None:
return "private"
posture = block.get("posture")
return posture if isinstance(posture, str) else "private"
def grants_of(loaded: Loaded) -> list[dict[str, Any]]:
block = exposure_block(loaded.doc) if isinstance(loaded.doc, dict) else None
if block is None:
return []
if loaded.family == "reef":
return [item for item in as_list(block.get("grants")) if isinstance(item, dict)]
grant = block.get("grant")
return [grant] if isinstance(grant, dict) else []
def reef_has_public_surface(loaded: Loaded) -> bool:
return (
loaded.family == "reef"
and isinstance(loaded.doc, dict)
and posture_of(loaded.doc) == "public"
and bool(grants_of(loaded))
)
def reject_forbidden_ports(loaded: Loaded, report: Report) -> None:
field_prefix = "exposure.grants" if loaded.family == "reef" else "exposure.grant"
for i, grant in enumerate(grants_of(loaded)):
port = grant.get("port")
if port in FORBIDDEN_PUBLIC_PORTS:
loc = field_prefix if loaded.family != "reef" else f"{field_prefix}[{i}].port"
if loaded.family != "reef":
loc = f"{field_prefix}.port"
report.add(
loaded.rel,
loc,
f"port {port} is not a grantable public surface",
)
def check_exposure(loaded_docs: list[Loaded], report: Report) -> None:
reefs: dict[str, Loaded] = {}
for loaded in loaded_docs:
if loaded.family != "reef" or not isinstance(loaded.doc, dict):
continue
reef_id = loaded.doc.get("reef_id")
if isinstance(reef_id, str):
reefs[reef_id] = loaded
for loaded in loaded_docs:
if not isinstance(loaded.doc, dict):
continue
reject_forbidden_ports(loaded, report)
posture = posture_of(loaded.doc)
block = exposure_block(loaded.doc) or {}
if loaded.family == "reef":
hosted = as_list(loaded.doc.get("hosted_rails"))
primary = loaded.doc.get("primary_rail")
provider_delegated = not primary and not hosted
if posture == "public" and provider_delegated:
report.add(
loaded.rel,
"exposure.posture",
"provider-delegated reef cannot use exposure.public",
)
if posture == "public" and not grants_of(loaded):
report.add(
loaded.rel,
"exposure.grants",
"public reef requires at least one substrate grant",
)
continue
if posture != "public":
continue
if not grants_of(loaded):
report.add(
loaded.rel,
"exposure.grant",
"public posture requires a grant object",
)
if loaded.family == "rail" and loaded.doc.get("readiness_state") != "production-approved":
report.add(
loaded.rel,
"readiness_state",
"public rail requires readiness_state production-approved",
)
if loaded.family != "rapp":
continue
admission = block.get("binding_admission")
if admission != "production-approved":
got = f"; got {admission!r}" if admission is not None else ""
report.add(
loaded.rel,
"exposure.binding_admission",
"public requires binding_admission production-approved "
f"(not rapp readiness_state){got}",
)
bound = [item for item in as_list(loaded.doc.get("bound_reefs")) if isinstance(item, str)]
if not any(reef_id in reefs and reef_has_public_surface(reefs[reef_id]) for reef_id in bound):
report.add(
loaded.rel,
"exposure.posture",
"public rapp is not bound to a reef that has granted a public surface",
)
def check_bound_rapps(loaded_docs: list[Loaded], report: Report) -> None:
derived: dict[str, set[str]] = defaultdict(set)
rapp_ids: set[str] = set()
@ -466,6 +583,7 @@ def validate(
check_reef(loaded, report)
check_resolution(loaded, present, root, report)
check_bound_rapps(loaded_docs, report)
check_exposure(loaded_docs, report)
check_deployable_uniqueness(loaded_docs, report)
check_undeclared(repos, loaded_docs, root, report)
if inventory_path is not None:
@ -521,6 +639,30 @@ def self_test() -> int:
if not bad.errors:
failures.append("bad-stale-bound produced no errors")
exposed_root = TESTDATA / "good-exposure"
exposed = validate(exposed_root, discover_repos(exposed_root), validators)
if exposed.errors:
failures.append(
"good-exposure fixture produced errors:\n "
+ "\n ".join(str(f) for f in exposed.errors)
)
bad_exp_root = TESTDATA / "bad-exposure"
bad_exp = validate(bad_exp_root, discover_repos(bad_exp_root), validators)
exp_messages = "\n".join(str(f) for f in bad_exp.errors)
expected_exposure = [
("binding_admission production-approved", "unapproved public rapp"),
("requires a grant object", "public rapp without grant"),
("not bound to a reef that has granted a public surface", "public rapp on a private reef"),
("port 6443 is not a grantable public surface", "6443 grant"),
("provider-delegated reef cannot use exposure.public", "public storage reef"),
]
for needle, label in expected_exposure:
if not any(needle in f.message for f in bad_exp.errors):
failures.append(f"bad-exposure did not flag {label}:\n{exp_messages}")
if not bad_exp.errors:
failures.append("bad-exposure produced no errors")
live_rails = [
Path("/home/worsch/rail-kubernetes"),
Path("/home/worsch/rail-knative"),
@ -541,7 +683,9 @@ def self_test() -> int:
return 1
print("self-test ok")
print(f" good: {good.files} file(s), {len(good.errors)} error(s)")
print(f" good-exposure: {exposed.files} file(s), {len(exposed.errors)} error(s)")
print(f" bad-stale-bound: {bad.files} file(s), {len(bad.errors)} error(s) (expected)")
print(f" bad-exposure: {bad_exp.files} file(s), {len(bad_exp.errors)} error(s) (expected)")
return 0