feat: harden zone reference contracts

Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a0291a-1e87-7151-9934-fcbfe3f65eb1
This commit is contained in:
tegwick 2026-08-23 12:27:13 +02:00
parent bed5c3b53a
commit be29c28100
19 changed files with 1712 additions and 454 deletions

View file

@ -0,0 +1,125 @@
#!/usr/bin/env python3
"""Verify a local canon-lineage record against an authoritative checkout."""
from __future__ import annotations
import argparse
import hashlib
import json
import subprocess
import sys
from pathlib import Path
from typing import Any, Mapping
import yaml
LINEAGE_STANDARD = "canon-lineage_v0.1"
class LineageError(ValueError):
"""The lineage manifest or canonical artifact is inconsistent."""
def _required(mapping: Mapping[str, Any], key: str) -> Any:
value = mapping.get(key)
if value is None or value == "":
raise LineageError(f"lineage.{key} is required")
return value
def _sha256(content: bytes) -> str:
return hashlib.sha256(content).hexdigest()
def _frontmatter(content: bytes) -> dict[str, Any]:
text = content.decode()
if not text.startswith("---\n") or "\n---\n" not in text[4:]:
raise LineageError("canonical artifact requires YAML frontmatter")
raw = text.split("\n---\n", 1)[0][4:]
value = yaml.safe_load(raw) or {}
if not isinstance(value, dict):
raise LineageError("canonical frontmatter must be a mapping")
return value
def check_lineage(
manifest: Any,
canon_root: Path,
*,
verify_revision: bool = True,
) -> dict[str, Any]:
if not isinstance(manifest, Mapping):
raise LineageError("lineage manifest must be a mapping")
if manifest.get("standard") != LINEAGE_STANDARD:
raise LineageError(f"lineage.standard must be {LINEAGE_STANDARD}")
relative = Path(str(_required(manifest, "canonical_path")))
if relative.is_absolute() or ".." in relative.parts:
raise LineageError("canonical_path must stay below canon_root")
revision = str(_required(manifest, "canonical_revision"))
expected_hash = str(_required(manifest, "canonical_sha256"))
expected_status = str(_required(manifest, "canonical_status"))
canonical_path = canon_root / relative
try:
content = canonical_path.read_bytes()
except OSError as exc:
raise LineageError(f"cannot read canonical artifact: {exc}") from exc
actual_hash = _sha256(content)
frontmatter = _frontmatter(content)
errors: list[str] = []
if actual_hash != expected_hash:
errors.append(
f"canonical content hash changed: expected {expected_hash}, got {actual_hash}"
)
if str(frontmatter.get("status")) != expected_status:
errors.append(
"canonical lifecycle changed: "
f"expected {expected_status}, got {frontmatter.get('status')}"
)
revision_hash = None
if verify_revision:
completed = subprocess.run(
["git", "-C", str(canon_root), "show", f"{revision}:{relative.as_posix()}"],
check=False,
capture_output=True,
)
if completed.returncode != 0:
errors.append(
f"cannot read canonical artifact at revision {revision}: "
+ completed.stderr.decode().strip()
)
else:
revision_hash = _sha256(completed.stdout)
if revision_hash != expected_hash:
errors.append(
f"revision {revision} content does not match canonical_sha256"
)
return {
"ok": not errors,
"artifact": manifest.get("artifact"),
"publication_owner": manifest.get("publication_owner"),
"canonical_path": relative.as_posix(),
"canonical_revision": revision,
"canonical_status": frontmatter.get("status"),
"canonical_sha256": actual_hash,
"revision_sha256": revision_hash,
"errors": errors,
}
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--manifest", required=True, type=Path)
parser.add_argument("--canon-root", required=True, type=Path)
args = parser.parse_args()
try:
manifest = yaml.safe_load(args.manifest.read_text()) or {}
result = check_lineage(manifest, args.canon_root)
except (OSError, yaml.YAMLError, LineageError) as exc:
result = {"ok": False, "errors": [str(exc)]}
print(json.dumps(result, indent=2, sort_keys=True))
return 0 if result["ok"] else 1
if __name__ == "__main__":
sys.exit(main())

View file

