provisioning-code/.ncl-cache/85bca1d573ca32bdf078d75d709999be14d9d72dcc7930e2dcaeb82289234ea1.json

149 lines
6.4 KiB
JSON

{
"id": "validate-playbooks",
"postconditions": [
"All playbook directories contain playbook.ncl",
"All playbook.ncl files conform to PlaybookDef schema",
"All step scripts exist relative to their playbook directory",
"All playbooks with rollback_strategy = automatic have rollback.nu",
"All .nu files pass nu --ide-check 50 with zero diagnostics",
"Dry-run tests (where present) executed and results reported"
],
"preconditions": [
"{provisioning_root}/catalog/playbooks/ exists",
"nickel is available in PATH",
"nu is available in PATH",
"jq is available in PATH",
"{schemas_root}/playbook.ncl is accessible"
],
"steps": [
{
"action": "list_playbook_dirs",
"actor": "Agent",
"cmd": "find {provisioning_root}/catalog/playbooks -maxdepth 1 -type d ! -name playbooks | sort",
"depends_on": [],
"id": "discover_playbooks",
"note": "Enumerate all playbook directories. Each must contain playbook.ncl at minimum.",
"on_error": {
"strategy": "Stop"
}
},
{
"action": "verify_manifest_present",
"actor": "Agent",
"cmd": "find {provisioning_root}/catalog/playbooks -maxdepth 2 -name 'playbook.ncl' | while read f; do echo \"OK: $f\"; done; find {provisioning_root}/catalog/playbooks -maxdepth 1 -mindepth 1 -type d | while read d; do test -f \"$d/playbook.ncl\" || echo \"MISSING playbook.ncl in $d\"; done",
"depends_on": [
{
"kind": "OnSuccess",
"step": "discover_playbooks"
}
],
"id": "check_playbook_ncl_exists",
"note": "Every playbook directory must contain playbook.ncl. Missing manifests are reported but do not stop subsequent checks on other playbooks.",
"on_error": {
"strategy": "Continue"
}
},
{
"action": "nickel_export_each_playbook",
"actor": "Agent",
"cmd": "find {provisioning_root}/catalog/playbooks -maxdepth 2 -name 'playbook.ncl' | while read f; do name=$(basename $(dirname $f)); echo \"--- $name\"; echo \"let pb = import \\\"{schemas_root}/playbook.ncl\\\" in (import \\\"$f\\\") | pb.PlaybookDef\" | nickel export /dev/stdin 2>&1 | tail -1 && echo \"$name: schema OK\" || echo \"$name: SCHEMA FAIL\"; done",
"depends_on": [
{
"kind": "Always",
"step": "check_playbook_ncl_exists"
}
],
"id": "validate_schema_conformance",
"note": "Apply PlaybookDef contract to each playbook.ncl. Schema failure means the playbook runner will refuse to execute this playbook.",
"on_error": {
"strategy": "Continue"
}
},
{
"action": "verify_step_scripts",
"actor": "Agent",
"cmd": "find {provisioning_root}/catalog/playbooks -maxdepth 2 -name 'playbook.ncl' | while read f; do dir=$(dirname $f); name=$(basename $dir); nickel export \"$f\" 2>/dev/null | jq -r '.steps[].script' | while read script; do test -f \"$dir/$script\" && echo \"OK: $name/$script\" || echo \"MISSING: $name/$script\"; done; done",
"depends_on": [
{
"kind": "Always",
"step": "validate_schema_conformance"
}
],
"id": "check_step_scripts_exist",
"note": "Every step script declared in playbook.ncl must exist as a file relative to the playbook directory.",
"on_error": {
"strategy": "Continue"
}
},
{
"action": "verify_rollback_nu_when_automatic",
"actor": "Agent",
"cmd": "find {provisioning_root}/catalog/playbooks -maxdepth 2 -name 'playbook.ncl' | while read f; do dir=$(dirname $f); name=$(basename $dir); strategy=$(nickel export \"$f\" 2>/dev/null | jq -r '.rollback_strategy // \"none\"'); if [ \"$strategy\" = \"automatic\" ]; then test -f \"$dir/rollback.nu\" && echo \"OK: $name/rollback.nu\" || echo \"MISSING rollback.nu for automatic rollback: $name\"; fi; done",
"depends_on": [
{
"kind": "Always",
"step": "validate_schema_conformance"
}
],
"id": "check_rollback_script",
"note": "When rollback_strategy = 'automatic, rollback.nu MUST exist. validate-playbooks reflection mode enforces this before any execution.",
"on_error": {
"strategy": "Continue"
}
},
{
"action": "nu_ide_check_all_playbook_scripts",
"actor": "Agent",
"cmd": "find {provisioning_root}/catalog/playbooks -name '*.nu' | while read f; do result=$(nu --ide-check 50 \"$f\" 2>&1); [ -z \"$result\" ] && echo \"OK: $f\" || echo \"FAIL: $f\\n$result\"; done",
"depends_on": [
{
"kind": "Always",
"step": "check_step_scripts_exist"
},
{
"kind": "Always",
"step": "check_rollback_script"
}
],
"id": "nushell_ide_check_scripts",
"note": "All .nu files in playbook directories must pass nu --ide-check 50 with zero diagnostics. This catches Nushell syntax errors and undefined variable references before runtime.",
"on_error": {
"strategy": "Continue"
}
},
{
"action": "execute_dry_run_tests",
"actor": "Agent",
"cmd": "find {provisioning_root}/catalog/playbooks -path '*/tests/dry_run.nu' | while read f; do name=$(basename $(dirname $(dirname $f))); echo \"--- dry_run: $name\"; nu \"$f\" 2>&1 && echo \"$name dry_run: PASS\" || echo \"$name dry_run: FAIL\"; done",
"depends_on": [
{
"kind": "Always",
"step": "nushell_ide_check_scripts"
}
],
"id": "run_dry_run_tests",
"note": "When tests/dry_run.nu is present, execute it as a smoke test. Failures are reported but do not fail the overall validation — the dry_run.nu is advisory, not mandatory.",
"on_error": {
"strategy": "Continue"
}
},
{
"action": "emit_playbook_validation_report",
"actor": "Agent",
"cmd": "echo '=== playbook validation complete ===' && echo 'All MISSING and FAIL entries above must be resolved before playbooks can be executed'",
"depends_on": [
{
"kind": "Always",
"step": "run_dry_run_tests"
}
],
"id": "summary_report",
"note": "Final summary. MISSING and FAIL lines are blocking. dry_run FAIL lines are advisory.",
"on_error": {
"strategy": "Stop"
}
}
],
"strategy": "Override",
"trigger": "Validate all playbooks: schema conformance, script existence, and Nushell ide-check"
}