Reconcile reef bindings and evidence
This commit is contained in:
parent
721398125b
commit
3e98b10d81
15 changed files with 541 additions and 36 deletions
|
|
@ -31,6 +31,11 @@ Those concerns stay with `railiance-infra`, `railiance-cluster`,
|
|||
|
||||
This repo now owns the wave-1 grouped home-reef boundary for Railiance.
|
||||
|
||||
The rail and rApp binding projections were reconciled against their owning
|
||||
family declarations on 2026-08-21. Live evidence still shows one Ready member
|
||||
carrying the Kubernetes control-plane and etcd roles, so the Qonto binding
|
||||
remains verified and private rather than production-approved.
|
||||
|
||||
The retained S1 compatibility path while reef localization is still in flight
|
||||
is documented in `docs/retained-s1-handoff.md`.
|
||||
|
||||
|
|
|
|||
7
SCOPE.md
7
SCOPE.md
|
|
@ -62,10 +62,11 @@ or one-host naming into the reef model.
|
|||
## Current State
|
||||
|
||||
- Status: bootstrapped first-wave grouped reef home
|
||||
- Implementation: declaration, grouped substrate files, and retained-S1
|
||||
compatibility handoff are present
|
||||
- Implementation: declaration, grouped substrate files, retained-S1
|
||||
compatibility handoff, and checked rail/rApp binding projections are present
|
||||
- Stability: evolving, with the migration-window split now explicit
|
||||
- Usage: wave-1 home reef for the Railiance server group
|
||||
- Usage: wave-1 home reef for the Railiance server group; Qonto production
|
||||
admission remains blocked on an independent failure domain
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
| workplan | REEF-RAILIANCE-WP-0002 | finished | — | workplans/REEF-RAILIANCE-WP-0002-knative-and-qonto-production-admission.md |
|
||||
| workplan | REEF-RAILIANCE-WP-0003 | blocked | — | workplans/REEF-RAILIANCE-WP-0003-rapp-qonto-production-gates.md |
|
||||
| workplan | REEF-RAILIANCE-WP-0004 | finished | — | workplans/REEF-RAILIANCE-WP-0004-exposure-grants.md |
|
||||
| workplan | REEF-RAILIANCE-WP-0005 | finished | — | workplans/REEF-RAILIANCE-WP-0005-binding-and-evidence-reconciliation.md |
|
||||
| task | REEF-RAILIANCE-WP-0001-T01 | done | — | workplans/REEF-RAILIANCE-WP-0001-bootstrap-and-wave1-import.md |
|
||||
| task | REEF-RAILIANCE-WP-0001-T02 | done | — | workplans/REEF-RAILIANCE-WP-0001-bootstrap-and-wave1-import.md |
|
||||
| task | REEF-RAILIANCE-WP-0001-T03 | done | — | workplans/REEF-RAILIANCE-WP-0001-bootstrap-and-wave1-import.md |
|
||||
|
|
@ -28,3 +29,6 @@
|
|||
| task | REEF-RAILIANCE-WP-0003-T04 | wait | — | workplans/REEF-RAILIANCE-WP-0003-rapp-qonto-production-gates.md |
|
||||
| task | REEF-RAILIANCE-WP-0004-T01 | done | — | workplans/REEF-RAILIANCE-WP-0004-exposure-grants.md |
|
||||
| task | REEF-RAILIANCE-WP-0004-T02 | done | — | workplans/REEF-RAILIANCE-WP-0004-exposure-grants.md |
|
||||
| task | REEF-RAILIANCE-WP-0005-T01 | done | — | workplans/REEF-RAILIANCE-WP-0005-binding-and-evidence-reconciliation.md |
|
||||
| task | REEF-RAILIANCE-WP-0005-T02 | done | — | workplans/REEF-RAILIANCE-WP-0005-binding-and-evidence-reconciliation.md |
|
||||
| task | REEF-RAILIANCE-WP-0005-T03 | done | — | workplans/REEF-RAILIANCE-WP-0005-binding-and-evidence-reconciliation.md |
|
||||
|
|
|
|||
|
|
@ -2,16 +2,18 @@ reef_id: reef-railiance
|
|||
hosted_rails:
|
||||
- rail_id: rail-kubernetes
|
||||
role: primary
|
||||
readiness_state: declared
|
||||
readiness_state: verified
|
||||
contract_version: 1.0.0
|
||||
evidence:
|
||||
- evidence/admission/rail-kubernetes-baseline.json
|
||||
notes: First-wave default execution rail for the grouped Railiance home reef.
|
||||
- evidence/verification/rail-runtime-2026-08-21.json
|
||||
notes: First-wave default execution rail; live verification still records one Ready control-plane and etcd node.
|
||||
- rail_id: rail-knative
|
||||
role: derived
|
||||
readiness_state: declared
|
||||
readiness_state: verified
|
||||
contract_version: 1.0.0
|
||||
base_rail: rail-kubernetes
|
||||
evidence:
|
||||
- evidence/admission/rail-knative-baseline.json
|
||||
notes: Declared second-wave rail; not installed or production-approved.
|
||||
- evidence/verification/rail-runtime-2026-08-21.json
|
||||
notes: Installed and verified for private operation; production approval remains blocked by the single-node failure domain.
|
||||
|
|
|
|||
|
|
@ -1,13 +1,30 @@
|
|||
reef_id: reef-railiance
|
||||
bound_rapps:
|
||||
- rapp_id: rapp-issue-core
|
||||
rail_id: rail-kubernetes
|
||||
package_readiness_state: verified
|
||||
readiness_state: verified
|
||||
evidence:
|
||||
- ../rapp-issue-core/declarations/rapp.yaml
|
||||
- ../rapp-issue-core/evidence/live/2026-08-19-railiance01.json
|
||||
- rapp_id: rapp-openbao
|
||||
rail_id: rail-kubernetes
|
||||
package_readiness_state: verified
|
||||
readiness_state: verified
|
||||
evidence:
|
||||
- ../rapp-openbao/declarations/rapp.yaml
|
||||
- ../railiance-platform/docs/rapp-openbao-boundary.md
|
||||
- ../railiance-platform/docs/openbao.md
|
||||
- rapp_id: rapp-qonto
|
||||
rail_id: rail-knative
|
||||
package_readiness_state: verified
|
||||
readiness_state: verified
|
||||
evidence:
|
||||
- ../rapp-qonto/docs/security-and-reliability-gates.md
|
||||
- ../rapp-qonto/evidence/live/2026-07-29-railiance01.json
|
||||
- rapp_id: rapp-policy-nexus
|
||||
rail_id: rail-kubernetes
|
||||
package_readiness_state: verified
|
||||
readiness_state: production-approved
|
||||
evidence:
|
||||
- ../rapp-policy-nexus/declarations/rapp.yaml
|
||||
|
|
@ -15,7 +32,24 @@ bound_rapps:
|
|||
- ../rapp-policy-nexus/bindings/reef-railiance.yaml
|
||||
- ../rapp-policy-nexus/evidence/live/2026-08-18-railiance01.json
|
||||
- ../rapp-policy-nexus/evidence/live/2026-08-18-railiance01-release2-rollback.json
|
||||
- rapp_id: rapp-postgres
|
||||
rail_id: rail-kubernetes
|
||||
package_readiness_state: verified
|
||||
readiness_state: verified
|
||||
evidence:
|
||||
- ../rapp-postgres/declarations/rapp.yaml
|
||||
- ../rapp-postgres/docs/evidence/node-reboot-2026-08-16.md
|
||||
- ../rapp-postgres/docs/evidence/backup-restore-2026-08-13.md
|
||||
- rapp_id: rapp-user-engine
|
||||
rail_id: rail-kubernetes
|
||||
package_readiness_state: verified
|
||||
readiness_state: declared
|
||||
evidence:
|
||||
- ../rapp-user-engine/declarations/rapp.yaml
|
||||
- ../rapp-user-engine/bindings/reef-railiance.yaml
|
||||
notes:
|
||||
- Membership is the derived projection of rApp declarations whose bound_reefs includes reef-railiance; package_readiness_state is not reef binding admission.
|
||||
- The Qonto binding is verified for non-production operation; production approval remains separate.
|
||||
- The policy-nexus release-2 binding is deployed and verified; rollback to release 1 and forward restoration to release 2 were exercised successfully on 2026-08-18.
|
||||
- User Engine remains declared at the reef binding even though its package readiness is verified.
|
||||
- Add or promote bindings only when the substrate decision is explicit and source-backed.
|
||||
|
|
|
|||
|
|
@ -3,29 +3,60 @@
|
|||
"reef_id": "reef-railiance",
|
||||
"subject": "rail-knative",
|
||||
"readiness_state": "verified",
|
||||
"checked_at": "2026-07-26T18:00:00Z",
|
||||
"checked_at": "2026-08-20T23:55:06Z",
|
||||
"checks": {
|
||||
"compatibility": {
|
||||
"status": "pass",
|
||||
"evidence": [
|
||||
"../rail-knative/declarations/rail.yaml",
|
||||
"../rail-kubernetes/declarations/rail.yaml"
|
||||
"../rail-kubernetes/declarations/rail.yaml",
|
||||
"../verification/rail-runtime-2026-08-21.json"
|
||||
],
|
||||
"notes": "Knative 1.22 minimum Kubernetes 1.34; observed Kubernetes 1.35.1."
|
||||
},
|
||||
"capacity": {
|
||||
"status": "pass",
|
||||
"evidence": ["../preflight/knative-2026-07-26-success.json"],
|
||||
"notes": "Installation verification passed; 4 CPU remains below the generic 6 CPU recommendation."
|
||||
"evidence": ["../verification/rail-runtime-2026-08-21.json"],
|
||||
"notes": "All Knative control-plane deployments are available; 4 CPU remains below the generic 6 CPU recommendation."
|
||||
},
|
||||
"ingress": {
|
||||
"status": "pass",
|
||||
"evidence": [
|
||||
"../verification/rail-knative-v1.22.0-2026-07-26.json",
|
||||
"../verification/rail-runtime-2026-08-21.json"
|
||||
],
|
||||
"notes": "Kourier remains ClusterIP-only; public exposure is disabled."
|
||||
},
|
||||
"network": {
|
||||
"status": "pass",
|
||||
"evidence": [
|
||||
"../verification/rail-knative-v1.22.0-2026-07-26.json",
|
||||
"../verification/rail-runtime-2026-08-21.json",
|
||||
"../../../rapp-qonto/evidence/live/2026-07-29-railiance01.json"
|
||||
]
|
||||
},
|
||||
"identity_and_secrets": {
|
||||
"status": "pass",
|
||||
"evidence": ["../../../rapp-qonto/evidence/live/2026-07-29-railiance01.json"]
|
||||
},
|
||||
"observability": {
|
||||
"status": "pass",
|
||||
"evidence": [
|
||||
"../verification/rail-knative-v1.22.0-2026-07-26.json",
|
||||
"../verification/rail-runtime-2026-08-21.json"
|
||||
],
|
||||
"notes": "Control-plane availability and lifecycle observations are recorded."
|
||||
},
|
||||
"recovery": {
|
||||
"status": "pass",
|
||||
"evidence": [
|
||||
"../verification/rail-knative-v1.22.0-2026-07-26.json",
|
||||
"../../../rapp-qonto/evidence/live/2026-07-29-railiance01.json"
|
||||
]
|
||||
},
|
||||
"ingress": {"status": "pass", "evidence": ["../verification/rail-knative-v1.22.0-2026-07-26.json"], "notes": "Kourier is verified ClusterIP-only; public exposure is disabled."},
|
||||
"network": {"status": "pass", "evidence": ["../verification/rail-knative-v1.22.0-2026-07-26.json"]},
|
||||
"identity_and_secrets": {"status": "unknown", "evidence": []},
|
||||
"observability": {"status": "pass", "evidence": ["../verification/rail-knative-v1.22.0-2026-07-26.json"], "notes": "Control-plane availability and lifecycle observations are recorded."},
|
||||
"recovery": {"status": "unknown", "evidence": []},
|
||||
"failure_domain": {
|
||||
"status": "fail",
|
||||
"evidence": ["../preflight/knative-2026-07-26-success.json"],
|
||||
"evidence": ["../verification/rail-runtime-2026-08-21.json"],
|
||||
"notes": "Production approval is rejected while Knative shares the single-member control plane."
|
||||
}
|
||||
},
|
||||
|
|
@ -33,8 +64,8 @@
|
|||
{
|
||||
"risk": "Single server and shared control plane for a critical bank-connected workload",
|
||||
"status": "open",
|
||||
"owner": "railiance-infra"
|
||||
,"decision": "Not accepted for production; verified non-production rail operation may continue."
|
||||
"owner": "railiance-infra",
|
||||
"decision": "Not accepted for production; verified non-production rail operation may continue."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,31 +2,43 @@
|
|||
"contract_version": "1.0.0",
|
||||
"reef_id": "reef-railiance",
|
||||
"subject": "rail-kubernetes",
|
||||
"readiness_state": "declared",
|
||||
"checked_at": "2026-07-26T00:00:00Z",
|
||||
"readiness_state": "verified",
|
||||
"checked_at": "2026-08-20T23:55:06Z",
|
||||
"checks": {
|
||||
"compatibility": {
|
||||
"status": "pass",
|
||||
"evidence": [
|
||||
"declarations/reef.yaml",
|
||||
"bindings/rails.yaml",
|
||||
"../rail-kubernetes/declarations/rail.yaml"
|
||||
"../rail-kubernetes/declarations/rail.yaml",
|
||||
"../verification/rail-runtime-2026-08-21.json"
|
||||
]
|
||||
},
|
||||
"capacity": {
|
||||
"status": "unknown",
|
||||
"evidence": [],
|
||||
"notes": "Automated capacity and headroom probe not yet recorded."
|
||||
"status": "pass",
|
||||
"evidence": ["../verification/rail-runtime-2026-08-21.json"],
|
||||
"notes": "The only node is Ready with 4 CPU and 16377028Ki allocatable memory; production failure-domain risk remains open."
|
||||
},
|
||||
"ingress": {
|
||||
"status": "pass",
|
||||
"evidence": ["../verification/rail-runtime-2026-08-21.json"],
|
||||
"notes": "Traefik is the observed ingress class."
|
||||
},
|
||||
"network": {
|
||||
"status": "pass",
|
||||
"evidence": [
|
||||
"../verification/rail-runtime-2026-08-21.json",
|
||||
"../../../rapp-qonto/evidence/live/2026-07-29-railiance01.json"
|
||||
],
|
||||
"notes": "NetworkPolicy objects are present and the Qonto binding has workload-level restricted-egress evidence."
|
||||
},
|
||||
"ingress": {"status": "unknown", "evidence": []},
|
||||
"network": {"status": "unknown", "evidence": []},
|
||||
"identity_and_secrets": {"status": "unknown", "evidence": []},
|
||||
"observability": {"status": "unknown", "evidence": []},
|
||||
"recovery": {"status": "unknown", "evidence": []},
|
||||
"failure_domain": {
|
||||
"status": "unknown",
|
||||
"evidence": [],
|
||||
"notes": "Current grouped reef has one declared member."
|
||||
"status": "fail",
|
||||
"evidence": ["../verification/rail-runtime-2026-08-21.json"],
|
||||
"notes": "Current grouped reef has one Ready member carrying control-plane and etcd roles."
|
||||
}
|
||||
},
|
||||
"residual_risks": [
|
||||
|
|
|
|||
76
evidence/verification/rail-runtime-2026-08-21.json
Normal file
76
evidence/verification/rail-runtime-2026-08-21.json
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
{
|
||||
"schema_version": "reef-railiance.rail-runtime-evidence/v1",
|
||||
"collected_at": "2026-08-20T23:55:06Z",
|
||||
"collector": "reef-railiance/tools/collect_rail_runtime_evidence.sh",
|
||||
"executor": "operator-ssh",
|
||||
"context": "default",
|
||||
"kubernetes": {
|
||||
"server_version": "v1.35.1+k3s1",
|
||||
"nodes": {
|
||||
"total": 1,
|
||||
"ready": 1,
|
||||
"members": [
|
||||
{
|
||||
"name": "239.62.205.92.host.secureserver.net",
|
||||
"roles": ["control-plane", "etcd"],
|
||||
"kubelet_version": "v1.35.1+k3s1",
|
||||
"allocatable": {"cpu": "4", "memory": "16377028Ki", "pods": "110"}
|
||||
}
|
||||
]
|
||||
},
|
||||
"ingress_classes": ["traefik"],
|
||||
"storage_classes": ["local-path"],
|
||||
"network_policy_count": 79
|
||||
},
|
||||
"knative": {
|
||||
"deployments": [
|
||||
{
|
||||
"name": "activator",
|
||||
"desired": 1,
|
||||
"available": 1,
|
||||
"images": ["gcr.io/knative-releases/knative.dev/serving/cmd/activator@sha256:8f7e9df2642a8ba715ebc55b62abee17b0984b6b6af0c6ec00dabaadf5f8cccb"]
|
||||
},
|
||||
{
|
||||
"name": "autoscaler",
|
||||
"desired": 1,
|
||||
"available": 1,
|
||||
"images": ["gcr.io/knative-releases/knative.dev/serving/cmd/autoscaler@sha256:ec66d97244395b57a67923d4a8c5a95f0264805f1fdb2ee0cdb49ec0f3bd7855"]
|
||||
},
|
||||
{
|
||||
"name": "controller",
|
||||
"desired": 1,
|
||||
"available": 1,
|
||||
"images": ["gcr.io/knative-releases/knative.dev/serving/cmd/controller@sha256:6833f2c83e9f356c274ddb2de40e5471ad2b1c08882c9bd11f5afa240e86d574"]
|
||||
},
|
||||
{
|
||||
"name": "net-kourier-controller",
|
||||
"desired": 1,
|
||||
"available": 1,
|
||||
"images": ["gcr.io/knative-releases/knative.dev/net-kourier/cmd/kourier@sha256:a2e8f568a4bf68ef6391bc3afea956d11a8698f6a22c4be50844b1da4f8bcc74"]
|
||||
},
|
||||
{
|
||||
"name": "webhook",
|
||||
"desired": 1,
|
||||
"available": 1,
|
||||
"images": ["gcr.io/knative-releases/knative.dev/serving/cmd/webhook@sha256:c505888f7ee34ccadc1b9a6877d6d49691f633ea28cf8cbe03fcfa6d3afcd584"]
|
||||
}
|
||||
],
|
||||
"all_deployments_available": true,
|
||||
"ingress": {
|
||||
"implementation": "net-kourier",
|
||||
"service_type": "ClusterIP",
|
||||
"cluster_ip": "10.43.29.12"
|
||||
},
|
||||
"services": [
|
||||
{
|
||||
"namespace": "rapp-qonto",
|
||||
"name": "rapp-qonto",
|
||||
"latest_created_revision": "rapp-qonto-00008",
|
||||
"latest_ready_revision": "rapp-qonto-00008",
|
||||
"ready": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"failure_domain": {"independent_members_observed": 1, "result": "fail-single-node"},
|
||||
"secret_values_collected": false
|
||||
}
|
||||
65
tests/test_binding_projection.py
Normal file
65
tests/test_binding_projection.py
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
import importlib.util
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
|
||||
MODULE = Path(__file__).parents[1] / "tools/check_binding_projection.py"
|
||||
SPEC = importlib.util.spec_from_file_location("binding_projection", MODULE)
|
||||
binding_projection = importlib.util.module_from_spec(SPEC)
|
||||
SPEC.loader.exec_module(binding_projection)
|
||||
|
||||
|
||||
def write_yaml(path: Path, value: dict) -> None:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text(yaml.safe_dump(value, sort_keys=False), encoding="utf-8")
|
||||
|
||||
|
||||
def test_matching_projection_passes(tmp_path):
|
||||
repo = tmp_path / "reef-example"
|
||||
write_yaml(
|
||||
repo / "declarations/reef.yaml",
|
||||
{"reef_id": "reef-example", "hosted_rails": ["rail-kubernetes"]},
|
||||
)
|
||||
write_yaml(
|
||||
repo / "bindings/rails.yaml",
|
||||
{"hosted_rails": [{"rail_id": "rail-kubernetes"}]},
|
||||
)
|
||||
write_yaml(
|
||||
repo / "bindings/rapps.yaml",
|
||||
{"bound_rapps": [{"rapp_id": "rapp-example"}]},
|
||||
)
|
||||
write_yaml(
|
||||
tmp_path / "rail-kubernetes/declarations/rail.yaml",
|
||||
{"rail_id": "rail-kubernetes"},
|
||||
)
|
||||
write_yaml(
|
||||
tmp_path / "rapp-example/declarations/rapp.yaml",
|
||||
{"rapp_id": "rapp-example", "bound_reefs": ["reef-example"]},
|
||||
)
|
||||
|
||||
assert binding_projection.assess(repo, tmp_path) == []
|
||||
|
||||
|
||||
def test_stale_rapp_projection_fails(tmp_path):
|
||||
repo = tmp_path / "reef-example"
|
||||
write_yaml(
|
||||
repo / "declarations/reef.yaml",
|
||||
{"reef_id": "reef-example", "hosted_rails": ["rail-kubernetes"]},
|
||||
)
|
||||
write_yaml(
|
||||
repo / "bindings/rails.yaml",
|
||||
{"hosted_rails": [{"rail_id": "rail-kubernetes"}]},
|
||||
)
|
||||
write_yaml(repo / "bindings/rapps.yaml", {"bound_rapps": []})
|
||||
write_yaml(
|
||||
tmp_path / "rail-kubernetes/declarations/rail.yaml",
|
||||
{"rail_id": "rail-kubernetes"},
|
||||
)
|
||||
write_yaml(
|
||||
tmp_path / "rapp-example/declarations/rapp.yaml",
|
||||
{"rapp_id": "rapp-example", "bound_reefs": ["reef-example"]},
|
||||
)
|
||||
|
||||
failures = binding_projection.assess(repo, tmp_path)
|
||||
assert failures and "rapp projection differs" in failures[0]
|
||||
86
tools/check_binding_projection.py
Executable file
86
tools/check_binding_projection.py
Executable file
|
|
@ -0,0 +1,86 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Check reef binding files against authoritative sibling declarations."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
|
||||
def load_yaml(path: Path) -> dict:
|
||||
value = yaml.safe_load(path.read_text(encoding="utf-8"))
|
||||
if not isinstance(value, dict):
|
||||
raise ValueError(f"{path}: expected a YAML mapping")
|
||||
return value
|
||||
|
||||
|
||||
def ids(items: object, key: str) -> set[str]:
|
||||
if not isinstance(items, list):
|
||||
return set()
|
||||
return {
|
||||
item[key]
|
||||
for item in items
|
||||
if isinstance(item, dict) and isinstance(item.get(key), str)
|
||||
}
|
||||
|
||||
|
||||
def expected_rapps(parent: Path, reef_id: str) -> set[str]:
|
||||
result: set[str] = set()
|
||||
for declaration_path in sorted(parent.glob("rapp-*/declarations/rapp.yaml")):
|
||||
declaration = load_yaml(declaration_path)
|
||||
if reef_id in declaration.get("bound_reefs", []):
|
||||
result.add(str(declaration["rapp_id"]))
|
||||
return result
|
||||
|
||||
|
||||
def expected_rails(parent: Path, declared: list[str]) -> set[str]:
|
||||
result: set[str] = set()
|
||||
for rail_id in declared:
|
||||
declaration_path = parent / rail_id / "declarations" / "rail.yaml"
|
||||
declaration = load_yaml(declaration_path)
|
||||
result.add(str(declaration["rail_id"]))
|
||||
return result
|
||||
|
||||
|
||||
def assess(repo: Path, parent: Path) -> list[str]:
|
||||
reef = load_yaml(repo / "declarations" / "reef.yaml")
|
||||
reef_id = str(reef["reef_id"])
|
||||
rapp_bindings = load_yaml(repo / "bindings" / "rapps.yaml")
|
||||
rail_bindings = load_yaml(repo / "bindings" / "rails.yaml")
|
||||
|
||||
actual_rapps = ids(rapp_bindings.get("bound_rapps"), "rapp_id")
|
||||
derived_rapps = expected_rapps(parent, reef_id)
|
||||
actual_rails = ids(rail_bindings.get("hosted_rails"), "rail_id")
|
||||
derived_rails = expected_rails(parent, list(reef.get("hosted_rails", [])))
|
||||
|
||||
failures: list[str] = []
|
||||
if actual_rapps != derived_rapps:
|
||||
failures.append(
|
||||
f"rapp projection differs: binding={sorted(actual_rapps)}, "
|
||||
f"derived={sorted(derived_rapps)}"
|
||||
)
|
||||
if actual_rails != derived_rails:
|
||||
failures.append(
|
||||
f"rail projection differs: binding={sorted(actual_rails)}, "
|
||||
f"declared={sorted(derived_rails)}"
|
||||
)
|
||||
return failures
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--repo", type=Path, default=Path(__file__).parents[1])
|
||||
parser.add_argument("--parent", type=Path)
|
||||
args = parser.parse_args()
|
||||
repo = args.repo.resolve()
|
||||
parent = (args.parent or repo.parent).resolve()
|
||||
failures = assess(repo, parent)
|
||||
print(json.dumps({"pass": not failures, "failures": failures}))
|
||||
return bool(failures)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
85
tools/collect_rail_runtime_evidence.sh
Executable file
85
tools/collect_rail_runtime_evidence.sh
Executable file
|
|
@ -0,0 +1,85 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Read-only, secret-free evidence collector for the rails hosted by this reef.
|
||||
# The cluster API is intentionally reached through the operator SSH path; 6443
|
||||
# remains non-public. Override only when the approved executor name changes.
|
||||
remote_host="${RAIL_RUNTIME_HOST:-railiance01}"
|
||||
|
||||
ssh -o BatchMode=yes "$remote_host" 'bash -s' <<'REMOTE'
|
||||
set -euo pipefail
|
||||
|
||||
context="$(kubectl config current-context)"
|
||||
server_version="$(kubectl version -o json | jq -r '.serverVersion.gitVersion')"
|
||||
nodes="$(kubectl get nodes -o json)"
|
||||
knative_deployments="$(kubectl -n knative-serving get deployments -o json)"
|
||||
kourier_service="$(kubectl -n kourier-system get service kourier -o json)"
|
||||
knative_services="$(kubectl get ksvc -A -o json)"
|
||||
ingress_classes="$(kubectl get ingressclass -o json)"
|
||||
storage_classes="$(kubectl get storageclass -o json)"
|
||||
network_policy_count="$(kubectl get networkpolicy -A -o json | jq '.items | length')"
|
||||
|
||||
jq -n \
|
||||
--arg context "$context" \
|
||||
--arg server_version "$server_version" \
|
||||
--argjson nodes "$nodes" \
|
||||
--argjson deployments "$knative_deployments" \
|
||||
--argjson kourier "$kourier_service" \
|
||||
--argjson services "$knative_services" \
|
||||
--argjson ingress_classes "$ingress_classes" \
|
||||
--argjson storage_classes "$storage_classes" \
|
||||
--argjson network_policy_count "$network_policy_count" \
|
||||
'{
|
||||
schema_version: "reef-railiance.rail-runtime-evidence/v1",
|
||||
collected_at: (now | todateiso8601),
|
||||
collector: "reef-railiance/tools/collect_rail_runtime_evidence.sh",
|
||||
executor: "operator-ssh",
|
||||
context: $context,
|
||||
kubernetes: {
|
||||
server_version: $server_version,
|
||||
nodes: {
|
||||
total: ($nodes.items | length),
|
||||
ready: ([$nodes.items[] | select(any(.status.conditions[]; .type == "Ready" and .status == "True"))] | length),
|
||||
members: [$nodes.items[] | {
|
||||
name: .metadata.name,
|
||||
roles: ([.metadata.labels | keys[] | select(startswith("node-role.kubernetes.io/")) | split("/")[1]] | sort),
|
||||
kubelet_version: .status.nodeInfo.kubeletVersion,
|
||||
allocatable: {
|
||||
cpu: .status.allocatable.cpu,
|
||||
memory: .status.allocatable.memory,
|
||||
pods: .status.allocatable.pods
|
||||
}
|
||||
}]
|
||||
},
|
||||
ingress_classes: [$ingress_classes.items[].metadata.name] | sort,
|
||||
storage_classes: [$storage_classes.items[].metadata.name] | sort,
|
||||
network_policy_count: $network_policy_count
|
||||
},
|
||||
knative: {
|
||||
deployments: [$deployments.items[] | {
|
||||
name: .metadata.name,
|
||||
desired: (.spec.replicas // 0),
|
||||
available: (.status.availableReplicas // 0),
|
||||
images: [.spec.template.spec.containers[].image]
|
||||
}] | sort_by(.name),
|
||||
all_deployments_available: (all($deployments.items[]; (.status.availableReplicas // 0) >= (.spec.replicas // 0))),
|
||||
ingress: {
|
||||
implementation: "net-kourier",
|
||||
service_type: $kourier.spec.type,
|
||||
cluster_ip: $kourier.spec.clusterIP
|
||||
},
|
||||
services: [$services.items[] | {
|
||||
namespace: .metadata.namespace,
|
||||
name: .metadata.name,
|
||||
latest_created_revision: .status.latestCreatedRevisionName,
|
||||
latest_ready_revision: .status.latestReadyRevisionName,
|
||||
ready: (any(.status.conditions[]?; .type == "Ready" and .status == "True"))
|
||||
}] | sort_by(.namespace, .name)
|
||||
},
|
||||
failure_domain: {
|
||||
independent_members_observed: ($nodes.items | length),
|
||||
result: (if ($nodes.items | length) > 1 then "requires-source-backed-review" else "fail-single-node" end)
|
||||
},
|
||||
secret_values_collected: false
|
||||
}'
|
||||
REMOTE
|
||||
|
|
@ -8,7 +8,11 @@ status: finished
|
|||
owner: codex
|
||||
topic_slug: railiance
|
||||
created: "2026-07-26"
|
||||
updated: "2026-07-26"
|
||||
updated: "2026-08-21"
|
||||
quality_dod: DoD-Ok
|
||||
quality_dod_at: "2026-08-21"
|
||||
quality_dod_by: codex
|
||||
quality_dod_note: "Retrospective assessment: all four tasks are done, the grouped boundary and handoff remain current, and repository checks pass."
|
||||
state_hub_workstream_id: "da64c718-68bf-4719-aa42-fcf26687ab23"
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,11 @@ status: finished
|
|||
owner: codex
|
||||
topic_slug: railiance
|
||||
created: "2026-07-26"
|
||||
updated: "2026-07-26"
|
||||
updated: "2026-08-21"
|
||||
quality_dod: DoD-Ok
|
||||
quality_dod_at: "2026-08-21"
|
||||
quality_dod_by: codex
|
||||
quality_dod_note: "Retrospective assessment: completed and cancelled work is explicit, Qonto residual work transferred to WP-0003, and rail evidence checks pass."
|
||||
state_hub_workstream_id: "5b31c13e-ddc9-495f-8325-88fa770982c5"
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ status: blocked
|
|||
owner: codex
|
||||
topic_slug: railiance
|
||||
created: "2026-07-26"
|
||||
updated: "2026-08-15"
|
||||
updated: "2026-08-21"
|
||||
related:
|
||||
- RAIL-BS-WP-0007
|
||||
- RCLUSTER-WP-0007
|
||||
- RMASTER-WP-0023
|
||||
- ADR-0006
|
||||
- ADR-0008
|
||||
|
|
@ -21,7 +21,7 @@ state_hub_workstream_id: "c3f9fbfd-3db1-4387-8b65-7d53ba57138d"
|
|||
|
||||
This reef records the `rapp-qonto` binding and refuses
|
||||
`production-approved` without ADR-0006 evidence. It does not implement
|
||||
HA (`RAIL-BS-WP-0007`), Knative packaging (`rapp-qonto`), or public
|
||||
HA (`RCLUSTER-WP-0007`), Knative packaging (`rapp-qonto`), or public
|
||||
listeners. Production approval does not make Qonto public (ADR-0008).
|
||||
New binds stay `private`. Exposure grants for already-public surfaces
|
||||
are `REEF-RAILIANCE-WP-0004`, not this file.
|
||||
|
|
@ -133,7 +133,7 @@ single-node production availability risk for Qonto. The current binding
|
|||
remains accurately `verified`, not `production-approved`.
|
||||
|
||||
2026-08-08 alignment: live inspection still reports one Ready node, which also
|
||||
owns the control-plane and etcd roles. `railiance-cluster/RAIL-BS-WP-0007` now
|
||||
owns the control-plane and etcd roles. `railiance-cluster/RCLUSTER-WP-0007` now
|
||||
owns the required three-server embedded-etcd topology, source-backed
|
||||
node-to-reef failure-domain map, and machine-readable one-server-loss S2
|
||||
drill. `state-hub/CUST-WP-0038` is a downstream stateful consumer and does not
|
||||
|
|
@ -144,6 +144,12 @@ dependency behavior, and restoration on the surviving cluster. The alternate
|
|||
closure remains explicit founder acceptance of the single-node production
|
||||
availability risk.
|
||||
|
||||
2026-08-21 evidence refresh: the read-only reef collector still observes one
|
||||
Ready Kubernetes node carrying both control-plane and etcd roles. All five
|
||||
Knative control-plane deployments and `rapp-qonto-00008` are Ready, and Kourier
|
||||
remains ClusterIP-only. `RCLUSTER-WP-0007` is still backlog, so this is fresh
|
||||
evidence for retaining the block, not grounds for production promotion.
|
||||
|
||||
This repo only updates `bindings/rapps.yaml` when those conditions hold.
|
||||
Do not implement the three-node topology here. Do not add an exposure
|
||||
grant for Qonto as a side effect of `production-approved`.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,90 @@
|
|||
---
|
||||
id: REEF-RAILIANCE-WP-0005
|
||||
type: workplan
|
||||
title: "Reconcile reef bindings and refresh rail evidence"
|
||||
domain: financials
|
||||
repo: reef-railiance
|
||||
status: finished
|
||||
owner: codex
|
||||
topic_slug: railiance
|
||||
created: "2026-08-21"
|
||||
updated: "2026-08-21"
|
||||
quality_dod: DoD-Ok
|
||||
quality_dod_at: "2026-08-21"
|
||||
quality_dod_by: codex
|
||||
quality_dod_note: "Binding projections match family declarations, live rail evidence is fresh, tests pass, and the Qonto production block remains explicit."
|
||||
related:
|
||||
- REEF-RAILIANCE-WP-0002
|
||||
- REEF-RAILIANCE-WP-0003
|
||||
- ADR-0006
|
||||
- ADR-0007
|
||||
state_hub_workstream_id: "99e8e93b-99a0-4ef6-91d7-e4f155fa7ee9"
|
||||
---
|
||||
|
||||
# REEF-RAILIANCE-WP-0005 — binding and evidence reconciliation
|
||||
|
||||
## Goal
|
||||
|
||||
Remove drift between the reef-local binding surfaces, family declarations,
|
||||
and current secret-free runtime evidence without promoting any workload beyond
|
||||
its proven reef admission state.
|
||||
|
||||
## T01 — Refresh hosted-rail evidence
|
||||
|
||||
```task
|
||||
id: REEF-RAILIANCE-WP-0005-T01
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "bebf85e7-db0a-41f1-9ad3-a7e184a6249c"
|
||||
```
|
||||
|
||||
Add a repeatable operator-SSH collector, capture fresh Kubernetes and Knative
|
||||
runtime evidence, and reconcile both hosted rails to `verified`.
|
||||
|
||||
Completed 2026-08-21. The collector observed Kubernetes v1.35.1+k3s1, one of
|
||||
one nodes Ready, all five Knative control-plane deployments available, Kourier
|
||||
as ClusterIP, and the Qonto Knative Service Ready. No Secret resources or
|
||||
values were read. The one-node control-plane/etcd failure-domain check remains
|
||||
failed, so neither the rail nor Qonto gained production approval.
|
||||
|
||||
## T02 — Reconcile the rApp binding projection
|
||||
|
||||
```task
|
||||
id: REEF-RAILIANCE-WP-0005-T02
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "88fb7abe-6b85-4cae-bd0b-d6d7c4a5deaa"
|
||||
```
|
||||
|
||||
Project every family rApp whose declaration names `reef-railiance`, while
|
||||
keeping package readiness distinct from reef binding admission. Add a check
|
||||
that fails when the local relation files diverge from sibling declarations.
|
||||
|
||||
Completed 2026-08-21. `bindings/rapps.yaml` now covers `rapp-issue-core`,
|
||||
`rapp-openbao`, `rapp-policy-nexus`, `rapp-postgres`, `rapp-qonto`, and
|
||||
`rapp-user-engine`. Only Policy Nexus is `production-approved`; Qonto remains
|
||||
`verified`, and User Engine remains `declared` at the reef binding.
|
||||
|
||||
## T03 — Close documentation and quality drift
|
||||
|
||||
```task
|
||||
id: REEF-RAILIANCE-WP-0005-T03
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "923647a0-1010-4023-8f2f-9e69c9f0b8e1"
|
||||
```
|
||||
|
||||
Correct the renamed ThreePhoenix dependency, state the current blocker in the
|
||||
orientation docs, and retrospectively assess the completed WP-0001 and WP-0002
|
||||
records against the current workplan Definition of Done.
|
||||
|
||||
Completed 2026-08-21. References now use `RCLUSTER-WP-0007`; the README and
|
||||
scope state the fresh single-node result; WP-0001 and WP-0002 are DoD-Ok.
|
||||
|
||||
## Outcome
|
||||
|
||||
The reef-local relationship files are current and mechanically checked. Rail
|
||||
evidence is fresh and secret-free. `REEF-RAILIANCE-WP-0003` remains correctly
|
||||
blocked until ThreePhoenix produces independent-failure-domain evidence and
|
||||
Qonto is reverified during loss of Railiance01, or the founder explicitly
|
||||
accepts the single-node availability risk.
|
||||
Loading…
Add table
Add a link
Reference in a new issue