From bb9784aef704d8f658b36646a85526d42f30356b Mon Sep 17 00:00:00 2001 From: Vlastimil Zeman Date: Thu, 23 Apr 2026 16:41:32 +0100 Subject: [PATCH] feat: migrate MutatingAdmissionPolicy from v1beta1 to v1 for k8s 1.36 Kubernetes 1.36 graduated MutatingAdmissionPolicy and MutatingAdmissionPolicyBinding from admissionregistration.k8s.io/v1beta1 to admissionregistration.k8s.io/v1. Changes: - Bump k8s.io/api, apimachinery, apiserver, client-go to v0.36.0 - Update PolicySet and TestSuite fields from v1beta1 to v1 types - Unify namespace selector and match condition evaluation by removing v1beta1-specific duplicates (matchesNamespaceSelectorV1Beta1, evaluateMatchConditionsV1Beta1) now that both Validating and Mutating policies share the same v1 types - Add error sentinels for v1beta1 MutatingAdmissionPolicy and MutatingAdmissionPolicyBinding rejection with clear migration messages - Migrate all test YAML manifests to admissionregistration.k8s.io/v1 - Update all Go test files to use v1 types --- go.mod | 50 ++--- go.sum | 99 ++++----- internal/evaluator/evaluator.go | 54 ++--- .../evaluator/evaluator_authorizer_test.go | 17 +- internal/evaluator/evaluator_params_test.go | 69 +++--- internal/evaluator/evaluator_test.go | 199 +++++++++--------- internal/loader/errors.go | 20 +- internal/loader/policy.go | 14 +- internal/loader/suite.go | 5 +- .../loader/testdata/mixed-types/policies.yaml | 4 +- .../testdata/multiple-policies/bindings.yaml | 4 +- .../testdata/multiple-policies/policies.yaml | 4 +- .../testdata/separate-files/binding.yaml | 2 +- .../testdata/separate-files/policy.yaml | 2 +- .../single-file-policy-binding/policy.yaml | 4 +- main.go | 7 +- .../add-default-labels/binding.yaml | 2 +- .../add-default-labels/policy.yaml | 2 +- .../mutating-with-binding/binding.yaml | 2 +- .../mutating-with-binding/policy.yaml | 2 +- .../mutating/add-default-labels/binding.yaml | 2 +- .../mutating/add-default-labels/policy.yaml | 2 +- .../mutating-with-binding/binding.yaml | 2 +- .../mutating-with-binding/policy.yaml | 2 +- .../binding.yaml | 2 +- .../policy.yaml | 2 +- .../mutating/sidecar-injection/binding.yaml | 2 +- .../mutating/sidecar-injection/policy.yaml | 2 +- 28 files changed, 280 insertions(+), 298 deletions(-) diff --git a/go.mod b/go.mod index b4eb798..68aa358 100644 --- a/go.mod +++ b/go.mod @@ -1,24 +1,24 @@ module github.com/zemanlx/kat -go 1.25.0 +go 1.26.0 require ( github.com/evanphx/json-patch/v5 v5.9.11 github.com/google/cel-go v0.26.1 github.com/google/go-cmp v0.7.0 - github.com/pmezard/go-difflib v1.0.0 - google.golang.org/protobuf v1.36.8 + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 + google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af gopkg.in/yaml.v3 v3.0.1 - k8s.io/api v0.35.0 - k8s.io/apimachinery v0.35.0 - k8s.io/apiserver v0.35.0 - k8s.io/client-go v0.35.0 - k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 + k8s.io/api v0.36.0 + k8s.io/apimachinery v0.36.0 + k8s.io/apiserver v0.36.0 + k8s.io/client-go v0.36.0 + k8s.io/utils v0.0.0-20260319190234-28399d86e0b5 sigs.k8s.io/yaml v1.6.0 ) require ( - cel.dev/expr v0.24.0 // indirect + cel.dev/expr v0.25.1 // indirect github.com/antlr4-go/antlr/v4 v4.13.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect @@ -38,28 +38,28 @@ require ( github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.66.1 // indirect - github.com/prometheus/procfs v0.16.1 // indirect - github.com/spf13/cobra v1.10.0 // indirect + github.com/prometheus/common v0.67.5 // indirect + github.com/prometheus/procfs v0.19.2 // indirect + github.com/spf13/cobra v1.10.2 // indirect github.com/spf13/pflag v1.0.9 // indirect github.com/stoewer/go-strcase v1.3.0 // indirect github.com/x448/float16 v0.8.4 // indirect - go.opentelemetry.io/otel v1.36.0 // indirect - go.opentelemetry.io/otel/trace v1.36.0 // indirect + go.opentelemetry.io/otel v1.41.0 // indirect + go.opentelemetry.io/otel/trace v1.41.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect - golang.org/x/net v0.47.0 // indirect - golang.org/x/sync v0.18.0 // indirect - golang.org/x/sys v0.38.0 // indirect - golang.org/x/text v0.31.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect + golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 // indirect + golang.org/x/net v0.49.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.40.0 // indirect + golang.org/x/text v0.33.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - k8s.io/component-base v0.35.0 // indirect - k8s.io/klog/v2 v2.130.1 // indirect - k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 // indirect + k8s.io/component-base v0.36.0 // indirect + k8s.io/klog/v2 v2.140.0 // indirect + k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.2 // indirect ) diff --git a/go.sum b/go.sum index 010d40b..d6c16f3 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY= -cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw= +cel.dev/expr v0.25.1 h1:1KrZg61W6TWSxuNZ37Xy49ps13NUovb66QLprthtwi4= +cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4= github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -11,8 +11,9 @@ github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM= github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= @@ -63,22 +64,22 @@ github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFd github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= -github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs= -github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= -github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= -github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= +github.com/prometheus/common v0.67.5 h1:pIgK94WWlQt1WLwAC5j2ynLaBRDiinoAb86HZHTUGI4= +github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw= +github.com/prometheus/procfs v0.19.2 h1:zUMhqEW66Ex7OXIiDkll3tl9a1ZdilUOd/F6ZXw4Vws= +github.com/prometheus/procfs v0.19.2/go.mod h1:M0aotyiemPhBCM0z5w87kL22CxfcH05ZpYlu+b4J7mw= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/spf13/cobra v1.10.0 h1:a5/WeUlSDCvV5a45ljW2ZFtV0bTDpkfSAj3uqB6Sc+0= -github.com/spf13/cobra v1.10.0/go.mod h1:9dhySC7dnTtEiqzmqfkLj47BslqLCUPMXjG2lj/NgoE= -github.com/spf13/pflag v1.0.8/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU= +github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4= github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= @@ -94,32 +95,32 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= -go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg= -go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E= -go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w= -go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= +go.opentelemetry.io/otel v1.41.0 h1:YlEwVsGAlCvczDILpUXpIpPSL/VPugt7zHThEMLce1c= +go.opentelemetry.io/otel v1.41.0/go.mod h1:Yt4UwgEKeT05QbLwbyHXEwhnjxNO6D8L5PQP51/46dE= +go.opentelemetry.io/otel/trace v1.41.0 h1:Vbk2co6bhj8L59ZJ6/xFTskY+tGAbOnCtQGVVa9TIN0= +go.opentelemetry.io/otel/trace v1.41.0/go.mod h1:U1NU4ULCoxeDKc09yCWdWe+3QoyweJcISEVa1RBzOis= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= -golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= -golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= -google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950= -google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc= -google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93 h1:fQsdNF2N+/YewlRZiricy4P1iimyPKZ/xwniHj8Q2a0= +golang.org/x/exp v0.0.0-20251219203646-944ab1f22d93/go.mod h1:EPRbTFwzwjXj9NpYyyrvenVh9Y+GFeEvMNh7Xuz7xgU= +golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= +golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= +golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= +golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= +google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409 h1:merA0rdPeUV3YIIfHHcH4qBkiQAc1nfCKSI7lB4cV2M= +google.golang.org/genproto/googleapis/api v0.0.0-20260128011058-8636f8732409/go.mod h1:fl8J1IvUjCilwZzQowmw2b7HQB2eAuYBabMXzWurF+I= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409 h1:H86B94AW+VfJWDqFeEbBPhEtHzJwJfTbgE2lZa54ZAQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260128011058-8636f8732409/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= +google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI= +google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= @@ -128,27 +129,27 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.35.0 h1:iBAU5LTyBI9vw3L5glmat1njFK34srdLmktWwLTprlY= -k8s.io/api v0.35.0/go.mod h1:AQ0SNTzm4ZAczM03QH42c7l3bih1TbAXYo0DkF8ktnA= -k8s.io/apimachinery v0.35.0 h1:Z2L3IHvPVv/MJ7xRxHEtk6GoJElaAqDCCU0S6ncYok8= -k8s.io/apimachinery v0.35.0/go.mod h1:jQCgFZFR1F4Ik7hvr2g84RTJSZegBc8yHgFWKn//hns= -k8s.io/apiserver v0.35.0 h1:CUGo5o+7hW9GcAEF3x3usT3fX4f9r8xmgQeCBDaOgX4= -k8s.io/apiserver v0.35.0/go.mod h1:QUy1U4+PrzbJaM3XGu2tQ7U9A4udRRo5cyxkFX0GEds= -k8s.io/client-go v0.35.0 h1:IAW0ifFbfQQwQmga0UdoH0yvdqrbwMdq9vIFEhRpxBE= -k8s.io/client-go v0.35.0/go.mod h1:q2E5AAyqcbeLGPdoRB+Nxe3KYTfPce1Dnu1myQdqz9o= -k8s.io/component-base v0.35.0 h1:+yBrOhzri2S1BVqyVSvcM3PtPyx5GUxCK2tinZz1G94= -k8s.io/component-base v0.35.0/go.mod h1:85SCX4UCa6SCFt6p3IKAPej7jSnF3L8EbfSyMZayJR0= -k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= -k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912 h1:Y3gxNAuB0OBLImH611+UDZcmKS3g6CthxToOb37KgwE= -k8s.io/kube-openapi v0.0.0-20250910181357-589584f1c912/go.mod h1:kdmbQkyfwUagLfXIad1y2TdrjPFWp2Q89B3qkRwf/pQ= -k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 h1:SjGebBtkBqHFOli+05xYbK8YF1Dzkbzn+gDM4X9T4Ck= -k8s.io/utils v0.0.0-20251002143259-bc988d571ff4/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/api v0.36.0 h1:SgqDhZzHdOtMk40xVSvCXkP9ME0H05hPM3p9AB1kL80= +k8s.io/api v0.36.0/go.mod h1:m1LVrGPNYax5NBHdO+QuAedXyuzTt4RryI/qnmNvs34= +k8s.io/apimachinery v0.36.0 h1:jZyPzhd5Z+3h9vJLt0z9XdzW9VzNzWAUw+P1xZ9PXtQ= +k8s.io/apimachinery v0.36.0/go.mod h1:FklypaRJt6n5wUIwWXIP6GJlIpUizTgfo1T/As+Tyxc= +k8s.io/apiserver v0.36.0 h1:Jg5OFAENUACByUCg15CmhZAYrr5ZyJ+jodyA1mHl3YE= +k8s.io/apiserver v0.36.0/go.mod h1:mHvwdHf+qKEm+1/hYm756SV+oREOKSPnsjagOpx6Vho= +k8s.io/client-go v0.36.0 h1:pOYi7C4RHChYjMiHpZSpSbIM6ZxVbRXBy7CuiIwqA3c= +k8s.io/client-go v0.36.0/go.mod h1:ZKKcpwF0aLYfkHFCjillCKaTK/yBkEDHTDXCFY6AS9Y= +k8s.io/component-base v0.36.0 h1:hFjEktssxiJhrK1zfybkH4kJOi8iZuF+mIDCqS5+jRo= +k8s.io/component-base v0.36.0/go.mod h1:JZvIfcNHk+uck+8LhJzhSBtydWXaZNQwX2OdL+Mnwsk= +k8s.io/klog/v2 v2.140.0 h1:Tf+J3AH7xnUzZyVVXhTgGhEKnFqye14aadWv7bzXdzc= +k8s.io/klog/v2 v2.140.0/go.mod h1:o+/RWfJ6PwpnFn7OyAG3QnO47BFsymfEfrz6XyYSSp0= +k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a h1:xCeOEAOoGYl2jnJoHkC3hkbPJgdATINPMAxaynU2Ovg= +k8s.io/kube-openapi v0.0.0-20260317180543-43fb72c5454a/go.mod h1:uGBT7iTA6c6MvqUvSXIaYZo9ukscABYi2btjhvgKGZ0= +k8s.io/utils v0.0.0-20260319190234-28399d86e0b5 h1:kBawHLSnx/mYHmRnNUf9d4CpjREbeZuxoSGOX/J+aYM= +k8s.io/utils v0.0.0-20260319190234-28399d86e0b5/go.mod h1:xDxuJ0whA3d0I4mf/C4ppKHxXynQ+fxnkmQH0vTHnuk= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5EXP7sU1kvOlxwZh5txg= sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco= -sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.2 h1:kwVWMx5yS1CrnFWA/2QHyRVJ8jM6dBA80uLmm0wJkk8= +sigs.k8s.io/structured-merge-diff/v6 v6.3.2/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/internal/evaluator/evaluator.go b/internal/evaluator/evaluator.go index 5303da7..9b6b94a 100644 --- a/internal/evaluator/evaluator.go +++ b/internal/evaluator/evaluator.go @@ -19,7 +19,6 @@ import ( "gopkg.in/yaml.v3" admissionv1 "k8s.io/api/admission/v1" admissionregv1 "k8s.io/api/admissionregistration/v1" - admissionv1beta1 "k8s.io/api/admissionregistration/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/labels" @@ -114,8 +113,8 @@ type TestCase interface { // EvaluateTest evaluates a policy against a test case and returns whether it passed. func (e *Evaluator) EvaluateTest( - mutatingPolicy *admissionv1beta1.MutatingAdmissionPolicy, - mutatingBinding *admissionv1beta1.MutatingAdmissionPolicyBinding, + mutatingPolicy *admissionregv1.MutatingAdmissionPolicy, + mutatingBinding *admissionregv1.MutatingAdmissionPolicyBinding, validatingPolicy *admissionregv1.ValidatingAdmissionPolicy, validatingBinding *admissionregv1.ValidatingAdmissionPolicyBinding, testCase TestCase, @@ -238,8 +237,8 @@ func getDiff(expected, actual string) string { // evaluatePolicy evaluates the appropriate policy (mutating or validating) and returns the result. func (e *Evaluator) evaluatePolicy( - mutatingPolicy *admissionv1beta1.MutatingAdmissionPolicy, - mutatingBinding *admissionv1beta1.MutatingAdmissionPolicyBinding, + mutatingPolicy *admissionregv1.MutatingAdmissionPolicy, + mutatingBinding *admissionregv1.MutatingAdmissionPolicyBinding, validatingPolicy *admissionregv1.ValidatingAdmissionPolicy, validatingBinding *admissionregv1.ValidatingAdmissionPolicyBinding, testCase TestCase, @@ -570,8 +569,8 @@ type TestOutcome struct { // EvaluateMutating evaluates a MutatingAdmissionPolicy against an admission request. func (e *Evaluator) EvaluateMutating( - policy *admissionv1beta1.MutatingAdmissionPolicy, - binding *admissionv1beta1.MutatingAdmissionPolicyBinding, + policy *admissionregv1.MutatingAdmissionPolicy, + binding *admissionregv1.MutatingAdmissionPolicyBinding, request *admissionv1.AdmissionRequest, object *unstructured.Unstructured, oldObject *unstructured.Unstructured, @@ -581,7 +580,7 @@ func (e *Evaluator) EvaluateMutating( userInfo user.Info, ) (*EvaluationResult, error) { // Evaluate binding's namespaceSelector if present - if matched, err := e.matchesNamespaceSelectorV1Beta1(binding, namespaceObj); err != nil { + if matched, err := e.matchesMutatingNamespaceSelector(binding, namespaceObj); err != nil { return nil, fmt.Errorf("evaluate namespace selector: %w", err) } else if !matched { // Namespace selector doesn't match, policy doesn't apply @@ -600,7 +599,7 @@ func (e *Evaluator) EvaluateMutating( vars := prepareMutatingVars(requestMap, primaryObject, oldObject, params, namespaceObj, authorizer, userInfo) - matched, err := e.evaluateMatchConditionsV1Beta1(policy.Spec.MatchConditions, vars) + matched, err := e.evaluateMatchConditions(policy.Spec.MatchConditions, vars) if err != nil { return nil, fmt.Errorf("evaluate match conditions: %w", err) } @@ -667,7 +666,7 @@ func prepareMutatingVars( } func (e *Evaluator) applyMutations( - mutations []admissionv1beta1.Mutation, + mutations []admissionregv1.Mutation, object *unstructured.Unstructured, vars map[string]any, ) (*unstructured.Unstructured, error) { @@ -675,7 +674,7 @@ func (e *Evaluator) applyMutations( for _, mutation := range mutations { switch mutation.PatchType { - case admissionv1beta1.PatchTypeJSONPatch: + case admissionregv1.PatchTypeJSONPatch: patch, err := e.evaluateJSONPatchMutation(mutation, vars) if err != nil { return nil, err @@ -689,7 +688,7 @@ func (e *Evaluator) applyMutations( return nil, err } } - case admissionv1beta1.PatchTypeApplyConfiguration: + case admissionregv1.PatchTypeApplyConfiguration: config, err := e.evaluateApplyConfigurationMutation(mutation, vars) if err != nil { return nil, err @@ -819,10 +818,10 @@ func (e *Evaluator) matchesNamespaceSelector( return matchesNamespaceSelectorByLabelSelector(binding.Spec.MatchResources.NamespaceSelector, namespaceObj) } -// matchesNamespaceSelectorV1Beta1 checks if the namespace object's labels match the binding's namespace selector. +// matchesMutatingNamespaceSelector checks if the namespace object's labels match the mutating binding's namespace selector. // Returns true if the selector matches (policy should be evaluated), false otherwise. -func (e *Evaluator) matchesNamespaceSelectorV1Beta1( - binding *admissionv1beta1.MutatingAdmissionPolicyBinding, +func (e *Evaluator) matchesMutatingNamespaceSelector( + binding *admissionregv1.MutatingAdmissionPolicyBinding, namespaceObj *unstructured.Unstructured, ) (bool, error) { if binding == nil || binding.Spec.MatchResources == nil { @@ -853,27 +852,6 @@ func (e *Evaluator) evaluateMatchConditions(conditions []admissionregv1.MatchCon return true, nil } -// evaluateMatchConditionsV1Beta1 evaluates v1beta1 match conditions. -func (e *Evaluator) evaluateMatchConditionsV1Beta1(conditions []admissionv1beta1.MatchCondition, vars map[string]any) (bool, error) { - for _, condition := range conditions { - result, err := e.evaluateExpression(condition.Expression, vars) - if err != nil { - return false, fmt.Errorf("evaluate match condition %q: %w", condition.Name, err) - } - - matched, ok := result.(bool) - if !ok { - return false, fmt.Errorf("%w: %s returned %T", errMatchConditionNonBoolean, condition.Name, result) - } - - if !matched { - return false, nil - } - } - - return true, nil -} - // evaluateExpression evaluates a single CEL expression with the given variables. func (e *Evaluator) evaluateExpression(expression string, vars map[string]any) (any, error) { celVal, err := e.evaluateExpressionRaw(expression, vars) @@ -996,7 +974,7 @@ func convertAdmissionRequest(req *admissionv1.AdmissionRequest) (map[string]any, // evaluateJSONPatchMutation evaluates a JSONPatch mutation and returns the patch result. func (e *Evaluator) evaluateJSONPatchMutation( - mutation admissionv1beta1.Mutation, + mutation admissionregv1.Mutation, vars map[string]any, ) (any, error) { if mutation.JSONPatch == nil { @@ -1014,7 +992,7 @@ func (e *Evaluator) evaluateJSONPatchMutation( // evaluateApplyConfigurationMutation evaluates an ApplyConfiguration mutation and returns the configuration. func (e *Evaluator) evaluateApplyConfigurationMutation( - mutation admissionv1beta1.Mutation, + mutation admissionregv1.Mutation, vars map[string]any, ) (*unstructured.Unstructured, error) { if mutation.ApplyConfiguration == nil { diff --git a/internal/evaluator/evaluator_authorizer_test.go b/internal/evaluator/evaluator_authorizer_test.go index e0e44d2..376caec 100644 --- a/internal/evaluator/evaluator_authorizer_test.go +++ b/internal/evaluator/evaluator_authorizer_test.go @@ -6,7 +6,6 @@ import ( "github.com/google/go-cmp/cmp" admissionv1 "k8s.io/api/admission/v1" admissionregv1 "k8s.io/api/admissionregistration/v1" - admissionv1beta1 "k8s.io/api/admissionregistration/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/types" @@ -20,7 +19,7 @@ func TestEvaluateMutating_WithAuthorizer(t *testing.T) { tests := []struct { name string - policy *admissionv1beta1.MutatingAdmissionPolicy + policy *admissionregv1.MutatingAdmissionPolicy object *unstructured.Unstructured authorizer *MockAuthorizer username string @@ -88,7 +87,7 @@ func TestEvaluateMutating_WithAuthorizer(t *testing.T) { } } -func runMutatingTest(t *testing.T, policy *admissionv1beta1.MutatingAdmissionPolicy, object *unstructured.Unstructured, auth *MockAuthorizer, username string, groups []string, expectedMutated bool, expectedObject *unstructured.Unstructured) { +func runMutatingTest(t *testing.T, policy *admissionregv1.MutatingAdmissionPolicy, object *unstructured.Unstructured, auth *MockAuthorizer, username string, groups []string, expectedMutated bool, expectedObject *unstructured.Unstructured) { t.Helper() evaluator, err := New() @@ -128,14 +127,14 @@ func runMutatingTest(t *testing.T, policy *admissionv1beta1.MutatingAdmissionPol } } -func makeMutatingPolicy(expression string) *admissionv1beta1.MutatingAdmissionPolicy { - return &admissionv1beta1.MutatingAdmissionPolicy{ +func makeMutatingPolicy(expression string) *admissionregv1.MutatingAdmissionPolicy { + return &admissionregv1.MutatingAdmissionPolicy{ ObjectMeta: metav1.ObjectMeta{Name: "test-policy"}, - Spec: admissionv1beta1.MutatingAdmissionPolicySpec{ - Mutations: []admissionv1beta1.Mutation{ + Spec: admissionregv1.MutatingAdmissionPolicySpec{ + Mutations: []admissionregv1.Mutation{ { - PatchType: admissionv1beta1.PatchTypeJSONPatch, - JSONPatch: &admissionv1beta1.JSONPatch{ + PatchType: admissionregv1.PatchTypeJSONPatch, + JSONPatch: &admissionregv1.JSONPatch{ Expression: expression, }, }, diff --git a/internal/evaluator/evaluator_params_test.go b/internal/evaluator/evaluator_params_test.go index d0aa935..722bbf1 100644 --- a/internal/evaluator/evaluator_params_test.go +++ b/internal/evaluator/evaluator_params_test.go @@ -6,7 +6,6 @@ import ( admissionv1 "k8s.io/api/admission/v1" admissionregv1 "k8s.io/api/admissionregistration/v1" - admissionv1beta1 "k8s.io/api/admissionregistration/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/types" @@ -20,7 +19,7 @@ func TestEvaluateMutating_WithParams(t *testing.T) { tests := []struct { name string - policy *admissionv1beta1.MutatingAdmissionPolicy + policy *admissionregv1.MutatingAdmissionPolicy object *unstructured.Unstructured params *unstructured.Unstructured expectedMutated bool @@ -28,13 +27,13 @@ func TestEvaluateMutating_WithParams(t *testing.T) { }{ { name: "add label from params", - policy: &admissionv1beta1.MutatingAdmissionPolicy{ + policy: &admissionregv1.MutatingAdmissionPolicy{ ObjectMeta: metav1.ObjectMeta{Name: "test-policy"}, - Spec: admissionv1beta1.MutatingAdmissionPolicySpec{ - Mutations: []admissionv1beta1.Mutation{ + Spec: admissionregv1.MutatingAdmissionPolicySpec{ + Mutations: []admissionregv1.Mutation{ { - PatchType: admissionv1beta1.PatchTypeJSONPatch, - JSONPatch: &admissionv1beta1.JSONPatch{ + PatchType: admissionregv1.PatchTypeJSONPatch, + JSONPatch: &admissionregv1.JSONPatch{ Expression: `[JSONPatch{op: "add", path: "/metadata/labels/env", value: params.environment}]`, }, }, @@ -70,19 +69,19 @@ func TestEvaluateMutating_WithParams(t *testing.T) { }, { name: "conditional mutation based on params", - policy: &admissionv1beta1.MutatingAdmissionPolicy{ + policy: &admissionregv1.MutatingAdmissionPolicy{ ObjectMeta: metav1.ObjectMeta{Name: "test-policy"}, - Spec: admissionv1beta1.MutatingAdmissionPolicySpec{ - MatchConditions: []admissionv1beta1.MatchCondition{ + Spec: admissionregv1.MutatingAdmissionPolicySpec{ + MatchConditions: []admissionregv1.MatchCondition{ { Name: "check-enabled", Expression: `params.enabled == true`, }, }, - Mutations: []admissionv1beta1.Mutation{ + Mutations: []admissionregv1.Mutation{ { - PatchType: admissionv1beta1.PatchTypeJSONPatch, - JSONPatch: &admissionv1beta1.JSONPatch{ + PatchType: admissionregv1.PatchTypeJSONPatch, + JSONPatch: &admissionregv1.JSONPatch{ Expression: `[JSONPatch{op: "add", path: "/metadata/labels/managed", value: "true"}]`, }, }, @@ -118,19 +117,19 @@ func TestEvaluateMutating_WithParams(t *testing.T) { }, { name: "no mutation when params condition not met", - policy: &admissionv1beta1.MutatingAdmissionPolicy{ + policy: &admissionregv1.MutatingAdmissionPolicy{ ObjectMeta: metav1.ObjectMeta{Name: "test-policy"}, - Spec: admissionv1beta1.MutatingAdmissionPolicySpec{ - MatchConditions: []admissionv1beta1.MatchCondition{ + Spec: admissionregv1.MutatingAdmissionPolicySpec{ + MatchConditions: []admissionregv1.MatchCondition{ { Name: "check-enabled", Expression: `params.enabled == true`, }, }, - Mutations: []admissionv1beta1.Mutation{ + Mutations: []admissionregv1.Mutation{ { - PatchType: admissionv1beta1.PatchTypeJSONPatch, - JSONPatch: &admissionv1beta1.JSONPatch{ + PatchType: admissionregv1.PatchTypeJSONPatch, + JSONPatch: &admissionregv1.JSONPatch{ Expression: `[JSONPatch{op: "add", path: "/metadata/labels/managed", value: "true"}]`, }, }, @@ -155,13 +154,13 @@ func TestEvaluateMutating_WithParams(t *testing.T) { }, { name: "add multiple labels from params object", - policy: &admissionv1beta1.MutatingAdmissionPolicy{ + policy: &admissionregv1.MutatingAdmissionPolicy{ ObjectMeta: metav1.ObjectMeta{Name: "test-policy"}, - Spec: admissionv1beta1.MutatingAdmissionPolicySpec{ - Mutations: []admissionv1beta1.Mutation{ + Spec: admissionregv1.MutatingAdmissionPolicySpec{ + Mutations: []admissionregv1.Mutation{ { - PatchType: admissionv1beta1.PatchTypeApplyConfiguration, - ApplyConfiguration: &admissionv1beta1.ApplyConfiguration{ + PatchType: admissionregv1.PatchTypeApplyConfiguration, + ApplyConfiguration: &admissionregv1.ApplyConfiguration{ Expression: `Object{metadata: {"labels": params.defaultLabels}}`, }, }, @@ -208,19 +207,19 @@ func TestEvaluateMutating_WithParams(t *testing.T) { }, { name: "set replica count from params", - policy: &admissionv1beta1.MutatingAdmissionPolicy{ + policy: &admissionregv1.MutatingAdmissionPolicy{ ObjectMeta: metav1.ObjectMeta{Name: "test-policy"}, - Spec: admissionv1beta1.MutatingAdmissionPolicySpec{ - MatchConditions: []admissionv1beta1.MatchCondition{ + Spec: admissionregv1.MutatingAdmissionPolicySpec{ + MatchConditions: []admissionregv1.MatchCondition{ { Name: "check-apply-limit", Expression: `has(params.maxReplicas) && object.spec.replicas > params.maxReplicas`, }, }, - Mutations: []admissionv1beta1.Mutation{ + Mutations: []admissionregv1.Mutation{ { - PatchType: admissionv1beta1.PatchTypeApplyConfiguration, - ApplyConfiguration: &admissionv1beta1.ApplyConfiguration{ + PatchType: admissionregv1.PatchTypeApplyConfiguration, + ApplyConfiguration: &admissionregv1.ApplyConfiguration{ Expression: `Object{spec: {"replicas": params.maxReplicas}}`, }, }, @@ -266,13 +265,13 @@ func TestEvaluateMutating_WithParams(t *testing.T) { }, { name: "add annotation with value from nested params", - policy: &admissionv1beta1.MutatingAdmissionPolicy{ + policy: &admissionregv1.MutatingAdmissionPolicy{ ObjectMeta: metav1.ObjectMeta{Name: "test-policy"}, - Spec: admissionv1beta1.MutatingAdmissionPolicySpec{ - Mutations: []admissionv1beta1.Mutation{ + Spec: admissionregv1.MutatingAdmissionPolicySpec{ + Mutations: []admissionregv1.Mutation{ { - PatchType: admissionv1beta1.PatchTypeJSONPatch, - JSONPatch: &admissionv1beta1.JSONPatch{ + PatchType: admissionregv1.PatchTypeJSONPatch, + JSONPatch: &admissionregv1.JSONPatch{ Expression: `[JSONPatch{op: "add", path: "/metadata/annotations", value: {"owner": params.team.owner, "contact": params.team.contact}}]`, }, }, diff --git a/internal/evaluator/evaluator_test.go b/internal/evaluator/evaluator_test.go index e43ccfc..f26c074 100644 --- a/internal/evaluator/evaluator_test.go +++ b/internal/evaluator/evaluator_test.go @@ -8,7 +8,6 @@ import ( "github.com/google/go-cmp/cmp" admissionv1 "k8s.io/api/admission/v1" admissionregv1 "k8s.io/api/admissionregistration/v1" - admissionv1beta1 "k8s.io/api/admissionregistration/v1beta1" authenticationv1 "k8s.io/api/authentication/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -39,7 +38,7 @@ func TestEvaluateMutating(t *testing.T) { tests := []struct { name string - policy *admissionv1beta1.MutatingAdmissionPolicy + policy *admissionregv1.MutatingAdmissionPolicy object *unstructured.Unstructured oldObject *unstructured.Unstructured expectedMutated bool // true if object should be mutated @@ -48,19 +47,19 @@ func TestEvaluateMutating(t *testing.T) { }{ { name: "add label when match conditions satisfied", - policy: &admissionv1beta1.MutatingAdmissionPolicy{ + policy: &admissionregv1.MutatingAdmissionPolicy{ ObjectMeta: metav1.ObjectMeta{Name: "test-policy"}, - Spec: admissionv1beta1.MutatingAdmissionPolicySpec{ - MatchConditions: []admissionv1beta1.MatchCondition{ + Spec: admissionregv1.MutatingAdmissionPolicySpec{ + MatchConditions: []admissionregv1.MatchCondition{ { Name: "check-namespace", Expression: `object.metadata.namespace == "default"`, }, }, - Mutations: []admissionv1beta1.Mutation{ + Mutations: []admissionregv1.Mutation{ { - PatchType: admissionv1beta1.PatchTypeJSONPatch, - JSONPatch: &admissionv1beta1.JSONPatch{ + PatchType: admissionregv1.PatchTypeJSONPatch, + JSONPatch: &admissionregv1.JSONPatch{ Expression: `[JSONPatch{op: "add", path: "/metadata/labels/matched", value: "true"}]`, }, }, @@ -93,19 +92,19 @@ func TestEvaluateMutating(t *testing.T) { }, { name: "no mutation when match conditions not satisfied", - policy: &admissionv1beta1.MutatingAdmissionPolicy{ + policy: &admissionregv1.MutatingAdmissionPolicy{ ObjectMeta: metav1.ObjectMeta{Name: "test-policy"}, - Spec: admissionv1beta1.MutatingAdmissionPolicySpec{ - MatchConditions: []admissionv1beta1.MatchCondition{ + Spec: admissionregv1.MutatingAdmissionPolicySpec{ + MatchConditions: []admissionregv1.MatchCondition{ { Name: "check-namespace", Expression: `object.metadata.namespace == "production"`, }, }, - Mutations: []admissionv1beta1.Mutation{ + Mutations: []admissionregv1.Mutation{ { - PatchType: admissionv1beta1.PatchTypeJSONPatch, - JSONPatch: &admissionv1beta1.JSONPatch{ + PatchType: admissionregv1.PatchTypeJSONPatch, + JSONPatch: &admissionregv1.JSONPatch{ Expression: `[JSONPatch{op: "add", path: "/metadata/labels/matched", value: "true"}]`, }, }, @@ -126,13 +125,13 @@ func TestEvaluateMutating(t *testing.T) { }, { name: "add multiple labels", - policy: &admissionv1beta1.MutatingAdmissionPolicy{ + policy: &admissionregv1.MutatingAdmissionPolicy{ ObjectMeta: metav1.ObjectMeta{Name: "test-policy"}, - Spec: admissionv1beta1.MutatingAdmissionPolicySpec{ - Mutations: []admissionv1beta1.Mutation{ + Spec: admissionregv1.MutatingAdmissionPolicySpec{ + Mutations: []admissionregv1.Mutation{ { - PatchType: admissionv1beta1.PatchTypeJSONPatch, - JSONPatch: &admissionv1beta1.JSONPatch{ + PatchType: admissionregv1.PatchTypeJSONPatch, + JSONPatch: &admissionregv1.JSONPatch{ Expression: `[ JSONPatch{op: "add", path: "/metadata/labels/env", value: "test"}, JSONPatch{op: "add", path: "/metadata/labels/team", value: "platform"} @@ -166,19 +165,19 @@ func TestEvaluateMutating(t *testing.T) { }, { name: "add audit label when replica count increased", - policy: &admissionv1beta1.MutatingAdmissionPolicy{ + policy: &admissionregv1.MutatingAdmissionPolicy{ ObjectMeta: metav1.ObjectMeta{Name: "test-policy"}, - Spec: admissionv1beta1.MutatingAdmissionPolicySpec{ - MatchConditions: []admissionv1beta1.MatchCondition{ + Spec: admissionregv1.MutatingAdmissionPolicySpec{ + MatchConditions: []admissionregv1.MatchCondition{ { Name: "check-replica-increase", Expression: `has(oldObject.spec.replicas) && has(object.spec.replicas) && object.spec.replicas > oldObject.spec.replicas`, }, }, - Mutations: []admissionv1beta1.Mutation{ + Mutations: []admissionregv1.Mutation{ { - PatchType: admissionv1beta1.PatchTypeJSONPatch, - JSONPatch: &admissionv1beta1.JSONPatch{ + PatchType: admissionregv1.PatchTypeJSONPatch, + JSONPatch: &admissionregv1.JSONPatch{ Expression: `[JSONPatch{op: "add", path: "/metadata/labels/scaled-up", value: "true"}]`, }, }, @@ -228,13 +227,13 @@ func TestEvaluateMutating(t *testing.T) { }, { name: "apply configuration - merge spec fields", - policy: &admissionv1beta1.MutatingAdmissionPolicy{ + policy: &admissionregv1.MutatingAdmissionPolicy{ ObjectMeta: metav1.ObjectMeta{Name: "test-policy"}, - Spec: admissionv1beta1.MutatingAdmissionPolicySpec{ - Mutations: []admissionv1beta1.Mutation{ + Spec: admissionregv1.MutatingAdmissionPolicySpec{ + Mutations: []admissionregv1.Mutation{ { - PatchType: admissionv1beta1.PatchTypeApplyConfiguration, - ApplyConfiguration: &admissionv1beta1.ApplyConfiguration{ + PatchType: admissionregv1.PatchTypeApplyConfiguration, + ApplyConfiguration: &admissionregv1.ApplyConfiguration{ Expression: `Object{spec: {"replicas": 10}}`, }, }, @@ -279,25 +278,25 @@ func TestEvaluateMutating(t *testing.T) { }, { name: "mixed patch types - preserve spec order", - policy: &admissionv1beta1.MutatingAdmissionPolicy{ + policy: &admissionregv1.MutatingAdmissionPolicy{ ObjectMeta: metav1.ObjectMeta{Name: "test-policy"}, - Spec: admissionv1beta1.MutatingAdmissionPolicySpec{ - Mutations: []admissionv1beta1.Mutation{ + Spec: admissionregv1.MutatingAdmissionPolicySpec{ + Mutations: []admissionregv1.Mutation{ { - PatchType: admissionv1beta1.PatchTypeJSONPatch, - JSONPatch: &admissionv1beta1.JSONPatch{ + PatchType: admissionregv1.PatchTypeJSONPatch, + JSONPatch: &admissionregv1.JSONPatch{ Expression: `[JSONPatch{op: "add", path: "/metadata/annotations/step", value: "1"}]`, }, }, { - PatchType: admissionv1beta1.PatchTypeApplyConfiguration, - ApplyConfiguration: &admissionv1beta1.ApplyConfiguration{ + PatchType: admissionregv1.PatchTypeApplyConfiguration, + ApplyConfiguration: &admissionregv1.ApplyConfiguration{ Expression: `Object{metadata: Object.metadata{annotations: {"step": "2"}}}`, }, }, { - PatchType: admissionv1beta1.PatchTypeJSONPatch, - JSONPatch: &admissionv1beta1.JSONPatch{ + PatchType: admissionregv1.PatchTypeJSONPatch, + JSONPatch: &admissionregv1.JSONPatch{ Expression: `[JSONPatch{op: "replace", path: "/metadata/annotations/step", value: "3"}]`, }, }, @@ -328,13 +327,13 @@ func TestEvaluateMutating(t *testing.T) { }, { name: "apply configuration - add nested labels", - policy: &admissionv1beta1.MutatingAdmissionPolicy{ + policy: &admissionregv1.MutatingAdmissionPolicy{ ObjectMeta: metav1.ObjectMeta{Name: "test-policy"}, - Spec: admissionv1beta1.MutatingAdmissionPolicySpec{ - Mutations: []admissionv1beta1.Mutation{ + Spec: admissionregv1.MutatingAdmissionPolicySpec{ + Mutations: []admissionregv1.Mutation{ { - PatchType: admissionv1beta1.PatchTypeApplyConfiguration, - ApplyConfiguration: &admissionv1beta1.ApplyConfiguration{ + PatchType: admissionregv1.PatchTypeApplyConfiguration, + ApplyConfiguration: &admissionregv1.ApplyConfiguration{ Expression: `Object{metadata: {"labels": {"managed-by": "kat", "env": "prod"}}}`, }, }, @@ -371,13 +370,13 @@ func TestEvaluateMutating(t *testing.T) { }, { name: "json patch - complex nested object value", - policy: &admissionv1beta1.MutatingAdmissionPolicy{ + policy: &admissionregv1.MutatingAdmissionPolicy{ ObjectMeta: metav1.ObjectMeta{Name: "test-policy"}, - Spec: admissionv1beta1.MutatingAdmissionPolicySpec{ - Mutations: []admissionv1beta1.Mutation{ + Spec: admissionregv1.MutatingAdmissionPolicySpec{ + Mutations: []admissionregv1.Mutation{ { - PatchType: admissionv1beta1.PatchTypeJSONPatch, - JSONPatch: &admissionv1beta1.JSONPatch{ + PatchType: admissionregv1.PatchTypeJSONPatch, + JSONPatch: &admissionregv1.JSONPatch{ // Using Object.spec.selector{} style nested object Expression: `[JSONPatch{op: "add", path: "/spec/selector", value: Object.spec.selector{matchLabels: {"app": "myapp", "env": "prod"}}}]`, }, @@ -419,13 +418,13 @@ func TestEvaluateMutating(t *testing.T) { }, { name: "json patch - array with complex objects", - policy: &admissionv1beta1.MutatingAdmissionPolicy{ + policy: &admissionregv1.MutatingAdmissionPolicy{ ObjectMeta: metav1.ObjectMeta{Name: "test-policy"}, - Spec: admissionv1beta1.MutatingAdmissionPolicySpec{ - Mutations: []admissionv1beta1.Mutation{ + Spec: admissionregv1.MutatingAdmissionPolicySpec{ + Mutations: []admissionregv1.Mutation{ { - PatchType: admissionv1beta1.PatchTypeJSONPatch, - JSONPatch: &admissionv1beta1.JSONPatch{ + PatchType: admissionregv1.PatchTypeJSONPatch, + JSONPatch: &admissionregv1.JSONPatch{ // Adding a complex container with nested env vars Expression: `[JSONPatch{op: "add", path: "/spec/containers", value: [{"name": "nginx", "image": "nginx:latest", "env": [{"name": "ENV", "value": "prod"}], "ports": [{"containerPort": 80}]}]}]`, }, @@ -475,13 +474,13 @@ func TestEvaluateMutating(t *testing.T) { }, { name: "json patch - nested map value", - policy: &admissionv1beta1.MutatingAdmissionPolicy{ + policy: &admissionregv1.MutatingAdmissionPolicy{ ObjectMeta: metav1.ObjectMeta{Name: "test-policy"}, - Spec: admissionv1beta1.MutatingAdmissionPolicySpec{ - Mutations: []admissionv1beta1.Mutation{ + Spec: admissionregv1.MutatingAdmissionPolicySpec{ + Mutations: []admissionregv1.Mutation{ { - PatchType: admissionv1beta1.PatchTypeJSONPatch, - JSONPatch: &admissionv1beta1.JSONPatch{ + PatchType: admissionregv1.PatchTypeJSONPatch, + JSONPatch: &admissionregv1.JSONPatch{ // Adding deeply nested configuration Expression: `[JSONPatch{op: "add", path: "/metadata/annotations", value: {"config.example.com/nested": "{\"key1\": \"value1\", \"key2\": {\"nested\": true}}"}}]`, }, @@ -514,13 +513,13 @@ func TestEvaluateMutating(t *testing.T) { }, { name: "apply configuration - deeply nested structure", - policy: &admissionv1beta1.MutatingAdmissionPolicy{ + policy: &admissionregv1.MutatingAdmissionPolicy{ ObjectMeta: metav1.ObjectMeta{Name: "test-policy"}, - Spec: admissionv1beta1.MutatingAdmissionPolicySpec{ - Mutations: []admissionv1beta1.Mutation{ + Spec: admissionregv1.MutatingAdmissionPolicySpec{ + Mutations: []admissionregv1.Mutation{ { - PatchType: admissionv1beta1.PatchTypeApplyConfiguration, - ApplyConfiguration: &admissionv1beta1.ApplyConfiguration{ + PatchType: admissionregv1.PatchTypeApplyConfiguration, + ApplyConfiguration: &admissionregv1.ApplyConfiguration{ // Complex nested structure with arrays and objects Expression: `Object{spec: Object.spec{template: Object.spec.template{spec: Object.spec.template.spec{containers: [{"name": "sidecar", "image": "sidecar:v1", "env": [{"name": "MODE", "value": "inject"}]}]}}}}`, }, @@ -557,13 +556,13 @@ func TestEvaluateMutating(t *testing.T) { }, { name: "apply configuration - merge arrays and objects", - policy: &admissionv1beta1.MutatingAdmissionPolicy{ + policy: &admissionregv1.MutatingAdmissionPolicy{ ObjectMeta: metav1.ObjectMeta{Name: "test-policy"}, - Spec: admissionv1beta1.MutatingAdmissionPolicySpec{ - Mutations: []admissionv1beta1.Mutation{ + Spec: admissionregv1.MutatingAdmissionPolicySpec{ + Mutations: []admissionregv1.Mutation{ { - PatchType: admissionv1beta1.PatchTypeApplyConfiguration, - ApplyConfiguration: &admissionv1beta1.ApplyConfiguration{ + PatchType: admissionregv1.PatchTypeApplyConfiguration, + ApplyConfiguration: &admissionregv1.ApplyConfiguration{ // Add volumes array with complex nested structure Expression: `Object{spec: {"volumes": [{"name": "config", "configMap": {"name": "app-config", "items": [{"key": "config.yaml", "path": "config.yaml"}]}}]}}`, }, @@ -623,13 +622,13 @@ func TestEvaluateMutating(t *testing.T) { }, { name: "json patch - multiple patches with complex values", - policy: &admissionv1beta1.MutatingAdmissionPolicy{ + policy: &admissionregv1.MutatingAdmissionPolicy{ ObjectMeta: metav1.ObjectMeta{Name: "test-policy"}, - Spec: admissionv1beta1.MutatingAdmissionPolicySpec{ - Mutations: []admissionv1beta1.Mutation{ + Spec: admissionregv1.MutatingAdmissionPolicySpec{ + Mutations: []admissionregv1.Mutation{ { - PatchType: admissionv1beta1.PatchTypeJSONPatch, - JSONPatch: &admissionv1beta1.JSONPatch{ + PatchType: admissionregv1.PatchTypeJSONPatch, + JSONPatch: &admissionregv1.JSONPatch{ // Multiple patches in one mutation with nested values Expression: `[ JSONPatch{op: "add", path: "/metadata/labels", value: {"tier": "backend", "version": "v1"}}, @@ -1167,21 +1166,21 @@ func TestEvaluateMatchConditions(t *testing.T) { tests := []struct { name string - conditions []admissionv1beta1.MatchCondition + conditions []admissionregv1.MatchCondition vars map[string]any want bool wantErr bool }{ { name: "no conditions - should match", - conditions: []admissionv1beta1.MatchCondition{}, + conditions: []admissionregv1.MatchCondition{}, vars: map[string]any{}, want: true, wantErr: false, }, { name: "single condition - match", - conditions: []admissionv1beta1.MatchCondition{ + conditions: []admissionregv1.MatchCondition{ {Name: "test", Expression: "true"}, }, vars: map[string]any{}, @@ -1190,7 +1189,7 @@ func TestEvaluateMatchConditions(t *testing.T) { }, { name: "single condition - no match", - conditions: []admissionv1beta1.MatchCondition{ + conditions: []admissionregv1.MatchCondition{ {Name: "test", Expression: "false"}, }, vars: map[string]any{}, @@ -1199,7 +1198,7 @@ func TestEvaluateMatchConditions(t *testing.T) { }, { name: "multiple conditions - all match", - conditions: []admissionv1beta1.MatchCondition{ + conditions: []admissionregv1.MatchCondition{ {Name: "test1", Expression: "true"}, {Name: "test2", Expression: "true"}, }, @@ -1209,7 +1208,7 @@ func TestEvaluateMatchConditions(t *testing.T) { }, { name: "multiple conditions - first fails", - conditions: []admissionv1beta1.MatchCondition{ + conditions: []admissionregv1.MatchCondition{ {Name: "test1", Expression: "false"}, {Name: "test2", Expression: "true"}, }, @@ -1219,7 +1218,7 @@ func TestEvaluateMatchConditions(t *testing.T) { }, { name: "condition with variables", - conditions: []admissionv1beta1.MatchCondition{ + conditions: []admissionregv1.MatchCondition{ {Name: "test", Expression: `object.namespace == "default"`}, }, vars: map[string]any{"object": map[string]any{"namespace": "default"}}, @@ -1228,7 +1227,7 @@ func TestEvaluateMatchConditions(t *testing.T) { }, { name: "invalid expression", - conditions: []admissionv1beta1.MatchCondition{ + conditions: []admissionregv1.MatchCondition{ {Name: "test", Expression: "not valid cel"}, }, vars: map[string]any{}, @@ -1242,7 +1241,7 @@ func TestEvaluateMatchConditions(t *testing.T) { t.Run(tc.name, func(t *testing.T) { t.Parallel() - got, err := evaluator.evaluateMatchConditionsV1Beta1(tc.conditions, tc.vars) + got, err := evaluator.evaluateMatchConditions(tc.conditions, tc.vars) if (err != nil) != tc.wantErr { t.Errorf("evaluateMatchConditions() error = %v, wantErr %v", err, tc.wantErr) @@ -1557,8 +1556,8 @@ func TestEvaluator_EvaluateTest(t *testing.T) { tests := []struct { name string - mutatingPolicy *admissionv1beta1.MutatingAdmissionPolicy - mutatingBinding *admissionv1beta1.MutatingAdmissionPolicyBinding + mutatingPolicy *admissionregv1.MutatingAdmissionPolicy + mutatingBinding *admissionregv1.MutatingAdmissionPolicyBinding validatingPolicy *admissionregv1.ValidatingAdmissionPolicy validatingBinding *admissionregv1.ValidatingAdmissionPolicyBinding testCase MockTestCase @@ -1631,12 +1630,12 @@ func TestEvaluator_EvaluateTest(t *testing.T) { }, { name: "Mutating Policy Success", - mutatingPolicy: &admissionv1beta1.MutatingAdmissionPolicy{ - Spec: admissionv1beta1.MutatingAdmissionPolicySpec{ - Mutations: []admissionv1beta1.Mutation{ + mutatingPolicy: &admissionregv1.MutatingAdmissionPolicy{ + Spec: admissionregv1.MutatingAdmissionPolicySpec{ + Mutations: []admissionregv1.Mutation{ { - PatchType: admissionv1beta1.PatchTypeJSONPatch, - JSONPatch: &admissionv1beta1.JSONPatch{ + PatchType: admissionregv1.PatchTypeJSONPatch, + JSONPatch: &admissionregv1.JSONPatch{ Expression: `[JSONPatch{op: "add", path: "/metadata/labels", value: {"foo": "bar"}}]`, }, }, @@ -1664,12 +1663,12 @@ func TestEvaluator_EvaluateTest(t *testing.T) { }, { name: "Mutating Policy - Expected Object Mismatch", - mutatingPolicy: &admissionv1beta1.MutatingAdmissionPolicy{ - Spec: admissionv1beta1.MutatingAdmissionPolicySpec{ - Mutations: []admissionv1beta1.Mutation{ + mutatingPolicy: &admissionregv1.MutatingAdmissionPolicy{ + Spec: admissionregv1.MutatingAdmissionPolicySpec{ + Mutations: []admissionregv1.Mutation{ { - PatchType: admissionv1beta1.PatchTypeJSONPatch, - JSONPatch: &admissionv1beta1.JSONPatch{ + PatchType: admissionregv1.PatchTypeJSONPatch, + JSONPatch: &admissionregv1.JSONPatch{ Expression: `[JSONPatch{op: "add", path: "/metadata/labels", value: {"foo": "bar"}}]`, }, }, @@ -1803,12 +1802,12 @@ func TestEvaluator_EvaluateTest(t *testing.T) { }, { name: "Mutating Policy Evaluation Error", - mutatingPolicy: &admissionv1beta1.MutatingAdmissionPolicy{ - Spec: admissionv1beta1.MutatingAdmissionPolicySpec{ - Mutations: []admissionv1beta1.Mutation{ + mutatingPolicy: &admissionregv1.MutatingAdmissionPolicy{ + Spec: admissionregv1.MutatingAdmissionPolicySpec{ + Mutations: []admissionregv1.Mutation{ { - PatchType: admissionv1beta1.PatchTypeJSONPatch, - JSONPatch: &admissionv1beta1.JSONPatch{ + PatchType: admissionregv1.PatchTypeJSONPatch, + JSONPatch: &admissionregv1.JSONPatch{ Expression: `invalid_syntax(`, // Invalid CEL }, }, diff --git a/internal/loader/errors.go b/internal/loader/errors.go index 5a46d75..b04cb0d 100644 --- a/internal/loader/errors.go +++ b/internal/loader/errors.go @@ -3,13 +3,15 @@ package loader import "errors" var ( - ErrCreateRequiresObject = errors.New("operation CREATE requires object data") - ErrDeleteRequiresOldObject = errors.New("operation DELETE requires oldObject data") - ErrUpdateRequiresObject = errors.New("operation UPDATE requires object data") - ErrUpdateRequiresOldObject = errors.New("operation UPDATE requires oldObject data") - ErrUnknownOperation = errors.New("unknown operation") - ErrCannotInferOperation = errors.New("cannot infer operation") - ErrUnknownFileType = errors.New("unknown file type") - ErrUnsupportedV1Beta1Policy = errors.New("ValidatingAdmissionPolicy v1beta1 not supported, use v1") - ErrUnsupportedV1Beta1Binding = errors.New("ValidatingAdmissionPolicyBinding v1beta1 not supported, use v1") + ErrCreateRequiresObject = errors.New("operation CREATE requires object data") + ErrDeleteRequiresOldObject = errors.New("operation DELETE requires oldObject data") + ErrUpdateRequiresObject = errors.New("operation UPDATE requires object data") + ErrUpdateRequiresOldObject = errors.New("operation UPDATE requires oldObject data") + ErrUnknownOperation = errors.New("unknown operation") + ErrCannotInferOperation = errors.New("cannot infer operation") + ErrUnknownFileType = errors.New("unknown file type") + ErrUnsupportedV1Beta1Policy = errors.New("ValidatingAdmissionPolicy v1beta1 not supported, use v1") + ErrUnsupportedV1Beta1Binding = errors.New("ValidatingAdmissionPolicyBinding v1beta1 not supported, use v1") + ErrUnsupportedV1Beta1MutPolicy = errors.New("MutatingAdmissionPolicy v1beta1 not supported, use v1") + ErrUnsupportedV1Beta1MutBinding = errors.New("MutatingAdmissionPolicyBinding v1beta1 not supported, use v1") ) diff --git a/internal/loader/policy.go b/internal/loader/policy.go index 9a83939..68edfe3 100644 --- a/internal/loader/policy.go +++ b/internal/loader/policy.go @@ -17,6 +17,8 @@ import ( "k8s.io/client-go/kubernetes/scheme" ) +// NOTE: admissionv1beta1 is still imported to detect and reject v1beta1 resources with clear errors. + // reuse a single universal deserializer across calls. // //nolint:gochecknoglobals // Used across the package for deserialization @@ -25,8 +27,8 @@ var universalDeserializer = serializer.NewCodecFactory(scheme.Scheme).UniversalD // PolicySet contains policies and bindings loaded from a directory. type PolicySet struct { Dir string - MutatingPolicies []*admissionv1beta1.MutatingAdmissionPolicy - MutatingBindings []*admissionv1beta1.MutatingAdmissionPolicyBinding + MutatingPolicies []*admissionv1.MutatingAdmissionPolicy + MutatingBindings []*admissionv1.MutatingAdmissionPolicyBinding ValidatingPolicies []*admissionv1.ValidatingAdmissionPolicy ValidatingBindings []*admissionv1.ValidatingAdmissionPolicyBinding } @@ -128,9 +130,9 @@ func (ps *PolicySet) loadDocuments(yamlBytes []byte, filePath string) error { } switch o := obj.(type) { - case *admissionv1beta1.MutatingAdmissionPolicy: + case *admissionv1.MutatingAdmissionPolicy: ps.MutatingPolicies = append(ps.MutatingPolicies, o) - case *admissionv1beta1.MutatingAdmissionPolicyBinding: + case *admissionv1.MutatingAdmissionPolicyBinding: ps.MutatingBindings = append(ps.MutatingBindings, o) case *admissionv1.ValidatingAdmissionPolicy: ps.ValidatingPolicies = append(ps.ValidatingPolicies, o) @@ -140,6 +142,10 @@ func (ps *PolicySet) loadDocuments(yamlBytes []byte, filePath string) error { return fmt.Errorf("%w: document %d in %s", ErrUnsupportedV1Beta1Policy, docNum, filePath) case *admissionv1beta1.ValidatingAdmissionPolicyBinding: return fmt.Errorf("%w: document %d in %s", ErrUnsupportedV1Beta1Binding, docNum, filePath) + case *admissionv1beta1.MutatingAdmissionPolicy: + return fmt.Errorf("%w: document %d in %s", ErrUnsupportedV1Beta1MutPolicy, docNum, filePath) + case *admissionv1beta1.MutatingAdmissionPolicyBinding: + return fmt.Errorf("%w: document %d in %s", ErrUnsupportedV1Beta1MutBinding, docNum, filePath) } docNum++ diff --git a/internal/loader/suite.go b/internal/loader/suite.go index e3712fc..368c7e1 100644 --- a/internal/loader/suite.go +++ b/internal/loader/suite.go @@ -10,7 +10,6 @@ import ( admissionv1 "k8s.io/api/admission/v1" admissionregv1 "k8s.io/api/admissionregistration/v1" - admissionv1beta1 "k8s.io/api/admissionregistration/v1beta1" authenticationv1 "k8s.io/api/authentication/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apiserver/pkg/authentication/user" @@ -22,8 +21,8 @@ import ( type TestSuite struct { Name string Path string - MutatingPolicies []*admissionv1beta1.MutatingAdmissionPolicy - MutatingBindings []*admissionv1beta1.MutatingAdmissionPolicyBinding + MutatingPolicies []*admissionregv1.MutatingAdmissionPolicy + MutatingBindings []*admissionregv1.MutatingAdmissionPolicyBinding ValidatingPolicies []*admissionregv1.ValidatingAdmissionPolicy ValidatingBindings []*admissionregv1.ValidatingAdmissionPolicyBinding Tests []*TestCase diff --git a/internal/loader/testdata/mixed-types/policies.yaml b/internal/loader/testdata/mixed-types/policies.yaml index 8b52d15..db34c73 100644 --- a/internal/loader/testdata/mixed-types/policies.yaml +++ b/internal/loader/testdata/mixed-types/policies.yaml @@ -1,4 +1,4 @@ -apiVersion: admissionregistration.k8s.io/v1beta1 +apiVersion: admissionregistration.k8s.io/v1 kind: MutatingAdmissionPolicy metadata: name: mutating-policy @@ -12,7 +12,7 @@ metadata: spec: failurePolicy: Fail --- -apiVersion: admissionregistration.k8s.io/v1beta1 +apiVersion: admissionregistration.k8s.io/v1 kind: MutatingAdmissionPolicyBinding metadata: name: mutating-binding diff --git a/internal/loader/testdata/multiple-policies/bindings.yaml b/internal/loader/testdata/multiple-policies/bindings.yaml index de8833b..9df2ae5 100644 --- a/internal/loader/testdata/multiple-policies/bindings.yaml +++ b/internal/loader/testdata/multiple-policies/bindings.yaml @@ -1,11 +1,11 @@ -apiVersion: admissionregistration.k8s.io/v1beta1 +apiVersion: admissionregistration.k8s.io/v1 kind: MutatingAdmissionPolicyBinding metadata: name: binding-a spec: policyName: policy-a --- -apiVersion: admissionregistration.k8s.io/v1beta1 +apiVersion: admissionregistration.k8s.io/v1 kind: MutatingAdmissionPolicyBinding metadata: name: binding-b diff --git a/internal/loader/testdata/multiple-policies/policies.yaml b/internal/loader/testdata/multiple-policies/policies.yaml index a4c61ae..e95254a 100644 --- a/internal/loader/testdata/multiple-policies/policies.yaml +++ b/internal/loader/testdata/multiple-policies/policies.yaml @@ -1,11 +1,11 @@ -apiVersion: admissionregistration.k8s.io/v1beta1 +apiVersion: admissionregistration.k8s.io/v1 kind: MutatingAdmissionPolicy metadata: name: policy-a spec: failurePolicy: Fail --- -apiVersion: admissionregistration.k8s.io/v1beta1 +apiVersion: admissionregistration.k8s.io/v1 kind: MutatingAdmissionPolicy metadata: name: policy-b diff --git a/internal/loader/testdata/separate-files/binding.yaml b/internal/loader/testdata/separate-files/binding.yaml index 25c96a4..9526fab 100644 --- a/internal/loader/testdata/separate-files/binding.yaml +++ b/internal/loader/testdata/separate-files/binding.yaml @@ -1,4 +1,4 @@ -apiVersion: admissionregistration.k8s.io/v1beta1 +apiVersion: admissionregistration.k8s.io/v1 kind: MutatingAdmissionPolicyBinding metadata: name: separate-binding diff --git a/internal/loader/testdata/separate-files/policy.yaml b/internal/loader/testdata/separate-files/policy.yaml index 3fcfbfb..2d19246 100644 --- a/internal/loader/testdata/separate-files/policy.yaml +++ b/internal/loader/testdata/separate-files/policy.yaml @@ -1,4 +1,4 @@ -apiVersion: admissionregistration.k8s.io/v1beta1 +apiVersion: admissionregistration.k8s.io/v1 kind: MutatingAdmissionPolicy metadata: name: separate-policy diff --git a/internal/loader/testdata/single-file-policy-binding/policy.yaml b/internal/loader/testdata/single-file-policy-binding/policy.yaml index 99ac968..e8e2fc4 100644 --- a/internal/loader/testdata/single-file-policy-binding/policy.yaml +++ b/internal/loader/testdata/single-file-policy-binding/policy.yaml @@ -1,4 +1,4 @@ -apiVersion: admissionregistration.k8s.io/v1beta1 +apiVersion: admissionregistration.k8s.io/v1 kind: MutatingAdmissionPolicy metadata: name: test-policy-1 @@ -11,7 +11,7 @@ spec: operations: ["CREATE"] resources: ["pods"] --- -apiVersion: admissionregistration.k8s.io/v1beta1 +apiVersion: admissionregistration.k8s.io/v1 kind: MutatingAdmissionPolicyBinding metadata: name: test-binding-1 diff --git a/main.go b/main.go index 0d39039..fe43eb2 100644 --- a/main.go +++ b/main.go @@ -8,7 +8,6 @@ import ( "runtime/debug" admissionregv1 "k8s.io/api/admissionregistration/v1" - admissionv1beta1 "k8s.io/api/admissionregistration/v1beta1" "github.com/zemanlx/kat/internal/evaluator" "github.com/zemanlx/kat/internal/loader" @@ -154,10 +153,10 @@ func runSuite(eval *evaluator.Evaluator, rep *reporter.Reporter, suite *loader.T return nil } -func findPolicies(suite *loader.TestSuite, policyName string) (*admissionv1beta1.MutatingAdmissionPolicy, *admissionv1beta1.MutatingAdmissionPolicyBinding, *admissionregv1.ValidatingAdmissionPolicy, *admissionregv1.ValidatingAdmissionPolicyBinding) { +func findPolicies(suite *loader.TestSuite, policyName string) (*admissionregv1.MutatingAdmissionPolicy, *admissionregv1.MutatingAdmissionPolicyBinding, *admissionregv1.ValidatingAdmissionPolicy, *admissionregv1.ValidatingAdmissionPolicyBinding) { var ( - mutatingPolicy *admissionv1beta1.MutatingAdmissionPolicy - mutatingBinding *admissionv1beta1.MutatingAdmissionPolicyBinding + mutatingPolicy *admissionregv1.MutatingAdmissionPolicy + mutatingBinding *admissionregv1.MutatingAdmissionPolicyBinding validatingPolicy *admissionregv1.ValidatingAdmissionPolicy validatingBinding *admissionregv1.ValidatingAdmissionPolicyBinding ) diff --git a/test-policies-fail/add-default-labels/binding.yaml b/test-policies-fail/add-default-labels/binding.yaml index c162a29..4ce6aa8 100644 --- a/test-policies-fail/add-default-labels/binding.yaml +++ b/test-policies-fail/add-default-labels/binding.yaml @@ -1,4 +1,4 @@ -apiVersion: admissionregistration.k8s.io/v1beta1 +apiVersion: admissionregistration.k8s.io/v1 kind: MutatingAdmissionPolicyBinding metadata: name: add-default-labels-binding diff --git a/test-policies-fail/add-default-labels/policy.yaml b/test-policies-fail/add-default-labels/policy.yaml index 6d488f0..ee0b65c 100644 --- a/test-policies-fail/add-default-labels/policy.yaml +++ b/test-policies-fail/add-default-labels/policy.yaml @@ -1,4 +1,4 @@ -apiVersion: admissionregistration.k8s.io/v1beta1 +apiVersion: admissionregistration.k8s.io/v1 kind: MutatingAdmissionPolicy metadata: name: add-default-labels diff --git a/test-policies-fail/mutating-with-binding/binding.yaml b/test-policies-fail/mutating-with-binding/binding.yaml index af3d7ee..548b135 100644 --- a/test-policies-fail/mutating-with-binding/binding.yaml +++ b/test-policies-fail/mutating-with-binding/binding.yaml @@ -1,4 +1,4 @@ -apiVersion: admissionregistration.k8s.io/v1beta1 +apiVersion: admissionregistration.k8s.io/v1 kind: MutatingAdmissionPolicyBinding metadata: name: add-label-from-params-binding diff --git a/test-policies-fail/mutating-with-binding/policy.yaml b/test-policies-fail/mutating-with-binding/policy.yaml index 8ace2de..1b486ab 100644 --- a/test-policies-fail/mutating-with-binding/policy.yaml +++ b/test-policies-fail/mutating-with-binding/policy.yaml @@ -1,4 +1,4 @@ -apiVersion: admissionregistration.k8s.io/v1beta1 +apiVersion: admissionregistration.k8s.io/v1 kind: MutatingAdmissionPolicy metadata: name: add-label-from-params diff --git a/test-policies-pass/mutating/add-default-labels/binding.yaml b/test-policies-pass/mutating/add-default-labels/binding.yaml index c162a29..4ce6aa8 100644 --- a/test-policies-pass/mutating/add-default-labels/binding.yaml +++ b/test-policies-pass/mutating/add-default-labels/binding.yaml @@ -1,4 +1,4 @@ -apiVersion: admissionregistration.k8s.io/v1beta1 +apiVersion: admissionregistration.k8s.io/v1 kind: MutatingAdmissionPolicyBinding metadata: name: add-default-labels-binding diff --git a/test-policies-pass/mutating/add-default-labels/policy.yaml b/test-policies-pass/mutating/add-default-labels/policy.yaml index 4c20577..2a007c3 100644 --- a/test-policies-pass/mutating/add-default-labels/policy.yaml +++ b/test-policies-pass/mutating/add-default-labels/policy.yaml @@ -1,4 +1,4 @@ -apiVersion: admissionregistration.k8s.io/v1beta1 +apiVersion: admissionregistration.k8s.io/v1 kind: MutatingAdmissionPolicy metadata: name: add-default-labels diff --git a/test-policies-pass/mutating/mutating-with-binding/binding.yaml b/test-policies-pass/mutating/mutating-with-binding/binding.yaml index af3d7ee..548b135 100644 --- a/test-policies-pass/mutating/mutating-with-binding/binding.yaml +++ b/test-policies-pass/mutating/mutating-with-binding/binding.yaml @@ -1,4 +1,4 @@ -apiVersion: admissionregistration.k8s.io/v1beta1 +apiVersion: admissionregistration.k8s.io/v1 kind: MutatingAdmissionPolicyBinding metadata: name: add-label-from-params-binding diff --git a/test-policies-pass/mutating/mutating-with-binding/policy.yaml b/test-policies-pass/mutating/mutating-with-binding/policy.yaml index 8ace2de..1b486ab 100644 --- a/test-policies-pass/mutating/mutating-with-binding/policy.yaml +++ b/test-policies-pass/mutating/mutating-with-binding/policy.yaml @@ -1,4 +1,4 @@ -apiVersion: admissionregistration.k8s.io/v1beta1 +apiVersion: admissionregistration.k8s.io/v1 kind: MutatingAdmissionPolicy metadata: name: add-label-from-params diff --git a/test-policies-pass/mutating/namespace-selector-binding-mutating/binding.yaml b/test-policies-pass/mutating/namespace-selector-binding-mutating/binding.yaml index 0a0a1f7..21775ca 100644 --- a/test-policies-pass/mutating/namespace-selector-binding-mutating/binding.yaml +++ b/test-policies-pass/mutating/namespace-selector-binding-mutating/binding.yaml @@ -1,4 +1,4 @@ -apiVersion: admissionregistration.k8s.io/v1beta1 +apiVersion: admissionregistration.k8s.io/v1 kind: MutatingAdmissionPolicyBinding metadata: name: namespace-selector-binding-mutating-test-binding diff --git a/test-policies-pass/mutating/namespace-selector-binding-mutating/policy.yaml b/test-policies-pass/mutating/namespace-selector-binding-mutating/policy.yaml index 7abd493..7ef10fb 100644 --- a/test-policies-pass/mutating/namespace-selector-binding-mutating/policy.yaml +++ b/test-policies-pass/mutating/namespace-selector-binding-mutating/policy.yaml @@ -1,4 +1,4 @@ -apiVersion: admissionregistration.k8s.io/v1beta1 +apiVersion: admissionregistration.k8s.io/v1 kind: MutatingAdmissionPolicy metadata: name: namespace-selector-binding-mutating-test diff --git a/test-policies-pass/mutating/sidecar-injection/binding.yaml b/test-policies-pass/mutating/sidecar-injection/binding.yaml index 36ba4c9..a6b3824 100644 --- a/test-policies-pass/mutating/sidecar-injection/binding.yaml +++ b/test-policies-pass/mutating/sidecar-injection/binding.yaml @@ -1,4 +1,4 @@ -apiVersion: admissionregistration.k8s.io/v1beta1 +apiVersion: admissionregistration.k8s.io/v1 kind: MutatingAdmissionPolicyBinding metadata: name: sidecar-injection-binding diff --git a/test-policies-pass/mutating/sidecar-injection/policy.yaml b/test-policies-pass/mutating/sidecar-injection/policy.yaml index d0db264..75121e3 100644 --- a/test-policies-pass/mutating/sidecar-injection/policy.yaml +++ b/test-policies-pass/mutating/sidecar-injection/policy.yaml @@ -1,4 +1,4 @@ -apiVersion: admissionregistration.k8s.io/v1beta1 +apiVersion: admissionregistration.k8s.io/v1 kind: MutatingAdmissionPolicy metadata: name: sidecar-injection