@ -0,0 +1,358 @@
#!/usr/bin/env python3
"""Validate security-zone exception records at an explicit instant."""
from __future__ import annotations
import argparse
import json
import sys
from datetime import datetime, timezone
from pathlib import Path
from typing import Any, Mapping
import yaml
try:
from tools.resolve_zones import ZONE_FLOOR
except ModuleNotFoundError: # direct ``python tools/...`` execution
from resolve_zones import ZONE_FLOOR
POLICY_STANDARD = "security-zone-exception-policy_v0.1"
RECORD_STANDARD = "security-zone-exceptions_v0.1"
class ExceptionConformanceError(ValueError):
"""The exception input or policy is structurally unusable."""
def _required(mapping: Mapping[str, Any], key: str, where: str) -> Any:
value = mapping.get(key)
if value is None or value == "" or value == []:
raise ExceptionConformanceError(f"{where}.{key} is required")
return value
def _instant(value: Any, where: str) -> datetime:
text = str(value)
if text.endswith("Z"):
text = text[:-1] + "+00:00"
try:
parsed = datetime.fromisoformat(text)
except ValueError as exc:
raise ExceptionConformanceError(f"{where} must be an ISO timestamp") from exc
if parsed.tzinfo is None:
raise ExceptionConformanceError(f"{where} must include a timezone")
return parsed.astimezone(timezone.utc)
def _policy(policy: Any) -> dict[str, Any]:
if not isinstance(policy, Mapping):
raise ExceptionConformanceError("exception policy must be a mapping")
if policy.get("standard") != POLICY_STANDARD:
raise ExceptionConformanceError(
f"exception policy standard must be {POLICY_STANDARD}"
)
policy_id = str(_required(policy, "policy_id", "policy"))
version = str(_required(policy, "version", "policy"))
controls = _required(policy, "controls", "policy")
if not isinstance(controls, Mapping) or not controls:
raise ExceptionConformanceError("policy.controls must be a non-empty mapping")
normalized: dict[str, Any] = {}
for control_id, control in controls.items():
where = f"policy.controls.{control_id}"
if not isinstance(control, Mapping):
raise ExceptionConformanceError(f"{where} must be a mapping")
if "/" not in str(control_id):
raise ExceptionConformanceError(f"{where} id must be owner-qualified")
authorities = _required(control, "grant_authorities", where)
if not isinstance(authorities, list) or not all(
isinstance(authority, str) and authority for authority in authorities
):
raise ExceptionConformanceError(
f"{where}.grant_authorities must be a non-empty string list"
)
maximum = _required(control, "maximum_duration_seconds", where)
if not isinstance(maximum, int) or maximum <= 0:
raise ExceptionConformanceError(
f"{where}.maximum_duration_seconds must be a positive integer"
)
normalized[str(control_id)] = {
"grant_authorities": set(authorities),
"maximum_duration_seconds": maximum,
}
return {
"policy_id": policy_id,
"version": version,
"policy_ref": f"{policy_id}@{version}",
"controls": normalized,
}
def _validate_relaxation(record: Mapping[str, Any], errors: list[str]) -> None:
base = record.get("base")
relaxation = record.get("relaxation")
if not isinstance(base, Mapping) or not isinstance(relaxation, Mapping):
errors.append("base and relaxation must be mappings")
return
changed = False
if "stance" in relaxation:
base_stance = base.get("stance")
relaxed_stance = relaxation.get("stance")
allowed = {
"enforced": {"advisory", "exempt"},
"advisory": {"exempt"},
}
if relaxed_stance not in allowed.get(base_stance, set()):
errors.append("relaxation.stance must strictly relax the base stance")
else:
changed = True
if "failure_mode" in relaxation:
if base.get("failure_mode") != "fail_closed" or relaxation.get(
"failure_mode"
) != "fail_open":
errors.append(
"failure-mode relaxation must change fail_closed to fail_open"
)
else:
changed = True
if not changed and not errors:
errors.append("relaxation must change stance or failure_mode")
def _record_result(
record: Any,
policy: Mapping[str, Any],
at: datetime,
) -> dict[str, Any]:
errors: list[str] = []
if not isinstance(record, Mapping):
return {
"exception_id": None,
"valid": False,
"active": False,
"state": "invalid",
"errors": ["exception record must be a mapping"],
}
exception_id = record.get("exception_id")
for key in (
"exception_id",
"security_zone",
"control",
"workloads",
"base",
"relaxation",
"justification",
"requested_by",
"granted_by",
"issued_at",
"not_before",
"not_after",
"maximum_duration_policy",
"change_ref",
):
value = record.get(key)
if value is None or value == "" or value == () or value == []:
errors.append(f"{key} is required")
zone = record.get("security_zone")
if zone not in ZONE_FLOOR:
errors.append("security_zone must be a named zone")
control_id = record.get("control")
control_policy = policy["controls"].get(control_id)
if control_policy is None:
errors.append("control is absent from the owner exception policy")
workloads = record.get("workloads")
if not isinstance(workloads, list) or not workloads:
errors.append("workloads must be a non-empty list")
workloads = []
elif any(
not isinstance(workload, str)
or not workload
or workload in {"*", "unknown"}
for workload in workloads
):
errors.append("workloads must contain exact resolved workload ids")
elif len(set(workloads)) != len(workloads):
errors.append("workloads must not contain duplicates")
_validate_relaxation(record, errors)
issued = before = after = None
for key in ("issued_at", "not_before", "not_after"):
try:
parsed = _instant(record.get(key), key)
if key == "issued_at":
issued = parsed
elif key == "not_before":
before = parsed
else:
after = parsed
except ExceptionConformanceError as exc:
errors.append(str(exc))
if issued and before and after:
if issued > before:
errors.append("issued_at must be at or before not_before")
if before >= after:
errors.append("not_before must be before not_after")
if control_policy and (after - before).total_seconds() > control_policy[
"maximum_duration_seconds"
]:
errors.append("exception duration exceeds owner maximum")
if control_policy and record.get("granted_by") not in control_policy[
"grant_authorities"
]:
errors.append("granted_by is not a designated control authority")
if record.get("maximum_duration_policy") != policy["policy_ref"]:
errors.append("maximum_duration_policy does not match evaluated owner policy")
durable = record.get("durable_authorities") or []
if not isinstance(durable, list):
errors.append("durable_authorities must be a list")
else:
for index, authority in enumerate(durable):
if not isinstance(authority, Mapping) or not authority.get("id"):
errors.append(f"durable_authorities[{index}] requires id and not_after")
continue
try:
authority_after = _instant(
authority.get("not_after"),
f"durable_authorities[{index}].not_after",
)
except ExceptionConformanceError as exc:
errors.append(str(exc))
continue
if after and authority_after > after:
errors.append(
f"durable_authorities[{index}] outlives the exception"
)
valid = not errors
active = bool(valid and before and after and before <= at < after)
if not valid:
state = "invalid"
elif at < before:
state = "future"
elif at >= after:
state = "expired"
else:
state = "active"
return {
"exception_id": exception_id,
"control": control_id,
"workloads": sorted(workloads),
"not_before": before.isoformat() if before else None,
"not_after": after.isoformat() if after else None,
"valid": valid,
"active": active,
"state": state,
"errors": errors,
}
def _overlap(left: Mapping[str, Any], right: Mapping[str, Any]) -> bool:
if left.get("control") != right.get("control"):
return False
if not set(left.get("workloads", [])).intersection(right.get("workloads", [])):
return False
if not all((left.get("not_before"), left.get("not_after"), right.get("not_before"), right.get("not_after"))):
return False
left_before = _instant(left["not_before"], "left.not_before")
left_after = _instant(left["not_after"], "left.not_after")
right_before = _instant(right["not_before"], "right.not_before")
right_after = _instant(right["not_after"], "right.not_after")
return max(left_before, right_before) < min(left_after, right_after)
def evaluate_exceptions(
document: Any,
policy_document: Any,
*,
at: datetime,
) -> dict[str, Any]:
policy = _policy(policy_document)
if not isinstance(document, Mapping) or document.get("standard") != RECORD_STANDARD:
raise ExceptionConformanceError(
f"exception document standard must be {RECORD_STANDARD}"
)
records = document.get("exceptions")
if not isinstance(records, list):
raise ExceptionConformanceError("exceptions must be a list")
results = [_record_result(record, policy, at) for record in records]
ids: dict[str, list[int]] = {}
for index, result in enumerate(results):
if result["exception_id"]:
ids.setdefault(str(result["exception_id"]), []).append(index)
for exception_id, indexes in ids.items():
if len(indexes) > 1:
for index in indexes:
results[index]["errors"].append(
f"duplicate exception_id {exception_id}"
)
results[index].update(valid=False, active=False, state="invalid")
source_by_id = {
str(record.get("exception_id")): record
for record in records
if isinstance(record, Mapping) and record.get("exception_id")
}
for index, record in enumerate(records):
if not isinstance(record, Mapping) or not record.get("renews"):
continue
renewed = str(record["renews"])
if renewed == str(record.get("exception_id")) or renewed not in source_by_id:
results[index]["errors"].append(
"renews must name a different existing exception id"
)
results[index].update(valid=False, active=False, state="invalid")
for left in range(len(records)):
for right in range(left + 1, len(records)):
if not results[left]["valid"] or not results[right]["valid"]:
continue
try:
overlapping = _overlap(records[left], records[right])
except ExceptionConformanceError:
overlapping = False
if overlapping:
for index in (left, right):
results[index]["errors"].append(
f"overlaps exception {results[right if index == left else left]['exception_id']}"
)
results[index].update(valid=False, active=False, state="invalid")
return {
"ok": all(result["valid"] for result in results),
"standard": RECORD_STANDARD,
"evaluated_at": at.astimezone(timezone.utc).isoformat(),
"policy": {"id": policy["policy_id"], "version": policy["version"]},
"results": sorted(results, key=lambda result: str(result["exception_id"])),
"active_exception_ids": sorted(
str(result["exception_id"])
for result in results
if result["active"]
),
}
def _load(path: Path) -> dict[str, Any]:
value = yaml.safe_load(path.read_text()) or {}
if not isinstance(value, dict):
raise ExceptionConformanceError(f"{path} must contain a mapping")
return value
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("exceptions", type=Path)
parser.add_argument("--policy", required=True, type=Path)
parser.add_argument("--at", required=True)
args = parser.parse_args()
try:
result = evaluate_exceptions(
_load(args.exceptions),
_load(args.policy),
at=_instant(args.at, "--at"),
)
except (OSError, yaml.YAMLError, ExceptionConformanceError) as exc:
result = {"ok": False, "errors": [str(exc)], "results": []}
print(json.dumps(result, indent=2, sort_keys=True))
return 0 if result["ok"] else 1
if __name__ == "__main__":
sys.exit(main())

