feat: adopt security zones and explicit workload refs
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a0291a-1e87-7151-9934-fcbfe3f65eb1
This commit is contained in:
tegwick 2026-08-22 15:36:37 +02:00
parent 12c637cbf2
commit 7ce58ae638
52 changed files with 1547 additions and 658 deletions

234
scripts/report_workload_join.py Executable file → Normal file
View file

@ -1,128 +1,156 @@
#!/usr/bin/env python3
"""Report the lane -> workload join, for the security-zone model (ZONE-WP-0001-T03).
"""Report explicit lane -> workload resolution for security-zones_v0.1.
A security zone's subject is the **workload**, not the lane — policy is about the
running thing and whoever answers for it. ops-warden's catalog is a credential
surface, so on its own it cannot name that subject. The other side of the join
lives in `rapp-*/declarations/rapp.yaml`, which declares `workload_identity`
along with `data_classification` and `criticality`; ops-warden's
`registry/policy/security-posture.yaml` then maps classification to a minimum
maturity via `dataclass_floor`.
The catalog owner declares whether each lane is workload-applicable. Managed
deployables use the exact Repo Manager v1 ``(rapp_id, name, deployable?)``
reference. Independently governed operational workloads use ``name`` plus an
owner declaration reference. Unknown and not-applicable are explicit results.
This script computes the join and reports its coverage. It asserts nothing it
cannot derive: a lane whose workload cannot be established is reported as
unmatched rather than guessed, because the unmatched set is the informative
output those are lanes existing for something that is not a declared workload.
Read-only. Touches no secret value and no live system.
Usage:
python scripts/report_workload_join.py [--rapp-root ~] [--json]
This script never parses a credential path, consults ``owner_repo`` as an
identity hint, or substitutes a repository name. It reads declarations only.
"""
from __future__ import annotations
import argparse
import json
import os
import sys
from pathlib import Path
from typing import Any, Dict, List, Optional
from typing import Any
_SRC = Path(__file__).resolve().parent.parent / "src"
if _SRC.is_dir() and str(_SRC) not in sys.path:
sys.path.insert(0, str(_SRC))
import yaml # noqa: E402
import yaml
def load_rapp_workloads(root: Path) -> Dict[str, Dict[str, Any]]:
"""workload name -> declaration, from every rapp-*/declarations/rapp.yaml."""
out: Dict[str, Dict[str, Any]] = {}
def load_rapp_workloads(root: Path) -> dict[tuple[str, str], dict[str, Any]]:
"""Exact Repo Manager v1 key -> authoritative declaration projection."""
out: dict[tuple[str, str], dict[str, Any]] = {}
for decl in sorted(root.glob("rapp-*/declarations/rapp.yaml")):
try:
data = yaml.safe_load(decl.read_text()) or {}
except yaml.YAMLError:
continue
identity = data.get("workload_identity") or {}
rapp_id = data.get("rapp_id")
name = identity.get("name")
if not name:
if not rapp_id or not name:
continue
out[str(name)] = {
"rapp_id": data.get("rapp_id"),
deployables = []
for member in (data.get("composition") or {}).get("member_repos") or []:
deployables.extend(str(value) for value in member.get("deployables") or [])
out[(str(rapp_id), str(name))] = {
"source": str(decl),
"deployables": sorted(set(deployables)),
"data_classification": data.get("data_classification"),
"criticality": data.get("criticality"),
"readiness_state": data.get("readiness_state"),
"bound_reefs": data.get("bound_reefs"),
}
return out
def candidate_workloads(path_template: Optional[str]) -> List[str]:
"""Workload names a path could plausibly name — never a single guess.
The convention is `platform/workloads/<domain>/<workload>/<bundle>`, but it
is not applied consistently: `platform/workloads/rapp-qonto/keycape-client`
has one level fewer, so position alone cannot say which segment is the
workload. Both are offered and matched against declarations.
"""
if not path_template or "<" in path_template:
return []
parts = [p for p in path_template.split("/") if p]
if len(parts) >= 4 and parts[1] == "workloads":
return [parts[3], parts[2]]
if parts and parts[0] == "tenants" and len(parts) >= 3:
return [parts[2], parts[1]]
return []
def _direct_declaration_path(
declaration_ref: str, *, catalog_path: Path, estate_root: Path
) -> Path:
ref = Path(declaration_ref)
if ref.is_absolute():
return ref
local = catalog_path.resolve().parents[2] / ref
return local if local.exists() else estate_root / ref
def build(catalog_path: Path, rapp_root: Path) -> Dict[str, Any]:
entries = (yaml.safe_load(catalog_path.read_text()) or {}).get("entries", [])
declared = load_rapp_workloads(rapp_root)
floor = (
yaml.safe_load(
(catalog_path.parent.parent / "policy" / "security-posture.yaml").read_text()
def _resolve_direct(
ref: dict[str, Any], *, catalog_path: Path, estate_root: Path
) -> tuple[dict[str, Any] | None, str | None]:
source = _direct_declaration_path(
str(ref["declaration_ref"]), catalog_path=catalog_path, estate_root=estate_root
)
if not source.exists():
return None, f"declaration not found: {source}"
try:
declaration = yaml.safe_load(source.read_text()) or {}
except yaml.YAMLError as exc:
return None, f"invalid declaration YAML: {exc}"
identity = declaration.get("workload_identity") or {}
if identity.get("name") != ref.get("name"):
return None, (
f"declared workload_identity.name={identity.get('name')!r}, "
f"expected {ref.get('name')!r}"
)
or {}
).get("dataclass_floor", {})
context = (declaration.get("zones") or {}).get("context", {})
return {
"source": str(source),
"data_classification": context.get("data_classification"),
"criticality": context.get("criticality"),
"maturity": context.get("maturity"),
"declared_zone": (declaration.get("zones") or {}).get("membership"),
}, None
matched, unmatched, no_path = [], [], []
def build(catalog_path: Path, estate_root: Path) -> dict[str, Any]:
entries = (yaml.safe_load(catalog_path.read_text()) or {}).get("entries", [])
managed = load_rapp_workloads(estate_root)
posture_path = catalog_path.parent.parent / "policy" / "security-posture.yaml"
floor = (yaml.safe_load(posture_path.read_text()) or {}).get("dataclass_floor", {})
resolved: list[dict[str, Any]] = []
unknown: list[dict[str, Any]] = []
not_applicable: list[dict[str, Any]] = []
for entry in entries:
lane = entry.get("id")
cands = candidate_workloads(entry.get("path_template"))
if not cands:
no_path.append({"lane": lane, "risk": entry.get("risk")})
lane = str(entry.get("id"))
ref = entry.get("workload_ref") or {}
applicability = ref.get("applicability")
if applicability == "not-applicable":
not_applicable.append({"lane": lane, "reason": ref.get("reason")})
continue
hit = next((c for c in cands if c in declared), None)
if hit is None:
unmatched.append(
{"lane": lane, "risk": entry.get("risk"), "candidates": cands}
if applicability != "applicable":
unknown.append({"lane": lane, "reason": "applicability missing or invalid"})
continue
if ref.get("unknown_reason"):
unknown.append({"lane": lane, "reason": ref["unknown_reason"]})
continue
projection: dict[str, Any] | None
error: str | None = None
if ref.get("rapp_id"):
key = (str(ref.get("rapp_id")), str(ref.get("name")))
projection = managed.get(key)
if projection is None:
error = f"Repo Manager reference does not resolve: {key[0]}/{key[1]}"
elif ref.get("deployable") and ref["deployable"] not in projection["deployables"]:
error = f"deployable {ref['deployable']!r} is not declared by {key[0]}/{key[1]}"
else:
projection, error = _resolve_direct(
ref, catalog_path=catalog_path, estate_root=estate_root
)
if error or projection is None:
unknown.append({"lane": lane, "reason": error or "reference unresolved"})
continue
decl = declared[hit]
cls = decl.get("data_classification")
matched.append(
classification = projection.get("data_classification")
resolved.append(
{
"lane": lane,
"workload": hit,
"risk": entry.get("risk"),
"data_classification": cls,
"criticality": decl.get("criticality"),
"min_maturity": floor.get(cls),
"unmapped_classification": bool(cls) and cls not in floor,
"workload_ref": ref,
"source": projection.get("source"),
"data_classification": classification,
"criticality": projection.get("criticality"),
"maturity": projection.get("maturity") or floor.get(classification),
"declared_zone": projection.get("declared_zone"),
"unmapped_classification": bool(classification) and classification not in floor,
}
)
return {
"declared_workloads": declared,
"matched": matched,
"unmatched": unmatched,
"no_path": no_path,
"dataclass_floor": floor,
"contract": "helixforge.workload-reference/v1",
"resolved": resolved,
"unknown": unknown,
"not_applicable": not_applicable,
"ok": len(resolved) + len(unknown) + len(not_applicable) == len(entries),
}
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--rapp-root", type=Path, default=Path.home())
parser.add_argument(
"--estate-root", "--rapp-root", dest="estate_root", type=Path, default=Path.home()
)
parser.add_argument("--json", action="store_true")
parser.add_argument(
"--catalog",
@ -133,40 +161,24 @@ def main() -> int:
/ "catalog.yaml",
)
args = parser.parse_args()
report = build(args.catalog, Path(os.path.expanduser(str(args.rapp_root))))
report = build(args.catalog, args.estate_root)
if args.json:
print(json.dumps(report, indent=2, sort_keys=True))
return 0
return 0 if report["ok"] else 1
print("lane -> workload join\n")
print(f" declared workloads (rapp-*): {len(report['declared_workloads'])}")
print(f" lanes matched to a workload: {len(report['matched'])}")
print(f" lanes unmatched: {len(report['unmatched'])}")
print(f" lanes with no usable path: {len(report['no_path'])}\n")
if report["matched"]:
print("MATCHED")
for m in report["matched"]:
flag = " <-- classification unmapped by dataclass_floor" if m[
"unmapped_classification"
] else ""
print(
f" {m['lane']:34} -> {str(m['workload']):16} "
f"{str(m['data_classification']):13} crit={str(m['criticality']):9} "
f"min={str(m['min_maturity']):4} risk={m['risk']}{flag}"
)
if report["unmatched"]:
print("\nUNMATCHED — a lane exists for something no rapp declares")
for u in report["unmatched"]:
print(
f" {u['lane']:34} risk={str(u['risk']):9} "
f"candidates={', '.join(u['candidates'])}"
)
if report["no_path"]:
print("\nNO USABLE PATH — not a KV lane, or a pattern rather than an address")
print(" " + ", ".join(n["lane"] for n in report["no_path"]))
return 0
print("explicit lane -> workload resolution\n")
print(f" resolved: {len(report['resolved'])}")
print(f" unknown: {len(report['unknown'])}")
print(f" not-applicable: {len(report['not_applicable'])}\n")
for row in report["resolved"]:
ref = row["workload_ref"]
prefix = f"{ref.get('rapp_id')}/" if ref.get("rapp_id") else ""
print(f"RESOLVED {row['lane']:34} -> {prefix}{ref.get('name')}")
for row in report["unknown"]:
print(f"UNKNOWN {row['lane']:34} {row['reason']}")
for row in report["not_applicable"]:
print(f"NOT-APPLICABLE {row['lane']:34} {row['reason']}")
return 0 if report["ok"] else 1
if __name__ == "__main__":