diff --git a/.github/workflows/workflow.yaml b/.github/workflows/workflow.yaml index 714892de9f1..e389de6ba7b 100644 --- a/.github/workflows/workflow.yaml +++ b/.github/workflows/workflow.yaml @@ -50,7 +50,7 @@ jobs: uses: golangci/golangci-lint-action@3cfe3a4abbb849e10058ce4af15d205b6da42804 # v4.0.0 with: # version of golangci-lint to use in form of v1.2 or v1.2.3 or `latest` to use the latest version - version: v1.54.2 + version: v1.55.2 test: name: "Unit test" @@ -178,7 +178,7 @@ jobs: IMG=gatekeeper-e2e:latest \ USE_LOCAL_IMG=true - make test-e2e + make test-e2e KUBERNETES_VERSION=${{ matrix.KUBERNETES_VERSION }} ENABLE_VAP_TESTS=1 - name: Save logs if: ${{ always() }} @@ -219,6 +219,7 @@ jobs: make e2e-bootstrap - name: Run e2e + # TODO(ritazh): add helm chart values for vap feature before alpha release run: | make docker-buildx \ IMG=gatekeeper-e2e:latest \ @@ -288,7 +289,7 @@ jobs: make e2e-bootstrap - name: Run e2e - run: | + run: | # TODO(ritazh): set ENABLE_VAP_TESTS=1 before alpha release make docker-buildx \ IMG=gatekeeper-e2e:latest diff --git a/Makefile b/Makefile index 48b7b246022..cdb45b25f70 100644 --- a/Makefile +++ b/Makefile @@ -23,6 +23,7 @@ KUSTOMIZE_VERSION ?= 3.8.9 BATS_VERSION ?= 1.8.2 ORAS_VERSION ?= 0.16.0 BATS_TESTS_FILE ?= test/bats/test.bats +KIND_CLUSTER_FILE ?= test/bats/tests/kindcluster.yml HELM_VERSION ?= 3.7.2 NODE_VERSION ?= 16-bullseye-slim YQ_VERSION ?= 4.30.6 @@ -32,7 +33,7 @@ GATEKEEPER_NAMESPACE ?= gatekeeper-system # When updating this, make sure to update the corresponding action in # workflow.yaml -GOLANGCI_LINT_VERSION := v1.51.2 +GOLANGCI_LINT_VERSION := v1.55.2 # Detects the location of the user golangci-lint cache. GOLANGCI_LINT_CACHE := $(shell pwd)/.tmp/golangci-lint @@ -70,6 +71,8 @@ MANAGER_IMAGE_PATCH := "apiVersion: apps/v1\ \n - --disable-opa-builtin=http.send\ \n - --log-mutations\ \n - --mutation-annotations\ +\n - --vap-enforcement=GATEKEEPER_DEFAULT\ +\n - --experimental-enable-k8s-native-validation\ \n---\ \napiVersion: apps/v1\ \nkind: Deployment\ @@ -89,7 +92,10 @@ MANAGER_IMAGE_PATCH := "apiVersion: apps/v1\ \n - --operation=status\ \n - --operation=mutation-status\ \n - --audit-chunk-size=500\ -\n - --logtostderr" +\n - --logtostderr\ +\n - --vap-enforcement=GATEKEEPER_DEFAULT\ +\n - --experimental-enable-k8s-native-validation\ +\n" # Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) ifeq (,$(shell go env GOBIN)) @@ -160,8 +166,10 @@ KIND_NODE_VERSION := kindest/node:v$(KUBERNETES_VERSION) e2e-bootstrap: e2e-dependencies # Check for existing kind cluster if [ $$(${GITHUB_WORKSPACE}/bin/kind get clusters) ]; then ${GITHUB_WORKSPACE}/bin/kind delete cluster; fi + # Create a new kind cluster - TERM=dumb ${GITHUB_WORKSPACE}/bin/kind create cluster --image $(KIND_NODE_VERSION) --wait 5m + # TODO(ritazh): remove KIND_CLUSTER_FILE when vap feature is GA + if [ $$(echo $(KUBERNETES_VERSION) | cut -d'.' -f2) -lt 28 ]; then ${GITHUB_WORKSPACE}/bin/kind create cluster --image $(KIND_NODE_VERSION) --wait 5m; else ${GITHUB_WORKSPACE}/bin/kind create cluster --config $(KIND_CLUSTER_FILE) --image $(KIND_NODE_VERSION) --wait 5m; fi e2e-build-load-image: docker-buildx e2e-build-load-externaldata-image kind load docker-image --name kind ${IMG} ${CRD_IMG} diff --git a/apis/status/v1beta1/constraintpodstatus_types.go b/apis/status/v1beta1/constraintpodstatus_types.go index 250886b29a4..292a298d154 100644 --- a/apis/status/v1beta1/constraintpodstatus_types.go +++ b/apis/status/v1beta1/constraintpodstatus_types.go @@ -46,7 +46,7 @@ type ConstraintPodStatusStatus struct { ObservedGeneration int64 `json:"observedGeneration,omitempty"` } -// Error represents a single error caught while adding a constraint to OPA. +// Error represents a single error caught while adding a constraint to engine. type Error struct { Code string `json:"code"` Message string `json:"message"` diff --git a/cmd/build/helmify/main.go b/cmd/build/helmify/main.go index ea81d4772da..0b91174162c 100644 --- a/cmd/build/helmify/main.go +++ b/cmd/build/helmify/main.go @@ -21,7 +21,10 @@ var kindRegex = regexp.MustCompile(`(?m)^kind:[\s]+([\S]+)[\s]*$`) // use exactly two spaces to be sure we are capturing metadata.name. var nameRegex = regexp.MustCompile(`(?m)^ name:[\s]+([\S]+)[\s]*$`) -const DeploymentKind = "Deployment" +const ( + DeploymentKind = "Deployment" + end = "{{- end }}" +) func isRbacKind(str string) bool { rbacKinds := [4]string{"Role", "ClusterRole", "RoleBinding", "ClusterRoleBinding"} @@ -105,12 +108,12 @@ func (ks *kindSet) Write() error { fileName := fmt.Sprintf("%s-%s.yaml", strings.ToLower(name), strings.ToLower(kind)) if name == "validation.gatekeeper.sh" { - obj = "{{- if not .Values.disableValidatingWebhook }}\n" + obj + "{{- end }}\n" + obj = "{{- if not .Values.disableValidatingWebhook }}\n" + obj + end + "\n" fileName = fmt.Sprintf("gatekeeper-validating-webhook-configuration-%s.yaml", strings.ToLower(kind)) } if name == "mutation.gatekeeper.sh" { - obj = "{{- if not .Values.disableMutation }}\n" + obj + "{{- end }}\n" + obj = "{{- if not .Values.disableMutation }}\n" + obj + end + "\n" fileName = fmt.Sprintf("gatekeeper-mutating-webhook-configuration-%s.yaml", strings.ToLower(kind)) } @@ -121,7 +124,7 @@ func (ks *kindSet) Write() error { } if name == "gatekeeper-critical-pods" && kind == "ResourceQuota" { - obj = "{{- if .Values.resourceQuota }}\n" + obj + "{{- end }}\n" + obj = "{{- if .Values.resourceQuota }}\n" + obj + end + "\n" } if name == "gatekeeper-controller-manager" && kind == DeploymentKind { @@ -143,7 +146,7 @@ func (ks *kindSet) Write() error { } if isRbacKind(kind) { - obj = "{{- if .Values.rbac.create }}\n" + obj + "{{- end }}\n" + obj = "{{- if .Values.rbac.create }}\n" + obj + end + "\n" } if name == "gatekeeper-controller-manager" && kind == "PodDisruptionBudget" { diff --git a/config/crd/bases/status.gatekeeper.sh_constraintpodstatuses.yaml b/config/crd/bases/status.gatekeeper.sh_constraintpodstatuses.yaml index 3fc9402bfbf..fa7b9a1da46 100644 --- a/config/crd/bases/status.gatekeeper.sh_constraintpodstatuses.yaml +++ b/config/crd/bases/status.gatekeeper.sh_constraintpodstatuses.yaml @@ -46,7 +46,7 @@ spec: errors: items: description: Error represents a single error caught while adding - a constraint to OPA. + a constraint to engine. properties: code: type: string diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index cb1aaf143ae..a258338234b 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -32,6 +32,19 @@ rules: - patch - update - watch +- apiGroups: + - admissionregistration.k8s.io + resources: + - validatingadmissionpolicies + - validatingadmissionpolicybindings + verbs: + - create + - delete + - get + - list + - patch + - update + - watch - apiGroups: - apiextensions.k8s.io resources: diff --git a/demo/k8s-validating-admission-policy/k8srequiredlabels_template.yaml b/demo/k8s-validating-admission-policy/k8srequiredlabels_template.yaml index 01f7644f5ef..f75aac3b2a7 100644 --- a/demo/k8s-validating-admission-policy/k8srequiredlabels_template.yaml +++ b/demo/k8s-validating-admission-policy/k8srequiredlabels_template.yaml @@ -2,6 +2,8 @@ apiVersion: templates.gatekeeper.sh/v1 kind: ConstraintTemplate metadata: name: k8srequiredlabels + labels: + "gatekeeper.sh/use-vap": "yes" spec: crd: spec: @@ -29,7 +31,7 @@ spec: - engine: K8sNativeValidation source: validations: - - expression: "variables.params.labels.all(entry, has(object.metadata.labels) && entry.key in object.metadata.labels)" + - expression: '[object, oldObject].exists(obj, obj != null && has(obj.metadata) && variables.params.labels.all(entry, has(obj.metadata.labels) && entry.key in obj.metadata.labels))' messageExpression: '"missing required label, requires all of: " + variables.params.labels.map(entry, entry.key).join(", ")' - - expression: "!variables.params.labels.exists(entry, has(object.metadata.labels) && entry.key in object.metadata.labels && !string(object.metadata.labels[entry.key]).matches(string(entry.allowedRegex)))" + - expression: '[object, oldObject].exists(obj, obj != null && !variables.params.labels.exists(entry, has(obj.metadata.labels) && entry.key in obj.metadata.labels && !string(obj.metadata.labels[entry.key]).matches(string(entry.allowedRegex))))' message: "regex mismatch" diff --git a/demo/k8s-validating-admission-policy/owner_must_be_provided.yaml b/demo/k8s-validating-admission-policy/owner_must_be_provided.yaml index 806e9862ffc..b11da01ef41 100644 --- a/demo/k8s-validating-admission-policy/owner_must_be_provided.yaml +++ b/demo/k8s-validating-admission-policy/owner_must_be_provided.yaml @@ -2,6 +2,8 @@ apiVersion: constraints.gatekeeper.sh/v1beta1 kind: K8sRequiredLabels metadata: name: all-must-have-owner + labels: + "gatekeeper.sh/use-vap": "yes" spec: match: kinds: diff --git a/go.mod b/go.mod index adbbe8ac2fe..c1f3525a26f 100644 --- a/go.mod +++ b/go.mod @@ -13,9 +13,9 @@ require ( github.com/golang/protobuf v1.5.3 github.com/google/go-cmp v0.6.0 github.com/google/uuid v1.5.0 - github.com/onsi/gomega v1.30.0 + github.com/onsi/gomega v1.31.1 github.com/open-policy-agent/cert-controller v0.10.1 - github.com/open-policy-agent/frameworks/constraint v0.0.0-20240110234408-18fa1fc7dc06 + github.com/open-policy-agent/frameworks/constraint v0.0.0-20240219192228-76869f816908 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.18.0 github.com/spf13/cobra v1.8.0 @@ -30,7 +30,7 @@ require ( go.opentelemetry.io/otel/sdk/metric v1.19.0 go.uber.org/automaxprocs v1.5.3 go.uber.org/zap v1.26.0 - golang.org/x/net v0.20.0 + golang.org/x/net v0.21.0 golang.org/x/oauth2 v0.16.0 golang.org/x/sync v0.6.0 golang.org/x/time v0.5.0 @@ -138,10 +138,10 @@ require ( go.opentelemetry.io/proto/otlp v1.0.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/crypto v0.18.0 // indirect + golang.org/x/crypto v0.19.0 // indirect golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect - golang.org/x/sys v0.16.0 // indirect - golang.org/x/term v0.16.0 // indirect + golang.org/x/sys v0.17.0 // indirect + golang.org/x/term v0.17.0 // indirect golang.org/x/text v0.14.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect google.golang.org/api v0.160.0 // indirect diff --git a/go.sum b/go.sum index a24c722d789..c87e13e4c2f 100644 --- a/go.sum +++ b/go.sum @@ -286,14 +286,14 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY 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/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/onsi/ginkgo/v2 v2.14.0 h1:vSmGj2Z5YPb9JwCWT6z6ihcUvDhuXLc3sJiqd3jMKAY= -github.com/onsi/ginkgo/v2 v2.14.0/go.mod h1:JkUdW7JkN0V6rFvsHcJ478egV3XH9NxpD27Hal/PhZw= -github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= -github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= +github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY= +github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM= +github.com/onsi/gomega v1.31.1 h1:KYppCUK+bUgAZwHOu7EXVBKyQA6ILvOESHkn/tgoqvo= +github.com/onsi/gomega v1.31.1/go.mod h1:y40C95dwAD1Nz36SsEnxvfFe8FFfNxzI5eJ0EYGyAy0= github.com/open-policy-agent/cert-controller v0.10.1 h1:RXSYoyn8FdCenWecRP//UV5nbVfmstNpj4kHQFkvPK4= github.com/open-policy-agent/cert-controller v0.10.1/go.mod h1:4uRbBLY5DsPOog+a9pqk3JLxuuhrWsbUedQW65HcLTI= -github.com/open-policy-agent/frameworks/constraint v0.0.0-20240110234408-18fa1fc7dc06 h1:scXMWxph905CdmX5HkFJXipCtG+wT1ynxw31G9qSrMk= -github.com/open-policy-agent/frameworks/constraint v0.0.0-20240110234408-18fa1fc7dc06/go.mod h1:Gl2I/z5dxvTOwa/ANYGGOkUqE4M0CbQpln0Ia/7KVro= +github.com/open-policy-agent/frameworks/constraint v0.0.0-20240219192228-76869f816908 h1:VwTOJNE/PuNXjxsgG85d/lVrwYSFYQFDt95KEzGNS0M= +github.com/open-policy-agent/frameworks/constraint v0.0.0-20240219192228-76869f816908/go.mod h1:MoEB2MwxsQL+xUDG6WdIpJ6gU+gEQuiBre67F3C+p3I= github.com/open-policy-agent/opa v0.60.0 h1:ZPoPt4yeNs5UXCpd/P/btpSyR8CR0wfhVoh9BOwgJNs= github.com/open-policy-agent/opa v0.60.0/go.mod h1:aD5IK6AiLNYBjNXn7E02++yC8l4Z+bRDvgM6Ss0bBzA= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= @@ -426,8 +426,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= -golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA= golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA= @@ -455,8 +455,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= @@ -486,12 +486,12 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE= -golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= +golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= diff --git a/main.go b/main.go index e07e535f0c2..e609948bad7 100644 --- a/main.go +++ b/main.go @@ -46,6 +46,7 @@ import ( "github.com/open-policy-agent/gatekeeper/v3/pkg/cachemanager" "github.com/open-policy-agent/gatekeeper/v3/pkg/controller" "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/config/process" + "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/constraint" "github.com/open-policy-agent/gatekeeper/v3/pkg/expansion" "github.com/open-policy-agent/gatekeeper/v3/pkg/externaldata" "github.com/open-policy-agent/gatekeeper/v3/pkg/metrics" @@ -132,6 +133,7 @@ func init() { // +kubebuilder:scaffold:scheme flag.Var(disabledBuiltins, "disable-opa-builtin", "disable opa built-in function, this flag can be declared more than once.") + flag.Var(&constraint.VapEnforcement, "vap-enforcement", "control VAP resource generation. Allowed values are NONE: do not generate, GATEKEEPER_DEFAULT: do not generate unless label gatekeeper.sh/use-vap: yes is added to policy explicitly, VAP_DEFAULT: generate unless label gatekeeper.sh/use-vap: no is added to policy explicitly.") } func main() { diff --git a/manifest_staging/charts/gatekeeper/crds/constraintpodstatus-customresourcedefinition.yaml b/manifest_staging/charts/gatekeeper/crds/constraintpodstatus-customresourcedefinition.yaml index 230a541bb72..c1e3199057d 100644 --- a/manifest_staging/charts/gatekeeper/crds/constraintpodstatus-customresourcedefinition.yaml +++ b/manifest_staging/charts/gatekeeper/crds/constraintpodstatus-customresourcedefinition.yaml @@ -39,7 +39,7 @@ spec: type: boolean errors: items: - description: Error represents a single error caught while adding a constraint to OPA. + description: Error represents a single error caught while adding a constraint to engine. properties: code: type: string diff --git a/manifest_staging/charts/gatekeeper/templates/gatekeeper-manager-role-clusterrole.yaml b/manifest_staging/charts/gatekeeper/templates/gatekeeper-manager-role-clusterrole.yaml index 3e55923360c..2693455e989 100644 --- a/manifest_staging/charts/gatekeeper/templates/gatekeeper-manager-role-clusterrole.yaml +++ b/manifest_staging/charts/gatekeeper/templates/gatekeeper-manager-role-clusterrole.yaml @@ -38,6 +38,19 @@ rules: - patch - update - watch +- apiGroups: + - admissionregistration.k8s.io + resources: + - validatingadmissionpolicies + - validatingadmissionpolicybindings + verbs: + - create + - delete + - get + - list + - patch + - update + - watch - apiGroups: - apiextensions.k8s.io resources: diff --git a/manifest_staging/deploy/gatekeeper.yaml b/manifest_staging/deploy/gatekeeper.yaml index 39d4384ad04..4fba41b01e4 100644 --- a/manifest_staging/deploy/gatekeeper.yaml +++ b/manifest_staging/deploy/gatekeeper.yaml @@ -1829,7 +1829,7 @@ spec: type: boolean errors: items: - description: Error represents a single error caught while adding a constraint to OPA. + description: Error represents a single error caught while adding a constraint to engine. properties: code: type: string @@ -3496,6 +3496,19 @@ rules: - patch - update - watch +- apiGroups: + - admissionregistration.k8s.io + resources: + - validatingadmissionpolicies + - validatingadmissionpolicybindings + verbs: + - create + - delete + - get + - list + - patch + - update + - watch - apiGroups: - apiextensions.k8s.io resources: diff --git a/pkg/controller/config/config_controller_suite_test.go b/pkg/controller/config/config_controller_suite_test.go index de77416982f..4d44e00ac31 100644 --- a/pkg/controller/config/config_controller_suite_test.go +++ b/pkg/controller/config/config_controller_suite_test.go @@ -38,6 +38,11 @@ func TestMain(m *testing.M) { }, ErrorIfCRDPathMissing: true, } + ///TODO(ritazh): remove when vap is GAed in k/k + args := t.ControlPlane.GetAPIServer().Configure() + args.Append("runtime-config", "api/all=true") + args.Append("feature-gates", "ValidatingAdmissionPolicy=true") + if err := apis.AddToScheme(scheme.Scheme); err != nil { stdlog.Fatal(err) } diff --git a/pkg/controller/constraint/constants.go b/pkg/controller/constraint/constants.go new file mode 100644 index 00000000000..afe7edfb52f --- /dev/null +++ b/pkg/controller/constraint/constants.go @@ -0,0 +1,16 @@ +package constraint + +const ( + // VapGenerationLabel indicates opting in and out preference for generating VAP objects. + VapGenerationLabel = "gatekeeper.sh/use-vap" + // VapFlagNone: do not generate. + VapFlagNone = "NONE" + // VapFlagGatekeeperDefault: do not generate unless label gatekeeper.sh/use-vap: yes is added to policy explicitly. + VapFlagGatekeeperDefault = "GATEKEEPER_DEFAULT" + // VapFlagVapDefault: generate unless label gatekeeper.sh/use-vap: no is added to policy explicitly. + VapFlagVapDefault = "VAP_DEFAULT" + // no value. + No = "no" + // yes value. + Yes = "yes" +) diff --git a/pkg/controller/constraint/constraint_controller.go b/pkg/controller/constraint/constraint_controller.go index 36c3f315ccc..c0cefcab8ec 100644 --- a/pkg/controller/constraint/constraint_controller.go +++ b/pkg/controller/constraint/constraint_controller.go @@ -18,12 +18,15 @@ package constraint import ( "context" "errors" + "fmt" + "reflect" "strings" "sync" "github.com/go-logr/logr" + v1beta1 "github.com/open-policy-agent/frameworks/constraint/pkg/apis/templates/v1beta1" constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client" - "github.com/open-policy-agent/frameworks/constraint/pkg/core/constraints" + "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/k8scel/transform" constraintstatusv1beta1 "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1" "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/config/process" "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/constraintstatus" @@ -33,6 +36,7 @@ import ( "github.com/open-policy-agent/gatekeeper/v3/pkg/readiness" "github.com/open-policy-agent/gatekeeper/v3/pkg/util" "github.com/open-policy-agent/gatekeeper/v3/pkg/watch" + admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/meta" @@ -40,8 +44,12 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/kubernetes" + rest "k8s.io/client-go/rest" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/apiutil" "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/event" "sigs.k8s.io/controller-runtime/pkg/handler" logf "sigs.k8s.io/controller-runtime/pkg/log" @@ -50,7 +58,47 @@ import ( "sigs.k8s.io/controller-runtime/pkg/source" ) -var log = logf.Log.WithName("controller").WithValues(logging.Process, "constraint_controller") +var ( + log = logf.Log.V(logging.DebugLevel).WithName("controller").WithValues(logging.Process, "constraint_controller") + discoveryErr *apiutil.ErrResourceDiscoveryFailed +) + +var vapMux sync.RWMutex + +var VapAPIEnabled *bool + +var VapEnforcement VapFlagType + +// VapFlagType is the custom type for the vap-enforcement flag. +type VapFlagType string + +// Allowed values for VapFlagType. +var allowedVapFlagVals = []string{VapFlagNone, VapFlagGatekeeperDefault, VapFlagVapDefault} + +// String returns the string representation of the flag value. +func (v *VapFlagType) String() string { + return string(*v) +} + +// Set validates and sets the value for the VapFlagType. +func (v *VapFlagType) Set(value string) error { + for _, val := range allowedVapFlagVals { + if val == value { + *v = VapFlagType(value) + return nil + } + } + return fmt.Errorf("invalid value %s. Allowed values are %s, %s, %s", value, VapFlagNone, VapFlagGatekeeperDefault, VapFlagVapDefault) +} + +// setting defaults when not set; required for unit test. +func (v *VapFlagType) SetDefaultIfEmpty() { + if *v == "" { + *v = VapFlagType(VapFlagGatekeeperDefault) + VapAPIEnabled = new(bool) + *VapAPIEnabled = true + } +} type Adder struct { CFClient *constraintclient.Client @@ -228,6 +276,7 @@ func (r *ReconcileConstraint) Reconcile(ctx context.Context, request reconcile.R return reconcile.Result{}, nil } + generateVapBinding := false deleted := false instance := &unstructured.Unstructured{} instance.SetGroupVersionKind(gvk) @@ -251,6 +300,26 @@ func (r *ReconcileConstraint) Reconcile(ctx context.Context, request reconcile.R deleted = deleted || !instance.GetDeletionTimestamp().IsZero() + labels := instance.GetLabels() + log.Info("constraint resource", "labels", labels) + useVap, ok := labels[VapGenerationLabel] + if ok { + log.Info("constraint resource", "useVap", useVap) + } + // unless constraint vap label is false, default to parent + if useVap == No { + generateVapBinding = false + } else { + log.Info("constraint resource use-vap label is not no; will default to parent constraint template label") + parentCTUseVap, err := r.getCTVapLabel(ctx, instance.GetKind()) + if err != nil { + log.Error(err, "could not get parent constraint template object") + return reconcile.Result{}, err + } + log.Info("constraint resource", "parentCTUseVap", parentCTUseVap) + generateVapBinding = ShouldGenerateVap(parentCTUseVap) + log.Info("constraint resource", "generateVapBinding", generateVapBinding) + } constraintKey := strings.Join([]string{instance.GetKind(), instance.GetName()}, "/") enforcementAction, err := util.GetEnforcementAction(instance.Object) if err != nil { @@ -274,7 +343,82 @@ func (r *ReconcileConstraint) Reconcile(ctx context.Context, request reconcile.R status.Status.ConstraintUID = instance.GetUID() status.Status.ObservedGeneration = instance.GetGeneration() status.Status.Errors = nil - if c, err := r.cfClient.GetConstraint(instance); err != nil || !constraints.SemanticEqual(instance, c) { + + if c, err := r.cfClient.GetConstraint(instance); err != nil || !reflect.DeepEqual(instance, c) { + // generate vapbinding resources + if generateVapBinding && IsVapAPIEnabled() { + currentVapBinding := &admissionregistrationv1beta1.ValidatingAdmissionPolicyBinding{} + vapBindingName := fmt.Sprintf("gatekeeper-%s", instance.GetName()) + log.Info("check if vapbinding exists", "vapBindingName", vapBindingName) + if err := r.reader.Get(ctx, types.NamespacedName{Name: vapBindingName}, currentVapBinding); err != nil { + if !apierrors.IsNotFound(err) && !errors.As(err, &discoveryErr) && !meta.IsNoMatchError(err) { + return reconcile.Result{}, err + } + currentVapBinding = nil + } + newVapBinding := &admissionregistrationv1beta1.ValidatingAdmissionPolicyBinding{} + transformedVapBinding, err := transform.ConstraintToBinding(instance) + if err != nil { + status.Status.Errors = append(status.Status.Errors, constraintstatusv1beta1.Error{Message: err.Error()}) + if err2 := r.writer.Update(ctx, status); err2 != nil { + log.Error(err2, "could not report transform vapbinding error status") + } + return reconcile.Result{}, err + } + if currentVapBinding == nil { + newVapBinding = transformedVapBinding.DeepCopy() + } else { + newVapBinding = currentVapBinding.DeepCopy() + newVapBinding.Spec = transformedVapBinding.Spec + } + + if err := controllerutil.SetControllerReference(instance, newVapBinding, r.scheme); err != nil { + return reconcile.Result{}, err + } + + if currentVapBinding == nil { + log.Info("creating vapbinding") + if err := r.writer.Create(ctx, newVapBinding); err != nil { + status.Status.Errors = append(status.Status.Errors, constraintstatusv1beta1.Error{Message: err.Error()}) + if err2 := r.writer.Update(ctx, status); err2 != nil { + log.Error(err2, "could not report creating vapbinding error status") + } + return reconcile.Result{}, err + } + } else if !reflect.DeepEqual(currentVapBinding, newVapBinding) { + log.Info("updating vapbinding") + if err := r.writer.Update(ctx, newVapBinding); err != nil { + status.Status.Errors = append(status.Status.Errors, constraintstatusv1beta1.Error{Message: err.Error()}) + if err2 := r.writer.Update(ctx, status); err2 != nil { + log.Error(err2, "could not report update vapbinding error status") + } + return reconcile.Result{}, err + } + } + } + // do not generate vapbinding resources + // remove if exists + if !generateVapBinding && IsVapAPIEnabled() { + currentVapBinding := &admissionregistrationv1beta1.ValidatingAdmissionPolicyBinding{} + vapBindingName := fmt.Sprintf("gatekeeper-%s", instance.GetName()) + log.Info("check if vapbinding exists", "vapBindingName", vapBindingName) + if err := r.reader.Get(ctx, types.NamespacedName{Name: vapBindingName}, currentVapBinding); err != nil { + if !apierrors.IsNotFound(err) && !errors.As(err, &discoveryErr) && !meta.IsNoMatchError(err) { + return reconcile.Result{}, err + } + currentVapBinding = nil + } + if currentVapBinding != nil { + log.Info("deleting vapbinding") + if err := r.writer.Delete(ctx, currentVapBinding); err != nil { + status.Status.Errors = append(status.Status.Errors, constraintstatusv1beta1.Error{Message: err.Error()}) + if err2 := r.writer.Update(ctx, status); err2 != nil { + log.Error(err2, "could not report delete vapbinding error status") + } + return reconcile.Result{}, err + } + } + } if err := r.cacheConstraint(ctx, instance); err != nil { r.constraintsCache.addConstraintKey(constraintKey, tags{ enforcementAction: enforcementAction, @@ -411,6 +555,22 @@ func (r *ReconcileConstraint) cacheConstraint(ctx context.Context, instance *uns return nil } +func (r *ReconcileConstraint) getCTVapLabel(ctx context.Context, gvk string) (string, error) { + ct := &v1beta1.ConstraintTemplate{} + ctName := strings.ToLower(gvk) + log.Info("get parent constraint template and its labels", "ctName", ctName) + if err := r.reader.Get(ctx, types.NamespacedName{Name: ctName}, ct); err != nil { + return "", err + } + labels := ct.GetLabels() + log.Info("parent constraint template", "labels", labels) + useVap, ok := labels[VapGenerationLabel] + if !ok { + return "", nil + } + return useVap, nil +} + func NewConstraintsCache() *ConstraintsCache { return &ConstraintsCache{ cache: make(map[string]tags), @@ -456,3 +616,46 @@ func (c *ConstraintsCache) reportTotalConstraints(ctx context.Context, reporter } } } + +func ShouldGenerateVap(useVapLabel string) bool { + if VapEnforcement == VapFlagGatekeeperDefault { + return useVapLabel == Yes + } + if VapEnforcement == VapFlagVapDefault { + return useVapLabel != No + } + return false +} + +func IsVapAPIEnabled() bool { + vapMux.Lock() + defer vapMux.Unlock() + + if VapAPIEnabled != nil { + return *VapAPIEnabled + } + groupVersion := schema.GroupVersion{Group: "admissionregistration.k8s.io", Version: "v1beta1"} + config, err := rest.InClusterConfig() + if err != nil { + log.Info("IsVapAPIEnabled InClusterConfig", "error", err) + VapAPIEnabled = new(bool) + *VapAPIEnabled = false + return false + } + clientset, err := kubernetes.NewForConfig(config) + if err != nil { + log.Info("IsVapAPIEnabled NewForConfig", "error", err) + *VapAPIEnabled = false + return false + } + if _, err := clientset.Discovery().ServerResourcesForGroupVersion(groupVersion.String()); err != nil { + log.Info("IsVapAPIEnabled ServerResourcesForGroupVersion", "error", err) + VapAPIEnabled = new(bool) + *VapAPIEnabled = false + return false + } + log.Info("IsVapAPIEnabled true") + VapAPIEnabled = new(bool) + *VapAPIEnabled = true + return true +} diff --git a/pkg/controller/constrainttemplate/constrainttemplate_controller.go b/pkg/controller/constrainttemplate/constrainttemplate_controller.go index 3a737f317c0..e6ef7571f1b 100644 --- a/pkg/controller/constrainttemplate/constrainttemplate_controller.go +++ b/pkg/controller/constrainttemplate/constrainttemplate_controller.go @@ -17,12 +17,14 @@ package constrainttemplate import ( "context" + "errors" "fmt" "reflect" "time" "github.com/open-policy-agent/frameworks/constraint/pkg/apis/templates/v1beta1" constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client" + "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/k8scel/transform" "github.com/open-policy-agent/frameworks/constraint/pkg/core/templates" statusv1beta1 "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1" "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/constraint" @@ -35,13 +37,17 @@ import ( "github.com/open-policy-agent/gatekeeper/v3/pkg/util" "github.com/open-policy-agent/gatekeeper/v3/pkg/watch" errorpkg "github.com/pkg/errors" + admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1" corev1 "k8s.io/api/core/v1" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - "k8s.io/apimachinery/pkg/api/errors" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/apiutil" "sigs.k8s.io/controller-runtime/pkg/controller" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/event" @@ -56,7 +62,10 @@ const ( ctrlName = "constrainttemplate-controller" ) -var logger = log.Log.WithName("controller").WithValues("kind", "ConstraintTemplate", logging.Process, "constraint_template_controller") +var ( + logger = log.Log.V(logging.DebugLevel).WithName("controller").WithValues("kind", "ConstraintTemplate", logging.Process, "constraint_template_controller") + discoveryErr *apiutil.ErrResourceDiscoveryFailed +) var gvkConstraintTemplate = schema.GroupVersionKind{ Group: v1beta1.SchemeGroupVersion.Group, @@ -112,7 +121,8 @@ func (a *Adder) InjectGetPod(getPod func(context.Context) (*corev1.Pod, error)) // regEvents is the channel registered by Registrar to put the events in // cstrEvents and regEvents point to same event channel except for testing. func newReconciler(mgr manager.Manager, cfClient *constraintclient.Client, wm *watch.Manager, cs *watch.ControllerSwitch, tracker *readiness.Tracker, cstrEvents <-chan event.GenericEvent, regEvents chan<- event.GenericEvent, getPod func(context.Context) (*corev1.Pod, error)) (*ReconcileConstraintTemplate, error) { - // constraintsCache contains total number of constraints and shared mutex + constraint.VapEnforcement.SetDefaultIfEmpty() + // constraintsCache contains total number of constraints and shared mutex and vap label constraintsCache := constraint.NewConstraintsCache() w, err := wm.NewRegistrar(ctrlName, regEvents) @@ -125,6 +135,7 @@ func newReconciler(mgr manager.Manager, cfClient *constraintclient.Client, wm *w } // via the registrar below. + constraintAdder := constraint.Adder{ CFClient: cfClient, ConstraintsCache: constraintsCache, @@ -176,6 +187,7 @@ func newReconciler(mgr manager.Manager, cfClient *constraintclient.Client, wm *w metrics: r, tracker: tracker, getPod: getPod, + cstrEvents: regEvents, } if getPod == nil { @@ -237,8 +249,10 @@ type ReconcileConstraintTemplate struct { metrics *reporter tracker *readiness.Tracker getPod func(context.Context) (*corev1.Pod, error) + cstrEvents chan<- event.GenericEvent } +// +kubebuilder:rbac:groups=admissionregistration.k8s.io,resources=validatingadmissionpolicies;validatingadmissionpolicybindings,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=apiextensions.k8s.io,resources=customresourcedefinitions,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=templates.gatekeeper.sh,resources=constrainttemplates,verbs=get;list;watch;create;update;patch;delete // TODO(acpana): remove in 3.16 as per https://github.com/open-policy-agent/gatekeeper/issues/3084 @@ -266,11 +280,12 @@ func (r *ReconcileConstraintTemplate) Reconcile(ctx context.Context, request rec ct := &v1beta1.ConstraintTemplate{} err := r.Get(ctx, request.NamespacedName, ct) if err != nil { - if !errors.IsNotFound(err) { + if !apierrors.IsNotFound(err) { return reconcile.Result{}, err } deleted = true } + deleted = deleted || !ct.GetDeletionTimestamp().IsZero() if deleted { @@ -290,7 +305,8 @@ func (r *ReconcileConstraintTemplate) Reconcile(ctx context.Context, request rec logError(request.NamespacedName.Name) r.metrics.registry.add(request.NamespacedName, metrics.ErrorStatus) return reconcile.Result{}, err - } else if !result.Requeue { + } + if !result.Requeue { logAction(ct, deletedAction) r.metrics.registry.remove(request.NamespacedName) } @@ -326,7 +342,7 @@ func (r *ReconcileConstraintTemplate) Reconcile(ctx context.Context, request rec status.Status.Errors = append(status.Status.Errors, createErr) if updateErr := r.Update(ctx, status); updateErr != nil { - logger.Error(updateErr, "update error") + logger.Error(updateErr, "update status error") return reconcile.Result{Requeue: true}, nil } logError(request.NamespacedName.Name) @@ -353,7 +369,7 @@ func (r *ReconcileConstraintTemplate) Reconcile(ctx context.Context, request rec case err == nil: break - case errors.IsNotFound(err): + case apierrors.IsNotFound(err): action = createdAction currentCRD = nil @@ -364,12 +380,36 @@ func (r *ReconcileConstraintTemplate) Reconcile(ctx context.Context, request rec return reconcile.Result{}, err } - result, err := r.handleUpdate(ctx, ct, unversionedCT, proposedCRD, currentCRD, status) + generateVap := false + labels := ct.GetLabels() + logger.Info("constraint template resource", "labels", labels) + useVap, ok := labels[constraint.VapGenerationLabel] + if !ok { + logger.Info("constraint template resource does not have a label for use-vap; will default to flag behavior", "VapEnforcement", constraint.VapEnforcement) + generateVap = constraint.ShouldGenerateVap("") + } else { + logger.Info("constraint template resource", "useVap", useVap) + generateVap = constraint.ShouldGenerateVap(useVap) + if useVap != constraint.No && useVap != constraint.Yes { + labelErr := &v1beta1.CreateCRDError{Code: ErrCreateCode, Message: fmt.Sprintf("constraint template resource has an invalid value for %s, allowed values are yes and no", constraint.VapGenerationLabel)} + status.Status.Errors = append(status.Status.Errors, labelErr) + + if updateErr := r.Update(ctx, status); updateErr != nil { + logger.Error(updateErr, "update status error") + return reconcile.Result{Requeue: true}, nil + } + } + } + logger.Info("generateVap", "r.generateVap", generateVap) + + result, err := r.handleUpdate(ctx, ct, unversionedCT, proposedCRD, currentCRD, status, generateVap) if err != nil { - logger.Error(err, "update error") + logger.Error(err, "handle update error") logError(request.NamespacedName.Name) r.metrics.registry.add(request.NamespacedName, metrics.ErrorStatus) - } else if !result.Requeue { + return result, err + } + if !result.Requeue { logAction(ct, action) r.metrics.registry.add(request.NamespacedName, metrics.ActiveStatus) } @@ -395,15 +435,16 @@ func (r *ReconcileConstraintTemplate) handleUpdate( unversionedCT *templates.ConstraintTemplate, proposedCRD, currentCRD *apiextensionsv1.CustomResourceDefinition, status *statusv1beta1.ConstraintTemplatePodStatus, + generateVap bool, ) (reconcile.Result, error) { name := proposedCRD.GetName() logger := logger.WithValues("name", ct.GetName(), "crdName", name) - logger.Info("loading code into OPA") + logger.Info("loading code into rule engine") beginCompile := time.Now() // It's important that cfClient.AddTemplate() is called first. That way we can - // rely on a template's existence in OPA to know whether a watch needs + // rely on a template's existence in rule engine to know whether a watch needs // to be removed if _, err := r.cfClient.AddTemplate(ctx, unversionedCT); err != nil { if err := r.metrics.reportIngestDuration(ctx, metrics.ErrorStatus, time.Since(beginCompile)); err != nil { @@ -453,8 +494,89 @@ func (r *ReconcileConstraintTemplate) handleUpdate( logger.Error(err, "error adding template to watch registry") return reconcile.Result{}, err } + // generating vap resources + if generateVap && constraint.IsVapAPIEnabled() { + currentVap := &admissionregistrationv1beta1.ValidatingAdmissionPolicy{} + vapName := fmt.Sprintf("gatekeeper-%s", unversionedCT.GetName()) + logger.Info("check if vap exists", "vapName", vapName) + if err := r.Get(ctx, types.NamespacedName{Name: vapName}, currentVap); err != nil { + if !apierrors.IsNotFound(err) && !errors.As(err, &discoveryErr) && !meta.IsNoMatchError(err) { + return reconcile.Result{}, err + } + currentVap = nil + } + logger.Info("get vap", "vapName", vapName, "currentVap", currentVap) + newVap := &admissionregistrationv1beta1.ValidatingAdmissionPolicy{} + transformedVap, err := transform.TemplateToPolicyDefinition(unversionedCT) + if err != nil { + logger.Info("transform to vap error", "vapName", vapName, "error", err) + createErr := &v1beta1.CreateCRDError{Code: ErrCreateCode, Message: err.Error()} + status.Status.Errors = append(status.Status.Errors, createErr) + err := r.reportErrorOnCTStatus(ctx, ErrCreateCode, "Could not transform to vap object", status, err) + return reconcile.Result{}, err + } + if currentVap == nil { + newVap = transformedVap.DeepCopy() + } else { + newVap = currentVap.DeepCopy() + newVap.Spec = transformedVap.Spec + } + + if err := controllerutil.SetControllerReference(ct, newVap, r.scheme); err != nil { + return reconcile.Result{}, err + } + + if currentVap == nil { + logger.Info("creating vap", "vapName", vapName) + if err := r.Create(ctx, newVap); err != nil { + logger.Info("creating vap error", "vapName", vapName, "error", err) + createErr := &v1beta1.CreateCRDError{Code: ErrCreateCode, Message: err.Error()} + status.Status.Errors = append(status.Status.Errors, createErr) + err := r.reportErrorOnCTStatus(ctx, ErrCreateCode, "Could not create vap object", status, err) + return reconcile.Result{}, err + } + // after vap is created, trigger update event for all constraints + if err := r.triggerConstraintEvents(ctx, ct, status); err != nil { + return reconcile.Result{}, err + } + } else if !reflect.DeepEqual(currentVap, newVap) { + logger.Info("updating vap") + if err := r.Update(ctx, newVap); err != nil { + updateErr := &v1beta1.CreateCRDError{Code: ErrUpdateCode, Message: err.Error()} + status.Status.Errors = append(status.Status.Errors, updateErr) + err := r.reportErrorOnCTStatus(ctx, ErrUpdateCode, "Could not update vap object", status, err) + return reconcile.Result{}, err + } + } + } + // do not generate vap resources + // remove if exists + if !generateVap && constraint.IsVapAPIEnabled() { + currentVap := &admissionregistrationv1beta1.ValidatingAdmissionPolicy{} + vapName := fmt.Sprintf("gatekeeper-%s", unversionedCT.GetName()) + logger.Info("check if vap exists", "vapName", vapName) + if err := r.Get(ctx, types.NamespacedName{Name: vapName}, currentVap); err != nil { + if !apierrors.IsNotFound(err) && !errors.As(err, &discoveryErr) && !meta.IsNoMatchError(err) { + return reconcile.Result{}, err + } + currentVap = nil + } + if currentVap != nil { + logger.Info("deleting vap") + if err := r.Delete(ctx, currentVap); err != nil { + updateErr := &v1beta1.CreateCRDError{Code: ErrUpdateCode, Message: err.Error()} + status.Status.Errors = append(status.Status.Errors, updateErr) + err := r.reportErrorOnCTStatus(ctx, ErrUpdateCode, "Could not delete vap object", status, err) + return reconcile.Result{}, err + } + // after vap is deleted, trigger update event for all constraints + if err := r.triggerConstraintEvents(ctx, ct, status); err != nil { + return reconcile.Result{}, err + } + } + } if err := r.Update(ctx, status); err != nil { - logger.Error(err, "update error") + logger.Error(err, "update ct pod status error") return reconcile.Result{Requeue: true}, nil } return reconcile.Result{}, nil @@ -495,7 +617,7 @@ func (r *ReconcileConstraintTemplate) deleteAllStatus(ctx context.Context, ctNam statusObj.SetName(sName) statusObj.SetNamespace(util.GetNamespace()) if err := r.Delete(ctx, statusObj); err != nil { - if !errors.IsNotFound(err) { + if !apierrors.IsNotFound(err) { return err } } @@ -509,7 +631,7 @@ func (r *ReconcileConstraintTemplate) deleteAllStatus(ctx context.Context, ctNam } for index := range cstrStatusObjs.Items { if err := r.Delete(ctx, &cstrStatusObjs.Items[index]); err != nil { - if !errors.IsNotFound(err) { + if !apierrors.IsNotFound(err) { return err } } @@ -526,7 +648,7 @@ func (r *ReconcileConstraintTemplate) getOrCreatePodStatus(ctx context.Context, } key := types.NamespacedName{Name: sName, Namespace: util.GetNamespace()} if err := r.Get(ctx, key, statusObj); err != nil { - if !errors.IsNotFound(err) { + if !apierrors.IsNotFound(err) { return nil, err } } else { @@ -560,6 +682,41 @@ func (r *ReconcileConstraintTemplate) removeWatch(ctx context.Context, kind sche return r.statusWatcher.RemoveWatch(ctx, kind) } +func (r *ReconcileConstraintTemplate) listObjects(ctx context.Context, gvk schema.GroupVersionKind) ([]unstructured.Unstructured, error) { + list := &unstructured.UnstructuredList{ + Object: map[string]interface{}{}, + Items: []unstructured.Unstructured{}, + } + gvk.Kind += "List" + list.SetGroupVersionKind(gvk) + err := r.List(ctx, list) + if err != nil { + return nil, err + } + return list.Items, nil +} + +func (r *ReconcileConstraintTemplate) triggerConstraintEvents(ctx context.Context, ct *v1beta1.ConstraintTemplate, status *statusv1beta1.ConstraintTemplatePodStatus) error { + gvk := makeGvk(ct.Spec.CRD.Spec.Names.Kind) + logger.Info("list gvk objects", "gvk", gvk) + cstrObjs, err := r.listObjects(ctx, gvk) + if err != nil { + logger.Error(err, "get all constraints listObjects") + updateErr := &v1beta1.CreateCRDError{Code: ErrUpdateCode, Message: err.Error()} + status.Status.Errors = append(status.Status.Errors, updateErr) + err := r.reportErrorOnCTStatus(ctx, ErrUpdateCode, "Could not list all constraint objects", status, err) + return err + } + logger.Info("list gvk objects", "cstrObjs", cstrObjs) + for _, cstr := range cstrObjs { + c := cstr + logger.Info("triggering cstrEvent") + r.cstrEvents <- event.GenericEvent{Object: &c} + } + + return nil +} + type action string const ( diff --git a/pkg/controller/constrainttemplate/constrainttemplate_controller_test.go b/pkg/controller/constrainttemplate/constrainttemplate_controller_test.go index e9abc8dbd76..32072c717c6 100644 --- a/pkg/controller/constrainttemplate/constrainttemplate_controller_test.go +++ b/pkg/controller/constrainttemplate/constrainttemplate_controller_test.go @@ -25,8 +25,12 @@ import ( templatesv1 "github.com/open-policy-agent/frameworks/constraint/pkg/apis/templates/v1" "github.com/open-policy-agent/frameworks/constraint/pkg/apis/templates/v1beta1" constraintclient "github.com/open-policy-agent/frameworks/constraint/pkg/client" + "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/k8scel" + celSchema "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/k8scel/schema" "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/rego" + "github.com/open-policy-agent/frameworks/constraint/pkg/core/templates" statusv1beta1 "github.com/open-policy-agent/gatekeeper/v3/apis/status/v1beta1" + "github.com/open-policy-agent/gatekeeper/v3/pkg/controller/constraint" "github.com/open-policy-agent/gatekeeper/v3/pkg/fakes" "github.com/open-policy-agent/gatekeeper/v3/pkg/readiness" "github.com/open-policy-agent/gatekeeper/v3/pkg/target" @@ -36,6 +40,7 @@ import ( "github.com/open-policy-agent/gatekeeper/v3/test/testutils" "golang.org/x/net/context" admissionv1 "k8s.io/api/admission/v1" + admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1" corev1 "k8s.io/api/core/v1" "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" @@ -47,22 +52,30 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes" "k8s.io/client-go/util/retry" + "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/event" ) +const ( + DenyAll = "DenyAll" + denyall = "denyall" +) + func makeReconcileConstraintTemplate(suffix string) *v1beta1.ConstraintTemplate { return &v1beta1.ConstraintTemplate{ TypeMeta: metav1.TypeMeta{ Kind: "ConstraintTemplate", APIVersion: templatesv1.SchemeGroupVersion.String(), }, - ObjectMeta: metav1.ObjectMeta{Name: "denyall" + strings.ToLower(suffix)}, + ObjectMeta: metav1.ObjectMeta{ + Name: denyall + strings.ToLower(suffix), + }, Spec: v1beta1.ConstraintTemplateSpec{ CRD: v1beta1.CRD{ Spec: v1beta1.CRDSpec{ Names: v1beta1.Names{ - Kind: "DenyAll" + suffix, + Kind: DenyAll + suffix, }, }, }, @@ -82,6 +95,63 @@ violation[{"msg": "denied!"}] { } } +func makeReconcileConstraintTemplateForVap(suffix string, labels map[string]string) *v1beta1.ConstraintTemplate { + source := &celSchema.Source{ + FailurePolicy: ptr.To[string]("Fail"), + MatchConditions: []celSchema.MatchCondition{ + { + Name: "must_match_something", + Expression: "true == true", + }, + }, + Variables: []celSchema.Variable{ + { + Name: "my_variable", + Expression: "true", + }, + }, + Validations: []celSchema.Validation{ + { + Expression: "1 == 1", + Message: "some fallback message", + MessageExpression: `"some CEL string"`, + }, + }, + } + return &v1beta1.ConstraintTemplate{ + TypeMeta: metav1.TypeMeta{ + Kind: "ConstraintTemplate", + APIVersion: templatesv1.SchemeGroupVersion.String(), + }, + ObjectMeta: metav1.ObjectMeta{ + Name: denyall + strings.ToLower(suffix), + Labels: labels, + }, + Spec: v1beta1.ConstraintTemplateSpec{ + CRD: v1beta1.CRD{ + Spec: v1beta1.CRDSpec{ + Names: v1beta1.Names{ + Kind: DenyAll + suffix, + }, + }, + }, + Targets: []v1beta1.Target{ + { + Target: target.Name, + Code: []v1beta1.Code{ + { + Engine: "K8sNativeValidation", + Source: &templates.Anything{ + Value: source.MustToUnstructured(), + }, + }, + }, + }, + }, + }, + } +} + func crdKey(suffix string) types.NamespacedName { return types.NamespacedName{Name: fmt.Sprintf("denyall%s.constraints.gatekeeper.sh", strings.ToLower(suffix))} } @@ -117,8 +187,13 @@ func TestReconcile(t *testing.T) { if err != nil { t.Fatalf("unable to set up Driver: %v", err) } + // initialize K8sValidation + k8sDriver, err := k8scel.New() + if err != nil { + t.Fatalf("unable to set up K8s native driver: %v", err) + } - cfClient, err := constraintclient.NewClient(constraintclient.Targets(&target.K8sValidationTarget{}), constraintclient.Driver(driver)) + cfClient, err := constraintclient.NewClient(constraintclient.Targets(&target.K8sValidationTarget{}), constraintclient.Driver(driver), constraintclient.Driver(k8sDriver)) if err != nil { t.Fatalf("unable to set up constraint framework client: %s", err) } @@ -172,7 +247,7 @@ func TestReconcile(t *testing.T) { return err } for _, r := range rs.APIResources { - if r.Kind == "DenyAll"+suffix { + if r.Kind == DenyAll+suffix { return nil } } @@ -183,6 +258,129 @@ func TestReconcile(t *testing.T) { } }) + t.Run("Vap should be created", func(t *testing.T) { + suffix := "VapShouldBeCreated" + + logger.Info("Running test: Vap should be created") + labels := map[string]string{ + constraint.VapGenerationLabel: constraint.Yes, + } + constraintTemplate := makeReconcileConstraintTemplateForVap(suffix, labels) + t.Cleanup(testutils.DeleteObjectAndConfirm(ctx, t, c, expectedCRD(suffix))) + testutils.CreateThenCleanup(ctx, t, c, constraintTemplate) + + err = retry.OnError(testutils.ConstantRetry, func(err error) bool { + return true + }, func() error { + // check if vap resource exists now + vap := &admissionregistrationv1beta1.ValidatingAdmissionPolicy{} + vapName := fmt.Sprintf("gatekeeper-%s", denyall+strings.ToLower(suffix)) + if err := c.Get(ctx, types.NamespacedName{Name: vapName}, vap); err != nil { + return err + } + return nil + }) + if err != nil { + t.Fatal(err) + } + }) + + t.Run("Vap should not be created", func(t *testing.T) { + suffix := "VapShouldNotBeCreated" + + logger.Info("Running test: Vap should not be created") + labels := map[string]string{ + constraint.VapGenerationLabel: constraint.No, + } + constraintTemplate := makeReconcileConstraintTemplateForVap(suffix, labels) + t.Cleanup(testutils.DeleteObjectAndConfirm(ctx, t, c, expectedCRD(suffix))) + testutils.CreateThenCleanup(ctx, t, c, constraintTemplate) + + err = retry.OnError(testutils.ConstantRetry, func(err error) bool { + return true + }, func() error { + // check if vap resource exists now + vap := &admissionregistrationv1beta1.ValidatingAdmissionPolicy{} + vapName := fmt.Sprintf("gatekeeper-%s", denyall+strings.ToLower(suffix)) + if err := c.Get(ctx, types.NamespacedName{Name: vapName}, vap); err != nil { + if !apierrors.IsNotFound(err) { + return err + } + return nil + } + return fmt.Errorf("should result in error, vap not found") + }) + if err != nil { + t.Fatal(err) + } + }) + + t.Run("Vap should not be created without label", func(t *testing.T) { + suffix := "VapShouldNotBeCreatedWithoutLabel" + + logger.Info("Running test: Vap should not be created without label") + labels := map[string]string{} + constraintTemplate := makeReconcileConstraintTemplateForVap(suffix, labels) + t.Cleanup(testutils.DeleteObjectAndConfirm(ctx, t, c, expectedCRD(suffix))) + testutils.CreateThenCleanup(ctx, t, c, constraintTemplate) + + err = retry.OnError(testutils.ConstantRetry, func(err error) bool { + return true + }, func() error { + // check if vap resource exists now + vap := &admissionregistrationv1beta1.ValidatingAdmissionPolicy{} + vapName := fmt.Sprintf("gatekeeper-%s", denyall+strings.ToLower(suffix)) + if err := c.Get(ctx, types.NamespacedName{Name: vapName}, vap); err != nil { + if !apierrors.IsNotFound(err) { + return err + } + return nil + } + return fmt.Errorf("should result in error, vap not found") + }) + if err != nil { + t.Fatal(err) + } + }) + // TODO(ritazh): uncomment this test after the fix for https://github.com/kubernetes/kubernetes/issues/122658 makes its way to a k8s release + // t.Run("VapBinding should be created", func(t *testing.T) { + // suffix := "VapBindingShouldBeCreated" + + // logger.Info("Running test: VapBinding should be created") + // labels := map[string]string{ + // constraint.VapGenerationLabel: constraint.Yes, + // } + // constraintTemplate := makeReconcileConstraintTemplateForVap(suffix, labels) + // cstr := newDenyAllCstrWithLabel(suffix, labels) + // t.Cleanup(testutils.DeleteObjectAndConfirm(ctx, t, c, expectedCRD(suffix))) + // testutils.CreateThenCleanup(ctx, t, c, constraintTemplate) + + // err = retry.OnError(testutils.ConstantRetry, func(err error) bool { + // return true + // }, func() error { + // // check if vap resource exists now + // vap := &admissionregistrationv1beta1.ValidatingAdmissionPolicy{} + // vapName := fmt.Sprintf("gatekeeper-%s", denyall+strings.ToLower(suffix)) + // if err := c.Get(ctx, types.NamespacedName{Name: vapName}, vap); err != nil { + // return err + // } + // return c.Create(ctx, cstr) + // }) + // if err != nil { + // logger.Error(err, "get vap and create cstr") + // t.Fatal(err) + // } + // logger.Info("cstr created") + // // check if vapbinding resource exists now + // vapBinding := &admissionregistrationv1beta1.ValidatingAdmissionPolicyBinding{} + // vapBindingName := fmt.Sprintf("gatekeeper-%s", denyall+strings.ToLower(suffix)) + // if err := c.Get(ctx, types.NamespacedName{Name: vapBindingName}, vapBinding); err != nil { + // logger.Error(err, "get vapBinding") + // t.Fatal(err) + // } + // logger.Info("vapbinding found") + // }) + t.Run("Constraint is marked as enforced", func(t *testing.T) { suffix := "MarkedEnforced" @@ -469,12 +667,12 @@ func TestReconcile_DeleteConstraintResources(t *testing.T) { // Create the constraint template object and expect Reconcile to be called // when the controller starts. instance := &v1beta1.ConstraintTemplate{ - ObjectMeta: metav1.ObjectMeta{Name: "denyall"}, + ObjectMeta: metav1.ObjectMeta{Name: denyall}, Spec: v1beta1.ConstraintTemplateSpec{ CRD: v1beta1.CRD{ Spec: v1beta1.CRDSpec{ Names: v1beta1.Names{ - Kind: "DenyAll", + Kind: DenyAll, }, }, }, @@ -505,11 +703,11 @@ violation[{"msg": "denied!"}] { gvk := schema.GroupVersionKind{ Group: "constraints.gatekeeper.sh", Version: "v1beta1", - Kind: "DenyAll", + Kind: DenyAll, } // Install constraint CRD - crd := makeCRD(gvk, "denyall") + crd := makeCRD(gvk, denyall) err = applyCRD(ctx, c, gvk, crd) if err != nil { t.Fatalf("applying CRD: %v", err) @@ -639,12 +837,24 @@ func newDenyAllCstr(suffix string) *unstructured.Unstructured { cstr.SetGroupVersionKind(schema.GroupVersionKind{ Group: "constraints.gatekeeper.sh", Version: "v1beta1", - Kind: "DenyAll" + suffix, + Kind: DenyAll + suffix, }) cstr.SetName("denyallconstraint") return cstr } +// func newDenyAllCstrWithLabel(suffix string, labels map[string]string) *unstructured.Unstructured { +// cstr := &unstructured.Unstructured{} +// cstr.SetGroupVersionKind(schema.GroupVersionKind{ +// Group: "constraints.gatekeeper.sh", +// Version: "v1beta1", +// Kind: DenyAll + suffix, +// }) +// cstr.SetName("denyallconstraintforvapbinding") +// cstr.SetLabels(labels) +// return cstr +// } + func getCTByPodStatus(templ *v1beta1.ConstraintTemplate) (v1beta1.ByPodStatus, bool) { statuses := templ.Status.ByPod for _, s := range statuses { diff --git a/pkg/controller/mutators/core/controller_suite_test.go b/pkg/controller/mutators/core/controller_suite_test.go index 0600f80994e..60153514734 100644 --- a/pkg/controller/mutators/core/controller_suite_test.go +++ b/pkg/controller/mutators/core/controller_suite_test.go @@ -37,6 +37,11 @@ func TestMain(m *testing.M) { }, ErrorIfCRDPathMissing: true, } + ///TODO(ritazh): remove when vap is GAed in k/k + args := t.ControlPlane.GetAPIServer().Configure() + args.Append("runtime-config", "api/all=true") + args.Append("feature-gates", "ValidatingAdmissionPolicy=true") + if err := apis.AddToScheme(scheme.Scheme); err != nil { log.Fatal(err) } diff --git a/pkg/mutation/mutators/assign/assign_mutator_benchmark_test.go b/pkg/mutation/mutators/assign/assign_mutator_benchmark_test.go index 74deef1c5d6..82d58712e18 100644 --- a/pkg/mutation/mutators/assign/assign_mutator_benchmark_test.go +++ b/pkg/mutation/mutators/assign/assign_mutator_benchmark_test.go @@ -12,6 +12,10 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ) +const ( + spec = "spec" +) + func assign(value interface{}, location string) *unversioned.Assign { result := &unversioned.Assign{ Spec: unversioned.AssignSpec{ @@ -31,7 +35,7 @@ func assign(value interface{}, location string) *unversioned.Assign { } func benchmarkAssignMutator(b *testing.B, n int) { - mutator, err := MutatorForAssign(assign("foo", "spec"+strings.Repeat(".spec", n-1))) + mutator, err := MutatorForAssign(assign("foo", spec+strings.Repeat(".spec", n-1))) if err != nil { b.Fatal(err) } @@ -41,7 +45,7 @@ func benchmarkAssignMutator(b *testing.B, n int) { } p := make([]string, n) for i := 0; i < n; i++ { - p[i] = "spec" + p[i] = spec } _, err = mutator.Mutate(&types.Mutable{Object: obj}) if err != nil { @@ -55,7 +59,7 @@ func benchmarkAssignMutator(b *testing.B, n int) { } func benchmarkNoAssignMutator(b *testing.B, n int) { - path := "spec" + strings.Repeat(".spec", n-1) + path := spec + strings.Repeat(".spec", n-1) a := assign("foo", path) a.Spec.Parameters.PathTests = []unversioned.PathTest{{ SubPath: path, @@ -71,7 +75,7 @@ func benchmarkNoAssignMutator(b *testing.B, n int) { } p := make([]string, n) for i := 0; i < n; i++ { - p[i] = "spec" + p[i] = spec } _, err = mutator.Mutate(&types.Mutable{Object: obj}) if err != nil { diff --git a/pkg/mutation/mutators/assignimage/assignimage_mutator_benchmark_test.go b/pkg/mutation/mutators/assignimage/assignimage_mutator_benchmark_test.go index 80a47cb1fba..e6821f5b8d4 100644 --- a/pkg/mutation/mutators/assignimage/assignimage_mutator_benchmark_test.go +++ b/pkg/mutation/mutators/assignimage/assignimage_mutator_benchmark_test.go @@ -12,6 +12,10 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ) +const ( + spec = "spec" +) + func assignImage(domain, path, tag, location string) *unversioned.AssignImage { result := &unversioned.AssignImage{ Spec: unversioned.AssignImageSpec{ @@ -33,7 +37,7 @@ func assignImage(domain, path, tag, location string) *unversioned.AssignImage { } func benchmarkAssignImageMutator(b *testing.B, n int) { - ai := assignImage("a.b.c", "lib/repo", ":latest", "spec"+strings.Repeat(".spec", n-1)) + ai := assignImage("a.b.c", "lib/repo", ":latest", spec+strings.Repeat(".spec", n-1)) mutator, err := MutatorForAssignImage(ai) if err != nil { b.Fatal(err) @@ -44,7 +48,7 @@ func benchmarkAssignImageMutator(b *testing.B, n int) { } p := make([]string, n) for i := 0; i < n; i++ { - p[i] = "spec" + p[i] = spec } _, err = mutator.Mutate(&types.Mutable{Object: obj}) if err != nil { @@ -58,7 +62,7 @@ func benchmarkAssignImageMutator(b *testing.B, n int) { } func benchmarkNoAssignImageMutator(b *testing.B, n int) { - location := "spec" + strings.Repeat(".spec", n-1) + location := spec + strings.Repeat(".spec", n-1) a := assignImage("a.b.c", "lib/repo", ":latest", location) a.Spec.Parameters.PathTests = []unversioned.PathTest{{ SubPath: location, @@ -74,7 +78,7 @@ func benchmarkNoAssignImageMutator(b *testing.B, n int) { } p := make([]string, n) for i := 0; i < n; i++ { - p[i] = "spec" + p[i] = spec } _, err = mutator.Mutate(&types.Mutable{Object: obj}) if err != nil { diff --git a/pkg/mutation/mutators/modifyset/modify_set_mutator_benchmark_test.go b/pkg/mutation/mutators/modifyset/modify_set_mutator_benchmark_test.go index c4793833556..566d822ec75 100644 --- a/pkg/mutation/mutators/modifyset/modify_set_mutator_benchmark_test.go +++ b/pkg/mutation/mutators/modifyset/modify_set_mutator_benchmark_test.go @@ -12,6 +12,10 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" ) +const ( + spec = "spec" +) + func modifyset(value interface{}, location string) *unversioned.ModifySet { return &unversioned.ModifySet{ Spec: unversioned.ModifySetSpec{ @@ -32,7 +36,7 @@ func modifyset(value interface{}, location string) *unversioned.ModifySet { } func benchmarkModifySetMutator(b *testing.B, n int) { - mutator, err := MutatorForModifySet(modifyset("foo", "spec"+strings.Repeat(".spec", n-1))) + mutator, err := MutatorForModifySet(modifyset("foo", spec+strings.Repeat(".spec", n-1))) if err != nil { b.Fatal(err) } @@ -42,7 +46,7 @@ func benchmarkModifySetMutator(b *testing.B, n int) { } p := make([]string, n) for i := 0; i < n; i++ { - p[i] = "spec" + p[i] = spec } _, err = mutator.Mutate(&types.Mutable{Object: obj}) if err != nil { @@ -56,7 +60,7 @@ func benchmarkModifySetMutator(b *testing.B, n int) { } func benchmarkNoModifySetMutator(b *testing.B, n int) { - path := "spec" + strings.Repeat(".spec", n-1) + path := spec + strings.Repeat(".spec", n-1) a := modifyset("foo", path) a.Spec.Parameters.PathTests = []unversioned.PathTest{{ SubPath: path, @@ -72,7 +76,7 @@ func benchmarkNoModifySetMutator(b *testing.B, n int) { } p := make([]string, n) for i := 0; i < n; i++ { - p[i] = "spec" + p[i] = spec } _, err = mutator.Mutate(&types.Mutable{Object: obj}) if err != nil { diff --git a/pkg/mutation/system_external_data_test.go b/pkg/mutation/system_external_data_test.go index 4bf374f904d..778bbf7b73b 100644 --- a/pkg/mutation/system_external_data_test.go +++ b/pkg/mutation/system_external_data_test.go @@ -44,7 +44,7 @@ PXy3PkB8++6U4Y3vdk2Ni2WYYlIls8yqbM4327IKmkDc2TimS8u60CT47mKU7aDY cbTV5RDkrlaYwm5yqlTIglvCv7o= -----END CERTIFICATE----- ` - + // nolint:gosec // only used for testing clientKey = ` -----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAvpnaPKLIKdvx98KW68lz8pGaRRcYersNGqPjpifMVjjE8LuC diff --git a/pkg/readiness/integration_suite_test.go b/pkg/readiness/integration_suite_test.go index 1fedd4961b4..aa99db7cfa8 100644 --- a/pkg/readiness/integration_suite_test.go +++ b/pkg/readiness/integration_suite_test.go @@ -36,7 +36,6 @@ var cfg *rest.Config func TestMain(m *testing.M) { var err error - t := &envtest.Environment{ CRDDirectoryPaths: []string{ filepath.Join("..", "..", "config", "crd", "bases"), @@ -45,6 +44,10 @@ func TestMain(m *testing.M) { }, ErrorIfCRDPathMissing: true, } + ///TODO(ritazh): remove when vap is GAed in k/k + args := t.ControlPlane.GetAPIServer().Configure() + args.Append("runtime-config", "api/all=true") + args.Append("feature-gates", "ValidatingAdmissionPolicy=true") if err := apis.AddToScheme(scheme.Scheme); err != nil { stdlog.Fatal(err) } diff --git a/pkg/target/review.go b/pkg/target/review.go index f2fbe1fa60b..34604cd5ce5 100644 --- a/pkg/target/review.go +++ b/pkg/target/review.go @@ -10,14 +10,20 @@ type AugmentedReview struct { AdmissionRequest *admissionv1.AdmissionRequest Namespace *corev1.Namespace Source types.SourceType + IsAdmission bool } type gkReview struct { admissionv1.AdmissionRequest - namespace *corev1.Namespace - source types.SourceType + namespace *corev1.Namespace + source types.SourceType + isAdmission bool } func (g *gkReview) GetAdmissionRequest() *admissionv1.AdmissionRequest { return &g.AdmissionRequest } + +func (g *gkReview) IsAdmissionRequest() bool { + return g.isAdmission +} diff --git a/pkg/target/target.go b/pkg/target/target.go index e6c14c7ca1d..95ca09e4e65 100644 --- a/pkg/target/target.go +++ b/pkg/target/target.go @@ -94,12 +94,14 @@ func (h *K8sValidationTarget) handleReview(obj interface{}) (bool, *gkReview, er AdmissionRequest: *data.AdmissionRequest, namespace: data.Namespace, source: data.Source, + isAdmission: data.IsAdmission, } case *AugmentedReview: review = &gkReview{ AdmissionRequest: *data.AdmissionRequest, namespace: data.Namespace, source: data.Source, + isAdmission: data.IsAdmission, } case AugmentedUnstructured: review, err = augmentedUnstructuredToAdmissionRequest(data) diff --git a/pkg/target/target_test.go b/pkg/target/target_test.go index 83f507465bd..878d3980b09 100644 --- a/pkg/target/target_test.go +++ b/pkg/target/target_test.go @@ -657,38 +657,42 @@ func TestMatcher_Match(t *testing.T) { ns := makeNamespace("my-ns", map[string]string{"ns": "label"}) tests := []struct { - name string - match *match.Match - cachedNs *corev1.Namespace - req interface{} - wantHandled bool - wantErr error - want bool + name string + match *match.Match + cachedNs *corev1.Namespace + req interface{} + wantHandled bool + wantErr error + want bool + wantIsAdmission bool }{ { - name: "nil", - req: nil, - match: nil, - wantHandled: false, - wantErr: nil, + name: "nil", + req: nil, + match: nil, + wantHandled: false, + wantErr: nil, + wantIsAdmission: false, }, { name: "AdmissionRequest supported", req: admissionv1.AdmissionRequest{ Object: runtime.RawExtension{Raw: matchedRawData()}, }, - match: fooMatch(), - wantHandled: true, - wantErr: nil, - want: false, + match: fooMatch(), + wantHandled: true, + wantErr: nil, + want: false, + wantIsAdmission: false, }, { - name: "unstructured.Unstructured supported", - req: makeResource(schema.GroupVersionKind{Group: "some", Kind: "Thing"}, "foo"), - match: fooMatch(), - wantHandled: true, - wantErr: nil, - want: false, + name: "unstructured.Unstructured supported", + req: makeResource(schema.GroupVersionKind{Group: "some", Kind: "Thing"}, "foo"), + match: fooMatch(), + wantHandled: true, + wantErr: nil, + want: false, + wantIsAdmission: false, }, { name: "Raw object doesn't unmarshal", @@ -699,10 +703,11 @@ func TestMatcher_Match(t *testing.T) { }}, Source: types.SourceTypeDefault, }, - match: fooMatch(), - wantHandled: true, - wantErr: ErrRequestObject, - want: false, + match: fooMatch(), + wantHandled: true, + wantErr: ErrRequestObject, + want: false, + wantIsAdmission: false, }, { name: "Match error", @@ -710,11 +715,13 @@ func TestMatcher_Match(t *testing.T) { AdmissionRequest: &admissionv1.AdmissionRequest{ Object: runtime.RawExtension{Raw: namespacedRawData("foo")}, }, + IsAdmission: true, }, - match: namespaceSelectorMatch(), - wantHandled: true, - wantErr: ErrMatching, - want: false, + match: namespaceSelectorMatch(), + wantHandled: true, + wantErr: ErrMatching, + want: false, + wantIsAdmission: true, }, { name: "Success if Namespace not cached", @@ -722,11 +729,13 @@ func TestMatcher_Match(t *testing.T) { AdmissionRequest: &admissionv1.AdmissionRequest{ Object: runtime.RawExtension{Raw: nsData}, }, + IsAdmission: true, }, - match: fooMatch(), - wantHandled: true, - wantErr: nil, - want: false, + match: fooMatch(), + wantHandled: true, + wantErr: nil, + want: false, + wantIsAdmission: true, }, { name: "AugmentedReview is supported", @@ -735,11 +744,13 @@ func TestMatcher_Match(t *testing.T) { AdmissionRequest: &admissionv1.AdmissionRequest{ Object: runtime.RawExtension{Raw: matchedRawData()}, }, + IsAdmission: true, }, - match: fooMatch(), - wantHandled: true, - wantErr: nil, - want: true, + match: fooMatch(), + wantHandled: true, + wantErr: nil, + want: true, + wantIsAdmission: true, }, { name: "AugmentedUnstructured is supported", @@ -747,10 +758,11 @@ func TestMatcher_Match(t *testing.T) { Namespace: ns, Object: *makeResource(schema.GroupVersionKind{Group: "some", Kind: "Thing"}, "foo", map[string]string{"obj": "label"}), }, - match: fooMatch(), - wantHandled: true, - wantErr: nil, - want: true, + match: fooMatch(), + wantHandled: true, + wantErr: nil, + want: true, + wantIsAdmission: false, }, { name: "Both object and old object are matched", @@ -760,11 +772,13 @@ func TestMatcher_Match(t *testing.T) { Object: runtime.RawExtension{Raw: matchedRawData()}, OldObject: runtime.RawExtension{Raw: matchedRawData()}, }, + IsAdmission: true, }, - match: fooMatch(), - wantHandled: true, - wantErr: nil, - want: true, + match: fooMatch(), + wantHandled: true, + wantErr: nil, + want: true, + wantIsAdmission: true, }, { name: "object is matched, old object is not matched", @@ -774,11 +788,13 @@ func TestMatcher_Match(t *testing.T) { Object: runtime.RawExtension{Raw: matchedRawData()}, OldObject: runtime.RawExtension{Raw: unmatchedRawData()}, }, + IsAdmission: true, }, - match: fooMatch(), - wantHandled: true, - wantErr: nil, - want: true, + match: fooMatch(), + wantHandled: true, + wantErr: nil, + want: true, + wantIsAdmission: true, }, { name: "object is not matched, old object is matched", @@ -788,11 +804,13 @@ func TestMatcher_Match(t *testing.T) { Object: runtime.RawExtension{Raw: unmatchedRawData()}, OldObject: runtime.RawExtension{Raw: matchedRawData()}, }, + IsAdmission: true, }, - match: fooMatch(), - wantHandled: true, - wantErr: nil, - want: true, + match: fooMatch(), + wantHandled: true, + wantErr: nil, + want: true, + wantIsAdmission: true, }, { name: "object is matched, old object is not matched", @@ -802,11 +820,13 @@ func TestMatcher_Match(t *testing.T) { Object: runtime.RawExtension{Raw: unmatchedRawData()}, OldObject: runtime.RawExtension{Raw: unmatchedRawData()}, }, + IsAdmission: true, }, - match: fooMatch(), - wantHandled: true, - wantErr: nil, - want: false, + match: fooMatch(), + wantHandled: true, + wantErr: nil, + want: false, + wantIsAdmission: true, }, { name: "new object is not matched, old object is not specified", @@ -815,11 +835,13 @@ func TestMatcher_Match(t *testing.T) { AdmissionRequest: &admissionv1.AdmissionRequest{ Object: runtime.RawExtension{Raw: unmatchedRawData()}, }, + IsAdmission: true, }, - match: fooMatch(), - wantHandled: true, - wantErr: nil, - want: false, + match: fooMatch(), + wantHandled: true, + wantErr: nil, + want: false, + wantIsAdmission: true, }, { name: "missing cached Namespace", @@ -830,15 +852,17 @@ func TestMatcher_Match(t *testing.T) { Namespace: "foo", Object: runtime.RawExtension{Raw: namespacedRawData("foo")}, }, + IsAdmission: true, }, match: &match.Match{ NamespaceSelector: &metav1.LabelSelector{ MatchLabels: map[string]string{"ns": "label"}, }, }, - wantHandled: true, - wantErr: ErrMatching, - want: false, + wantHandled: true, + wantErr: ErrMatching, + want: false, + wantIsAdmission: true, }, { name: "use cached Namespace no match", @@ -853,15 +877,17 @@ func TestMatcher_Match(t *testing.T) { Namespace: "foo", Object: runtime.RawExtension{Raw: namespacedRawData("foo")}, }, + IsAdmission: true, }, match: &match.Match{ NamespaceSelector: &metav1.LabelSelector{ MatchLabels: map[string]string{"ns": "label"}, }, }, - wantHandled: true, - wantErr: nil, - want: false, + wantHandled: true, + wantErr: nil, + want: false, + wantIsAdmission: true, }, { name: "use cached Namespace match", @@ -879,26 +905,30 @@ func TestMatcher_Match(t *testing.T) { Namespace: "foo", Object: runtime.RawExtension{Raw: namespacedRawData("foo")}, }, + IsAdmission: true, }, match: &match.Match{ NamespaceSelector: &metav1.LabelSelector{ MatchLabels: map[string]string{"ns": "label"}, }, }, - wantHandled: true, - wantErr: nil, - want: true, + wantHandled: true, + wantErr: nil, + want: true, + wantIsAdmission: true, }, { name: "neither new or old object is specified", req: &AugmentedReview{ Namespace: ns, AdmissionRequest: &admissionv1.AdmissionRequest{}, + IsAdmission: true, }, - match: fooMatch(), - wantHandled: true, - wantErr: ErrRequestObject, - want: false, + match: fooMatch(), + wantHandled: true, + wantErr: ErrRequestObject, + want: false, + wantIsAdmission: true, }, } for _, tt := range tests { @@ -918,6 +948,16 @@ func TestMatcher_Match(t *testing.T) { if err != nil { t.Fatal(err) } + if review != nil { + gkr, ok := review.(*gkReview) + if !ok { + t.Fatalf("test %v: HandleReview failed to return gkReview object", tt.name) + } + + if gkr != nil && tt.wantIsAdmission != gkr.IsAdmissionRequest() { + t.Fatalf("test %v: isAdmission = %v, wantIsAdmission %v", tt.name, gkr.IsAdmissionRequest(), tt.wantIsAdmission) + } + } if tt.wantHandled != handled { t.Fatalf("got handled = %t, want %t", handled, tt.want) diff --git a/pkg/watch/manager_suite_test.go b/pkg/watch/manager_suite_test.go index e70d09f0ab7..8bcc9f92f7b 100644 --- a/pkg/watch/manager_suite_test.go +++ b/pkg/watch/manager_suite_test.go @@ -30,6 +30,11 @@ var cfg *rest.Config func TestMain(m *testing.M) { t := &envtest.Environment{} + ///TODO(ritazh): remove when vap is GAed in k/k + args := t.ControlPlane.GetAPIServer().Configure() + args.Append("runtime-config", "api/all=true") + args.Append("feature-gates", "ValidatingAdmissionPolicy=true") + if err := apis.AddToScheme(scheme.Scheme); err != nil { stdlog.Fatal(err) } diff --git a/pkg/webhook/policy.go b/pkg/webhook/policy.go index b73261a3ebd..e6c36d46ac1 100644 --- a/pkg/webhook/policy.go +++ b/pkg/webhook/policy.go @@ -625,6 +625,7 @@ func (h *validationHandler) createReviewForRequest(ctx context.Context, req *adm review := &target.AugmentedReview{ AdmissionRequest: &req.AdmissionRequest, Source: mutationtypes.SourceTypeOriginal, + IsAdmission: true, } if req.AdmissionRequest.Namespace != "" { ns := &corev1.Namespace{} diff --git a/pkg/webhook/policy_test.go b/pkg/webhook/policy_test.go index cc463cf3910..66945de36a5 100644 --- a/pkg/webhook/policy_test.go +++ b/pkg/webhook/policy_test.go @@ -128,6 +128,8 @@ spec: kinds: ["Pod"] ` nameLargerThan63 = "abignameabignameabignameabignameabignameabignameabignameabigname" + + withMaxThreads = " with max threads" ) func validProvider() *externadatav1alpha1.Provider { @@ -339,7 +341,7 @@ func TestReviewRequest(t *testing.T) { t.Run(tt.Name, testFn) maxThreads = 1 - t.Run(tt.Name+" with max threads", testFn) + t.Run(tt.Name+withMaxThreads, testFn) } } @@ -684,7 +686,7 @@ func TestTracing(t *testing.T) { } t.Run(tt.Name, testFn) maxThreads = 1 - t.Run(tt.Name+" with max threads", testFn) + t.Run(tt.Name+withMaxThreads, testFn) } } @@ -849,7 +851,7 @@ func TestGetValidationMessages(t *testing.T) { t.Run(tt.Name, testFn) maxThreads = 1 - t.Run(tt.Name+" with max threads", testFn) + t.Run(tt.Name+withMaxThreads, testFn) } } diff --git a/test/bats/test.bats b/test/bats/test.bats index dc7ef017afa..5e67e773e23 100644 --- a/test/bats/test.bats +++ b/test/bats/test.bats @@ -60,6 +60,39 @@ teardown_file() { wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "kubectl get validatingwebhookconfigurations.admissionregistration.k8s.io gatekeeper-validating-webhook-configuration" } +@test "vap test" { + minor_version=$(echo "$KUBERNETES_VERSION" | cut -d'.' -f2) + if [ "$minor_version" -lt 28 ] || [ -z $ENABLE_VAP_TESTS ]; then + skip "skipping vap tests" + fi + local api="$(kubectl api-resources | grep validatingadmission)" + if [[ -z "$api" ]]; then + echo "vap is not enabled for the cluster. skip vap test" + else + wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "kubectl apply -f ${BATS_TESTS_DIR}/templates/k8srequiredlabels_template_vap.yaml" + + # check status resource on expansion template + wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "kubectl get constrainttemplates.templates.gatekeeper.sh k8srequiredlabelsvap -ojson | jq -r -e '.status.byPod[0]'" + + kubectl get constrainttemplates.templates.gatekeeper.sh k8srequiredlabelsvap -oyaml + + wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "kubectl get ValidatingAdmissionPolicy gatekeeper-k8srequiredlabelsvap" + + wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "kubectl apply -f ${BATS_TESTS_DIR}/constraints/all_ns_must_have_label_provided_vapbinding.yaml" + + wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "kubectl get ValidatingAdmissionPolicyBinding gatekeeper-all-must-have-label" + + run kubectl apply -f ${BATS_TESTS_DIR}/bad/bad_ns.yaml + assert_match 'denied' "${output}" + assert_failure + kubectl apply -f ${BATS_TESTS_DIR}/good/good_ns.yaml + kubectl delete --ignore-not-found -f ${BATS_TESTS_DIR}/good/good_ns.yaml + kubectl delete --ignore-not-found -f ${BATS_TESTS_DIR}/bad/bad_ns.yaml + + wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "kubectl delete --ignore-not-found -f ${BATS_TESTS_DIR}/templates/k8srequiredlabels_template_vap.yaml" + fi +} + @test "gatekeeper mutation test" { kubectl apply -f ${BATS_TESTS_DIR}/mutations/k8sownerlabel_assignmetadata.yaml wait_for_process ${WAIT_TIME} ${SLEEP_TIME} "mutator_enforced AssignMetadata k8sownerlabel" diff --git a/test/bats/tests/bad/bad_ns.yaml b/test/bats/tests/bad/bad_ns.yaml new file mode 100644 index 00000000000..71f1f6f400e --- /dev/null +++ b/test/bats/tests/bad/bad_ns.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: gatekeeper-test-ns diff --git a/test/bats/tests/constraints/all_ns_must_have_label_provided_vapbinding.yaml b/test/bats/tests/constraints/all_ns_must_have_label_provided_vapbinding.yaml new file mode 100644 index 00000000000..6349be3455b --- /dev/null +++ b/test/bats/tests/constraints/all_ns_must_have_label_provided_vapbinding.yaml @@ -0,0 +1,16 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sRequiredLabelsVap +metadata: + name: all-must-have-label + labels: + "gatekeeper.sh/use-vap": "yes" +spec: + match: + kinds: + - apiGroups: [""] + kinds: ["Namespace"] + parameters: + message: "All namespaces must have an `owner` label that points to your company username" + labels: + - key: owner + allowedRegex: "^[a-zA-Z]+.agilebank.demo$" diff --git a/test/bats/tests/good/good_ns.yaml b/test/bats/tests/good/good_ns.yaml new file mode 100644 index 00000000000..a08eb5c5270 --- /dev/null +++ b/test/bats/tests/good/good_ns.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: gatekeeper-test-ns2 + labels: + owner: me.agilebank.demo diff --git a/test/bats/tests/kindcluster.yml b/test/bats/tests/kindcluster.yml new file mode 100644 index 00000000000..8b9b46ba5e0 --- /dev/null +++ b/test/bats/tests/kindcluster.yml @@ -0,0 +1,6 @@ +kind: Cluster +apiVersion: kind.x-k8s.io/v1alpha4 +featureGates: + ValidatingAdmissionPolicy: true +runtimeConfig: + admissionregistration.k8s.io/v1beta1: true diff --git a/test/bats/tests/templates/k8srequiredlabels_template_vap.yaml b/test/bats/tests/templates/k8srequiredlabels_template_vap.yaml new file mode 100644 index 00000000000..b637bc9f60b --- /dev/null +++ b/test/bats/tests/templates/k8srequiredlabels_template_vap.yaml @@ -0,0 +1,37 @@ +apiVersion: templates.gatekeeper.sh/v1 +kind: ConstraintTemplate +metadata: + name: k8srequiredlabelsvap + labels: + "gatekeeper.sh/use-vap": "yes" +spec: + crd: + spec: + names: + kind: K8sRequiredLabelsVap + validation: + # Schema for the `parameters` field + openAPIV3Schema: + type: object + properties: + message: + type: string + labels: + type: array + items: + type: object + properties: + key: + type: string + allowedRegex: + type: string + targets: + - target: admission.k8s.gatekeeper.sh + code: + - engine: K8sNativeValidation + source: + validations: + - expression: '[object, oldObject].exists(obj, obj != null && has(obj.metadata) && variables.params.labels.all(entry, has(obj.metadata.labels) && entry.key in obj.metadata.labels))' + messageExpression: '"missing required label, requires all of: " + variables.params.labels.map(entry, entry.key).join(", ")' + - expression: '[object, oldObject].exists(obj, obj != null && !variables.params.labels.exists(entry, has(obj.metadata.labels) && entry.key in obj.metadata.labels && !string(obj.metadata.labels[entry.key]).matches(string(entry.allowedRegex))))' + message: "regex mismatch" diff --git a/test/testutils/controller.go b/test/testutils/controller.go index 0daa2b0e479..7dd11303e3a 100644 --- a/test/testutils/controller.go +++ b/test/testutils/controller.go @@ -16,6 +16,7 @@ import ( "github.com/open-policy-agent/gatekeeper/v3/apis" "github.com/open-policy-agent/gatekeeper/v3/pkg/fakes" "github.com/open-policy-agent/gatekeeper/v3/pkg/target" + admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1" v1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -134,10 +135,19 @@ func StartControlPlane(m *testing.M, cfg **rest.Config, testerDepth int) { }, ErrorIfCRDPathMissing: true, } + ///TODO(ritazh): remove when vap is GAed in k/k + args := t.ControlPlane.GetAPIServer().Configure() + args.Append("runtime-config", "api/all=true") + args.Append("feature-gates", "ValidatingAdmissionPolicy=true") + if err := apis.AddToScheme(scheme.Scheme); err != nil { log.Fatal(err) } + if err := admissionregistrationv1beta1.AddToScheme(scheme.Scheme); err != nil { + log.Fatal(err) + } + var err error if *cfg, err = t.Start(); err != nil { log.Fatal(err) @@ -161,7 +171,6 @@ func CreateThenCleanup(ctx context.Context, t *testing.T, c client.Client, obj c if !ok { t.Fatalf("got obj.DeepCopyObject() type = %T, want %T", cpy, client.Object(nil)) } - err := c.Create(ctx, cpyObj) if err != nil { t.Fatal(err) diff --git a/vendor/github.com/onsi/gomega/CHANGELOG.md b/vendor/github.com/onsi/gomega/CHANGELOG.md index fe72a7b183f..9a14b81517e 100644 --- a/vendor/github.com/onsi/gomega/CHANGELOG.md +++ b/vendor/github.com/onsi/gomega/CHANGELOG.md @@ -1,3 +1,28 @@ +## 1.31.1 + +### Fixes +- Inverted arguments order of FailureMessage of BeComparableToMatcher [e0dd999] +- Update test in case keeping msg is desired [ad1a367] + +### Maintenance +- Show how to import the format sub package [24e958d] +- tidy up go.sum [26661b8] +- bump dependencies [bde8f7a] + +## 1.31.0 + +### Features +- Async assertions include context cancellation cause if present [121c37f] + +### Maintenance +- Bump minimum go version [dee1e3c] +- docs: fix typo in example usage "occured" -> "occurred" [49005fe] +- Bump actions/setup-go from 4 to 5 (#714) [f1c8757] +- Bump github/codeql-action from 2 to 3 (#715) [9836e76] +- Bump github.com/onsi/ginkgo/v2 from 2.13.0 to 2.13.2 (#713) [54726f0] +- Bump golang.org/x/net from 0.17.0 to 0.19.0 (#711) [df97ecc] +- docs: fix `HaveExactElement` typo (#712) [a672c86] + ## 1.30.0 ### Features diff --git a/vendor/github.com/onsi/gomega/gomega_dsl.go b/vendor/github.com/onsi/gomega/gomega_dsl.go index c271a366ae0..5b46a165815 100644 --- a/vendor/github.com/onsi/gomega/gomega_dsl.go +++ b/vendor/github.com/onsi/gomega/gomega_dsl.go @@ -22,7 +22,7 @@ import ( "github.com/onsi/gomega/types" ) -const GOMEGA_VERSION = "1.30.0" +const GOMEGA_VERSION = "1.31.1" const nilGomegaPanic = `You are trying to make an assertion, but haven't registered Gomega's fail handler. If you're using Ginkgo then you probably forgot to put your assertion in an It(). diff --git a/vendor/github.com/onsi/gomega/internal/async_assertion.go b/vendor/github.com/onsi/gomega/internal/async_assertion.go index 1188b0bce37..cde9e2ec8bd 100644 --- a/vendor/github.com/onsi/gomega/internal/async_assertion.go +++ b/vendor/github.com/onsi/gomega/internal/async_assertion.go @@ -553,7 +553,12 @@ func (assertion *AsyncAssertion) match(matcher types.GomegaMatcher, desiredMatch lock.Unlock() } case <-contextDone: - fail("Context was cancelled") + err := context.Cause(assertion.ctx) + if err != nil && err != context.Canceled { + fail(fmt.Sprintf("Context was cancelled (cause: %s)", err)) + } else { + fail("Context was cancelled") + } return false case <-timeout: if assertion.asyncType == AsyncAssertionTypeEventually { diff --git a/vendor/github.com/onsi/gomega/matchers.go b/vendor/github.com/onsi/gomega/matchers.go index 43f994374da..8860d677fc8 100644 --- a/vendor/github.com/onsi/gomega/matchers.go +++ b/vendor/github.com/onsi/gomega/matchers.go @@ -394,7 +394,7 @@ func ConsistOf(elements ...interface{}) types.GomegaMatcher { } } -// HaveExactElemets succeeds if actual contains elements that precisely match the elemets passed into the matcher. The ordering of the elements does matter. +// HaveExactElements succeeds if actual contains elements that precisely match the elemets passed into the matcher. The ordering of the elements does matter. // By default HaveExactElements() uses Equal() to match the elements, however custom matchers can be passed in instead. Here are some examples: // // Expect([]string{"Foo", "FooBar"}).Should(HaveExactElements("Foo", "FooBar")) diff --git a/vendor/github.com/onsi/gomega/matchers/be_comparable_to_matcher.go b/vendor/github.com/onsi/gomega/matchers/be_comparable_to_matcher.go index 8ab4bb91949..4e3897858c7 100644 --- a/vendor/github.com/onsi/gomega/matchers/be_comparable_to_matcher.go +++ b/vendor/github.com/onsi/gomega/matchers/be_comparable_to_matcher.go @@ -41,9 +41,9 @@ func (matcher *BeComparableToMatcher) Match(actual interface{}) (success bool, m } func (matcher *BeComparableToMatcher) FailureMessage(actual interface{}) (message string) { - return cmp.Diff(matcher.Expected, actual, matcher.Options) + return fmt.Sprint("Expected object to be comparable, diff: ", cmp.Diff(actual, matcher.Expected, matcher.Options...)) } func (matcher *BeComparableToMatcher) NegatedFailureMessage(actual interface{}) (message string) { - return format.Message(actual, "not to equal", matcher.Expected) + return format.Message(actual, "not to be comparable to", matcher.Expected) } diff --git a/vendor/github.com/open-policy-agent/frameworks/constraint/pkg/client/crds/schema.go b/vendor/github.com/open-policy-agent/frameworks/constraint/pkg/client/crds/schema.go index e9ad23e9c6b..f13c0dcc9f7 100644 --- a/vendor/github.com/open-policy-agent/frameworks/constraint/pkg/client/crds/schema.go +++ b/vendor/github.com/open-policy-agent/frameworks/constraint/pkg/client/crds/schema.go @@ -9,9 +9,10 @@ import ( // CreateSchema combines the schema of the match target and the ConstraintTemplate parameters // to form the schema of the actual constraint resource. func CreateSchema(templ *templates.ConstraintTemplate, target MatchSchemaProvider) *apiextensions.JSONSchemaProps { + defaultEnforcementAction := apiextensions.JSON("deny") props := map[string]apiextensions.JSONSchemaProps{ "match": target.MatchSchema(), - "enforcementAction": {Type: "string"}, + "enforcementAction": {Type: "string", Default: &defaultEnforcementAction}, } if templ.Spec.CRD.Spec.Validation != nil && templ.Spec.CRD.Spec.Validation.OpenAPIV3Schema != nil { diff --git a/vendor/github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/k8scel/schema/schema.go b/vendor/github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/k8scel/schema/schema.go index 63f9c2b3a8c..f67f65e0997 100644 --- a/vendor/github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/k8scel/schema/schema.go +++ b/vendor/github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/k8scel/schema/schema.go @@ -7,7 +7,7 @@ import ( "github.com/open-policy-agent/frameworks/constraint/pkg/core/templates" admissionv1 "k8s.io/api/admissionregistration/v1" - admissionv1alpha1 "k8s.io/api/admissionregistration/v1alpha1" + admissionv1beta1 "k8s.io/api/admissionregistration/v1beta1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apiserver/pkg/admission/plugin/cel" "k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy" @@ -99,14 +99,14 @@ func (in *Source) GetMatchConditions() ([]cel.ExpressionAccessor, error) { return matchConditions, nil } -func (in *Source) GetV1Alpha1MatchConditions() ([]admissionv1alpha1.MatchCondition, error) { +func (in *Source) GetV1Beta1MatchConditions() ([]admissionv1beta1.MatchCondition, error) { if err := in.validateMatchConditions(); err != nil { return nil, err } - var matchConditions []admissionv1alpha1.MatchCondition + var matchConditions []admissionv1beta1.MatchCondition for _, mc := range in.MatchConditions { - matchConditions = append(matchConditions, admissionv1alpha1.MatchCondition{ + matchConditions = append(matchConditions, admissionv1beta1.MatchCondition{ Name: mc.Name, Expression: mc.Expression, }) @@ -142,14 +142,14 @@ func (in *Source) GetVariables() ([]cel.NamedExpressionAccessor, error) { return vars, nil } -func (in *Source) GetV1Alpha1Variables() ([]admissionv1alpha1.Variable, error) { +func (in *Source) GetV1Beta1Variables() ([]admissionv1beta1.Variable, error) { if err := in.validateVariables(); err != nil { return nil, err } - var variables []admissionv1alpha1.Variable + var variables []admissionv1beta1.Variable for _, v := range in.Variables { - variables = append(variables, admissionv1alpha1.Variable{ + variables = append(variables, admissionv1beta1.Variable{ Name: v.Name, Expression: v.Expression, }) @@ -169,10 +169,10 @@ func (in *Source) GetValidations() ([]cel.ExpressionAccessor, error) { return validations, nil } -func (in *Source) GetV1Alpha1Validatons() ([]admissionv1alpha1.Validation, error) { - var validations []admissionv1alpha1.Validation +func (in *Source) GetV1Beta1Validatons() ([]admissionv1beta1.Validation, error) { + var validations []admissionv1beta1.Validation for _, v := range in.Validations { - validations = append(validations, admissionv1alpha1.Validation{ + validations = append(validations, admissionv1beta1.Validation{ Expression: v.Expression, Message: v.Message, MessageExpression: v.MessageExpression, @@ -213,18 +213,19 @@ func (in *Source) GetFailurePolicy() (*admissionv1.FailurePolicyType, error) { return &out, nil } -func (in *Source) GetV1alpha1FailurePolicy() (*admissionv1alpha1.FailurePolicyType, error) { +func (in *Source) GetV1Beta1FailurePolicy() (*admissionv1beta1.FailurePolicyType, error) { + var out admissionv1beta1.FailurePolicyType + /// TODO(ritazh): default for now until the feature is safe to fail close if in.FailurePolicy == nil { - return nil, nil + out = admissionv1beta1.Ignore + return &out, nil } - var out admissionv1alpha1.FailurePolicyType - switch *in.FailurePolicy { case string(admissionv1.Fail): - out = admissionv1alpha1.Fail + out = admissionv1beta1.Fail case string(admissionv1.Ignore): - out = admissionv1alpha1.Ignore + out = admissionv1beta1.Ignore default: return nil, fmt.Errorf("%w: unrecognized failure policy: %s", ErrBadFailurePolicy, *in.FailurePolicy) } diff --git a/vendor/github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/k8scel/transform/cel_snippets.go b/vendor/github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/k8scel/transform/cel_snippets.go index 93f7472f31c..f6d0ed0c108 100644 --- a/vendor/github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/k8scel/transform/cel_snippets.go +++ b/vendor/github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/k8scel/transform/cel_snippets.go @@ -2,7 +2,7 @@ package transform import ( "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/k8scel/schema" - admissionregistrationv1alpha1 "k8s.io/api/admissionregistration/v1alpha1" + admissionregistrationv1beta1 "k8s.io/api/admissionregistration/v1beta1" "k8s.io/apiserver/pkg/admission/plugin/cel" "k8s.io/apiserver/pkg/admission/plugin/validatingadmissionpolicy" "k8s.io/apiserver/pkg/admission/plugin/webhook/matchconditions" @@ -28,8 +28,12 @@ const ( !has(params.spec) ? true: ( !has(params.spec.match) ? true: ( !has(params.spec.match.name) ? true : ( - (has(object.metadata.generateName) && object.metadata.generateName != "" && params.spec.match.name.endsWith("*") && string(object.metadata.generateName).matches("^" + string(params.spec.match.name).replace("*", ".*") + "$")) || - (has(object.metadata.name) && string(object.metadata.name).matches("^" + string(params.spec.match.name).replace("*", ".*") + "$")) + [object, oldObject].exists(obj, + obj != null && ( + (has(obj.metadata.generateName) && obj.metadata.generateName != "" && params.spec.match.name.endsWith("*") && string(obj.metadata.generateName).matches("^" + string(params.spec.match.name).replace("*", ".*") + "$")) || + (has(obj.metadata.name) && string(obj.metadata.name).matches("^" + string(params.spec.match.name).replace("*", ".*") + "$")) + ) + ) ) ) ) @@ -37,14 +41,19 @@ const ( // Note that switching the glob to a regex is valid because of how Gatekeeper validates the wildcard matcher // (with this regex: "+kubebuilder:validation:Pattern=`^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$`"). + // TODO: consider using the `namespaceObject` field provided by ValidatingAdmissionPolicy. matchNamespacesGlob = ` !has(params.spec) ? true: ( !has(params.spec.match) ? true: ( !has(params.spec.match.namespaces) ? true : ( - // cluster-scoped objects always match - !has(object.metadata.namespace) || object.metadata.namespace == "" ? true : ( - params.spec.match.namespaces.exists(nsMatcher, - (string(object.metadata.namespace).matches("^" + string(nsMatcher).replace("*", ".*") + "$")) + [object, oldObject].exists(obj, + obj != null && ( + // cluster-scoped objects always match + !has(obj.metadata.namespace) || obj.metadata.namespace == "" ? true : ( + params.spec.match.namespaces.exists(nsMatcher, + (string(obj.metadata.namespace).matches("^" + string(nsMatcher).replace("*", ".*") + "$")) + ) + ) ) ) ) @@ -54,31 +63,36 @@ const ( // Note that switching the glob to a regex is valid because of how Gatekeeper validates the wildcard matcher // (with this regex: "+kubebuilder:validation:Pattern=`^(\*|\*-)?[a-z0-9]([-:a-z0-9]*[a-z0-9])?(\*|-\*)?$`"). + // TODO: consider using the `namespaceObject` field provided by ValidatingAdmissionPolicy. matchExcludedNamespacesGlob = ` !has(params.spec) ? true: ( !has(params.spec.match) ? true: ( !has(params.spec.match.excludedNamespaces) ? true : ( - // cluster-scoped objects always match - !has(object.metadata.namespace) || object.metadata.namespace == "" ? true : ( - !params.spec.match.excludedNamespaces.exists(nsMatcher, - (string(object.metadata.namespace).matches("^" + string(nsMatcher).replace("*", ".*") + "$")) + [object, oldObject].exists(obj, + obj != null && ( + // cluster-scoped objects always match + !has(obj.metadata.namespace) || obj.metadata.namespace == "" ? true : ( + !params.spec.match.excludedNamespaces.exists(nsMatcher, + (string(obj.metadata.namespace).matches("^" + string(nsMatcher).replace("*", ".*") + "$")) + ) ) ) + ) ) ) ) ` ) -func MatchExcludedNamespacesGlobV1Alpha1() admissionregistrationv1alpha1.MatchCondition { - return admissionregistrationv1alpha1.MatchCondition{ +func MatchExcludedNamespacesGlobV1Beta1() admissionregistrationv1beta1.MatchCondition { + return admissionregistrationv1beta1.MatchCondition{ Name: "gatekeeper_internal_match_excluded_namespaces", Expression: matchExcludedNamespacesGlob, } } func MatchExcludedNamespacesGlobCEL() []cel.ExpressionAccessor { - mc := MatchExcludedNamespacesGlobV1Alpha1() + mc := MatchExcludedNamespacesGlobV1Beta1() return []cel.ExpressionAccessor{ &matchconditions.MatchCondition{ Name: mc.Name, @@ -87,15 +101,15 @@ func MatchExcludedNamespacesGlobCEL() []cel.ExpressionAccessor { } } -func MatchNamespacesGlobV1Alpha1() admissionregistrationv1alpha1.MatchCondition { - return admissionregistrationv1alpha1.MatchCondition{ +func MatchNamespacesGlobV1Beta1() admissionregistrationv1beta1.MatchCondition { + return admissionregistrationv1beta1.MatchCondition{ Name: "gatekeeper_internal_match_namespaces", Expression: matchNamespacesGlob, } } func MatchNamespacesGlobCEL() []cel.ExpressionAccessor { - mc := MatchNamespacesGlobV1Alpha1() + mc := MatchNamespacesGlobV1Beta1() return []cel.ExpressionAccessor{ &matchconditions.MatchCondition{ Name: mc.Name, @@ -104,15 +118,15 @@ func MatchNamespacesGlobCEL() []cel.ExpressionAccessor { } } -func MatchNameGlobV1Alpha1() admissionregistrationv1alpha1.MatchCondition { - return admissionregistrationv1alpha1.MatchCondition{ +func MatchNameGlobV1Beta1() admissionregistrationv1beta1.MatchCondition { + return admissionregistrationv1beta1.MatchCondition{ Name: "gatekeeper_internal_match_name", Expression: matchNameGlob, } } func MatchNameGlobCEL() []cel.ExpressionAccessor { - mc := MatchNameGlobV1Alpha1() + mc := MatchNameGlobV1Beta1() return []cel.ExpressionAccessor{ &matchconditions.MatchCondition{ Name: mc.Name, @@ -121,15 +135,15 @@ func MatchNameGlobCEL() []cel.ExpressionAccessor { } } -func MatchKindsV1Alpha1() admissionregistrationv1alpha1.MatchCondition { - return admissionregistrationv1alpha1.MatchCondition{ +func MatchKindsV1Beta1() admissionregistrationv1beta1.MatchCondition { + return admissionregistrationv1beta1.MatchCondition{ Name: "gatekeeper_internal_match_kinds", Expression: matchKinds, } } func MatchKindsCEL() []cel.ExpressionAccessor { - mc := MatchKindsV1Alpha1() + mc := MatchKindsV1Beta1() return []cel.ExpressionAccessor{ &matchconditions.MatchCondition{ Name: mc.Name, @@ -138,15 +152,15 @@ func MatchKindsCEL() []cel.ExpressionAccessor { } } -func BindParamsV1Alpha1() admissionregistrationv1alpha1.Variable { - return admissionregistrationv1alpha1.Variable{ +func BindParamsV1Beta1() admissionregistrationv1beta1.Variable { + return admissionregistrationv1beta1.Variable{ Name: schema.ParamsName, - Expression: "params.spec.parameters", + Expression: "!has(params.spec) ? null : !has(params.spec.parameters) ? null: params.spec.parameters", } } func BindParamsCEL() []cel.NamedExpressionAccessor { - v := BindParamsV1Alpha1() + v := BindParamsV1Beta1() return []cel.NamedExpressionAccessor{ &validatingadmissionpolicy.Variable{ Name: v.Name, @@ -155,12 +169,12 @@ func BindParamsCEL() []cel.NamedExpressionAccessor { } } -func AllMatchersV1Alpha1() []admissionregistrationv1alpha1.MatchCondition { - return []admissionregistrationv1alpha1.MatchCondition{ - MatchExcludedNamespacesGlobV1Alpha1(), - MatchNamespacesGlobV1Alpha1(), - MatchNameGlobV1Alpha1(), - MatchKindsV1Alpha1(), +func AllMatchersV1Beta1() []admissionregistrationv1beta1.MatchCondition { + return []admissionregistrationv1beta1.MatchCondition{ + MatchExcludedNamespacesGlobV1Beta1(), + MatchNamespacesGlobV1Beta1(), + MatchNameGlobV1Beta1(), + MatchKindsV1Beta1(), } } @@ -168,8 +182,8 @@ func AllVariablesCEL() []cel.NamedExpressionAccessor { return BindParamsCEL() } -func AllVariablesV1Alpha1() []admissionregistrationv1alpha1.Variable { - return []admissionregistrationv1alpha1.Variable{ - BindParamsV1Alpha1(), +func AllVariablesV1Beta1() []admissionregistrationv1beta1.Variable { + return []admissionregistrationv1beta1.Variable{ + BindParamsV1Beta1(), } } diff --git a/vendor/github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/k8scel/transform/errors.go b/vendor/github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/k8scel/transform/errors.go new file mode 100644 index 00000000000..9691c7d181c --- /dev/null +++ b/vendor/github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/k8scel/transform/errors.go @@ -0,0 +1,5 @@ +package transform + +import "errors" + +var ErrBadEnforcementAction = errors.New("invalid enforcement action") diff --git a/vendor/github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/k8scel/transform/make_vap_objects.go b/vendor/github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/k8scel/transform/make_vap_objects.go index 53b0aa33abf..002f2091709 100644 --- a/vendor/github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/k8scel/transform/make_vap_objects.go +++ b/vendor/github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/k8scel/transform/make_vap_objects.go @@ -2,52 +2,67 @@ package transform import ( "fmt" + "strings" + apiconstraints "github.com/open-policy-agent/frameworks/constraint/pkg/apis/constraints" templatesv1beta1 "github.com/open-policy-agent/frameworks/constraint/pkg/apis/templates/v1beta1" "github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers/k8scel/schema" "github.com/open-policy-agent/frameworks/constraint/pkg/core/templates" - admissionregistrationv1alpha1 "k8s.io/api/admissionregistration/v1alpha1" + admissionregistrationv1beta1 "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/runtime" + "k8s.io/utils/ptr" ) -func TemplateToPolicyDefinition(template *templates.ConstraintTemplate) (*admissionregistrationv1alpha1.ValidatingAdmissionPolicy, error) { +func TemplateToPolicyDefinition(template *templates.ConstraintTemplate) (*admissionregistrationv1beta1.ValidatingAdmissionPolicy, error) { source, err := schema.GetSourceFromTemplate(template) if err != nil { return nil, err } - matchConditions, err := source.GetV1Alpha1MatchConditions() + matchConditions, err := source.GetV1Beta1MatchConditions() if err != nil { return nil, err } - matchConditions = append(matchConditions, AllMatchersV1Alpha1()...) + matchConditions = append(matchConditions, AllMatchersV1Beta1()...) - validations, err := source.GetV1Alpha1Validatons() + validations, err := source.GetV1Beta1Validatons() if err != nil { return nil, err } - variables, err := source.GetV1Alpha1Variables() + variables, err := source.GetV1Beta1Variables() if err != nil { return nil, err } - variables = append(variables, AllVariablesV1Alpha1()...) + variables = append(variables, AllVariablesV1Beta1()...) - failurePolicy, err := source.GetV1alpha1FailurePolicy() + failurePolicy, err := source.GetV1Beta1FailurePolicy() if err != nil { return nil, err } - policy := &admissionregistrationv1alpha1.ValidatingAdmissionPolicy{ + policy := &admissionregistrationv1beta1.ValidatingAdmissionPolicy{ ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf("g8r-%s", template.GetName()), + Name: fmt.Sprintf("gatekeeper-%s", template.GetName()), }, - Spec: admissionregistrationv1alpha1.ValidatingAdmissionPolicySpec{ - ParamKind: &admissionregistrationv1alpha1.ParamKind{ - APIVersion: templatesv1beta1.SchemeGroupVersion.Version, + Spec: admissionregistrationv1beta1.ValidatingAdmissionPolicySpec{ + ParamKind: &admissionregistrationv1beta1.ParamKind{ + APIVersion: fmt.Sprintf("%s/%s", apiconstraints.Group, templatesv1beta1.SchemeGroupVersion.Version), Kind: template.Spec.CRD.Spec.Names.Kind, }, - MatchConstraints: nil, // We cannot support match constraints since `resource` is not available shift-left + MatchConstraints: &admissionregistrationv1beta1.MatchResources{ + ResourceRules: []admissionregistrationv1beta1.NamedRuleWithOperations{ + { + RuleWithOperations: admissionregistrationv1beta1.RuleWithOperations{ + /// TODO(ritazh): default for now until we can safely expose these to users + Operations: []admissionregistrationv1beta1.OperationType{admissionregistrationv1beta1.Create, admissionregistrationv1beta1.Update}, + Rule: admissionregistrationv1beta1.Rule{APIGroups: []string{"*"}, APIVersions: []string{"*"}, Resources: []string{"*"}}, + }, + }, + }, + }, MatchConditions: matchConditions, Validations: validations, FailurePolicy: failurePolicy, @@ -57,3 +72,61 @@ func TemplateToPolicyDefinition(template *templates.ConstraintTemplate) (*admiss } return policy, nil } + +func ConstraintToBinding(constraint *unstructured.Unstructured) (*admissionregistrationv1beta1.ValidatingAdmissionPolicyBinding, error) { + enforcementActionStr, err := apiconstraints.GetEnforcementAction(constraint) + if err != nil { + return nil, err + } + + var enforcementAction admissionregistrationv1beta1.ValidationAction + switch enforcementActionStr { + case apiconstraints.EnforcementActionDeny: + enforcementAction = admissionregistrationv1beta1.Deny + case "warn": + enforcementAction = admissionregistrationv1beta1.Warn + default: + return nil, fmt.Errorf("%w: unrecognized enforcement action %s, must be `warn` or `deny`", ErrBadEnforcementAction, enforcementActionStr) + } + + binding := &admissionregistrationv1beta1.ValidatingAdmissionPolicyBinding{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("gatekeeper-%s", constraint.GetName()), + }, + Spec: admissionregistrationv1beta1.ValidatingAdmissionPolicyBindingSpec{ + PolicyName: fmt.Sprintf("gatekeeper-%s", strings.ToLower(constraint.GetKind())), + ParamRef: &admissionregistrationv1beta1.ParamRef{ + Name: constraint.GetName(), + ParameterNotFoundAction: ptr.To[admissionregistrationv1beta1.ParameterNotFoundActionType](admissionregistrationv1beta1.AllowAction), + }, + MatchResources: &admissionregistrationv1beta1.MatchResources{}, + ValidationActions: []admissionregistrationv1beta1.ValidationAction{enforcementAction}, + }, + } + objectSelectorMap, found, err := unstructured.NestedMap(constraint.Object, "spec", "match", "labelSelector") + if err != nil { + return nil, err + } + var objectSelector *metav1.LabelSelector + if found { + objectSelector = &metav1.LabelSelector{} + if err := runtime.DefaultUnstructuredConverter.FromUnstructured(objectSelectorMap, objectSelector); err != nil { + return nil, err + } + binding.Spec.MatchResources.ObjectSelector = objectSelector + } + + namespaceSelectorMap, found, err := unstructured.NestedMap(constraint.Object, "spec", "match", "namespaceSelector") + if err != nil { + return nil, err + } + var namespaceSelector *metav1.LabelSelector + if found { + namespaceSelector = &metav1.LabelSelector{} + if err := runtime.DefaultUnstructuredConverter.FromUnstructured(namespaceSelectorMap, namespaceSelector); err != nil { + return nil, err + } + binding.Spec.MatchResources.NamespaceSelector = namespaceSelector + } + return binding, nil +} diff --git a/vendor/github.com/open-policy-agent/frameworks/constraint/pkg/core/constraints/constraints.go b/vendor/github.com/open-policy-agent/frameworks/constraint/pkg/core/constraints/constraints.go index 87c8e6e3d6e..1776fe5afd5 100644 --- a/vendor/github.com/open-policy-agent/frameworks/constraint/pkg/core/constraints/constraints.go +++ b/vendor/github.com/open-policy-agent/frameworks/constraint/pkg/core/constraints/constraints.go @@ -7,9 +7,11 @@ import ( ) // SemanticEqual returns whether the specs of the constraints are equal. It -// ignores status and metadata because neither are relevant as to how a +// ignores status and most metadata because neither are relevant as to how a // constraint is enforced. It is assumed that the author is comparing -// two constraints with the same GVK/namespace/name. +// two constraints with the same GVK/namespace/name. Labels are compared +// because the labels of a constraint may impact functionality (e.g. whether +// a constraint is expected to be enforced by Kubernetes' Validating Admission Policy). func SemanticEqual(c1 *unstructured.Unstructured, c2 *unstructured.Unstructured) bool { if c1 == nil || c2 == nil { return c1 == c2 @@ -21,7 +23,10 @@ func SemanticEqual(c1 *unstructured.Unstructured, c2 *unstructured.Unstructured) s1 := c1.Object["spec"] s2 := c2.Object["spec"] - return reflect.DeepEqual(s1, s2) + + l1, _, _ := unstructured.NestedFieldNoCopy(c1.Object, "metadata", "labels") + l2, _, _ := unstructured.NestedFieldNoCopy(c2.Object, "metadata", "labels") + return reflect.DeepEqual(s1, s2) && reflect.DeepEqual(l1, l2) } // Matcher matches object review requests. diff --git a/vendor/github.com/open-policy-agent/frameworks/constraint/pkg/core/templates/constrainttemplate_types.go b/vendor/github.com/open-policy-agent/frameworks/constraint/pkg/core/templates/constrainttemplate_types.go index 5e0a7ef019c..c50da2d6a48 100644 --- a/vendor/github.com/open-policy-agent/frameworks/constraint/pkg/core/templates/constrainttemplate_types.go +++ b/vendor/github.com/open-policy-agent/frameworks/constraint/pkg/core/templates/constrainttemplate_types.go @@ -169,8 +169,10 @@ func (in *Anything) DeepCopyInto(out *Anything) { } // SemanticEqual returns whether there have been changes to a constraint that -// the framework should know about. It can ignore metadata as it assumes the -// two comparables share the same identity. +// the framework should know about. It can ignore most metadata as it assumes the +// two comparables share the same identity. Labels are compared +// because the labels of a constraint may impact functionality (e.g. whether +// a constraint is expected to be enforced by Kubernetes' Validating Admission Policy). func (ct *ConstraintTemplate) SemanticEqual(other *ConstraintTemplate) bool { - return reflect.DeepEqual(ct.Spec, other.Spec) + return reflect.DeepEqual(ct.Spec, other.Spec) && reflect.DeepEqual(ct.ObjectMeta.Labels, other.ObjectMeta.Labels) } diff --git a/vendor/golang.org/x/net/html/token.go b/vendor/golang.org/x/net/html/token.go index de67f938a14..3c57880d697 100644 --- a/vendor/golang.org/x/net/html/token.go +++ b/vendor/golang.org/x/net/html/token.go @@ -910,9 +910,6 @@ func (z *Tokenizer) readTagAttrKey() { return } switch c { - case ' ', '\n', '\r', '\t', '\f', '/': - z.pendingAttr[0].end = z.raw.end - 1 - return case '=': if z.pendingAttr[0].start+1 == z.raw.end { // WHATWG 13.2.5.32, if we see an equals sign before the attribute name @@ -920,7 +917,9 @@ func (z *Tokenizer) readTagAttrKey() { continue } fallthrough - case '>': + case ' ', '\n', '\r', '\t', '\f', '/', '>': + // WHATWG 13.2.5.33 Attribute name state + // We need to reconsume the char in the after attribute name state to support the / character z.raw.end-- z.pendingAttr[0].end = z.raw.end return @@ -939,6 +938,11 @@ func (z *Tokenizer) readTagAttrVal() { if z.err != nil { return } + if c == '/' { + // WHATWG 13.2.5.34 After attribute name state + // U+002F SOLIDUS (/) - Switch to the self-closing start tag state. + return + } if c != '=' { z.raw.end-- return diff --git a/vendor/golang.org/x/net/http2/frame.go b/vendor/golang.org/x/net/http2/frame.go index c1f6b90dc32..e2b298d8593 100644 --- a/vendor/golang.org/x/net/http2/frame.go +++ b/vendor/golang.org/x/net/http2/frame.go @@ -1510,13 +1510,12 @@ func (mh *MetaHeadersFrame) checkPseudos() error { } func (fr *Framer) maxHeaderStringLen() int { - v := fr.maxHeaderListSize() - if uint32(int(v)) == v { - return int(v) + v := int(fr.maxHeaderListSize()) + if v < 0 { + // If maxHeaderListSize overflows an int, use no limit (0). + return 0 } - // They had a crazy big number for MaxHeaderBytes anyway, - // so give them unlimited header lengths: - return 0 + return v } // readMetaFrame returns 0 or more CONTINUATION frames from fr and diff --git a/vendor/golang.org/x/sys/unix/mkerrors.sh b/vendor/golang.org/x/sys/unix/mkerrors.sh index c6492020ec7..fdcaa974d23 100644 --- a/vendor/golang.org/x/sys/unix/mkerrors.sh +++ b/vendor/golang.org/x/sys/unix/mkerrors.sh @@ -584,7 +584,7 @@ ccflags="$@" $2 ~ /^KEY_(SPEC|REQKEY_DEFL)_/ || $2 ~ /^KEYCTL_/ || $2 ~ /^PERF_/ || - $2 ~ /^SECCOMP_MODE_/ || + $2 ~ /^SECCOMP_/ || $2 ~ /^SEEK_/ || $2 ~ /^SCHED_/ || $2 ~ /^SPLICE_/ || diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux.go b/vendor/golang.org/x/sys/unix/zerrors_linux.go index a5d3ff8df95..36bf8399f4f 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux.go @@ -1785,6 +1785,8 @@ const ( LANDLOCK_ACCESS_FS_REMOVE_FILE = 0x20 LANDLOCK_ACCESS_FS_TRUNCATE = 0x4000 LANDLOCK_ACCESS_FS_WRITE_FILE = 0x2 + LANDLOCK_ACCESS_NET_BIND_TCP = 0x1 + LANDLOCK_ACCESS_NET_CONNECT_TCP = 0x2 LANDLOCK_CREATE_RULESET_VERSION = 0x1 LINUX_REBOOT_CMD_CAD_OFF = 0x0 LINUX_REBOOT_CMD_CAD_ON = 0x89abcdef @@ -2465,6 +2467,7 @@ const ( PR_MCE_KILL_GET = 0x22 PR_MCE_KILL_LATE = 0x0 PR_MCE_KILL_SET = 0x1 + PR_MDWE_NO_INHERIT = 0x2 PR_MDWE_REFUSE_EXEC_GAIN = 0x1 PR_MPX_DISABLE_MANAGEMENT = 0x2c PR_MPX_ENABLE_MANAGEMENT = 0x2b @@ -2669,8 +2672,9 @@ const ( RTAX_FEATURES = 0xc RTAX_FEATURE_ALLFRAG = 0x8 RTAX_FEATURE_ECN = 0x1 - RTAX_FEATURE_MASK = 0xf + RTAX_FEATURE_MASK = 0x1f RTAX_FEATURE_SACK = 0x2 + RTAX_FEATURE_TCP_USEC_TS = 0x10 RTAX_FEATURE_TIMESTAMP = 0x4 RTAX_HOPLIMIT = 0xa RTAX_INITCWND = 0xb @@ -2913,9 +2917,38 @@ const ( SCM_RIGHTS = 0x1 SCM_TIMESTAMP = 0x1d SC_LOG_FLUSH = 0x100000 + SECCOMP_ADDFD_FLAG_SEND = 0x2 + SECCOMP_ADDFD_FLAG_SETFD = 0x1 + SECCOMP_FILTER_FLAG_LOG = 0x2 + SECCOMP_FILTER_FLAG_NEW_LISTENER = 0x8 + SECCOMP_FILTER_FLAG_SPEC_ALLOW = 0x4 + SECCOMP_FILTER_FLAG_TSYNC = 0x1 + SECCOMP_FILTER_FLAG_TSYNC_ESRCH = 0x10 + SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV = 0x20 + SECCOMP_GET_ACTION_AVAIL = 0x2 + SECCOMP_GET_NOTIF_SIZES = 0x3 + SECCOMP_IOCTL_NOTIF_RECV = 0xc0502100 + SECCOMP_IOCTL_NOTIF_SEND = 0xc0182101 + SECCOMP_IOC_MAGIC = '!' SECCOMP_MODE_DISABLED = 0x0 SECCOMP_MODE_FILTER = 0x2 SECCOMP_MODE_STRICT = 0x1 + SECCOMP_RET_ACTION = 0x7fff0000 + SECCOMP_RET_ACTION_FULL = 0xffff0000 + SECCOMP_RET_ALLOW = 0x7fff0000 + SECCOMP_RET_DATA = 0xffff + SECCOMP_RET_ERRNO = 0x50000 + SECCOMP_RET_KILL = 0x0 + SECCOMP_RET_KILL_PROCESS = 0x80000000 + SECCOMP_RET_KILL_THREAD = 0x0 + SECCOMP_RET_LOG = 0x7ffc0000 + SECCOMP_RET_TRACE = 0x7ff00000 + SECCOMP_RET_TRAP = 0x30000 + SECCOMP_RET_USER_NOTIF = 0x7fc00000 + SECCOMP_SET_MODE_FILTER = 0x1 + SECCOMP_SET_MODE_STRICT = 0x0 + SECCOMP_USER_NOTIF_FD_SYNC_WAKE_UP = 0x1 + SECCOMP_USER_NOTIF_FLAG_CONTINUE = 0x1 SECRETMEM_MAGIC = 0x5345434d SECURITYFS_MAGIC = 0x73636673 SEEK_CUR = 0x1 @@ -3075,6 +3108,7 @@ const ( SOL_TIPC = 0x10f SOL_TLS = 0x11a SOL_UDP = 0x11 + SOL_VSOCK = 0x11f SOL_X25 = 0x106 SOL_XDP = 0x11b SOMAXCONN = 0x1000 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go index 4920821cf3b..42ff8c3c1b0 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_386.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_386.go @@ -281,6 +281,9 @@ const ( SCM_TIMESTAMPNS = 0x23 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103 + SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102 + SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104 SFD_CLOEXEC = 0x80000 SFD_NONBLOCK = 0x800 SIOCATMARK = 0x8905 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go index a0c1e411275..dca436004fa 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go @@ -282,6 +282,9 @@ const ( SCM_TIMESTAMPNS = 0x23 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103 + SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102 + SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104 SFD_CLOEXEC = 0x80000 SFD_NONBLOCK = 0x800 SIOCATMARK = 0x8905 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go index c63985560f6..5cca668ac30 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go @@ -288,6 +288,9 @@ const ( SCM_TIMESTAMPNS = 0x23 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103 + SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102 + SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104 SFD_CLOEXEC = 0x80000 SFD_NONBLOCK = 0x800 SIOCATMARK = 0x8905 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go index 47cc62e25c1..d8cae6d1534 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go @@ -278,6 +278,9 @@ const ( SCM_TIMESTAMPNS = 0x23 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103 + SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102 + SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104 SFD_CLOEXEC = 0x80000 SFD_NONBLOCK = 0x800 SIOCATMARK = 0x8905 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go index 27ac4a09e22..28e39afdcb4 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go @@ -275,6 +275,9 @@ const ( SCM_TIMESTAMPNS = 0x23 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103 + SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102 + SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104 SFD_CLOEXEC = 0x80000 SFD_NONBLOCK = 0x800 SIOCATMARK = 0x8905 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go index 54694642a5d..cd66e92cb42 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go @@ -281,6 +281,9 @@ const ( SCM_TIMESTAMPNS = 0x23 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103 + SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102 + SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104 SFD_CLOEXEC = 0x80000 SFD_NONBLOCK = 0x80 SIOCATMARK = 0x40047307 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go index 3adb81d7582..c1595eba78e 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go @@ -281,6 +281,9 @@ const ( SCM_TIMESTAMPNS = 0x23 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103 + SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102 + SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104 SFD_CLOEXEC = 0x80000 SFD_NONBLOCK = 0x80 SIOCATMARK = 0x40047307 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go index 2dfe98f0d1b..ee9456b0da7 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go @@ -281,6 +281,9 @@ const ( SCM_TIMESTAMPNS = 0x23 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103 + SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102 + SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104 SFD_CLOEXEC = 0x80000 SFD_NONBLOCK = 0x80 SIOCATMARK = 0x40047307 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go index f5398f84f04..8cfca81e1b5 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go @@ -281,6 +281,9 @@ const ( SCM_TIMESTAMPNS = 0x23 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103 + SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102 + SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104 SFD_CLOEXEC = 0x80000 SFD_NONBLOCK = 0x80 SIOCATMARK = 0x40047307 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go index c54f152d68f..60b0deb3af7 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go @@ -336,6 +336,9 @@ const ( SCM_TIMESTAMPNS = 0x23 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103 + SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102 + SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104 SFD_CLOEXEC = 0x80000 SFD_NONBLOCK = 0x800 SIOCATMARK = 0x8905 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go index 76057dc72fb..f90aa7281bf 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go @@ -340,6 +340,9 @@ const ( SCM_TIMESTAMPNS = 0x23 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103 + SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102 + SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104 SFD_CLOEXEC = 0x80000 SFD_NONBLOCK = 0x800 SIOCATMARK = 0x8905 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go index e0c3725e2b8..ba9e0150338 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go @@ -340,6 +340,9 @@ const ( SCM_TIMESTAMPNS = 0x23 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103 + SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102 + SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104 SFD_CLOEXEC = 0x80000 SFD_NONBLOCK = 0x800 SIOCATMARK = 0x8905 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go index 18f2813ed54..07cdfd6e9fd 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go @@ -272,6 +272,9 @@ const ( SCM_TIMESTAMPNS = 0x23 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103 + SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102 + SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104 SFD_CLOEXEC = 0x80000 SFD_NONBLOCK = 0x800 SIOCATMARK = 0x8905 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go index 11619d4ec88..2f1dd214a74 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go @@ -344,6 +344,9 @@ const ( SCM_TIMESTAMPNS = 0x23 SCM_TXTIME = 0x3d SCM_WIFI_STATUS = 0x29 + SECCOMP_IOCTL_NOTIF_ADDFD = 0x40182103 + SECCOMP_IOCTL_NOTIF_ID_VALID = 0x40082102 + SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x40082104 SFD_CLOEXEC = 0x80000 SFD_NONBLOCK = 0x800 SIOCATMARK = 0x8905 diff --git a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go index 396d994da79..f40519d9018 100644 --- a/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go +++ b/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go @@ -335,6 +335,9 @@ const ( SCM_TIMESTAMPNS = 0x21 SCM_TXTIME = 0x3f SCM_WIFI_STATUS = 0x25 + SECCOMP_IOCTL_NOTIF_ADDFD = 0x80182103 + SECCOMP_IOCTL_NOTIF_ID_VALID = 0x80082102 + SECCOMP_IOCTL_NOTIF_SET_FLAGS = 0x80082104 SFD_CLOEXEC = 0x400000 SFD_NONBLOCK = 0x4000 SF_FP = 0x38 diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go index fcf3ecbddee..0cc3ce496e2 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go @@ -448,4 +448,8 @@ const ( SYS_SET_MEMPOLICY_HOME_NODE = 450 SYS_CACHESTAT = 451 SYS_FCHMODAT2 = 452 + SYS_MAP_SHADOW_STACK = 453 + SYS_FUTEX_WAKE = 454 + SYS_FUTEX_WAIT = 455 + SYS_FUTEX_REQUEUE = 456 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go index f56dc2504ae..856d92d69ef 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go @@ -371,4 +371,7 @@ const ( SYS_CACHESTAT = 451 SYS_FCHMODAT2 = 452 SYS_MAP_SHADOW_STACK = 453 + SYS_FUTEX_WAKE = 454 + SYS_FUTEX_WAIT = 455 + SYS_FUTEX_REQUEUE = 456 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go index 974bf246767..8d467094cf5 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go @@ -412,4 +412,8 @@ const ( SYS_SET_MEMPOLICY_HOME_NODE = 450 SYS_CACHESTAT = 451 SYS_FCHMODAT2 = 452 + SYS_MAP_SHADOW_STACK = 453 + SYS_FUTEX_WAKE = 454 + SYS_FUTEX_WAIT = 455 + SYS_FUTEX_REQUEUE = 456 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go index 39a2739e231..edc173244d0 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go @@ -315,4 +315,8 @@ const ( SYS_SET_MEMPOLICY_HOME_NODE = 450 SYS_CACHESTAT = 451 SYS_FCHMODAT2 = 452 + SYS_MAP_SHADOW_STACK = 453 + SYS_FUTEX_WAKE = 454 + SYS_FUTEX_WAIT = 455 + SYS_FUTEX_REQUEUE = 456 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go index cf9c9d77e10..445eba20615 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go @@ -309,4 +309,8 @@ const ( SYS_SET_MEMPOLICY_HOME_NODE = 450 SYS_CACHESTAT = 451 SYS_FCHMODAT2 = 452 + SYS_MAP_SHADOW_STACK = 453 + SYS_FUTEX_WAKE = 454 + SYS_FUTEX_WAIT = 455 + SYS_FUTEX_REQUEUE = 456 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go index 10b7362ef44..adba01bca70 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go @@ -432,4 +432,8 @@ const ( SYS_SET_MEMPOLICY_HOME_NODE = 4450 SYS_CACHESTAT = 4451 SYS_FCHMODAT2 = 4452 + SYS_MAP_SHADOW_STACK = 4453 + SYS_FUTEX_WAKE = 4454 + SYS_FUTEX_WAIT = 4455 + SYS_FUTEX_REQUEUE = 4456 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go index cd4d8b4fd35..014c4e9c7a7 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go @@ -362,4 +362,8 @@ const ( SYS_SET_MEMPOLICY_HOME_NODE = 5450 SYS_CACHESTAT = 5451 SYS_FCHMODAT2 = 5452 + SYS_MAP_SHADOW_STACK = 5453 + SYS_FUTEX_WAKE = 5454 + SYS_FUTEX_WAIT = 5455 + SYS_FUTEX_REQUEUE = 5456 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go index 2c0efca818b..ccc97d74d05 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go @@ -362,4 +362,8 @@ const ( SYS_SET_MEMPOLICY_HOME_NODE = 5450 SYS_CACHESTAT = 5451 SYS_FCHMODAT2 = 5452 + SYS_MAP_SHADOW_STACK = 5453 + SYS_FUTEX_WAKE = 5454 + SYS_FUTEX_WAIT = 5455 + SYS_FUTEX_REQUEUE = 5456 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go index a72e31d391d..ec2b64a95d7 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go @@ -432,4 +432,8 @@ const ( SYS_SET_MEMPOLICY_HOME_NODE = 4450 SYS_CACHESTAT = 4451 SYS_FCHMODAT2 = 4452 + SYS_MAP_SHADOW_STACK = 4453 + SYS_FUTEX_WAKE = 4454 + SYS_FUTEX_WAIT = 4455 + SYS_FUTEX_REQUEUE = 4456 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go index c7d1e374713..21a839e338b 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go @@ -439,4 +439,8 @@ const ( SYS_SET_MEMPOLICY_HOME_NODE = 450 SYS_CACHESTAT = 451 SYS_FCHMODAT2 = 452 + SYS_MAP_SHADOW_STACK = 453 + SYS_FUTEX_WAKE = 454 + SYS_FUTEX_WAIT = 455 + SYS_FUTEX_REQUEUE = 456 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go index f4d4838c870..c11121ec3b4 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go @@ -411,4 +411,8 @@ const ( SYS_SET_MEMPOLICY_HOME_NODE = 450 SYS_CACHESTAT = 451 SYS_FCHMODAT2 = 452 + SYS_MAP_SHADOW_STACK = 453 + SYS_FUTEX_WAKE = 454 + SYS_FUTEX_WAIT = 455 + SYS_FUTEX_REQUEUE = 456 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go index b64f0e59114..909b631fcb4 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go @@ -411,4 +411,8 @@ const ( SYS_SET_MEMPOLICY_HOME_NODE = 450 SYS_CACHESTAT = 451 SYS_FCHMODAT2 = 452 + SYS_MAP_SHADOW_STACK = 453 + SYS_FUTEX_WAKE = 454 + SYS_FUTEX_WAIT = 455 + SYS_FUTEX_REQUEUE = 456 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go index 95711195a06..e49bed16ea6 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go @@ -316,4 +316,8 @@ const ( SYS_SET_MEMPOLICY_HOME_NODE = 450 SYS_CACHESTAT = 451 SYS_FCHMODAT2 = 452 + SYS_MAP_SHADOW_STACK = 453 + SYS_FUTEX_WAKE = 454 + SYS_FUTEX_WAIT = 455 + SYS_FUTEX_REQUEUE = 456 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go index f94e943bc4f..66017d2d32b 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go @@ -377,4 +377,8 @@ const ( SYS_SET_MEMPOLICY_HOME_NODE = 450 SYS_CACHESTAT = 451 SYS_FCHMODAT2 = 452 + SYS_MAP_SHADOW_STACK = 453 + SYS_FUTEX_WAKE = 454 + SYS_FUTEX_WAIT = 455 + SYS_FUTEX_REQUEUE = 456 ) diff --git a/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go b/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go index ba0c2bc5154..47bab18dced 100644 --- a/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go +++ b/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go @@ -390,4 +390,8 @@ const ( SYS_SET_MEMPOLICY_HOME_NODE = 450 SYS_CACHESTAT = 451 SYS_FCHMODAT2 = 452 + SYS_MAP_SHADOW_STACK = 453 + SYS_FUTEX_WAKE = 454 + SYS_FUTEX_WAIT = 455 + SYS_FUTEX_REQUEUE = 456 ) diff --git a/vendor/golang.org/x/sys/unix/ztypes_linux.go b/vendor/golang.org/x/sys/unix/ztypes_linux.go index bbf8399ff58..dc0c955eecd 100644 --- a/vendor/golang.org/x/sys/unix/ztypes_linux.go +++ b/vendor/golang.org/x/sys/unix/ztypes_linux.go @@ -174,7 +174,8 @@ type FscryptPolicyV2 struct { Contents_encryption_mode uint8 Filenames_encryption_mode uint8 Flags uint8 - _ [4]uint8 + Log2_data_unit_size uint8 + _ [3]uint8 Master_key_identifier [16]uint8 } @@ -455,60 +456,63 @@ type Ucred struct { } type TCPInfo struct { - State uint8 - Ca_state uint8 - Retransmits uint8 - Probes uint8 - Backoff uint8 - Options uint8 - Rto uint32 - Ato uint32 - Snd_mss uint32 - Rcv_mss uint32 - Unacked uint32 - Sacked uint32 - Lost uint32 - Retrans uint32 - Fackets uint32 - Last_data_sent uint32 - Last_ack_sent uint32 - Last_data_recv uint32 - Last_ack_recv uint32 - Pmtu uint32 - Rcv_ssthresh uint32 - Rtt uint32 - Rttvar uint32 - Snd_ssthresh uint32 - Snd_cwnd uint32 - Advmss uint32 - Reordering uint32 - Rcv_rtt uint32 - Rcv_space uint32 - Total_retrans uint32 - Pacing_rate uint64 - Max_pacing_rate uint64 - Bytes_acked uint64 - Bytes_received uint64 - Segs_out uint32 - Segs_in uint32 - Notsent_bytes uint32 - Min_rtt uint32 - Data_segs_in uint32 - Data_segs_out uint32 - Delivery_rate uint64 - Busy_time uint64 - Rwnd_limited uint64 - Sndbuf_limited uint64 - Delivered uint32 - Delivered_ce uint32 - Bytes_sent uint64 - Bytes_retrans uint64 - Dsack_dups uint32 - Reord_seen uint32 - Rcv_ooopack uint32 - Snd_wnd uint32 - Rcv_wnd uint32 - Rehash uint32 + State uint8 + Ca_state uint8 + Retransmits uint8 + Probes uint8 + Backoff uint8 + Options uint8 + Rto uint32 + Ato uint32 + Snd_mss uint32 + Rcv_mss uint32 + Unacked uint32 + Sacked uint32 + Lost uint32 + Retrans uint32 + Fackets uint32 + Last_data_sent uint32 + Last_ack_sent uint32 + Last_data_recv uint32 + Last_ack_recv uint32 + Pmtu uint32 + Rcv_ssthresh uint32 + Rtt uint32 + Rttvar uint32 + Snd_ssthresh uint32 + Snd_cwnd uint32 + Advmss uint32 + Reordering uint32 + Rcv_rtt uint32 + Rcv_space uint32 + Total_retrans uint32 + Pacing_rate uint64 + Max_pacing_rate uint64 + Bytes_acked uint64 + Bytes_received uint64 + Segs_out uint32 + Segs_in uint32 + Notsent_bytes uint32 + Min_rtt uint32 + Data_segs_in uint32 + Data_segs_out uint32 + Delivery_rate uint64 + Busy_time uint64 + Rwnd_limited uint64 + Sndbuf_limited uint64 + Delivered uint32 + Delivered_ce uint32 + Bytes_sent uint64 + Bytes_retrans uint64 + Dsack_dups uint32 + Reord_seen uint32 + Rcv_ooopack uint32 + Snd_wnd uint32 + Rcv_wnd uint32 + Rehash uint32 + Total_rto uint16 + Total_rto_recoveries uint16 + Total_rto_time uint32 } type CanFilter struct { @@ -551,7 +555,7 @@ const ( SizeofIPv6MTUInfo = 0x20 SizeofICMPv6Filter = 0x20 SizeofUcred = 0xc - SizeofTCPInfo = 0xf0 + SizeofTCPInfo = 0xf8 SizeofCanFilter = 0x8 SizeofTCPRepairOpt = 0x8 ) @@ -3399,7 +3403,7 @@ const ( DEVLINK_PORT_FN_ATTR_STATE = 0x2 DEVLINK_PORT_FN_ATTR_OPSTATE = 0x3 DEVLINK_PORT_FN_ATTR_CAPS = 0x4 - DEVLINK_PORT_FUNCTION_ATTR_MAX = 0x4 + DEVLINK_PORT_FUNCTION_ATTR_MAX = 0x5 ) type FsverityDigest struct { @@ -4183,7 +4187,8 @@ const ( ) type LandlockRulesetAttr struct { - Access_fs uint64 + Access_fs uint64 + Access_net uint64 } type LandlockPathBeneathAttr struct { @@ -5134,7 +5139,7 @@ const ( NL80211_FREQUENCY_ATTR_GO_CONCURRENT = 0xf NL80211_FREQUENCY_ATTR_INDOOR_ONLY = 0xe NL80211_FREQUENCY_ATTR_IR_CONCURRENT = 0xf - NL80211_FREQUENCY_ATTR_MAX = 0x1b + NL80211_FREQUENCY_ATTR_MAX = 0x1c NL80211_FREQUENCY_ATTR_MAX_TX_POWER = 0x6 NL80211_FREQUENCY_ATTR_NO_10MHZ = 0x11 NL80211_FREQUENCY_ATTR_NO_160MHZ = 0xc @@ -5547,7 +5552,7 @@ const ( NL80211_REGDOM_TYPE_CUSTOM_WORLD = 0x2 NL80211_REGDOM_TYPE_INTERSECTION = 0x3 NL80211_REGDOM_TYPE_WORLD = 0x1 - NL80211_REG_RULE_ATTR_MAX = 0x7 + NL80211_REG_RULE_ATTR_MAX = 0x8 NL80211_REKEY_DATA_AKM = 0x4 NL80211_REKEY_DATA_KCK = 0x2 NL80211_REKEY_DATA_KEK = 0x1 diff --git a/vendor/golang.org/x/sys/windows/env_windows.go b/vendor/golang.org/x/sys/windows/env_windows.go index b8ad1925068..d4577a42388 100644 --- a/vendor/golang.org/x/sys/windows/env_windows.go +++ b/vendor/golang.org/x/sys/windows/env_windows.go @@ -37,14 +37,17 @@ func (token Token) Environ(inheritExisting bool) (env []string, err error) { return nil, err } defer DestroyEnvironmentBlock(block) - blockp := unsafe.Pointer(block) - for { - entry := UTF16PtrToString((*uint16)(blockp)) - if len(entry) == 0 { - break + size := unsafe.Sizeof(*block) + for *block != 0 { + // find NUL terminator + end := unsafe.Pointer(block) + for *(*uint16)(end) != 0 { + end = unsafe.Add(end, size) } - env = append(env, entry) - blockp = unsafe.Add(blockp, 2*(len(entry)+1)) + + entry := unsafe.Slice(block, (uintptr(end)-uintptr(unsafe.Pointer(block)))/size) + env = append(env, UTF16ToString(entry)) + block = (*uint16)(unsafe.Add(end, size)) } return env, nil } diff --git a/vendor/golang.org/x/sys/windows/syscall_windows.go b/vendor/golang.org/x/sys/windows/syscall_windows.go index ffb8708ccf8..6395a031d45 100644 --- a/vendor/golang.org/x/sys/windows/syscall_windows.go +++ b/vendor/golang.org/x/sys/windows/syscall_windows.go @@ -125,8 +125,7 @@ func UTF16PtrToString(p *uint16) string { for ptr := unsafe.Pointer(p); *(*uint16)(ptr) != 0; n++ { ptr = unsafe.Pointer(uintptr(ptr) + unsafe.Sizeof(*p)) } - - return string(utf16.Decode(unsafe.Slice(p, n))) + return UTF16ToString(unsafe.Slice(p, n)) } func Getpagesize() int { return 4096 } diff --git a/vendor/modules.txt b/vendor/modules.txt index fda63f13371..efabdff0346 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -398,8 +398,8 @@ github.com/modern-go/reflect2 # github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 ## explicit github.com/munnerz/goautoneg -# github.com/onsi/gomega v1.30.0 -## explicit; go 1.18 +# github.com/onsi/gomega v1.31.1 +## explicit; go 1.20 github.com/onsi/gomega github.com/onsi/gomega/format github.com/onsi/gomega/internal @@ -413,7 +413,7 @@ github.com/onsi/gomega/types # github.com/open-policy-agent/cert-controller v0.10.1 ## explicit; go 1.20 github.com/open-policy-agent/cert-controller/pkg/rotator -# github.com/open-policy-agent/frameworks/constraint v0.0.0-20240110234408-18fa1fc7dc06 +# github.com/open-policy-agent/frameworks/constraint v0.0.0-20240219192228-76869f816908 ## explicit; go 1.18 github.com/open-policy-agent/frameworks/constraint/deploy github.com/open-policy-agent/frameworks/constraint/pkg/apis @@ -723,7 +723,7 @@ go.uber.org/zap/internal/exit go.uber.org/zap/internal/pool go.uber.org/zap/internal/stacktrace go.uber.org/zap/zapcore -# golang.org/x/crypto v0.18.0 +# golang.org/x/crypto v0.19.0 ## explicit; go 1.18 golang.org/x/crypto/chacha20 golang.org/x/crypto/chacha20poly1305 @@ -737,7 +737,7 @@ golang.org/x/crypto/internal/poly1305 golang.org/x/exp/constraints golang.org/x/exp/maps golang.org/x/exp/slices -# golang.org/x/net v0.20.0 +# golang.org/x/net v0.21.0 ## explicit; go 1.18 golang.org/x/net/context golang.org/x/net/html @@ -765,7 +765,7 @@ golang.org/x/oauth2/jwt golang.org/x/sync/errgroup golang.org/x/sync/semaphore golang.org/x/sync/singleflight -# golang.org/x/sys v0.16.0 +# golang.org/x/sys v0.17.0 ## explicit; go 1.18 golang.org/x/sys/cpu golang.org/x/sys/execabs @@ -773,7 +773,7 @@ golang.org/x/sys/plan9 golang.org/x/sys/unix golang.org/x/sys/windows golang.org/x/sys/windows/registry -# golang.org/x/term v0.16.0 +# golang.org/x/term v0.17.0 ## explicit; go 1.18 golang.org/x/term # golang.org/x/text v0.14.0