View file

@ -9,11 +9,14 @@ import json
import sys
from datetime import date
from pathlib import Path
from typing import Any, Iterable
from typing import Any, Iterable, Mapping
import yaml
STANDARD = "security-zones_v0.1"
INPUT_STANDARD = "zone-resolver-input_v0.1"
PROFILE_STANDARD = "security-zone-control-profile_v0.1"
MATURITY_RANK = {"M0": 0, "M1": 1, "M2": 2, "M3": 3}
CRITICALITY_FLOOR = {"low": 0, "medium": 1, "high": 2, "critical": 3}
DATACLASS_FLOOR = {
@ -29,52 +32,49 @@ ZONE_FLOOR = {
"z2-continuity": 2,
"z3-critical": 3,
}
CONTROL_PROFILE = {
"z0-experimental": {
"flex-auth/pre-sign": ("advisory", "fail_open"),
"ops-warden/agent-high-risk-read": ("enforced", "fail_closed"),
"ops-warden/plan-zone-rule": ("advisory", "fail_closed"),
},
"z1-operational": {
"flex-auth/pre-sign": ("advisory", "fail_open"),
"ops-warden/agent-high-risk-read": ("enforced", "fail_closed"),
"ops-warden/plan-zone-rule": ("advisory", "fail_closed"),
},
"z2-protected": {
"flex-auth/pre-sign": ("enforced", "fail_open"),
"ops-warden/agent-high-risk-read": ("enforced", "fail_closed"),
"ops-warden/plan-zone-rule": ("enforced", "fail_closed"),
},
"z2-continuity": {
"flex-auth/pre-sign": ("enforced", "fail_open"),
"ops-warden/agent-high-risk-read": ("enforced", "fail_closed"),
"ops-warden/plan-zone-rule": ("enforced", "fail_closed"),
},
"z3-critical": {
"flex-auth/pre-sign": ("enforced", "fail_closed"),
"ops-warden/agent-high-risk-read": ("enforced", "fail_closed"),
"ops-warden/plan-zone-rule": ("enforced", "fail_closed"),
},
"unknown": {
"flex-auth/pre-sign": ("advisory", "fail_open"),
"ops-warden/agent-high-risk-read": ("enforced", "fail_closed"),
"ops-warden/plan-zone-rule": ("enforced", "fail_closed"),
},
}
PROFILE_ZONES = frozenset({*ZONE_FLOOR, "unknown"})
class DeclarationError(ValueError):
"""A declaration violates the security-zones_v0.1 contract."""
def _required(mapping: dict[str, Any], key: str, where: str) -> Any:
class ProfileError(ValueError):
"""A control profile lacks authoritative, total provenance."""
def _required(mapping: Mapping[str, Any], key: str, where: str) -> Any:
value = mapping.get(key)
if value is None or value == "" or value == []:
raise DeclarationError(f"{where}.{key} is required")
return value
def _canonical(value: Any) -> Any:
"""Return a stable, mapping- and list-order-independent JSON value."""
if isinstance(value, Mapping):
return {str(key): _canonical(value[key]) for key in sorted(value)}
if isinstance(value, list):
items = [_canonical(item) for item in value]
return sorted(
items,
key=lambda item: json.dumps(
item, sort_keys=True, separators=(",", ":"), default=str
),
)
if isinstance(value, date):
return value.isoformat()
return value
def _digest(value: Any) -> str:
encoded = json.dumps(
_canonical(value), sort_keys=True, separators=(",", ":"), default=str
).encode()
return "sha256:" + hashlib.sha256(encoded).hexdigest()
def _parse_date(value: Any, where: str) -> date:
if isinstance(value, date):
return value
@ -84,7 +84,7 @@ def _parse_date(value: Any, where: str) -> date:
raise DeclarationError(f"{where} must be an ISO date") from exc
def _services(document: dict[str, Any]) -> Iterable[dict[str, Any]]:
def _services(document: Mapping[str, Any]) -> Iterable[dict[str, Any]]:
services = document.get("services")
if services is not None:
if not isinstance(services, list) or not services:
@ -95,7 +95,7 @@ def _services(document: dict[str, Any]) -> Iterable[dict[str, Any]]:
)
yield from services
return
yield document
yield dict(document)
def _validate_identity(service: str, identity: Any) -> dict[str, Any]:
@ -111,10 +111,11 @@ def _validate_identity(service: str, identity: Any) -> dict[str, Any]:
bindings = _required(
identity, "identity_bindings", f"{service}.workload_identity"
)
if not isinstance(bindings, list):
if not isinstance(bindings, list) or not bindings:
raise DeclarationError(
f"{service}.workload_identity.identity_bindings must be a list"
f"{service}.workload_identity.identity_bindings must be a non-empty list"
)
seen: set[tuple[str, str, str, str]] = set()
for index, binding in enumerate(bindings):
where = f"{service}.workload_identity.identity_bindings[{index}]"
if not isinstance(binding, dict):
@ -123,15 +124,97 @@ def _validate_identity(service: str, identity: Any) -> dict[str, Any]:
_required(binding, key, where)
if binding["principal_type"] not in {"service", "agent"}:
raise DeclarationError(f"{where}.principal_type must be service or agent")
identity_key = tuple(
str(binding[key])
for key in ("scheme", "authority", "subject", "principal_type")
)
if identity_key in seen:
raise DeclarationError(f"{where} duplicates an identity binding")
seen.add(identity_key)
return identity
def _admission(service: str, zones: dict[str, Any]) -> tuple[str, str]:
def _binding_refs(identity: Mapping[str, Any] | None) -> list[str]:
if not identity:
return []
return sorted(
"/".join(
str(binding[key]) for key in ("scheme", "authority", "subject")
)
for binding in identity["identity_bindings"]
)
def _validate_workload_ref(
service: str,
workload_ref: Any,
identity: Mapping[str, Any] | None,
) -> dict[str, Any]:
if workload_ref is None:
if identity is None:
return {
"applicability": "applicable",
"rapp_id": None,
"name": None,
"deployable": None,
}
return {
"applicability": "applicable",
"rapp_id": None,
"name": str(identity["name"]),
"deployable": None,
}
if not isinstance(workload_ref, Mapping):
raise DeclarationError(f"{service}.workload_ref must be a mapping")
applicability = str(
_required(workload_ref, "applicability", f"{service}.workload_ref")
)
if applicability not in {"applicable", "not-applicable"}:
raise DeclarationError(
f"{service}.workload_ref.applicability must be applicable or not-applicable"
)
rapp_id = workload_ref.get("rapp_id") or None
name = workload_ref.get("name") or None
deployable = workload_ref.get("deployable") or None
if applicability == "not-applicable":
if any(value is not None for value in (rapp_id, name, deployable)):
raise DeclarationError(
f"{service}.workload_ref not-applicable must not carry a workload tuple"
)
if identity is not None:
raise DeclarationError(
f"{service} cannot be both an authoritative workload and not-applicable"
)
return {
"applicability": applicability,
"rapp_id": None,
"name": None,
"deployable": None,
}
if deployable is not None and rapp_id is None:
raise DeclarationError(
f"{service}.workload_ref.deployable requires rapp_id"
)
if name is not None:
name = str(name)
if identity is not None and name is not None and name != identity["name"]:
raise DeclarationError(
f"{service}.workload_ref.name must equal workload_identity.name"
)
return {
"applicability": applicability,
"rapp_id": str(rapp_id) if rapp_id is not None else None,
"name": name,
"deployable": str(deployable) if deployable is not None else None,
}
def _admission(service: str, zones: Mapping[str, Any]) -> tuple[str, str]:
membership = str(_required(zones, "membership", f"{service}.zones"))
if membership not in ZONE_FLOOR:
raise DeclarationError(f"{service}.zones.membership is unknown: {membership!r}")
context = _required(zones, "context", f"{service}.zones")
if not isinstance(context, dict):
if not isinstance(context, Mapping):
raise DeclarationError(f"{service}.zones.context must be a mapping")
maturity = str(_required(context, "maturity", f"{service}.zones.context"))
criticality = str(
@ -147,11 +230,7 @@ def _admission(service: str, zones: dict[str, Any]) -> tuple[str, str]:
if dataclass == "public":
return "unknown", "public_data_classification_floor_unresolved"
if dataclass == "n/a":
_required(
context,
"data_classification_reason",
f"{service}.zones.context",
)
_required(context, "data_classification_reason", f"{service}.zones.context")
data_floor = 0
elif dataclass in DATACLASS_FLOOR:
data_floor = DATACLASS_FLOOR[dataclass]
@ -169,7 +248,7 @@ def _admission(service: str, zones: dict[str, Any]) -> tuple[str, str]:
supported = {
str(fact)
for item in zones["evidence"]
if isinstance(item, dict)
if isinstance(item, Mapping)
for fact in item.get("supports", [])
}
required = {"continuity-dependency", "recovery"}
@ -178,27 +257,91 @@ def _admission(service: str, zones: dict[str, Any]) -> tuple[str, str]:
return "satisfied", "admission_floor_met"
def resolve_service(service_entry: dict[str, Any], source: str) -> dict[str, Any]:
def _base_record(
service: str,
source: str,
source_revision: str | None,
workload_ref: Mapping[str, Any],
identity: Mapping[str, Any] | None,
) -> dict[str, Any]:
return {
"subject_id": service,
"workload_id": workload_ref.get("name"),
"workload_ref": dict(workload_ref),
"identity_bindings": _binding_refs(identity),
"declared_zone": None,
"admission": "unknown",
"admission_reason": "zone_membership_absent",
"effective_zone": "unknown",
"membership_revision": None,
"membership_revision_reason": "source_revision_absent"
if source_revision is None
else "zone_membership_absent",
"guarantees": ["non-inferred-resolution"],
"source": source,
"source_revision": source_revision,
}
def resolve_service(
service_entry: dict[str, Any],
source: str,
*,
source_revision: str | None = None,
workload_ref: Mapping[str, Any] | None = None,
) -> dict[str, Any]:
service = str(_required(service_entry, "service", source))
identity_value = service_entry.get("workload_identity")
identity = (
_validate_identity(service, identity_value)
if identity_value is not None
else None
)
reference = _validate_workload_ref(service, workload_ref, identity)
record = _base_record(service, source, source_revision, reference, identity)
if reference["applicability"] == "not-applicable":
record.update(
{
"workload_id": None,
"admission": "not-applicable",
"admission_reason": "catalog_declared_not_applicable",
"effective_zone": None,
"membership_revision_reason": "not_applicable",
"guarantees": [
"catalog-declared-not-applicable",
"non-inferred-resolution",
],
}
)
return record
if reference["name"] is None:
record["admission_reason"] = "workload_reference_unresolved"
record["membership_revision_reason"] = "workload_reference_unresolved"
return record
record["workload_id"] = reference["name"]
if identity is None:
if service_entry.get("zones") is not None:
raise DeclarationError(
f"{service}.workload_identity is required beside zones"
)
record["admission_reason"] = "workload_identity_unresolved"
record["membership_revision_reason"] = "workload_identity_unresolved"
record["guarantees"].append("explicit-workload-reference")
return record
record["guarantees"].extend(
["authoritative-workload-identity", "explicit-workload-reference"]
)
zones = service_entry.get("zones")
if zones is None:
return {
"workload_id": service,
"declared_zone": None,
"admission": "unknown",
"admission_reason": "zone_membership_absent",
"effective_zone": "unknown",
"membership_revision": None,
"controls": _controls("unknown"),
"source": source,
}
identity = _validate_identity(service, service_entry.get("workload_identity"))
return record
if not isinstance(zones, dict):
raise DeclarationError(f"{service}.zones must be a mapping")
if zones.get("standard") != "security-zones_v0.1":
raise DeclarationError(
f"{service}.zones.standard must be security-zones_v0.1"
)
if zones.get("standard") != STANDARD:
raise DeclarationError(f"{service}.zones.standard must be {STANDARD}")
for key in (
"responsible_party",
"justification",
@ -207,8 +350,8 @@ def resolve_service(service_entry: dict[str, Any], source: str) -> dict[str, Any
"review_due",
):
_required(zones, key, f"{service}.zones")
if not isinstance(zones["evidence"], list):
raise DeclarationError(f"{service}.zones.evidence must be a list")
if not isinstance(zones["evidence"], list) or not zones["evidence"]:
raise DeclarationError(f"{service}.zones.evidence must be a non-empty list")
reviewed = _parse_date(zones["reviewed"], f"{service}.zones.reviewed")
review_due = _parse_date(zones["review_due"], f"{service}.zones.review_due")
if review_due <= reviewed:
@ -216,60 +359,405 @@ def resolve_service(service_entry: dict[str, Any], source: str) -> dict[str, Any
admission, reason = _admission(service, zones)
membership = str(zones["membership"])
effective = membership if admission == "satisfied" else "unknown"
revision_input = json.dumps(
{"workload_identity": identity, "zones": zones},
sort_keys=True,
separators=(",", ":"),
default=str,
).encode()
revision = "sha256:" + hashlib.sha256(revision_input).hexdigest()
revision = None
revision_reason = "source_revision_absent"
if source_revision:
revision = _digest(
{
"source_revision": source_revision,
"workload_ref": reference,
"workload_identity": identity,
"zones": zones,
}
)
revision_reason = "source_bound"
record.update(
{
"declared_zone": membership,
"admission": admission,
"admission_reason": reason,
"effective_zone": effective,
"membership_revision": revision,
"membership_revision_reason": revision_reason,
"guarantees": sorted(
set(
record["guarantees"]
+ ["explicit-zone-membership"]
+ (["source-revision-bound-membership"] if revision else [])
)
),
}
)
return record
def validate_control_profile(profile: Any) -> dict[str, Any]:
if not isinstance(profile, Mapping):
raise ProfileError("control profile must be a mapping")
if profile.get("standard") != PROFILE_STANDARD:
raise ProfileError(f"control profile standard must be {PROFILE_STANDARD}")
profile_id = profile.get("profile_id")
version = profile.get("version")
if not profile_id or not version:
raise ProfileError("control profile requires profile_id and version")
controls = profile.get("controls")
if not isinstance(controls, Mapping) or not controls:
raise ProfileError("control profile controls must be a non-empty mapping")
normalized: dict[str, Any] = {
"standard": PROFILE_STANDARD,
"profile_id": str(profile_id),
"version": str(version),
"controls": {},
}
for control_id in sorted(controls):
definition = controls[control_id]
where = f"controls.{control_id}"
if not isinstance(definition, Mapping):
raise ProfileError(f"{where} must be a mapping")
policy_owner = definition.get("policy_owner")
pep_owner = definition.get("pep_owner")
policy_ref = definition.get("policy_ref")
if not policy_owner or not pep_owner or not policy_ref:
raise ProfileError(
f"{where} requires policy_owner, pep_owner, and policy_ref"
)
if "/" not in str(control_id) or not str(control_id).startswith(
f"{policy_owner}/"
):
raise ProfileError(
f"{where} id must be owner-qualified by policy_owner"
)
mappings = definition.get("zones")
if not isinstance(mappings, Mapping):
raise ProfileError(f"{where}.zones must be a mapping")
supplied = set(mappings)
if supplied != PROFILE_ZONES:
missing = sorted(PROFILE_ZONES - supplied)
extra = sorted(supplied - PROFILE_ZONES)
raise ProfileError(
f"{where}.zones must be total; missing={missing}, extra={extra}"
)
normalized_zones: dict[str, dict[str, Any]] = {}
for zone in sorted(PROFILE_ZONES):
rule = mappings[zone]
if not isinstance(rule, Mapping):
raise ProfileError(f"{where}.zones.{zone} must be a mapping")
stance = rule.get("stance")
failure_mode = rule.get("failure_mode")
if stance not in {"enforced", "advisory", "exempt"}:
raise ProfileError(f"{where}.zones.{zone}.stance is invalid")
if stance == "exempt":
if failure_mode not in {None, ""}:
raise ProfileError(
f"{where}.zones.{zone} exempt must not have failure_mode"
)
failure_mode = None
elif failure_mode not in {"fail_open", "fail_closed"}:
raise ProfileError(
f"{where}.zones.{zone}.failure_mode is invalid"
)
normalized_zones[zone] = {
"stance": stance,
"failure_mode": failure_mode,
}
normalized["controls"][str(control_id)] = {
"policy_owner": str(policy_owner),
"pep_owner": str(pep_owner),
"policy_ref": str(policy_ref),
"zones": normalized_zones,
}
return normalized
def project_controls(record: dict[str, Any], profile: Mapping[str, Any]) -> None:
zone = record.get("effective_zone")
if zone not in PROFILE_ZONES:
return
record["control_profile"] = {
"id": profile["profile_id"],
"version": profile["version"],
}
record["controls"] = []
for control_id, definition in profile["controls"].items():
rule = definition["zones"][zone]
record["controls"].append(
{
"id": control_id,
"policy_owner": definition["policy_owner"],
"pep_owner": definition["pep_owner"],
"policy_ref": definition["policy_ref"],
"stance": rule["stance"],
"failure_mode": rule["failure_mode"],
}
)
def compare_snapshots(
records: Iterable[Mapping[str, Any]],
previous: Mapping[str, Any] | None,
) -> dict[str, Any]:
current_by_id = {str(record["subject_id"]): record for record in records}
previous_records = previous.get("records", []) if previous else []
previous_by_id = {
str(record["subject_id"]): record
for record in previous_records
if isinstance(record, Mapping) and record.get("subject_id")
}
current_ids = set(current_by_id)
previous_ids = set(previous_by_id)
changed: list[dict[str, Any]] = []
for subject_id in sorted(current_ids & previous_ids):
current = current_by_id[subject_id]
prior = previous_by_id[subject_id]
fields = (
"workload_ref",
"identity_bindings",
"declared_zone",
"admission",
"effective_zone",
"membership_revision",
)
if any(_canonical(current.get(key)) != _canonical(prior.get(key)) for key in fields):
changed.append(
{
"subject_id": subject_id,
"before_revision": prior.get("membership_revision"),
"after_revision": current.get("membership_revision"),
}
)
return {
"workload_id": service,
"declared_zone": membership,
"admission": admission,
"admission_reason": reason,
"effective_zone": effective,
"membership_revision": revision,
"guarantees": [
"authoritative-workload-identity",
"explicit-zone-membership",
"non-inferred-resolution",
"enforcement-time-exception-expiry",
],
"controls": _controls(effective),
"source": source,
"baseline": "previous" if previous is not None else "initial",
"added": sorted(current_ids - previous_ids),
"removed": sorted(previous_ids - current_ids),
"changed": changed,
}
def _controls(zone: str) -> list[dict[str, str]]:
return [
{"id": control, "stance": stance, "failure_mode": failure}
for control, (stance, failure) in CONTROL_PROFILE[zone].items()
]
def resolve_paths(paths: Iterable[Path]) -> dict[str, Any]:
def _resolve_documents(
sources: Iterable[tuple[Path, str | None, Mapping[str, Any]]],
*,
profile: Mapping[str, Any] | None = None,
previous: Mapping[str, Any] | None = None,
) -> dict[str, Any]:
records: list[dict[str, Any]] = []
errors: list[dict[str, str]] = []
for path in paths:
profile_errors: list[str] = []
validated_profile: Mapping[str, Any] | None = None
if profile is not None:
try:
validated_profile = validate_control_profile(profile)
except ProfileError as exc:
profile_errors.append(str(exc))
for path, source_revision, workload_refs in sources:
try:
document = yaml.safe_load(path.read_text()) or {}
if not isinstance(document, dict):
if not isinstance(document, Mapping):
raise DeclarationError("document must be a mapping")
for entry in _services(document):
if not isinstance(entry, dict):
raise DeclarationError("service entry must be a mapping")
records.append(resolve_service(entry, str(path)))
service = str(_required(entry, "service", str(path)))
record = resolve_service(
entry,
str(path),
source_revision=source_revision,
workload_ref=workload_refs.get(service),
)
if validated_profile is not None:
project_controls(record, validated_profile)
records.append(record)
except (OSError, yaml.YAMLError, DeclarationError) as exc:
errors.append({"source": str(path), "error": str(exc)})
return {"ok": not errors, "standard": "security-zones_v0.1", "records": records, "errors": errors}
records.sort(key=lambda record: str(record["subject_id"]))
duplicate_ids = sorted(
subject_id
for subject_id in {record["subject_id"] for record in records}
if sum(record["subject_id"] == subject_id for record in records) > 1
)
if duplicate_ids:
errors.append(
{
"source": "resolved-records",
"error": f"duplicate subject ids: {duplicate_ids}",
}
)
return {
"ok": not errors and not profile_errors,
"standard": STANDARD,
"records": records,
"changes": compare_snapshots(records, previous),
"errors": errors,
"profile_errors": profile_errors,
}
def resolve_paths(
paths: Iterable[Path],
*,
source_revision: str | None = None,
source_revisions: Mapping[str, str] | None = None,
workload_refs: Mapping[str, Any] | None = None,
profile: Mapping[str, Any] | None = None,
previous: Mapping[str, Any] | None = None,
) -> dict[str, Any]:
revisions = source_revisions or {}
refs = workload_refs or {}
sources = [
(
path,
revisions.get(str(path), source_revision),
refs,
)
for path in paths
]
return _resolve_documents(sources, profile=profile, previous=previous)
def resolve_manifest(
manifest: Mapping[str, Any],
*,
base_dir: Path,
profile: Mapping[str, Any] | None = None,
previous: Mapping[str, Any] | None = None,
) -> dict[str, Any]:
if manifest.get("standard") != INPUT_STANDARD:
raise DeclarationError(f"manifest.standard must be {INPUT_STANDARD}")
entries = manifest.get("sources")
if not isinstance(entries, list) or not entries:
raise DeclarationError("manifest.sources must be a non-empty list")
sources: list[tuple[Path, str | None, Mapping[str, Any]]] = []
for index, entry in enumerate(entries):
if not isinstance(entry, Mapping):
raise DeclarationError(f"manifest.sources[{index}] must be a mapping")
path_value = _required(entry, "path", f"manifest.sources[{index}]")
path = Path(str(path_value))
if not path.is_absolute():
path = base_dir / path
source_revision = entry.get("source_revision")
refs = entry.get("workload_refs") or {}
if not isinstance(refs, Mapping):
raise DeclarationError(
f"manifest.sources[{index}].workload_refs must be a mapping"
)
sources.append(
(
path,
str(source_revision) if source_revision else None,
refs,
)
)
result = _resolve_documents(sources, profile=profile, previous=previous)
subjects = manifest.get("subjects") or []
if not isinstance(subjects, list):
raise DeclarationError("manifest.subjects must be a list")
for index, subject in enumerate(subjects):
if not isinstance(subject, Mapping):
raise DeclarationError(f"manifest.subjects[{index}] must be a mapping")
subject_id = str(
_required(subject, "subject_id", f"manifest.subjects[{index}]")
)
reference = _validate_workload_ref(
subject_id, subject.get("workload_ref"), None
)
if reference["applicability"] != "not-applicable":
raise DeclarationError(
f"manifest.subjects[{index}] is only for explicit not-applicable subjects"
)
record = _base_record(
subject_id,
str(subject.get("source") or "manifest.subjects"),
str(subject["source_revision"]) if subject.get("source_revision") else None,
reference,
None,
)
record.update(
{
"workload_id": None,
"admission": "not-applicable",
"admission_reason": "catalog_declared_not_applicable",
"effective_zone": None,
"membership_revision_reason": "not_applicable",
"guarantees": [
"catalog-declared-not-applicable",
"non-inferred-resolution",
],
}
)
result["records"].append(record)
result["records"].sort(key=lambda record: str(record["subject_id"]))
subject_ids = [str(record["subject_id"]) for record in result["records"]]
duplicates = sorted(
subject_id
for subject_id in set(subject_ids)
if subject_ids.count(subject_id) > 1
)
if duplicates:
result["errors"].append(
{
"source": "manifest",
"error": f"duplicate subject ids: {duplicates}",
}
)
result["ok"] = False
result["changes"] = compare_snapshots(result["records"], previous)
return result
def _load_mapping(path: Path, where: str) -> dict[str, Any]:
try:
value = yaml.safe_load(path.read_text()) or {}
except (OSError, yaml.YAMLError) as exc:
raise DeclarationError(f"could not read {where}: {exc}") from exc
if not isinstance(value, dict):
raise DeclarationError(f"{where} must be a mapping")
return value
def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("paths", nargs="+", type=Path)
parser.add_argument("paths", nargs="*", type=Path)
parser.add_argument("--manifest", type=Path)
parser.add_argument("--source-revision")
parser.add_argument("--control-profile", type=Path)
parser.add_argument("--previous", type=Path)
args = parser.parse_args()
result = resolve_paths(args.paths)
if bool(args.manifest) == bool(args.paths):
parser.error("provide either declaration paths or --manifest")
try:
profile = (
_load_mapping(args.control_profile, "control profile")
if args.control_profile
else None
)
previous = (
_load_mapping(args.previous, "previous snapshot")
if args.previous
else None
)
if args.manifest:
manifest = _load_mapping(args.manifest, "manifest")
result = resolve_manifest(
manifest,
base_dir=args.manifest.parent,
profile=profile,
previous=previous,
)
else:
result = resolve_paths(
args.paths,
source_revision=args.source_revision,
profile=profile,
previous=previous,
)
except DeclarationError as exc:
result = {
"ok": False,
"standard": STANDARD,
"records": [],
"changes": {"baseline": "initial", "added": [], "removed": [], "changed": []},
"errors": [{"source": "input", "error": str(exc)}],
"profile_errors": [],
}
print(json.dumps(result, indent=2, sort_keys=True))
return 0 if result["ok"] else 1