devantler-tech / devantler-tech/ksail

feat(workload): validate Kyverno policies against rendered manifests in `workload validate` (blocked on Kyverno + k8s.io v0.36)

Open
#5,355 3 comments 0 reactions 0 assignees View on GitHub
enhancement
Dominant language
Go
Stars
165
Forks
12
Avg merge
5h 51m
Merged PRs (30d)
347

Description

> 🤖 Drafted by Claude Code from a dependency spike, at the maintainer's request. Follow-up to #5344.

## Goal

Extend `ksail workload validate` with a third shift-left dimension: **policy-engine validation**. When the cluster is configured with Kyverno (`spec.cluster.policyEngine == Kyverno`), apply the repo's **own** Kyverno policies (`ClusterPolicy`/`Policy`/`ValidatingPolicy` declared in the GitOps source — Kyverno is installed with no bundled policies) to the **rendered** manifests offline, catching the same admission denials that would otherwise only surface at deploy time.

This belongs in `validate` (an admission accept/reject check — the natural extension of "will the cluster accept this?"), not `scan` (kubescape framework scoring). It composes with the Helm-rendering work from #5344: it runs on the same rendered output.

## Why this is split out / currently blocked

A dependency-integration spike (2026-06-19) showed **the in-process Kyverno engine does not compile against ksail's pinned k8s.io v0.36**:

- `go get github.com/kyverno/kyverno@v1.18.1` + `go mod tidy` resolve fine (MVS keeps ksail at k8s.io v0.36), but `go build` fails.
- Kyverno v1.18.1 (and even `main`, built 2026-06-18) target **k8s.io v0.35**. v0.36 made breaking changes in the exact internal packages Kyverno's `pkg/pss` and `pkg/admissionpolicy` use: `k8s.io/pod-security-admission/policy` (`CheckResult.ErrList` removed, `CheckPod` signature, `policy.WithFieldErrors` gone) and `k8s.io/apiserver/.../admission/plugin` (`validating.NewValidator` extra return; `MutatingAdmissionPolicy` type moved).
- No no-fork path currently works: (a) **narrow import** — `pkg/engine` transitively pulls *both* broken packages (`pkg/pss` via the podSecurity handler, `pkg/admissionpolicy` via the CEL handler + `internal/match.go`), so there's no engine subset that avoids them; (b) **newer Kyverno** — `main` still pins k8s.io v0.35; (c) **`replace`-pin** the broken k8s.io packages to v0.35 — blocked by MVS (apiserver@v0.35 would still compile against api@v0.36); (d) **kyverno-json / reimplement** — different policy model / abandons in-cluster fidelity.

Also note: importing the Kyverno CLI processor pulls a very heavy transitive tree (gatekeeper, notary/cosign, CUE, alibaba/aliyun, Kerberos/LDAP).

## Unblock condition

When Kyverno ships a release built on **k8s.io v0.36** (it lags k8s by ~a release — likely Kyverno v1.19), in-process integration becomes a clean `go get` with **no fork**. This issue should be revisited then.

## Proposed design (ready to wire when unblocked)

- New `pkg/client/kyverno` wrapper mirroring `pkg/client/kubeconform` / `pkg/client/kubescape`: `NewClient()`, a `ValidateResources(ctx, policies, targets [][]byte, opts) (Report, error)` method, and an `ErrPolicyValidationFailed` sentinel, backed by Kyverno's offline-apply (`cmd/cli/kubectl-kyverno/processor.PolicyProcessor.ApplyPoliciesOnResource`).
- Wire into `validate` after the existing render + kubeconform stages: read `spec.cluster.policyEngine` via the existing `DefaultPolicyEngineFieldSelector()`; partition the rendered `render.Result.Documents` into Kyverno policy CRs vs target resources; evaluate; surface offline violations as failures (`policy/ rule/: `) and cluster-context-dependent rules (apiCall/configMap vars, cross-resource CEL, image verification) as skipped + warned (the same graceful-degradation philosophy as Helm rendering). Add `--skip-policy-validation` + `spec.workload.validation.policyValidation`.
- The render package (`pkg/svc/gitops/render`, added in #5344) already produces the rendered, provenance-tagged documents this needs — the seam exists.

## Alternative (if needed before the unblock)

An **optional `kyverno` CLI shim** (shell out to the `kyverno` binary, eksctl precedent — gated on `policyEngine == Kyverno` and the binary being present) delivers the capability now with no Go deps and no fork, at the cost of not being embedded. Deferred in favor of the clean in-process path once Kyverno supports v0.36.

## Acceptance criteria

- [ ] `validate` applies in-repo Kyverno policies to the rendered manifests when `policyEngine == Kyverno`.
- [ ] Offline-evaluable policy violations fail `validate`; cluster-context-dependent rules are skipped with a warning, never a hard failure.
- [ ] `--skip-policy-validation` + `spec.workload.validation.policyValidation` opt-out; default on when Kyverno is the engine.
- [ ] In-process, no fork (gated on Kyverno releasing against k8s.io v0.36); docs + offline tests.

Contributor guide

Open the contributing guide

Research direction

Wait for a Kyverno release built against k8s.io v0.36, then start at pkg/client/kubeconform, pkg/client/kubescape, and pkg/svc/gitops/render. Wire the policy stage into validate after rendering and kubeconform, using the acceptance criteria and offline tests to verify violations, skips, opt-outs, and default behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
go, helm, kubernetes
Domain
cli, devops, security
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.