Files
acdl/adapters/kyverno
Jon Chery e74a8c2f5d feat(P42): stub implementation — SoD, HITL gates, attestation matrix, Wiz, Kyverno
---ci---
project: acdl
phase: 42
milestone: v1.9
status: execute
---/ci---

Phase 42 — stub-implementation (REQ-107..111, D-084):

route_halt_artifact (REQ-107):
- core/separation_of_duties.py: real SNS publish (ACDL_SOD_HALT_TOPIC_ARN)
  + outbox fallback (SEPARATION_OF_DUTIES_VIOLATION event via
  outbox_writer) + stderr emission. No silent print-only stub.
- terraform/platform/main.tf: aws_sns_topic.acdl-sod-halt + output.

HITL attestation gates (REQ-108):
- core/hitl_gates.py: attest(contract_id, env, approver, evidence,
  outbox_client) records approver_qa/approver_prod/approver_dr to
  outbox, runs SoD check on prod, invokes attestation matrix, returns
  (ok, reason). Dev skips (autonomous). approver_from_env() reads
  GITHUB_ACTOR/GITEA_ACTOR.
- scripts/run_platform.sh: Step 7b HITL gate before apply for qa/prod/dr.

8-concern attestation matrix (REQ-109, D-084):
- core/attestation_matrix.py: check(env, evidence) runs the 8 concerns
  from hitl_matrix_design.md §10.4. Offline-testable (contract_nfrs,
  schema_validity, policy_pass) run for real. Operator-supplied accept
  signed artifacts validated for freshness (FRESHNESS_DAYS table) +
  schema. Signature skip when ACDL_ATTESTATION_SIGNING_KEY_ID unset
  (D-089). Fail loud if missing/expired for prod/dr.

Wiz real client (REQ-110):
- adapters/wiz/wiz_adapter.py: WizClient (GraphQL API, Bearer auth,
  pagination via pageInfo.hasNextPage + endCursor). fetch_and_adapt
  translates issues → PolicyCheckResult; graceful degrade when
  WIZ_API_TOKEN/WIZ_API_URL unset.

Kyverno fleshed out (REQ-111):
- adapters/kyverno/kyverno_adapter.py: full PolicyReport →
  PolicyCheckResult mapping (pass/fail/skip/warn + severity + skip-with-
  reason + resource ref construction from kind/name/namespace).
  adapt_inactive() emits KYVERNO_INACTIVE_TF_STACK guard. --kube-version
  stub parsed for future GitOps.

Tests: +47 (test_route_halt_artifact.py, test_hitl_gates.py,
test_attestation_matrix.py, test_wiz_adapter_real_client.py, expanded
test_kyverno_adapter.py). Existing wiz_adapter tests updated for the
real client's control.name ruleId. 493 passed; run_ci.sh green;
run_platform.sh --check-only green.
2026-07-23 04:40:44 +00:00
..

Kyverno Adapter

The Kyverno adapter translates Kyverno PolicyReport results to the normalized ACDL PolicyCheckResult schema (engine: "kyverno"), mirroring the Checkov/Wiz adapter pattern.

What Kyverno is

Kyverno is a Kubernetes-native policy engine. It runs as an admission controller inside a cluster, validates / mutates / generates K8s resources against declarative ClusterPolicy rules, and publishes results to PolicyReport resources.

When to use it

Kyverno is the right engine when the platform emits Kubernetes manifests (a K8s-native stack). The ACDL platform today emits Terraform only (D-053), so this adapter is ready but inactive: it ships now so the schema path, severity/result mapping and sample policies are in place ahead of the GitOps reconciler that will emit K8s manifests (roadmap).

How the adapter translates PolicyReport results

kyverno_adapter.py <policyreport.json> <contract-id> reads a JSON file containing a Kyverno PolicyReport (or just its .results[] array) and emits a list of PolicyCheckResult dicts:

Kyverno PolicyReport result field PolicyCheckResult field
policy ruleId (default KYVERNO_UNKNOWN)
severity severity (lower-cased, mapped)
result result (pass/fail/error as-is, warn/skipskipped)
message message
resource resourceRef + evidence.resource
namespace, kind, name evidence.*

The adapter is read-only against a local JSON fixture; the GitOps reconciler is responsible for fetching the live PolicyReport and writing the file. When there are zero results, the adapter returns an empty list (unlike Wiz it does not synthesize a SKIPPED record — Kyverno not running is a deployment state, not a configuration gap).

Roadmap dependency

This adapter activates when the GitOps reconciler (roadmap) emits K8s manifests. Until then it is documentation-only; the pipeline does not invoke it. The engine: "kyverno" enum value is present in schemas/policy_check_result.schema.json so future records validate.

Sample policies

The policies/ directory holds three valid Kyverno ClusterPolicy manifests (documentation-only today — the platform does not run them):

  • disallow-privileged-containers.yaml — fail pods with securityContext.privileged: true.
  • require-resource-labels.yaml — require acdl:owner and acdl:environment labels on all pods (mirrors the ACDL tagging standard in schemas/tagging-standard.json).
  • require-image-digests.yaml — require container images to reference a digest (image@sha256:...), not a mutable tag.

Schema path

The output records validate against schemas/policy_check_result.schema.json (engine: "kyverno" was already in the enum and is retained in Phase 23).