Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ go 1.26.6

require (
cel.dev/cel-go v0.32.0
github.com/coroot/logparser v1.4.2
// Test-only consumer: match the deployed node-agent source ee62018e73b9.
github.com/coroot/logparser v1.4.0
github.com/santhosh-tekuri/jsonschema/v6 v6.0.3
github.com/siderolabs/talos/pkg/machinery v1.14.2
go.yaml.in/yaml/v2 v2.4.4
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ github.com/containernetworking/cni v1.3.0 h1:v6EpN8RznAZj9765HhXQrtXgX+ECGebEYEm
github.com/containernetworking/cni v1.3.0/go.mod h1:Bs8glZjjFfGPHMw6hQu82RUgEPNGEaBb9KS5KtNMnJ4=
github.com/coroot/logparser v1.4.0 h1:/b+XnAh7kuKR1mVSekPCSPpKloWx6wJveHa0HDcXueY=
github.com/coroot/logparser v1.4.0/go.mod h1:5mgr/LIFAEuhxLgnFTtEXVWKthT1l2ZTsPHF6oOGc/E=
github.com/coroot/logparser v1.4.2 h1:0UxS7R2jLGc0l4seLkA42IKDGivwLFBPC7yzqc9LQv8=
github.com/coroot/logparser v1.4.2/go.mod h1:5mgr/LIFAEuhxLgnFTtEXVWKthT1l2ZTsPHF6oOGc/E=
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ spec:
# given an explicit limit below (see the admissionController.container.resources block
# and the OOM incident it documents); the chart default proved too low.
features:
# Preserve producer severity for every controller; colored text lets a
# resource kind such as "Alert" promote an informational notice to fatal.
logging:
format: json
backgroundScan:
# Honor config.resourceFilters during background scans (chart default is
# true = filters skipped = report-per-resource for everything). With this
Expand Down
72 changes: 47 additions & 25 deletions scripts/tests/kyverno-logs/log_format_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"os/exec"
"path/filepath"
"reflect"
"strings"
"testing"
"time"

Expand Down Expand Up @@ -53,6 +52,7 @@ func renderArguments(t *testing.T, baseline bool) map[string][]string {
values[name].(map[string]any)["replicas"] = replicas
}
if baseline {
delete(values["features"].(map[string]any), "logging")
if overrides, ok := values["admissionController"].(map[string]any)["featuresOverride"].(map[string]any); ok {
delete(overrides, "logging")
}
Expand Down Expand Up @@ -106,13 +106,18 @@ func renderArguments(t *testing.T, baseline bool) map[string][]string {
return result
}

type consumedLog struct {
logparser.LogEntry
attributes map[string]string
}

// consume exercises the deployed CRI decoder and parser callback, preserving fields.
func consume(t *testing.T, body string) logparser.LogEntry {
func consume(t *testing.T, body string) consumedLog {
t.Helper()
entries := make(chan logparser.LogEntry, 1)
results := make(chan logparser.LogEntry, 1)
parser := logparser.NewParser(entries, logparser.CriDecoder{}, func(timestamp time.Time, level logparser.Level, _, _ string, attributes map[string]string) {
results <- logparser.LogEntry{Timestamp: timestamp, Level: level, Content: attributes["allowedResults"]}
results := make(chan consumedLog, 1)
parser := logparser.NewParser(entries, logparser.CriDecoder{}, func(timestamp time.Time, level logparser.Level, _, message string, attributes map[string]string) {
results <- consumedLog{LogEntry: logparser.LogEntry{Timestamp: timestamp, Level: level, Content: message}, attributes: attributes}
}, 5*time.Millisecond, 256, true, nil)
defer parser.Stop()
entries <- logparser.LogEntry{Timestamp: time.Unix(100, 0), Content: "2000-01-01T05:03:39Z stderr F " + body, Level: logparser.LevelUnknown}
Expand All @@ -121,28 +126,27 @@ func consume(t *testing.T, body string) logparser.LogEntry {
return result
case <-time.After(time.Second):
t.Fatal("native CRI consumer timed out")
return logparser.LogEntry{}
return consumedLog{}
}
}

// TestAdmissionProducerArguments checks only the admission formatter changes.
func TestAdmissionProducerArguments(t *testing.T) {
// TestControllerProducerArguments rejects colored text from any controller,
// while retaining the original admission regression and every other argument.
func TestControllerProducerArguments(t *testing.T) {
current, baseline := renderArguments(t, false), renderArguments(t, true)
admission := "kyverno-admission-controller"
want := append([]string(nil), baseline[admission]...)
replacements := 0
for i, arg := range want {
if arg == "--loggingFormat=text" {
want[i], replacements = "--loggingFormat=json", replacements+1
}
}
if replacements != 1 || !reflect.DeepEqual(current[admission], want) {
t.Fatal("admission must change only text to JSON; verbosity and other arguments must remain identical")
}
for name, args := range baseline {
if name != admission && !reflect.DeepEqual(current[name], args) {
t.Fatalf("unrelated controller %s arguments changed", name)
}
for _, name := range []string{"kyverno-admission-controller", "kyverno-background-controller", "kyverno-reports-controller", "kyverno-cleanup-controller"} {
t.Run(name, func(t *testing.T) {
want := append([]string(nil), baseline[name]...)
replacements := 0
for i, arg := range want {
if arg == "--loggingFormat=text" {
want[i], replacements = "--loggingFormat=json", replacements+1
}
}
if replacements != 1 || !reflect.DeepEqual(current[name], want) {
t.Fatal("controller must change only text to JSON; verbosity and other arguments must remain identical")
}
})
}
}

Expand All @@ -155,17 +159,35 @@ func TestCRISeverity(t *testing.T) {
level string
want logparser.Level
}{
{"trace", logparser.LevelDebug}, {"debug", logparser.LevelDebug}, {"info", logparser.LevelInfo}, {"warn", logparser.LevelWarning}, {"error", logparser.LevelError},
{"trace", logparser.LevelDebug}, {"debug", logparser.LevelDebug}, {"info", logparser.LevelInfo}, {"warn", logparser.LevelWarning}, {"error", logparser.LevelError}, {"fatal", logparser.LevelCritical},
} {
t.Run(tc.level, func(t *testing.T) {
body, err := json.Marshal(map[string]any{"level": tc.level, "time": "2000-01-01T05:03:39Z", "message": "configuration includes error and warn", "allowedResults": "pass,fail,error,warn,skip", "logger": "setup/flag", "v": 2})
if err != nil {
t.Fatal(err)
}
got := consume(t, string(body))
if got.Level != tc.want || !strings.Contains(got.Content, "pass,fail,error,warn,skip") {
if got.Level != tc.want || got.Content != "configuration includes error and warn" || got.attributes["allowedResults"] != "pass,fail,error,warn,skip" {
t.Fatalf("structured severity or original flag value changed: %s %q", got.Level, got.Content)
}
})
}
}

// A resource kind called Alert must not promote a deprecation notice to fatal.
// Characterize the observed colored-text defect and exercise its JSON replacement.
func TestCRIDeprecationSeverity(t *testing.T) {
const message = "Warning: v1beta2 Alert is deprecated, upgrade to v1beta3"
colored := "\x1b[90m2000-01-01T05:03:39Z\x1b[0m \x1b[32mINF\x1b[0m \x1b[1mk8s.io/client-go@v0.36.3/rest/warnings.go:107\x1b[0m\x1b[36m >\x1b[0m \x1b[1m" + message + "\x1b[0m \x1b[36mlogger=\x1b[0mklog \x1b[36mv=\x1b[0m0"
if got := consume(t, colored); got.Level != logparser.LevelCritical {
t.Fatalf("observed colored deprecation defect changed: level=%s", got.Level)
}
body, err := json.Marshal(map[string]any{"level": "info", "time": "2000-01-01T05:03:39Z", "message": message, "logger": "klog", "v": 0})
if err != nil {
t.Fatal(err)
}
got := consume(t, string(body))
if got.Level != logparser.LevelInfo || got.Content != message || got.attributes["logger"] != "klog" {
t.Fatalf("deprecation severity or content changed: level=%s message=%q", got.Level, got.Content)
}
}
18 changes: 18 additions & 0 deletions scripts/validate-eks-ci-role-policy/approved-surface-history.md
Original file line number Diff line number Diff line change
Expand Up @@ -3531,3 +3531,21 @@ nothing added or removed:

No issuer, artifact, RBAC binding, IAM policy, credential or permission grant
changes. The set of accepted identities shrinks by one.

## 2026-10-15 — Preserve severity across Kyverno controller logs

platform#4919 extends structured logging to the remaining controllers. Against
main `c25cb3c45e8d5afe87659c5e228168f2e77a0c8f`, the pinned kubectl v1.36.2 /
Kustomize v5.8.1 renderer reports exactly one changed authorization entry and
nothing added or removed: HelmRelease kyverno/kyverno moves from
`5083866cbaa1a7133755230e0d4c6d0d534277df9b99f9d2c7e3ac0d488a7c86` to
`9d5bf8b9ff67800bfc3ad3e11ba48d9ba9f0237b2a0126c5de34f34056d3d98a`.

The only manifest change selects the shared JSON formatter. The actual pinned
chart regression compares every argument of all four controllers with the
text baseline: only the formatter differs, and verbosity remains unchanged.
The admission controller was already using JSON. CRI regressions against the
deployed node-agent's log parser preserve informational deprecation notices,
message contents and attributes, and real warning, error and critical levels.
No chart version, RBAC, service account, admission scope, failure action,
resource filter, AWS identity, credential or permission grant changes.
2 changes: 1 addition & 1 deletion scripts/validate-eks-ci-role-policy/approved-surface.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ helm.toolkit.fluxcd.io/v2|HelmRelease|kubescape|alertmanager 4ee4b8a2fc512253c45

helm.toolkit.fluxcd.io/v2|HelmRelease|kubescape|kubescape fc4feb22be5f61469646c02fd66490b8a9e11626dc99bf13280cd075c2972cc1

helm.toolkit.fluxcd.io/v2|HelmRelease|kyverno|kyverno 5083866cbaa1a7133755230e0d4c6d0d534277df9b99f9d2c7e3ac0d488a7c86
helm.toolkit.fluxcd.io/v2|HelmRelease|kyverno|kyverno 9d5bf8b9ff67800bfc3ad3e11ba48d9ba9f0237b2a0126c5de34f34056d3d98a

helm.toolkit.fluxcd.io/v2|HelmRelease|longhorn-system|longhorn c0f77790ab49bd8c26359b00eb32f6341ed1690cc9f3f92c974f3c415d429b8f

Expand Down
Loading