Files
acdl/adapters/kyverno-json
Jon Chery e22661ab54 feat(P03 W4): pilot-readiness + settlement-finality kyverno-json policies (REQ-315, REQ-320)
REQ-320: policies/pilot-readiness/no-placeholder-account.json asserts
account_id != "000000000000" over the env JSON (critical severity — a
placeholder account drives a block band). Passes on dev (581513795199),
fails on placeholder. REQ-315: policies/settlement-finality/all-matches-
committed.json asserts all_committed == true over the settlement status
JSON (critical severity). Authored + tested in v1.26; enforcement gates
qa/prod/dr promotions, not dev (G-Q6 — dev all_committed is vacuously
true). Both policy tests run against real kj (not skipped).

---ci---
project: acdl
phase: 3
milestone: v1.26
status: execute
wave: W4
---
2026-08-18 22:36:57 +00:00
..

kyverno-json Engine Adapter (v1.25)

The kyverno-json engine is Nova's primary compliance/policy tool (v1.25), implemented behind the swappable PolicyEngine protocol so OPA (or any other engine) can replace it one day.

What kyverno-json is

kyverno-json is a standalone Go binary from the Kyverno project — a separate runtime from the K8s Kyverno admission controller. It applies Kyverno ValidatingPolicy resources to any JSON or YAML payload file via the kj scan CLI. Unlike the K8s Kyverno adapter (adapters/kyverno/), which only speaks to K8s manifests, kyverno-json evaluates consumer contracts, resolved Stack IR, terraform plan JSON, and even the merged PCR list itself (meta-policies).

Install

bash scripts/install-kyverno-json.sh
# or directly:
go install github.com/kyverno/kyverno-json/cmd/kj@latest
kj version

The platform functions without the binary — is_configured() returns False when which kj is absent → evaluate() returns a single SKIPPED PCR (KJ_ENGINE_NOT_CONFIGURED). The confidence signal proceeds with a neutral policy input (D-120 graceful degradation).

Policy directory layout

adapters/kyverno-json/policies/
├── _smoke.json                  # round-trip smoke test
├── contract/                    # consumer contract JSON policies
│   ├── require-id-pattern.json
│   ├── require-env-in-enum.json
│   ├── require-infrastructure-min-1.json
│   └── forbid-unknown-fields.json
├── stack-ir/                    # resolved Stack IR policies
│   ├── require-tagging-standard.json
│   ├── forbid-public-ingress.json
│   └── require-encryption-by-default.json
├── plan-json/                   # terraform show -json policies
│   ├── forbid-plaintext-secrets.json
│   ├── forbid-iam-wildcard.json
│   └── require-kms-reference.json
├── meta/                        # policies over the merged PCR list
│   ├── block-on-any-critical.json
│   └── tagging-rules-agree.json
└── regression/                   # capability-inventory policies
    ├── cap-013-adapter-dedup.json
    ├── cap-023-metrics-collector.json
    └── cap-024-deck-structure.json

The four policy categories

  1. contract/ — over the consumer contract JSON (pre-resolve).
  2. stack-ir/ — over the resolved Target Stack IR (post-resolve).
  3. plan-json/ — over terraform show -json output (pipeline Step 5b).
  4. meta/ — over the merged list[PolicyCheckResult] (meta-policies).
  5. regression/ — over the capability-inventory JSON (declarative mirrors of core/regression_verify.py).

Severity convention

kyverno-json does not natively assign severities. Each Nova policy declares its severity via a metadata.annotations field:

metadata:
  annotations:
    nova.cloudinit.dev/severity: high

Valid values: critical, high, medium, low, info (default when absent).

Engine enum reuse (D-116)

kyverno-json PCR records carry engine: "kyverno" (no new enum value). The engine field records the policy-engine family, not the specific binary. The K8s Kyverno adapter and the kyverno-json engine are distinguished by ruleId prefix (KYVERNO_ vs KJ_) and evidence payload shape (namespace/kind vs assertion/jmespath).

Schema path

The output records validate against schemas/policy_check_result.schema.json (engine: "kyverno" is in the enum). The confidence signal consumes the merged PCR list engine-agnostically.

Swap boundary

The PolicyEngine protocol (core/policy_engine.py) is the swap boundary. The OPA-equivalent surface is documented in .ciagent/RESEARCH.md §4.2 — a future OpaEngine implements the same protocol without touching the confidence signal, the PCR schema, or the pipeline.