diff --git a/go.mod b/go.mod index 7c97a067..9abb6062 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.24.2 require ( github.com/Masterminds/sprig/v3 v3.3.0 github.com/go-logr/logr v1.4.2 + github.com/gobwas/glob v0.2.3 github.com/hashicorp/go-multierror v1.1.1 github.com/iancoleman/strcase v0.3.0 github.com/onsi/ginkgo/v2 v2.23.4 @@ -50,11 +51,9 @@ require ( github.com/go-openapi/swag v0.23.0 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/protobuf v1.5.4 // indirect github.com/google/btree v1.1.3 // indirect github.com/google/gnostic-models v0.6.9 // indirect github.com/google/go-cmp v0.7.0 // indirect - github.com/google/gofuzz v1.2.0 // indirect github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.6.0 // indirect diff --git a/go.sum b/go.sum index 4f0f685c..28751a48 100644 --- a/go.sum +++ b/go.sum @@ -47,10 +47,10 @@ github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+Gr github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= +github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= -github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg= github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= @@ -61,8 +61,6 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= -github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8= github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= @@ -115,8 +113,6 @@ github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/ github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4= 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/onsi/ginkgo/v2 v2.23.3 h1:edHxnszytJ4lD9D5Jjc4tiDkPBZ3siDeJJkUZJJVkp0= -github.com/onsi/ginkgo/v2 v2.23.3/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM= github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus= github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8= github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y= @@ -128,6 +124,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= +github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= @@ -136,11 +134,9 @@ github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sap/go-generics v0.2.31 h1:AM1+V5ytqn6IN16JdjdSIsF3AckiplmQnXyBzECjy2w= -github.com/sap/go-generics v0.2.31/go.mod h1:RahWFdEaztludxH9GOvH8N5kJJkpxTfn93C/o1gXcHE= github.com/sap/go-generics v0.2.32 h1:ip5J8BFUWxPJvtEdsjK9CrHgsGeqLtA3nYmIBOMtgJE= github.com/sap/go-generics v0.2.32/go.mod h1:sp7WNwGuu8dapfhzJIzugANpSq8D3H/YClbCl8fbPgQ= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= @@ -185,12 +181,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= -golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= -golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= -golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M= golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -202,8 +194,6 @@ golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= @@ -218,8 +208,6 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= -golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU= golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -240,46 +228,20 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.32.3 h1:Hw7KqxRusq+6QSplE3NYG4MBxZw1BZnq4aP4cJVINls= -k8s.io/api v0.32.3/go.mod h1:2wEDTXADtm/HA7CCMD8D8bK4yuBUptzaRhYcYEEYA3k= -k8s.io/api v0.32.4 h1:kw8Y/G8E7EpNy7gjB8gJZl3KJkNz8HM2YHrZPtAZsF4= -k8s.io/api v0.32.4/go.mod h1:5MYFvLvweRhyKylM3Es/6uh/5hGp0dg82vP34KifX4g= k8s.io/api v0.33.0 h1:yTgZVn1XEe6opVpP1FylmNrIFWuDqe2H0V8CT5gxfIU= k8s.io/api v0.33.0/go.mod h1:CTO61ECK/KU7haa3qq8sarQ0biLq2ju405IZAd9zsiM= -k8s.io/apiextensions-apiserver v0.32.3 h1:4D8vy+9GWerlErCwVIbcQjsWunF9SUGNu7O7hiQTyPY= -k8s.io/apiextensions-apiserver v0.32.3/go.mod h1:8YwcvVRMVzw0r1Stc7XfGAzB/SIVLunqApySV5V7Dss= -k8s.io/apiextensions-apiserver v0.32.4 h1:IA+CoR63UDOijR/vEpow6wQnX4V6iVpzazJBskHrpHE= -k8s.io/apiextensions-apiserver v0.32.4/go.mod h1:Y06XO/b92H8ymOdG1HlA1submf7gIhbEDc3RjriqZOs= k8s.io/apiextensions-apiserver v0.33.0 h1:d2qpYL7Mngbsc1taA4IjJPRJ9ilnsXIrndH+r9IimOs= k8s.io/apiextensions-apiserver v0.33.0/go.mod h1:VeJ8u9dEEN+tbETo+lFkwaaZPg6uFKLGj5vyNEwwSzc= -k8s.io/apimachinery v0.32.3 h1:JmDuDarhDmA/Li7j3aPrwhpNBA94Nvk5zLeOge9HH1U= -k8s.io/apimachinery v0.32.3/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= -k8s.io/apimachinery v0.32.4 h1:8EEksaxA7nd7xWJkkwLDN4SvWS5ot9g6Z/VZb3ju25I= -k8s.io/apimachinery v0.32.4/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= k8s.io/apimachinery v0.33.0 h1:1a6kHrJxb2hs4t8EE5wuR/WxKDwGN1FKH3JvDtA0CIQ= k8s.io/apimachinery v0.33.0/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= -k8s.io/cli-runtime v0.32.3 h1:khLF2ivU2T6Q77H97atx3REY9tXiA3OLOjWJxUrdvss= -k8s.io/cli-runtime v0.32.3/go.mod h1:vZT6dZq7mZAca53rwUfdFSZjdtLyfF61mkf/8q+Xjak= -k8s.io/cli-runtime v0.32.4 h1:5O9eC50+yFFODAan3QXeTJHtoe69ie/A9vWBITIn+KM= -k8s.io/cli-runtime v0.32.4/go.mod h1:Zn7nvBY625sEEYGtTMMPS619nrmVxabGssHyAKFK7RA= k8s.io/cli-runtime v0.33.0 h1:Lbl/pq/1o8BaIuyn+aVLdEPHVN665tBAXUePs8wjX7c= k8s.io/cli-runtime v0.33.0/go.mod h1:QcA+r43HeUM9jXFJx7A+yiTPfCooau/iCcP1wQh4NFw= -k8s.io/client-go v0.32.3 h1:RKPVltzopkSgHS7aS98QdscAgtgah/+zmpAogooIqVU= -k8s.io/client-go v0.32.3/go.mod h1:3v0+3k4IcT9bXTc4V2rt+d2ZPPG700Xy6Oi0Gdl2PaY= -k8s.io/client-go v0.32.4 h1:zaGJS7xoYOYumoWIFXlcVrsiYioRPrXGO7dBfVC5R6M= -k8s.io/client-go v0.32.4/go.mod h1:k0jftcyYnEtwlFW92xC7MTtFv5BNcZBr+zn9jPlT9Ic= k8s.io/client-go v0.33.0 h1:UASR0sAYVUzs2kYuKn/ZakZlcs2bEHaizrrHUZg0G98= k8s.io/client-go v0.33.0/go.mod h1:kGkd+l/gNGg8GYWAPr0xF1rRKvVWvzh9vmZAMXtaKOg= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-aggregator v0.32.3 h1:j+lUE4V1sMANYv/wCdU2E8SgnSLJksaJ+6bNnoV6Pfs= -k8s.io/kube-aggregator v0.32.3/go.mod h1:aAl5az9Rlq4sPPSf8/ckpDGSYit75g4g1dp6rKInXZM= -k8s.io/kube-aggregator v0.32.4 h1:4ma+w6nwvc2nsMohZtVcEGWCI8ro4tVKbuxCx3qBMbI= -k8s.io/kube-aggregator v0.32.4/go.mod h1:2mtQeDk9CUqFDCNRn+dBLVzIR2a2eJ9KnEwqfTkxpJU= k8s.io/kube-aggregator v0.33.0 h1:jTjEe/DqpJcaPp4x1CjNaMb1XPD+H8SSf/yVpC8coFg= k8s.io/kube-aggregator v0.33.0/go.mod h1:6BRnSnWzh6nWUxjQhNwGP9gMnPfSW0WsFeOZGMHtvZw= -k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7 h1:hcha5B1kVACrLujCKLbr8XWMxCxzQx42DY8QKYJrDLg= -k8s.io/kube-openapi v0.0.0-20241212222426-2c72e554b1e7/go.mod h1:GewRfANuJ70iYzvn+i4lezLDAFzvjxZYK1gn1lWcfas= k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4= k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8= k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= @@ -294,12 +256,9 @@ sigs.k8s.io/kustomize/api v0.19.0 h1:F+2HB2mU1MSiR9Hp1NEgoU2q9ItNOaBJl0I4Dlus5SQ sigs.k8s.io/kustomize/api v0.19.0/go.mod h1:/BbwnivGVcBh1r+8m3tH1VNxJmHSk1PzP5fkP6lbL1o= sigs.k8s.io/kustomize/kyaml v0.19.0 h1:RFge5qsO1uHhwJsu3ipV7RNolC7Uozc0jUBC/61XSlA= sigs.k8s.io/kustomize/kyaml v0.19.0/go.mod h1:FeKD5jEOH+FbZPpqUghBP8mrLjJ3+zD3/rf9NNu1cwY= -sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016 h1:kXv6kKdoEtedwuqMmkqhbkgvYKeycVbC8+iPCP9j5kQ= sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0 h1:IUA9nvMmnKWcj5jl84xn+T5MnlZKThmUW1TdblaLVAc= -sigs.k8s.io/structured-merge-diff/v4 v4.6.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI= sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= diff --git a/internal/fileutils/find.go b/internal/fileutils/find.go index 8f91bd18..fe179f4b 100644 --- a/internal/fileutils/find.go +++ b/internal/fileutils/find.go @@ -65,6 +65,7 @@ func fileTypeFromMode(mode fs.FileMode) uint { // in this file; passing any other values will lead to a panic; supplying fileType as zero is the same as passing fileTypeAny. // The parameter maxDepth can be any integer between 0 and 10000 (where 0 is interpreted as 10000). // The returned paths will be relative (to the provided fsys), and filepath.Clean() will be run on each entry. +// Note that Find() does not follow symlinks. func Find(fsys fs.FS, dir string, namePattern string, fileType uint, maxDepth uint) ([]string, error) { if dir == "" { dir = "." diff --git a/internal/helm/chart.go b/internal/helm/chart.go index 4d1241aa..3bdd3c37 100644 --- a/internal/helm/chart.go +++ b/internal/helm/chart.go @@ -31,6 +31,7 @@ import ( ) // TODO: give errors more context +// TODO: double-check symlink handling type RenderContext struct { LocalClient client.Client @@ -48,6 +49,7 @@ type Chart struct { crds [][]byte t0 *template.Template templates []string + files Files } func ParseChart(fsys fs.FS, chartPath string, parent *Chart) (*Chart, error) { @@ -71,6 +73,8 @@ func ParseChart(fsys fs.FS, chartPath string, parent *Chart) (*Chart, error) { } chartPath = filepath.Clean(chartPath) + // TODO: we should filter out according to .helmignore + chartRaw, err := fs.ReadFile(fsys, filepath.Clean(chartPath+"/Chart.yaml")) if err != nil { return nil, err @@ -87,7 +91,7 @@ func ParseChart(fsys fs.FS, chartPath string, parent *Chart) (*Chart, error) { } if chart.metadata.Type == ChartTypeApplication { - crds, err := fileutils.Find(fsys, filepath.Clean(chartPath+"/crds"), "*.yaml", fileutils.FileTypeRegular, 0) + crds, err := fileutils.Find(fsys, filepath.Clean(chartPath+"/crds"), "*.yaml", fileutils.FileTypeRegular|fileutils.FileTypeSymlink, 0) if err != nil { return nil, err } @@ -99,7 +103,7 @@ func ParseChart(fsys fs.FS, chartPath string, parent *Chart) (*Chart, error) { chart.crds = append(chart.crds, raw) } - manifests, err := fileutils.Find(fsys, filepath.Clean(chartPath+"/templates"), "[^_]*.yaml", fileutils.FileTypeRegular, 0) + manifests, err := fileutils.Find(fsys, filepath.Clean(chartPath+"/templates"), "[^_]*.yaml", fileutils.FileTypeRegular|fileutils.FileTypeSymlink, 0) if err != nil { return nil, err } @@ -110,7 +114,7 @@ func ParseChart(fsys fs.FS, chartPath string, parent *Chart) (*Chart, error) { } } - includes, err := fileutils.Find(fsys, filepath.Clean(chartPath+"/templates"), "_*", fileutils.FileTypeRegular, 0) + includes, err := fileutils.Find(fsys, filepath.Clean(chartPath+"/templates"), "_*", fileutils.FileTypeRegular|fileutils.FileTypeSymlink, 0) if err != nil { return nil, err } @@ -120,6 +124,19 @@ func ParseChart(fsys fs.FS, chartPath string, parent *Chart) (*Chart, error) { } } + chart.files = Files{} + files, err := fileutils.Find(fsys, "", "", fileutils.FileTypeRegular|fileutils.FileTypeSymlink, 0) + if err != nil { + return nil, err + } + for _, file := range files { + raw, err := fs.ReadFile(fsys, file) + if err != nil { + return nil, err + } + chart.files.add(file, raw) + } + valuesRaw, err := fs.ReadFile(fsys, filepath.Clean(chartPath+"/values.yaml")) if err == nil { chart.values = make(map[string]any) @@ -246,6 +263,7 @@ func (c *Chart) render(name string, t0 *template.Template, capabilities *Capabil data["Capabilities"] = capabilities data["Release"] = release data["Values"] = values + data["Files"] = c.files for _, dep := range c.metadata.Dependencies { enabled := true diff --git a/internal/helm/files.go b/internal/helm/files.go new file mode 100644 index 00000000..23922eae --- /dev/null +++ b/internal/helm/files.go @@ -0,0 +1,99 @@ +/* +SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and component-operator-runtime contributors +SPDX-License-Identifier: Apache-2.0 +*/ + +package helm + +import ( + "encoding/base64" + "path" + "strings" + + "github.com/gobwas/glob" + + kyaml "sigs.k8s.io/yaml" +) + +type Files map[string][]byte + +func (f Files) add(name string, data []byte) { + if isIgnored(name) { + return + } + f[name] = data +} + +func (f Files) Get(name string) string { + return string(f.GetBytes(name)) +} + +func (f Files) GetBytes(name string) []byte { + if data, ok := f[name]; ok { + return data + } + return []byte{} +} + +func (f Files) Lines(name string) []string { + data, ok := f[name] + if !ok { + return []string{} + } + s := string(data) + if s[len(s)-1] == '\n' { + s = s[:len(s)-1] + } + return strings.Split(s, "\n") +} + +func (f Files) Glob(pattern string) (Files, error) { + g, err := glob.Compile(pattern, '/') + if err != nil { + return nil, err + } + + files := Files{} + + for name, data := range f { + if g.Match(name) { + files[name] = data + } + } + + return files, nil +} + +func (f Files) AsConfig() string { + configData := make(map[string]string) + + for name, data := range f { + configData[path.Base(name)] = string(data) + } + + // note: this must() is ok because the map can always be serialized + return string(must(kyaml.Marshal(configData))) +} + +func (f Files) AsSecrets() string { + secretData := make(map[string]string) + + for name, data := range f { + secretData[path.Base(name)] = base64.StdEncoding.EncodeToString(data) + } + + // note: this must() is ok because the map can always be serialized + return string(must(kyaml.Marshal(secretData))) +} + +func isIgnored(name string) bool { + return name == "Chart.yaml" || + name == "LICENSE" || + name == "README.md" || + name == "values.yaml" || + name == "values.schema.json" || + name == ".helmignore" || + strings.HasPrefix(name, "charts/") || + strings.HasPrefix(name, "crds/") || + strings.HasPrefix(name, "templates/") +} diff --git a/internal/helm/util.go b/internal/helm/util.go index a7ce2b9b..6dc917ac 100644 --- a/internal/helm/util.go +++ b/internal/helm/util.go @@ -70,6 +70,13 @@ func getArray(data map[string]any, key string) ([]any, bool, bool) { } */ +func must[T any](x T, err error) T { + if err != nil { + panic(err) + } + return x +} + func getMap(data map[string]any, key string) (map[string]any, bool, bool) { if v, ok := data[key]; ok { if v, ok := v.(map[string]any); ok { diff --git a/pkg/component/reconciler.go b/pkg/component/reconciler.go index cb711cb7..92f1197a 100755 --- a/pkg/component/reconciler.go +++ b/pkg/component/reconciler.go @@ -327,9 +327,9 @@ func (r *Reconciler[T]) Reconcile(ctx context.Context, req ctrl.Request) (result err = nil } else { if component.GetDeletionTimestamp().IsZero() && haveTimeout { - status.SetState(StateError, ReadyConditionReasonTimeout, err.Error()) + status.SetState(StateError, ReadyConditionReasonTimeout, capitalize(err.Error())) } else { - status.SetState(StateError, ReadyConditionReasonError, err.Error()) + status.SetState(StateError, ReadyConditionReasonError, capitalize(err.Error())) } } } diff --git a/pkg/manifests/helm/generator.go b/pkg/manifests/helm/generator.go index ade297aa..b0f41401 100644 --- a/pkg/manifests/helm/generator.go +++ b/pkg/manifests/helm/generator.go @@ -39,6 +39,9 @@ var _ manifests.Generator = &HelmGenerator{} // The client parameter is deprecated (ignored) and will be removed in a future release. // If fsys is nil, the local operating system filesystem will be used, and chartPath can be an absolute or relative path (in the latter case it will be considered // relative to the current working directory). If fsys is non-nil, then chartPath should be a relative path; if an absolute path is supplied, it will be turned +// into a relative path by stripping the leading slash. If fsys is specified as a real filesystem, it is recommended to use os.Root.FS() instead of os.DirFS(), +// in order to fence symbolic links. + // An empty chartPath will be treated like ".". func NewHelmGenerator(fsys fs.FS, chartPath string, _ client.Client) (*HelmGenerator, error) { chart, err := helm.ParseChart(fsys, chartPath, nil) diff --git a/pkg/manifests/kustomize/generator.go b/pkg/manifests/kustomize/generator.go index 0dab8e59..d1b6755d 100644 --- a/pkg/manifests/kustomize/generator.go +++ b/pkg/manifests/kustomize/generator.go @@ -18,6 +18,8 @@ import ( "text/template" "github.com/Masterminds/sprig/v3" + "github.com/gobwas/glob" + "github.com/sap/go-generics/maps" "github.com/sap/go-generics/slices" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -39,6 +41,7 @@ import ( ) // TODO: carve out logic into an internal Kustomization type (similar to the helm Chart case) +// TODO: double-check symlink handling const ( componentConfigFilename = ".component-config.yaml" @@ -58,9 +61,10 @@ type KustomizeGeneratorOptions struct { // Note: KustomizeGenerator's Generate() method expects local client, client and component to be set in the passed context; // see: Context.WithLocalClient(), Context.WithClient() and Context.WithComponent() in package pkg/component. type KustomizeGenerator struct { - kustomizer *krusty.Kustomizer - files map[string][]byte - templates map[string]*template.Template + kustomizer *krusty.Kustomizer + files map[string][]byte + nonTemplates map[string][]byte + templates map[string]*template.Template } var _ manifests.Generator = &KustomizeGenerator{} @@ -71,7 +75,8 @@ var _ manifests.Generator = &KustomizeGenerator{} // The client parameter is deprecated (ignored) and will be removed in a future release. // If fsys is nil, the local operating system filesystem will be used, and kustomizationPath can be an absolute or relative path (in the latter case it will be considered // relative to the current working directory). If fsys is non-nil, then kustomizationPath should be a relative path; if an absolute path is supplied, it will be turned -// An empty kustomizationPath will be treated like ".". +// into a relative path by stripping the leading slash. If fsys is specified as a real filesystem, it is recommended to use os.Root.FS() instead of os.DirFS(), in order +// to fence symbolic links. An empty kustomizationPath will be treated like ".". func NewKustomizeGenerator(fsys fs.FS, kustomizationPath string, _ client.Client, options KustomizeGeneratorOptions) (*KustomizeGenerator, error) { if options.TemplateSuffix == nil { options.TemplateSuffix = ref("") @@ -84,8 +89,9 @@ func NewKustomizeGenerator(fsys fs.FS, kustomizationPath string, _ client.Client } g := KustomizeGenerator{ - files: make(map[string][]byte), - templates: make(map[string]*template.Template), + files: make(map[string][]byte), + nonTemplates: make(map[string][]byte), + templates: make(map[string]*template.Template), } if fsys == nil { @@ -116,7 +122,7 @@ func NewKustomizeGenerator(fsys fs.FS, kustomizationPath string, _ client.Client // (which is probably a common usecase); however it has to be clarified how to handle template scopes; // for example it might be desired that subtrees with a kustomization.yaml file are processed in an own // template context - files, err := fileutils.Find(fsys, kustomizationPath, "*", fileutils.FileTypeRegular, 0) + files, err := fileutils.Find(fsys, kustomizationPath, "*", fileutils.FileTypeRegular|fileutils.FileTypeSymlink, 0) if err != nil { return nil, err } @@ -128,6 +134,7 @@ func NewKustomizeGenerator(fsys fs.FS, kustomizationPath string, _ client.Client // Note: we use relative paths as templates names to make it easier to copy the kustomization // content into the ephemeral in-memory filesystem used by krusty in Generate() name, err := filepath.Rel(kustomizationPath, file) + g.files[name] = raw if err != nil { // TODO: is it ok to panic here in case of error ? panic("this cannot happen") @@ -142,7 +149,7 @@ func NewKustomizeGenerator(fsys fs.FS, kustomizationPath string, _ client.Client Funcs(templatex.FuncMapForTemplate(nil)). Funcs(templatex.FuncMapForLocalClient(nil)). Funcs(templatex.FuncMapForClient(nil)). - Funcs(funcMapForGenerateContext(nil, nil, nil, "", "")) + Funcs(funcMapForGenerateContext(nil, nil, nil, nil, "", "")) } else { t = t.New(name) } @@ -151,11 +158,11 @@ func NewKustomizeGenerator(fsys fs.FS, kustomizationPath string, _ client.Client } g.templates[strings.TrimSuffix(name, *options.TemplateSuffix)] = t } else { - g.files[name] = raw + g.nonTemplates[name] = raw } } - // TODO: check that g.files and g.templates are disjoint + // TODO: check that g.nonTemplates and g.templates are disjoint return &g, nil } @@ -216,7 +223,7 @@ func (g *KustomizeGenerator) Generate(ctx context.Context, namespace string, nam data := parameters.ToUnstructured() fsys := kustfsys.MakeFsInMemory() - for n, f := range g.files { + for n, f := range g.nonTemplates { if err := fsys.WriteFile(n, f); err != nil { return nil, err } @@ -233,7 +240,7 @@ func (g *KustomizeGenerator) Generate(ctx context.Context, namespace string, nam Funcs(templatex.FuncMapForTemplate(t0)). Funcs(templatex.FuncMapForLocalClient(localClient)). Funcs(templatex.FuncMapForClient(clnt)). - Funcs(funcMapForGenerateContext(serverVersion, serverGroupsWithResources, component, namespace, name)) + Funcs(funcMapForGenerateContext(g.files, serverVersion, serverGroupsWithResources, component, namespace, name)) } var buf bytes.Buffer // TODO: templates (accidentally or intentionally) could modify data, or even some of the objects supplied through builtin functions; @@ -292,10 +299,13 @@ func (g *KustomizeGenerator) Generate(ctx context.Context, namespace string, nam return objects, nil } -func funcMapForGenerateContext(serverInfo *version.Info, serverGroupsWithResources []*metav1.APIResourceList, component component.Component, namespace string, name string) template.FuncMap { +func funcMapForGenerateContext(files map[string][]byte, serverInfo *version.Info, serverGroupsWithResources []*metav1.APIResourceList, component component.Component, namespace string, name string) template.FuncMap { return template.FuncMap{ // TODO: maybe it would it be better to convert component to unstructured; // then calling methods would no longer be possible, and attributes would be in lowercase + "listFiles": makeFuncListFiles(files), + "existsFile": makeFuncExistsFile(files), + "readFile": makeFuncReadFile(files), "component": makeFuncData(component), "namespace": func() string { return namespace }, "name": func() string { return name }, @@ -304,6 +314,33 @@ func funcMapForGenerateContext(serverInfo *version.Info, serverGroupsWithResourc } } +func makeFuncListFiles(files map[string][]byte) func(pattern string) ([]string, error) { + return func(pattern string) ([]string, error) { + g, err := glob.Compile(pattern, '/') + if err != nil { + return nil, err + } + return slices.Select(maps.Keys(files), func(path string) bool { return g.Match(path) }), nil + } +} + +func makeFuncExistsFile(files map[string][]byte) func(path string) bool { + return func(path string) bool { + _, ok := files[path] + return ok + } +} + +func makeFuncReadFile(files map[string][]byte) func(path string) ([]byte, error) { + return func(path string) ([]byte, error) { + data, ok := files[path] + if !ok { + return nil, fs.ErrNotExist + } + return data, nil + } +} + func makeFuncData(data any) any { if data == nil { return func() any { return nil } @@ -322,12 +359,14 @@ func generateKustomization(fsys kustfsys.FileSystem) ([]byte, error) { if err != nil { return err } + // TODO: IsDir() is false if it is a symlink; is that wanted to be this way? if !info.IsDir() && !strings.HasPrefix(filepath.Base(path), ".") && (strings.HasSuffix(path, ".yaml") || strings.HasSuffix(path, ".yml")) { resources = append(resources, path) } return nil } + // TODO: does this work correctly with symlinks? if err := fsys.Walk(".", f); err != nil { return nil, err } diff --git a/website/content/en/docs/generators/helm.md b/website/content/en/docs/generators/helm.md index b3b31d09..ff26db39 100644 --- a/website/content/en/docs/generators/helm.md +++ b/website/content/en/docs/generators/helm.md @@ -32,5 +32,6 @@ A few differences and restrictions arise from this: - for the `.Chart` builtin, only `.Chart.Name`, `.Chart.Version`, `.Chart.Type`, `.Chart.AppVersion`, `.Chart.Dependencies` are supported - for the `.Capabilities` builtin, only `.Capabilities.KubeVersion` and `.Capabilities.APIVersions` are supported - the `.Template` builtin is fully supported - - the `.Files` builtin is not supported at all. -- Regarding hooks, `pre-delete` and `post-delete` hooks are not allowed; test and rollback hooks are ignored, and `pre-install`, `post-install`, `pre-upgrade`, `post-upgrade` hooks might be handled in a sligthly different way; hook weights will be handled in a compatible way; hook deletion policy `hook-failed` is not allowed, but `before-hook-creation` and `hook-succeeded` should work as expected. \ No newline at end of file + - the `.Files` builtin is supported but does not return any of the paths reserved by Helm (such as `Chart.yaml`, `templates/` and so on) +- Regarding hooks, `pre-delete` and `post-delete` hooks are not allowed; test and rollback hooks are ignored, and `pre-install`, `post-install`, `pre-upgrade`, `post-upgrade` hooks might be handled in a sligthly different way; hook weights will be handled in a compatible way; hook deletion policy `hook-failed` is not allowed, but `before-hook-creation` and `hook-succeeded` should work as expected. +- The `.helmignore` file is currently not evaluated; in particular, files can be accessed through `.Files` altough they are listed in `.helmignore`. \ No newline at end of file diff --git a/website/content/en/docs/generators/kustomize.md b/website/content/en/docs/generators/kustomize.md index 414b80a2..e4c18ef7 100644 --- a/website/content/en/docs/generators/kustomize.md +++ b/website/content/en/docs/generators/kustomize.md @@ -13,7 +13,9 @@ In addition, all (or selected; see below) files in the kustomization directory c That means, they will be considered as a common template group (where all templates are associated with each other), and the same template function set that is available on Helm can be used; so, all the [sprig](http://masterminds.github.io/sprig) functions, and custom functions such as `include`, `tpl`, `lookup` can be used. In addition: - parameterless functions `namespace` and `name` are defined, which return the corresponding arguments passed to `Generate()` -- a function `kubernetesVersion` is available, which returns the version information of the target cluster, as a [version.Info](https://pkg.go.dev/k8s.io/apimachinery/pkg/version#Info) structure. +- a function `kubernetesVersion` is available, which returns the version information of the target cluster, as a [version.Info](https://pkg.go.dev/k8s.io/apimachinery/pkg/version#Info) structure +- files from the kustomization path can be retrieved using the template function `readFile`; there are auxiliary functions `existsFile` and `listFiles`, + the latter one expecting a pattern as supported by the [gobwas/glob](https://pkg.go.dev/github.com/gobwas/glob) library. In the generation step, first, all the go templates will be rendered, and the result of this pre-step will be passed to kustomize.