pkg/policyreports/engine.go
Rama main · réplica de lectura del repositorio original.
package policyreports
import "strings"
// Engine is the normalized policy/security engine that produced a Finding.
//
// It exists because a PolicyReport's `results[].source` is a *producer
// type*, not an engine. One engine emits several source values — a single
// Kyverno 1.18 cluster writes `kyverno` (legacy Policy/ClusterPolicy),
// `KyvernoValidatingPolicy`, and `KyvernoGeneratingPolicy` into the same
// report stream. Filtering on the raw string would fragment one engine
// into as many buckets as it has policy types, and every new upstream
// policy kind would silently create another bucket.
//
// Consumers that ask "what does Kyverno say about this resource" filter on
// Engine; consumers that need to name the exact producer keep reading
// Finding.Source.
type Engine string
const (
// EngineKyverno — Kyverno, via either the legacy kyverno.io family or
// the modern policies.kyverno.io CEL family.
EngineKyverno Engine = "kyverno"
// EngineVAP — Kubernetes-native ValidatingAdmissionPolicy /
// MutatingAdmissionPolicy. Kyverno's reports controller can evaluate
// VAPs and write the results into PolicyReports, but the evaluating
// engine is the apiserver, so these are attributed to VAP rather than
// to whichever controller happened to write the report.
EngineVAP Engine = "vap"
// EngineTrivy — Trivy Operator (vulnerability, config-audit, secret,
// and SBOM reports).
EngineTrivy Engine = "trivy"
// EngineFalco — Falco runtime security, via a PolicyReport adapter.
EngineFalco Engine = "falco"
// EngineOther — the report named a producer we don't have a mapping
// for. Distinct from EngineUnknown: the data is attributable, we just
// don't recognize the name. Consumers should show it rather than drop
// it, and the raw Source is the thing worth displaying.
EngineOther Engine = "other"
// EngineUnknown — the report carried no `source` at all. Older engines
// and hand-written reports omit it. Never conflate this with
// EngineOther: "nobody said" and "somebody we don't know" lead to
// different operator conclusions.
EngineUnknown Engine = "unknown"
)
// EnginesAttributableToKyverno is the engine set that may legitimately fill a
// Kyverno-labelled rollup.
//
// EngineUnknown is included deliberately. `results[].source` is optional and
// older Kyverno builds omit it, so those findings normalize to EngineUnknown.
// Excluding them would empty the Kyverno summary on exactly the legacy
// clusters this integration still has to serve, so an unattributed finding
// keeps the historical assumption that Kyverno wrote it.
//
// EngineVAP is deliberately NOT included, even though Kyverno's reports
// controller is what writes VAP results into PolicyReports: the evaluating
// engine is the apiserver, and a rollup labelled "kyverno" must not count
// enforcement Kyverno did not perform.
var EnginesAttributableToKyverno = []Engine{EngineKyverno, EngineUnknown}
// EngineForSource normalizes a raw PolicyReport `results[].source` value to
// the engine that produced it. Matching is case-insensitive and
// whitespace-trimmed because the field is free-form — nothing upstream
// validates it.
//
// Observed source values this maps (Kyverno 1.18, Trivy Operator 0.2x,
// falcosidekick's PolicyReport output):
//
// kyverno, KyvernoValidatingPolicy, KyvernoImageValidatingPolicy,
// KyvernoMutatingPolicy, KyvernoGeneratingPolicy → kyverno
// ValidatingAdmissionPolicy, MutatingAdmissionPolicy → vap
// Trivy Vulnerability, trivy-operator → trivy
// falco, falcosidekick → falco
//
// Unrecognized non-empty values map to EngineOther; an empty source maps
// to EngineUnknown.
func EngineForSource(source string) Engine {
s := strings.ToLower(strings.TrimSpace(source))
if s == "" {
return EngineUnknown
}
switch {
// Prefix, not equality: the modern family appends the policy type
// (KyvernoValidatingPolicy, KyvernoImageValidatingPolicy, ...) and
// upstream adds new ones every release. Matching the prefix means a
// policy kind Radar has never heard of still attributes correctly.
case strings.HasPrefix(s, "kyverno"):
return EngineKyverno
// Suffix covers both ValidatingAdmissionPolicy and
// MutatingAdmissionPolicy without enumerating them. Ordered after the
// kyverno prefix so a hypothetical "KyvernoValidatingAdmissionPolicy"
// attributes to the controller that owns the policy object.
case strings.HasSuffix(s, "admissionpolicy"):
return EngineVAP
case strings.Contains(s, "trivy"):
return EngineTrivy
case strings.Contains(s, "falco"):
return EngineFalco
}
return EngineOther
}