# VERIFY — P1 engine-core (v1.25) > 4-layer verify gate: structural, behavioral, security, quality. > Phase: P1. Requirements: REQ-291..294, 308, 309. Result: PASS. ## Structural - `core/policy_engine.py` exists, implements `PolicyEngine` Protocol (PEP 544, `@runtime_checkable`), `PolicyEngineRegistry` with `register()` + `get_engine()`, `NullEngine` fallback. - `adapters/kyverno-json/kyverno_json_engine.py` exists, exports `KyvernoJsonEngine` with `name`, `is_configured()`, `evaluate()`. - `adapters/kyverno-json/__init__.py` loads the engine by file path (the dir name has a hyphen — not a valid Python package name). - `adapters/kyverno-json/policies/_smoke.json` exists (trivial policy for round-trip validation). - `scripts/install-kyverno-json.sh` exists (go install kj@latest). - `.ciagent/config.json` has the `policy` object (`engine: kyverno-json`, `policy_root`). - `.gitea/workflows/ci.yml` + `.github/workflows/ci.yml` have the Go + kj install step (best-effort, tests skip when kj absent). - `tests/test_policy_engine.py` (10 tests) + `tests/test_kyverno_json_engine.py` (16 tests) exist. ## Behavioral - `pytest tests/test_policy_engine.py tests/test_kyverno_json_engine.py`: **24 passed, 2 skipped** (kj not installed — expected; `pytest.skip("kj not installed")`). - `NullEngine` satisfies the `PolicyEngine` Protocol (G-Q8a — `isinstance(NullEngine(), PolicyEngine)` is True). Proves the swap boundary is real without implementing OPA. - `KyvernoJsonEngine.is_configured()` returns `False` when `which kj` is absent → `evaluate()` returns a single `KJ_ENGINE_NOT_CONFIGURED` SKIPPED PCR (distinct `ruleId` from NullEngine's `NULL_ENGINE_INACTIVE` — G-Q4). - PCR records validate against `schemas/policy_check_result.schema.json` (via `jsonschema.validate` in tests). - Defensive parsing: malformed kyverno-json output → `error` PCR (`KJ_ENGINE_ERROR`), never an exception. - Severity annotation reading (G-Q10a): policies with `nova.cloudinit.dev/severity: high` produce PCRs with `severity: high`; policies without the annotation default to `info`. - Registry: `get_engine()` returns the configured engine; unknown engine name raises `KeyError`; `policy` key absent → `NullEngine`. - No regression: `pytest tests/test_confidence_signal.py tests/test_adapter.py tests/test_checkov_adapter.py tests/test_kyverno_adapter.py tests/test_contract_resolver.py` — **132 passed** (unchanged). ## Security - No new secrets, no new network calls in the engine core (the engine shells to a local binary; the binary makes no network calls for `scan`). - `is_configured()` guard ensures the platform runs without the binary (no hard dependency that could be exploited as a DoS vector). - The engine writes the payload to a temp file (`tempfile.NamedTemporaryFile`) and unlinks it in a `finally` block (no leftover payload on disk). - No `shell=True` in the `subprocess.run` call (command is a list — no shell injection surface). ## Quality - `python3 -m py_compile` passes on all new Python files. - The `PolicyEngine` Protocol is minimal (3 members) — the swap boundary is the moat (NORTH_STAR Strategic Objective #2). - The `NullEngine` proves a second implementation exists (structural conformance) — the OPA swap is a known quantity (RESEARCH §4.2). - Tests use `pytest.skip` when `which kj` is absent, so the CI matrix passes with or without the binary (the suite is green in both cases). ## Must-have checklist - [x] `PolicyEngine` Protocol + `PolicyEngineRegistry` + `NullEngine` (REQ-291) - [x] `config.json.policy` object (REQ-292) - [x] `KyvernoJsonEngine` adapter (REQ-293) - [x] `__init__.py` + `_smoke.json` + `install-kyverno-json.sh` + CI install (REQ-294) - [x] `test_policy_engine.py` — protocol conformance, registry, NullEngine fallback (REQ-308) - [x] `test_kyverno_json_engine.py` — PCR schema validity, defensive parsing, skip-without-kj (REQ-309) **Verdict: PASS** — all P1 must-haves met, no regressions, 24 new tests pass (2 skip-without-kj), 132 existing tests unchanged.