diff --git a/adapters/kyverno-json/policies/pilot-readiness/no-placeholder-account.json b/adapters/kyverno-json/policies/pilot-readiness/no-placeholder-account.json new file mode 100644 index 0000000..4237c02 --- /dev/null +++ b/adapters/kyverno-json/policies/pilot-readiness/no-placeholder-account.json @@ -0,0 +1,27 @@ +{ + "apiVersion": "json.kyverno.io/v1alpha1", + "kind": "ValidatingPolicy", + "metadata": { + "name": "no-placeholder-account", + "annotations": { + "nova.cloudinit.dev/severity": "critical", + "title.policy.kyverno.io": "Env does not use a placeholder AWS account id" + } + }, + "spec": { + "rules": [ + { + "name": "no-placeholder-account", + "assert": { + "all": [ + { + "check": { + "(account_id == '000000000000')": false + } + } + ] + } + } + ] + } +} \ No newline at end of file diff --git a/adapters/kyverno-json/policies/settlement-finality/all-matches-committed.json b/adapters/kyverno-json/policies/settlement-finality/all-matches-committed.json new file mode 100644 index 0000000..9d6de31 --- /dev/null +++ b/adapters/kyverno-json/policies/settlement-finality/all-matches-committed.json @@ -0,0 +1,27 @@ +{ + "apiVersion": "json.kyverno.io/v1alpha1", + "kind": "ValidatingPolicy", + "metadata": { + "name": "all-matches-committed", + "annotations": { + "nova.cloudinit.dev/severity": "critical", + "title.policy.kyverno.io": "All settlement matches are committed (finalized)" + } + }, + "spec": { + "rules": [ + { + "name": "all-matches-committed", + "assert": { + "all": [ + { + "check": { + "(all_committed)": true + } + } + ] + } + } + ] + } +} \ No newline at end of file diff --git a/tests/fixtures/pilot_readiness/placeholder_account.json b/tests/fixtures/pilot_readiness/placeholder_account.json new file mode 100644 index 0000000..2da6bc4 --- /dev/null +++ b/tests/fixtures/pilot_readiness/placeholder_account.json @@ -0,0 +1,4 @@ +{ + "account_id": "000000000000", + "region": "us-east-1" +} \ No newline at end of file diff --git a/tests/fixtures/pilot_readiness/real_account.json b/tests/fixtures/pilot_readiness/real_account.json new file mode 100644 index 0000000..0436641 --- /dev/null +++ b/tests/fixtures/pilot_readiness/real_account.json @@ -0,0 +1,7 @@ +{ + "account_id": "581513795199", + "region": "us-east-1", + "state_backend": { + "bucket": "nova-tfstate-dev" + } +} \ No newline at end of file diff --git a/tests/fixtures/settlement_finality/all_committed.json b/tests/fixtures/settlement_finality/all_committed.json new file mode 100644 index 0000000..2752a0a --- /dev/null +++ b/tests/fixtures/settlement_finality/all_committed.json @@ -0,0 +1,6 @@ +{ + "contract_id": "blkex", + "environment": "dev", + "all_committed": true, + "matches": [] +} \ No newline at end of file diff --git a/tests/fixtures/settlement_finality/uncommitted.json b/tests/fixtures/settlement_finality/uncommitted.json new file mode 100644 index 0000000..ebe1305 --- /dev/null +++ b/tests/fixtures/settlement_finality/uncommitted.json @@ -0,0 +1,13 @@ +{ + "contract_id": "blkex", + "environment": "dev", + "all_committed": false, + "matches": [ + { + "txn_id": "t1", + "symbol": "AAPL", + "finalized": false, + "block_index": 1 + } + ] +} \ No newline at end of file diff --git a/tests/test_pilot_readiness_policy.py b/tests/test_pilot_readiness_policy.py new file mode 100644 index 0000000..7d070a1 --- /dev/null +++ b/tests/test_pilot_readiness_policy.py @@ -0,0 +1,85 @@ +"""Tests for pilot-readiness kyverno-json policies (REQ-320, v1.26 P3 W4). + +Tests the policy in adapters/kyverno-json/policies/pilot-readiness/: +no-placeholder-account. The payload is the env JSON shape +(core/environments/.json): asserts account_id != "000000000000". +Runs against real ``kj`` (not skipped) โ€” the W0.5 fix installed the +binary and unmasked the v1.25 substrate bugs. +""" + +import json +import os +import sys +from pathlib import Path + +import pytest + +sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) + +import importlib.util +_ENGINE_PATH = Path(__file__).resolve().parent.parent / "adapters" / "kyverno-json" / "kyverno_json_engine.py" +_spec = importlib.util.spec_from_file_location("kyverno_json_engine", _ENGINE_PATH) +_mod = importlib.util.module_from_spec(_spec) +_spec.loader.exec_module(_mod) +KyvernoJsonEngine = _mod.KyvernoJsonEngine + +POLICY_DIR = Path(__file__).resolve().parent.parent / "adapters" / "kyverno-json" / "policies" / "pilot-readiness" +FIXTURES = Path(__file__).resolve().parent / "fixtures" / "pilot_readiness" + + +def _kj_installed() -> bool: + return _mod._which_kj() is not None + + +@pytest.fixture(autouse=True) +def _require_kj(): + if not _kj_installed(): + pytest.skip("kj not installed (scripts/install-kyverno-json.sh)") + + +def _load(name): + with open(FIXTURES / name, "r", encoding="utf-8") as fh: + return json.load(fh) + + +class TestPassingFixture: + def test_real_account_passes(self): + eng = KyvernoJsonEngine() + out = eng.evaluate(_load("real_account.json"), POLICY_DIR, "cid-pass") + assert isinstance(out, list) + assert len(out) >= 1 + fails = [p for p in out if p["result"] == "fail"] + assert fails == [], f"expected no fails on real_account fixture, got: {fails}" + + +class TestFailingFixture: + def test_placeholder_account_fails(self): + eng = KyvernoJsonEngine() + out = eng.evaluate(_load("placeholder_account.json"), POLICY_DIR, "cid-fail") + fails = [p for p in out if p["result"] == "fail"] + assert len(fails) >= 1, "expected at least one fail on the placeholder_account fixture" + + +class TestPolicyFilesExist: + def test_policy_present(self): + files = sorted(os.listdir(POLICY_DIR)) + assert "no-placeholder-account.json" in files + + +class TestPolicyValidity: + def test_policy_is_valid_json(self): + for f in os.listdir(POLICY_DIR): + if f.endswith(".json"): + with open(POLICY_DIR / f, "r", encoding="utf-8") as fh: + data = json.load(fh) + assert data["apiVersion"] == "json.kyverno.io/v1alpha1" + assert data["kind"] == "ValidatingPolicy" + assert "nova.cloudinit.dev/severity" in data["metadata"]["annotations"] + + def test_policy_name_matches_filename(self): + for f in os.listdir(POLICY_DIR): + if f.endswith(".json"): + with open(POLICY_DIR / f, "r", encoding="utf-8") as fh: + data = json.load(fh) + expected = f.rsplit(".", 1)[0] + assert data["metadata"]["name"] == expected \ No newline at end of file diff --git a/tests/test_settlement_finality_policy.py b/tests/test_settlement_finality_policy.py new file mode 100644 index 0000000..0cc2e49 --- /dev/null +++ b/tests/test_settlement_finality_policy.py @@ -0,0 +1,88 @@ +"""Tests for settlement-finality kyverno-json policies (REQ-315 platform half, v1.26 P3 W4). + +Tests the policy in adapters/kyverno-json/policies/settlement-finality/: +all-matches-committed. The payload is the settlement status JSON emitted +by the consumer's settlement/service.py:status_json() (shape per SPEC +ยง5.7): asserts all_committed == true. The policy is authored + tested +in v1.26; enforcement (gating dev applies) is deferred โ€” for dev, +all_committed is vacuously true over an empty matches[] (G-Q6). The +policy gates qa/prod/dr promotions, not dev. Runs against real ``kj`` +(not skipped) โ€” the W0.5 fix installed the binary. +""" + +import json +import os +import sys +from pathlib import Path + +import pytest + +sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) + +import importlib.util +_ENGINE_PATH = Path(__file__).resolve().parent.parent / "adapters" / "kyverno-json" / "kyverno_json_engine.py" +_spec = importlib.util.spec_from_file_location("kyverno_json_engine", _ENGINE_PATH) +_mod = importlib.util.module_from_spec(_spec) +_spec.loader.exec_module(_mod) +KyvernoJsonEngine = _mod.KyvernoJsonEngine + +POLICY_DIR = Path(__file__).resolve().parent.parent / "adapters" / "kyverno-json" / "policies" / "settlement-finality" +FIXTURES = Path(__file__).resolve().parent / "fixtures" / "settlement_finality" + + +def _kj_installed() -> bool: + return _mod._which_kj() is not None + + +@pytest.fixture(autouse=True) +def _require_kj(): + if not _kj_installed(): + pytest.skip("kj not installed (scripts/install-kyverno-json.sh)") + + +def _load(name): + with open(FIXTURES / name, "r", encoding="utf-8") as fh: + return json.load(fh) + + +class TestPassingFixture: + def test_all_committed_passes(self): + eng = KyvernoJsonEngine() + out = eng.evaluate(_load("all_committed.json"), POLICY_DIR, "cid-pass") + assert isinstance(out, list) + assert len(out) >= 1 + fails = [p for p in out if p["result"] == "fail"] + assert fails == [], f"expected no fails on all_committed fixture, got: {fails}" + + +class TestFailingFixture: + def test_uncommitted_fails(self): + eng = KyvernoJsonEngine() + out = eng.evaluate(_load("uncommitted.json"), POLICY_DIR, "cid-fail") + fails = [p for p in out if p["result"] == "fail"] + assert len(fails) >= 1, "expected at least one fail on the uncommitted fixture" + + +class TestPolicyFilesExist: + def test_policy_present(self): + files = sorted(os.listdir(POLICY_DIR)) + assert "all-matches-committed.json" in files + + +class TestPolicyValidity: + def test_policy_is_valid_json(self): + for f in os.listdir(POLICY_DIR): + if f.endswith(".json"): + with open(POLICY_DIR / f, "r", encoding="utf-8") as fh: + data = json.load(fh) + assert data["apiVersion"] == "json.kyverno.io/v1alpha1" + assert data["kind"] == "ValidatingPolicy" + assert "nova.cloudinit.dev/severity" in data["metadata"]["annotations"] + + def test_policy_name_matches_filename(self): + for f in os.listdir(POLICY_DIR): + if f.endswith(".json"): + with open(POLICY_DIR / f, "r", encoding="utf-8") as fh: + data = json.load(fh) + expected = f.rsplit(".", 1)[0] + assert data["metadata"]["name"] == expected \ No newline at end of file