Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a023c0-a0a3-7c03-b395-5a0d2757214d
238 lines
7.9 KiB
Python
238 lines
7.9 KiB
Python
"""Read-only index and resolver for authoritative rapp workload declarations."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import asdict, dataclass
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
import yaml
|
|
|
|
REFERENCE_CONTRACT = "helixforge.workload-reference/v1"
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class WorkloadRecord:
|
|
rapp_id: str
|
|
name: str
|
|
declaration_repo: str
|
|
declaration_path: str
|
|
ownership_repo: str | None
|
|
readiness_state: str | None
|
|
data_classification: str | None
|
|
criticality: str | None
|
|
deployables: tuple[str, ...]
|
|
|
|
def to_dict(self) -> dict[str, Any]:
|
|
data = asdict(self)
|
|
data["deployables"] = list(self.deployables)
|
|
data["reference"] = {"rapp_id": self.rapp_id, "name": self.name}
|
|
return data
|
|
|
|
|
|
def _error(code: str, path: Path, message: str) -> dict[str, str]:
|
|
return {"code": code, "path": str(path), "message": message}
|
|
|
|
|
|
def _package_dirs(root: Path) -> list[Path]:
|
|
root = root.expanduser().resolve()
|
|
if root.name.startswith("rapp-"):
|
|
return [root]
|
|
return sorted(path for path in root.glob("rapp-*") if path.is_dir())
|
|
|
|
|
|
def _text(value: Any) -> str | None:
|
|
if not isinstance(value, str):
|
|
return None
|
|
stripped = value.strip()
|
|
return stripped or None
|
|
|
|
|
|
def index_workloads(root: Path) -> dict[str, Any]:
|
|
"""Index authoritative declarations without inventing missing identity."""
|
|
root = root.expanduser().resolve()
|
|
records: list[WorkloadRecord] = []
|
|
errors: list[dict[str, str]] = []
|
|
|
|
for package_dir in _package_dirs(root):
|
|
declaration = package_dir / "declarations" / "rapp.yaml"
|
|
if not declaration.is_file():
|
|
errors.append(
|
|
_error(
|
|
"declaration_missing",
|
|
declaration,
|
|
"rapp repository has no authoritative declarations/rapp.yaml",
|
|
)
|
|
)
|
|
continue
|
|
try:
|
|
raw = yaml.safe_load(declaration.read_text(encoding="utf-8")) or {}
|
|
except (OSError, yaml.YAMLError) as exc:
|
|
errors.append(_error("declaration_invalid", declaration, str(exc)))
|
|
continue
|
|
if not isinstance(raw, dict):
|
|
errors.append(
|
|
_error("declaration_invalid", declaration, "declaration root must be a mapping")
|
|
)
|
|
continue
|
|
if raw.get("kind") != "managed-workload-package":
|
|
errors.append(
|
|
_error(
|
|
"declaration_kind_invalid",
|
|
declaration,
|
|
"kind must be managed-workload-package",
|
|
)
|
|
)
|
|
continue
|
|
|
|
rapp_id = _text(raw.get("rapp_id"))
|
|
identity = raw.get("workload_identity")
|
|
name = _text(identity.get("name")) if isinstance(identity, dict) else None
|
|
if not rapp_id or not name:
|
|
errors.append(
|
|
_error(
|
|
"identity_missing",
|
|
declaration,
|
|
"rapp_id and workload_identity.name are required",
|
|
)
|
|
)
|
|
continue
|
|
if rapp_id != package_dir.name:
|
|
errors.append(
|
|
_error(
|
|
"rapp_repo_mismatch",
|
|
declaration,
|
|
f"rapp_id {rapp_id!r} does not match declaration repo {package_dir.name!r}",
|
|
)
|
|
)
|
|
continue
|
|
|
|
deployables: list[str] = []
|
|
composition = raw.get("composition")
|
|
members = composition.get("member_repos", []) if isinstance(composition, dict) else []
|
|
if not isinstance(members, list):
|
|
errors.append(
|
|
_error(
|
|
"composition_invalid",
|
|
declaration,
|
|
"composition.member_repos must be a list",
|
|
)
|
|
)
|
|
continue
|
|
for member in members:
|
|
if not isinstance(member, dict) or not isinstance(member.get("deployables"), list):
|
|
errors.append(
|
|
_error(
|
|
"composition_invalid",
|
|
declaration,
|
|
"every composition member must declare a deployables list",
|
|
)
|
|
)
|
|
continue
|
|
deployables.extend(
|
|
value for value in (_text(item) for item in member["deployables"]) if value
|
|
)
|
|
if not deployables:
|
|
errors.append(
|
|
_error(
|
|
"deployables_missing",
|
|
declaration,
|
|
"the workload declaration has no running deployables",
|
|
)
|
|
)
|
|
continue
|
|
|
|
records.append(
|
|
WorkloadRecord(
|
|
rapp_id=rapp_id,
|
|
name=name,
|
|
declaration_repo=package_dir.name,
|
|
declaration_path=str(declaration.relative_to(root)),
|
|
ownership_repo=_text(raw.get("ownership_repo")),
|
|
readiness_state=_text(raw.get("readiness_state")),
|
|
data_classification=_text(raw.get("data_classification")),
|
|
criticality=_text(raw.get("criticality")),
|
|
deployables=tuple(sorted(set(deployables))),
|
|
)
|
|
)
|
|
|
|
references: dict[tuple[str, str], list[WorkloadRecord]] = {}
|
|
deployable_owners: dict[str, list[WorkloadRecord]] = {}
|
|
for record in records:
|
|
references.setdefault((record.rapp_id, record.name), []).append(record)
|
|
for deployable in record.deployables:
|
|
deployable_owners.setdefault(deployable, []).append(record)
|
|
for reference, owners in sorted(references.items()):
|
|
if len(owners) > 1:
|
|
errors.append(
|
|
_error(
|
|
"reference_duplicate",
|
|
root,
|
|
f"workload reference {reference!r} resolves to {len(owners)} declarations",
|
|
)
|
|
)
|
|
for deployable, owners in sorted(deployable_owners.items()):
|
|
if len(owners) > 1:
|
|
errors.append(
|
|
_error(
|
|
"deployable_duplicate",
|
|
root,
|
|
f"deployable {deployable!r} belongs to more than one rapp: "
|
|
+ ", ".join(sorted(owner.rapp_id for owner in owners)),
|
|
)
|
|
)
|
|
|
|
return {
|
|
"ok": not errors,
|
|
"contract": REFERENCE_CONTRACT,
|
|
"root": str(root),
|
|
"declaration_count": len(records),
|
|
"workloads": [record.to_dict() for record in sorted(records, key=lambda r: r.rapp_id)],
|
|
"errors": errors,
|
|
}
|
|
|
|
|
|
def resolve_workload(
|
|
root: Path,
|
|
*,
|
|
rapp_id: str,
|
|
name: str,
|
|
deployable: str | None = None,
|
|
) -> dict[str, Any]:
|
|
"""Resolve an explicit reference, returning unknown instead of guessing."""
|
|
index = index_workloads(root)
|
|
matches = [
|
|
record
|
|
for record in index["workloads"]
|
|
if record["rapp_id"] == rapp_id and record["name"] == name
|
|
]
|
|
reference: dict[str, str] = {"rapp_id": rapp_id, "name": name}
|
|
if deployable:
|
|
reference["deployable"] = deployable
|
|
if len(matches) != 1:
|
|
return {
|
|
"ok": True,
|
|
"contract": REFERENCE_CONTRACT,
|
|
"status": "unknown",
|
|
"reference": reference,
|
|
"reason": "not_found" if not matches else "ambiguous",
|
|
"index_errors": index["errors"],
|
|
}
|
|
workload = matches[0]
|
|
if deployable and deployable not in workload["deployables"]:
|
|
return {
|
|
"ok": True,
|
|
"contract": REFERENCE_CONTRACT,
|
|
"status": "unknown",
|
|
"reference": reference,
|
|
"reason": "deployable_not_declared",
|
|
"index_errors": index["errors"],
|
|
}
|
|
return {
|
|
"ok": True,
|
|
"contract": REFERENCE_CONTRACT,
|
|
"status": "resolved",
|
|
"reference": reference,
|
|
"workload": workload,
|
|
"index_errors": index["errors"],
|
|
}
|