feat(P4): pipeline hardening — Checkov before plan, Wiz-or-Checkov on plan (REQ-250)
Nova Slides Render / render (push) Failing after 1m1s

Two-stage policy scan per item 20:

1. Checkov on static code BEFORE terraform plan (fail-fast, quick dev
   feedback). Added to run_platform.sh Step 3c + run_codegen.sh Step 3c
   (runs on the authored TF dir before plan, using --framework terraform).

2. Runtime policy scan on the plan AFTER terraform plan: Wiz when
   configured (WIZ_API_TOKEN + WIZ_API_URL), else Checkov against the
   plan as a drop-in replacement (--framework terraform_plan). Wiz and
   Checkov are NEVER both run on the plan. Replaces the old single
   Checkov-on-main.tf step in run_platform.sh Step 5 + run_postapply.sh
   Step 5.

pipelines/contract.yml: stage list updated — 'checkov' stage replaced by
'checkov-static' (before terraform-plan) + 'runtime-policy-scan' (after
terraform-plan). 9 stages → 10 stages. Header comment updated.

adapters/wiz/wiz_adapter.py: add --plan mode CLI (fetch_and_adapt_plan)
for scanning a terraform plan; backward-compat with the positional
<wiz_issues.json> <contract-id> mode. is_configured() gates the Wiz path.

Tests: test_pipeline_contract.py (9 → 10 stages, new stage names);
test_contract_resolver.py (rename test, assert checkov-static +
runtime-policy-scan present, old 'checkov' gone). Full suite: 685 pass
+ 1 pre-existing attestation failure (NOVA_ATTESTATION_SIGNING_KEY_ID
unset, unrelated to v1.21, fails on main without these changes too).

---ci---
project: acdl
phase: 4
milestone: v1.21
status: execute
phase_role: execution
---/ci---
This commit is contained in:
Jon Chery
2026-08-11 14:10:42 +00:00
parent 301aa2c8d8
commit 85c500e45a
7 changed files with 150 additions and 40 deletions
+5 -2
View File
@@ -173,16 +173,19 @@ class TestDeployPipelineContract:
contract = yaml.safe_load(fh)
jsonschema.validate(contract, schema)
def test_deploy_pipeline_has_six_stages(self):
def test_deploy_pipeline_has_required_stages(self):
with open(ROOT / "pipelines/contract.yml") as fh:
contract = yaml.safe_load(fh)
stage_names = [s["name"] for s in contract["stages"]]
assert "validate-contract" in stage_names
assert "resolve-stack" in stage_names
assert "checkov-static" in stage_names, "REQ-250: checkov-static stage missing"
assert "terraform-plan" in stage_names
assert "checkov" in stage_names
assert "runtime-policy-scan" in stage_names, "REQ-250: runtime-policy-scan stage missing"
assert "confidence" in stage_names
assert "apply" in stage_names
# The old single 'checkov' stage is gone (split into checkov-static + runtime-policy-scan)
assert "checkov" not in stage_names, "old 'checkov' stage should be replaced by checkov-static + runtime-policy-scan"
class TestL2OutputsResolution:
+3 -2
View File
@@ -206,14 +206,15 @@ class TestDeployPipelineContract:
contract = _load_yaml("pipelines/contract.yml")
jsonschema.validate(contract, schema)
def test_deploy_contract_has_nine_stages(self):
def test_deploy_contract_has_ten_stages(self):
contract = _load_yaml("pipelines/contract.yml")
stage_names = [s["name"] for s in contract["stages"]]
assert stage_names == [
"validate-contract",
"resolve-stack",
"checkov-static",
"terraform-plan",
"checkov",
"runtime-policy-scan",
"confidence",
"apply",
"publish-outputs",