{ "id": "validate-keeper-policy", "postconditions": [ "No policy.ncl files contain Nickel function definitions", "All policy.ncl files export valid JSON conforming to PolicyDef schema", "All policy.ncl files declare version = 1", "Validation report produced listing pass/fail per workspace" ], "preconditions": [ "{policy_repos_root} exists and contains at least one policy-/ directory", "nickel is available in PATH", "schemas/lib/keeper_policy.ncl is accessible at {schemas_root}/keeper_policy.ncl", "Each policy-/ directory contains policy.ncl" ], "steps": [ { "action": "list_policy_repos", "actor": "Agent", "cmd": "find {policy_repos_root} -maxdepth 1 -type d -name 'policy-*' | sort", "depends_on": [], "id": "discover_policy_repos", "note": "Enumerate all policy- repos present in the configured clones root. Hard stop — if no repos are found the subsequent steps have nothing to validate.", "on_error": { "strategy": "Stop" } }, { "action": "grep_forbidden_patterns", "actor": "Agent", "cmd": "find {policy_repos_root} -name 'policy.ncl' | xargs grep -lE 'fun |let [a-z_]+ = fun ' 2>/dev/null && echo 'VIOLATION: function definitions found in policy files' || echo 'OK: no function definitions'", "depends_on": [ { "kind": "OnSuccess", "step": "discover_policy_repos" } ], "id": "check_declarative_only", "note": "ADR-038 constraint policy-files-are-declarative-only: policy.ncl files must contain only data conforming to PolicyDef schema. Any Nickel function definition (fun or let x = fun) is a hard violation.", "on_error": { "strategy": "Stop" } }, { "action": "nickel_export_each_policy", "actor": "Agent", "cmd": "find {policy_repos_root} -name 'policy.ncl' | while read f; do ws=$(basename $(dirname $f)); echo \"--- $ws\"; echo \"let kp = import \\\"{schemas_root}/keeper_policy.ncl\\\" in (import \\\"$f\\\") | kp.PolicyDef\" | nickel export /dev/stdin 2>&1 && echo \"$ws: OK\" || echo \"$ws: SCHEMA FAIL\"; done", "depends_on": [ { "kind": "OnSuccess", "step": "check_declarative_only" } ], "id": "validate_schema_conformance", "note": "Apply keeper_policy.ncl PolicyDef contract to each policy.ncl. A policy that fails to export against the schema is invalid and will be rejected by keeper-daemon at startup.", "on_error": { "strategy": "Continue" } }, { "action": "verify_schema_version", "actor": "Agent", "cmd": "find {policy_repos_root} -name 'policy.ncl' | while read f; do ws=$(basename $(dirname $f)); v=$(nickel export \"$f\" 2>/dev/null | jq -r '.version // \"MISSING\"'); echo \"$ws version: $v\"; [ \"$v\" = \"1\" ] || echo \"$ws: WARNING — expected version=1, got $v\"; done", "depends_on": [ { "kind": "Always", "step": "validate_schema_conformance" } ], "id": "check_version_field", "note": "Verify each policy file declares schema_version = 1. Version mismatch means keeper-daemon will reject the policy file at startup (fail-fast per ADR-038).", "on_error": { "strategy": "Continue" } }, { "action": "emit_validation_report", "actor": "Agent", "cmd": "echo '=== keeper policy validation complete ===' && echo 'All violations above must be resolved before keeper-daemon will start'", "depends_on": [ { "kind": "Always", "step": "check_version_field" } ], "id": "summary_report", "note": "Final report: any VIOLATION or SCHEMA FAIL lines above indicate files that keeper-daemon will refuse to load.", "on_error": { "strategy": "Stop" } } ], "strategy": "Override", "trigger": "Validate all workspace keeper policy files: schema conformance + declarative-only enforcement" }