diff --git a/go.mod b/go.mod index c5509ad5f..cc8c4e21f 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( k8s.io/kubernetes v1.34.4 k8s.io/utils v0.0.0-20251002143259-bc988d571ff4 sigs.k8s.io/controller-runtime v0.22.4 - sigs.k8s.io/structured-merge-diff/v6 v6.3.0 + sigs.k8s.io/structured-merge-diff/v6 v6.3.1 sigs.k8s.io/yaml v1.6.0 ) diff --git a/go.sum b/go.sum index d99b37976..efd3c6a19 100644 --- a/go.sum +++ b/go.sum @@ -392,7 +392,7 @@ sigs.k8s.io/kube-storage-version-migrator v0.0.6-0.20230721195810-5c8923c5ff96 h sigs.k8s.io/kube-storage-version-migrator v0.0.6-0.20230721195810-5c8923c5ff96/go.mod h1:EOBQyBowOUsd7U4CJnMHNE0ri+zCXyouGdLwC/jZU+I= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco= -sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.1 h1:JrhdFMqOd/+3ByqlP2I45kTOZmTRLBUm5pvRjeheg7E= +sigs.k8s.io/structured-merge-diff/v6 v6.3.1/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/go.work.sum b/go.work.sum index ce79fb2dd..ee7738f7a 100644 --- a/go.work.sum +++ b/go.work.sum @@ -26,13 +26,10 @@ codeberg.org/go-latex/latex v0.1.0/go.mod h1:LA0q/AyWIYrqVd+A9Upkgsb+IqPcmSTKc9D codeberg.org/go-pdf/fpdf v0.10.0/go.mod h1:Y0DGRAdZ0OmnZPvjbMp/1bYxmIPxm0ws4tfoPOc4LjU= git.sr.ht/~sbinet/gg v0.6.0/go.mod h1:uucygbfC9wVPQIfrmwM2et0imr8L7KQWywX0xpFMm94= github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.19.1/go.mod h1:YD5h/ldMsG0XiIw7PdyNhLxaM317eFh5yNLccNfGdyw= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.12.0/go.mod h1:J7MUC/wtRpfGVbQ5sIItY5/FuVWmvzlY21WAOfQnq/I= -github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.2/go.mod h1:XtLgD3ZD34DAaVIIAyG3objl5DynM3CQ/vMcbBNJZGI= github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0/go.mod h1:fSvRkb8d26z9dbL40Uf/OO6Vo9iExtZK3D0ulRV+8M0= github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/AzureAD/microsoft-authentication-library-for-go v1.5.0/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk= github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0/go.mod h1:Cz6ft6Dkn3Et6l2v2a9/RpN7epQ1GtDlO6lj8bEcOvw= github.com/JeffAshton/win_pdh v0.0.0-20161109143554-76bb4ee9f0ab/go.mod h1:3VYc5hodBMJ5+l/7J4xAyMeuM2PNuepvHlGs8yilUCA= github.com/Khan/genqlient v0.8.1/go.mod h1:R2G6DzjBvCbhjsEajfRjbWdVglSH/73kSivC9TLWVjU= @@ -75,9 +72,6 @@ github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91 github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= -github.com/charmbracelet/colorprofile v0.3.1/go.mod h1:/GkGusxNs8VB/RSOh3fu0TJmQ4ICMMPApIIVn0KszZ0= -github.com/charmbracelet/x/ansi v0.9.2/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE= -github.com/charmbracelet/x/cellbuf v0.0.13/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs= github.com/charmbracelet/x/exp/golden v0.0.0-20240806155701-69247e0abc2a/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= @@ -92,11 +86,13 @@ github.com/containerd/typeurl/v2 v2.2.2/go.mod h1:95ljDnPfD3bAbDJRugOiShd/DlAAsx github.com/coredns/caddy v1.1.1/go.mod h1:A6ntJQlAWuQfFlsd9hvigKbo2WS0VUs2l1e2F+BawD4= github.com/coredns/corefile-migration v1.0.26/go.mod h1:56DPqONc3njpVPsdilEnfijCwNGC3/kTJLl7i7SPavY= github.com/coreos/go-oidc v2.3.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/cristalhq/acmd v0.12.0/go.mod h1:LG5oa43pE/BbxtfMoImHCQN++0Su7dzipdgBjMCBVDQ= github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= github.com/digitalocean/godo v1.165.1/go.mod h1:xQsWpVCCbkDrWisHA72hPzPlnC+4W5w/McZY5ij9uvU= github.com/distribution/distribution/v3 v3.0.0-20230511163743-f7717b7855ca/go.mod h1:t1IxPNGdTGez+YGKyJyQrtSSqisfMIm1hnFhvMPlxtE= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE= @@ -116,9 +112,10 @@ github.com/euank/go-kmsg-parser v2.0.0+incompatible/go.mod h1:MhmAMZ8V4CYH4ybgdR github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fvbommel/sortorder v1.1.0/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk= +github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a/go.mod h1:I79BieaU4fxrw4LMXby6q5OS9XnoR9UIKLOzDFjUmuw= github.com/go-jose/go-jose/v4 v4.1.1 h1:JYhSgy4mXXzAdF3nUx3ygx347LRXJRrpgyU3adRmkAI= github.com/go-jose/go-jose/v4 v4.1.1/go.mod h1:BdsZGqgdO3b6tTc6LSE56wcDbMMLuPsw5d4ZD5f94kA= @@ -166,11 +163,11 @@ github.com/gonum/lapack v0.0.0-20181123203213-e4cdc5a0bff9/go.mod h1:XA3DeT6rxh2 github.com/gonum/matrix v0.0.0-20181209220409-c518dec07be9/go.mod h1:0EXg4mc1CNP0HCqCz+K4ts155PXIlUywf0wqN+GfPZw= github.com/google/cadvisor v0.52.1/go.mod h1:OAhPcx1nOm5YwMh/JhpUOMKyv1YKLRtS9KgzWPndHmA= github.com/google/cel-go v0.23.0/go.mod h1:52Pb6QsDbC5kvgxvZhiL9QX1oZEkcUF/ZqaPx1J5Wwo= -github.com/google/cel-go v0.26.1/go.mod h1:A9O8OU9rdvrK5MQyrqfIxo1a0u4g3sF8KB6PUIaryMM= github.com/google/certificate-transparency-go v1.3.1/go.mod h1:gg+UQlx6caKEDQ9EElFOujyxEQEfOiQzAt6782Bvi8k= github.com/google/generative-ai-go v0.19.0/go.mod h1:JYolL13VG7j79kM5BtHz4qwONHkeJQzOCkKXnpqtS/E= github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-pkcs11 v0.3.0/go.mod h1:6eQoGcuNJpa7jnd5pMGdkSaQpNDYvPlXWMcjXXThLlY= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= @@ -183,7 +180,6 @@ github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y= github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.1.0/go.mod h1:XKMd7iuf/RGPSMJ/U4HP0zS2Z9Fh8Ps9a+6X26m/tmI= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= @@ -252,9 +248,11 @@ github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBL github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= +github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/mozilla/tls-observatory v0.0.0-20210609171429-7bc42856d2e5/go.mod h1:FUqVoUPHSEdDR0MnFM3Dh8AU0pZHLXUD127SAJGER/s= github.com/mozilla/tls-observatory v0.0.0-20250923143331-eef96233227e/go.mod h1:FUqVoUPHSEdDR0MnFM3Dh8AU0pZHLXUD127SAJGER/s= github.com/mrunalp/fileutils v0.5.1/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= @@ -276,7 +274,7 @@ github.com/pavlo-v-chernykh/keystore-go/v4 v4.5.0/go.mod h1:lAVhWwbNaveeJmxrxuST github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw= github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= @@ -302,13 +300,13 @@ github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlT github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71/go.mod h1:4cgAphtvu7Ftv7vOT2ZOYhC6CvBxZixcasr8qIOTA50= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/sagikazarmark/crypt v0.6.0/go.mod h1:U8+INwJo3nBv1m6A/8OBXAq7Jnpspk5AxSgDyEQcea8= -github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/shirou/gopsutil/v4 v4.25.4/go.mod h1:xbuxyoZj+UsgnZrENu3lQivsngRR5BdjbJwf2fv4szA= github.com/shirou/gopsutil/v4 v4.25.11/go.mod h1:EivAfP5x2EhLp2ovdpKSozecVXn1TmuG7SMzs/Wh4PU= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= @@ -316,7 +314,6 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sosodev/duration v1.3.1/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg= -github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= github.com/spf13/cobra v1.10.0/go.mod h1:9dhySC7dnTtEiqzmqfkLj47BslqLCUPMXjG2lj/NgoE= github.com/spf13/pflag v1.0.8/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE= @@ -363,7 +360,6 @@ go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zL go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY= go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4= go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= -go.opentelemetry.io/proto/otlp v1.8.0/go.mod h1:tIeYOeNBU4cvmPqpaji1P+KbB4Oloai8wN4rWzRrFF0= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo= go.uber.org/multierr v1.10.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= @@ -379,7 +375,6 @@ golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnL golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= -golang.org/x/exp v0.0.0-20250911091902-df9299821621/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk= golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= @@ -421,7 +416,6 @@ golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= @@ -486,21 +480,22 @@ gopkg.in/go-jose/go-jose.v2 v2.6.3/go.mod h1:zzZDPkNNw/c9IE7Z9jr11mBZQhKQTMzoEEI gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +k8s.io/cli-runtime v0.34.3/go.mod h1:GVwL1L5uaGEgM7eGeKjaTG2j3u134JgG4dAI6jQKhMc= k8s.io/cri-api v0.32.1/go.mod h1:DCzMuTh2padoinefWME0G678Mc3QFbLMF2vEweGzBAI= +k8s.io/cri-api v0.34.4/go.mod h1:4qVUjidMg7/Z9YGZpqIDygbkPWkg3mkS1PvOx/kpHTE= k8s.io/gengo v0.0.0-20220902162205-c0856e24416d h1:U9tB195lKdzwqicbJvyJeOXV7Klv+wNAWENRnXEGi08= k8s.io/gengo v0.0.0-20220902162205-c0856e24416d/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/gengo/v2 v2.0.0-20250820003526-c297c0c1eb9d h1:qUrYOinhdAUL0xxhA4gPqogPBaS9nIq2l2kTb6pmeB0= k8s.io/gengo/v2 v2.0.0-20250820003526-c297c0c1eb9d/go.mod h1:EJykeLsmFC60UQbYJezXkEsG2FLrt0GPNkU5iK5GWxU= -k8s.io/gengo/v2 v2.0.0-20250922181213-ec3ebc5fd46b/go.mod h1:CgujABENc3KuTrcsdpGmrrASjtQsWCT7R99mEV4U/fM= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kms v0.35.0 h1:/x87FED2kDSo66csKtcYCEHsxF/DBlNl7LfJ1fVQs1o= k8s.io/kms v0.35.0/go.mod h1:VT+4ekZAdrZDMgShK37vvlyHUVhwI9t/9tvh0AyCWmQ= k8s.io/system-validators v1.10.1/go.mod h1:awfSS706v9R12VC7u7K89FKfqVy44G+E0L1A0FX9Wmw= +k8s.io/system-validators v1.10.2/go.mod h1:awfSS706v9R12VC7u7K89FKfqVy44G+E0L1A0FX9Wmw= k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= -sigs.k8s.io/controller-runtime/tools/setup-envtest v0.0.0-20250308055145-5fe7bb3edc86/go.mod h1:IaDsO8xSPRxRG1/rm9CP7+jPmj0nMNAuNi/yiHnLX8k= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/knftables v0.0.17/go.mod h1:f/5ZLKYEUPUhVjUCg6l80ACdL7CIIyeL0DxfgojGRTk= sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= diff --git a/test/e2e/suite_test.go b/test/e2e/suite_test.go index 788700ef3..66aaa1d4e 100644 --- a/test/e2e/suite_test.go +++ b/test/e2e/suite_test.go @@ -23,9 +23,14 @@ import ( operatorv1 "github.com/openshift/client-go/operator/clientset/versioned/typed/operator/v1" routev1 "github.com/openshift/client-go/route/clientset/versioned/typed/route/v1" + corev1 "k8s.io/api/core/v1" + k8sruntime "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" + crclient "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/config" + + trustapi "github.com/cert-manager/trust-manager/pkg/apis/trust/v1alpha1" ) const ( @@ -55,6 +60,7 @@ var ( routeClient *routev1.RouteV1Client certmanageroperatorclient *certmanoperatorclient.Clientset certmanagerClient *certmanagerclientset.Clientset + bundleClient crclient.Client validOperatorStatusConditions = map[string]opv1.ConditionStatus{ "Available": opv1.ConditionTrue, @@ -153,6 +159,13 @@ var _ = BeforeSuite(func() { certmanagerClient, err = certmanagerclientset.NewForConfig(cfg) Expect(err).NotTo(HaveOccurred()) + By("creating controller-runtime client for Bundle CRs") + bundleScheme := k8sruntime.NewScheme() + Expect(trustapi.AddToScheme(bundleScheme)).NotTo(HaveOccurred()) + Expect(corev1.AddToScheme(bundleScheme)).NotTo(HaveOccurred()) + bundleClient, err = crclient.New(cfg, crclient.Options{Scheme: bundleScheme}) + Expect(err).NotTo(HaveOccurred()) + By("setting defaultNetworkPolicy to true") err = resetCertManagerNetworkPolicyState(context.TODO(), certmanageroperatorclient) Expect(err).NotTo(HaveOccurred()) diff --git a/test/e2e/trustmanager_bundle_test.go b/test/e2e/trustmanager_bundle_test.go new file mode 100644 index 000000000..258dedd01 --- /dev/null +++ b/test/e2e/trustmanager_bundle_test.go @@ -0,0 +1,789 @@ +//go:build e2e +// +build e2e + +// This file tests end-to-end Bundle CR behavior under various TrustManager configurations. +// Tests are grouped by TrustManager configuration and exercise the full flow from +// Bundle creation through target sync verification. +// +// Group 1 — Default TrustManager (no optional features): +// - Inline source → ConfigMap target (+ target data drift reconciliation) +// - ConfigMap source → ConfigMap target (+ source update propagation) +// - Secret source → ConfigMap target +// - Multiple sources (ConfigMap + Inline) → ConfigMap target +// - Custom metadata (labels/annotations) on target ConfigMaps +// - Namespace selector filtering +// - Inline source update → target re-sync +// - Bundle deletion → target cleanup +// - Negative: Secret target without SecretTargets enabled +// - Negative: useDefaultCAs without DefaultCAPackage enabled +// - Negative: ConfigMap + Secret sources outside trust namespace not synced +// +// Group 2 — SecretTargets enabled: +// - Inline source → Secret target +// - Inline source → ConfigMap + Secret dual targets +// - ConfigMap source → Secret target +// - Secret target data drift reconciliation (tamper → restore) +// - Negative: Bundle name not in authorizedSecrets list +// - Transition: Enabled → Disabled → existing synced Bundle reports SecretTargetsDisabled +// +// Group 3 — DefaultCAPackage enabled: +// - useDefaultCAs → ConfigMap target +// - useDefaultCAs + Inline → ConfigMap target (combined data) +// +// Group 4 — SecretTargets + DefaultCAPackage enabled: +// - useDefaultCAs + Inline → ConfigMap + Secret dual targets +// +// Group 5 — Custom TrustNamespace: +// - ConfigMap source in custom trust namespace → ConfigMap target +// - Secret source in custom trust namespace → ConfigMap target +// - Negative: ConfigMap + Secret sources in default namespace not synced when custom trust namespace is configured +// +// Group 6 — FilterExpiredCertificates enabled: +// - ConfigMap source with valid + expired certs → only valid cert in ConfigMap target +// - Transition to Disabled → same Bundle re-syncs with both certs in target +package e2e + +import ( + "context" + "crypto/x509" + "fmt" + "strings" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + trustapi "github.com/cert-manager/trust-manager/pkg/apis/trust/v1alpha1" + "github.com/openshift/cert-manager-operator/api/operator/v1alpha1" + testutils "github.com/openshift/cert-manager-operator/pkg/controller/istiocsr" + + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + crclient "sigs.k8s.io/controller-runtime/pkg/client" +) + +const ( + bundleTargetKey = "ca-bundle.crt" + bundleTestNamespaceLabel = "bundle-e2e-test" + bundleSourceKey = "ca.crt" +) + +var _ = Describe("Bundle", Ordered, Label("Feature:TrustManager"), func() { + ctx := context.TODO() + + var ( + testNS *corev1.Namespace + testCertPEM1, testCertPEM2, expiredCertPEM string + ) + + BeforeAll(func() { + By("enabling TrustManager feature gate") + err := patchSubscriptionWithEnvVars(ctx, loader, map[string]string{ + "UNSUPPORTED_ADDON_FEATURES": "TrustManager=true", + }) + Expect(err).ShouldNot(HaveOccurred()) + + By("waiting for operator deployment rollout with feature gate") + err = waitForDeploymentEnvVarAndRollout(ctx, operatorNamespace, operatorDeploymentName, + "UNSUPPORTED_ADDON_FEATURES", "TrustManager=true", highTimeout) + Expect(err).ShouldNot(HaveOccurred()) + + By("generating test certificates") + caTweak := func(cert *x509.Certificate) { + cert.IsCA = true + cert.KeyUsage |= x509.KeyUsageCertSign + } + testCertPEM1 = testutils.GenerateCertificate("e2e-test-ca-1", []string{"cert-manager-operator-e2e"}, caTweak) + testCertPEM2 = testutils.GenerateCertificate("e2e-test-ca-2", []string{"cert-manager-operator-e2e"}, caTweak) + + expiredCATweak := func(cert *x509.Certificate) { + cert.IsCA = true + cert.KeyUsage |= x509.KeyUsageCertSign + cert.NotBefore = time.Now().Add(-48 * time.Hour) + cert.NotAfter = time.Now().Add(-24 * time.Hour) + } + expiredCertPEM = testutils.GenerateCertificate("e2e-expired-ca", []string{"cert-manager-operator-e2e"}, expiredCATweak) + + By("creating test namespace for target verification") + testNS = createNamespaceWithCleanup(ctx, "bundle-e2e-", map[string]string{bundleTestNamespaceLabel: "true"}) + }) + + // ===== Group 1: Default TrustManager ===== + Context("with default TrustManager configuration", Ordered, func() { + BeforeAll(func() { createTrustManager(ctx, newTrustManagerCR()) }) + AfterAll(func() { deleteTrustManager(ctx) }) + + It("should sync inline source to ConfigMap target and restore tampered target", func() { + bundleName := "bundle-inline-cm-" + randomStr(5) + bundle := newBundle(bundleName). + WithInLineSource(testCertPEM1). + WithConfigMapTarget(bundleTargetKey). + Build() + + createBundleWithCleanup(ctx, bundle) + + By("verifying ConfigMap target is synced in test namespace") + err := waitForConfigMapTarget(ctx, bundleClient, bundleName, testNS.Name, bundleTargetKey, testCertPEM1, highTimeout) + Expect(err).ShouldNot(HaveOccurred()) + + verifyBundleSynced(ctx, bundleName) + + By("tampering with the target ConfigMap data") + targetCM, err := k8sClientSet.CoreV1().ConfigMaps(testNS.Name).Get(ctx, bundleName, metav1.GetOptions{}) + Expect(err).ShouldNot(HaveOccurred()) + targetCM.Data[bundleTargetKey] = "tampered-data" + _, err = k8sClientSet.CoreV1().ConfigMaps(testNS.Name).Update(ctx, targetCM, metav1.UpdateOptions{}) + Expect(err).ShouldNot(HaveOccurred()) + + By("verifying trust-manager restores the target ConfigMap") + err = waitForConfigMapTarget(ctx, bundleClient, bundleName, testNS.Name, bundleTargetKey, testCertPEM1, highTimeout) + Expect(err).ShouldNot(HaveOccurred()) + }) + + It("should sync ConfigMap source to ConfigMap target and re-sync on source update", func() { + bundleName := "bundle-cm-src-" + randomStr(5) + sourceCMName := "bundle-source-cm-" + randomStr(5) + + By("creating source ConfigMap in trust namespace") + createSourceConfigMap(ctx, trustManagerNamespace, sourceCMName, bundleSourceKey, testCertPEM1) + + bundle := newBundle(bundleName). + WithConfigMapSource(sourceCMName, bundleSourceKey). + WithConfigMapTarget(bundleTargetKey). + Build() + + createBundleWithCleanup(ctx, bundle) + + By("verifying ConfigMap target contains source data") + err := waitForConfigMapTarget(ctx, bundleClient, bundleName, testNS.Name, bundleTargetKey, testCertPEM1, highTimeout) + Expect(err).ShouldNot(HaveOccurred()) + + By("updating source ConfigMap data") + Eventually(func() error { + current, err := k8sClientSet.CoreV1().ConfigMaps(trustManagerNamespace).Get(ctx, sourceCMName, metav1.GetOptions{}) + if err != nil { + return err + } + current.Data[bundleSourceKey] = testCertPEM2 + _, err = k8sClientSet.CoreV1().ConfigMaps(trustManagerNamespace).Update(ctx, current, metav1.UpdateOptions{}) + return err + }, lowTimeout, fastPollInterval).Should(Succeed()) + + By("verifying target reflects updated source data") + err = waitForConfigMapTarget(ctx, bundleClient, bundleName, testNS.Name, bundleTargetKey, testCertPEM2, highTimeout) + Expect(err).ShouldNot(HaveOccurred()) + }) + + It("should sync Secret source to ConfigMap target", func() { + bundleName := "bundle-secret-src-" + randomStr(5) + sourceSecretName := "bundle-source-secret-" + randomStr(5) + + By("creating source Secret in trust namespace") + createSourceSecret(ctx, trustManagerNamespace, sourceSecretName, bundleSourceKey, testCertPEM1) + + bundle := newBundle(bundleName). + WithSecretSource(sourceSecretName, bundleSourceKey). + WithConfigMapTarget(bundleTargetKey). + Build() + + createBundleWithCleanup(ctx, bundle) + + By("verifying ConfigMap target contains source Secret data") + err := waitForConfigMapTarget(ctx, bundleClient, bundleName, testNS.Name, bundleTargetKey, testCertPEM1, highTimeout) + Expect(err).ShouldNot(HaveOccurred()) + }) + + It("should sync multiple sources to ConfigMap target", func() { + bundleName := "bundle-multi-src-" + randomStr(5) + sourceCMName := "bundle-multi-cm-" + randomStr(5) + + By("creating source ConfigMap in trust namespace") + createSourceConfigMap(ctx, trustManagerNamespace, sourceCMName, bundleSourceKey, testCertPEM1) + + bundle := newBundle(bundleName). + WithConfigMapSource(sourceCMName, bundleSourceKey). + WithInLineSource(testCertPEM2). + WithConfigMapTarget(bundleTargetKey). + Build() + + createBundleWithCleanup(ctx, bundle) + + By("verifying ConfigMap target contains data from all sources") + err := waitForConfigMapTarget(ctx, bundleClient, bundleName, testNS.Name, bundleTargetKey, testCertPEM1, highTimeout) + Expect(err).ShouldNot(HaveOccurred()) + err = waitForConfigMapTarget(ctx, bundleClient, bundleName, testNS.Name, bundleTargetKey, testCertPEM2, lowTimeout) + Expect(err).ShouldNot(HaveOccurred()) + }) + + It("should apply custom metadata to target ConfigMaps", func() { + bundleName := "bundle-meta-" + randomStr(5) + bundle := newBundle(bundleName). + WithInLineSource(testCertPEM1). + WithConfigMapTarget(bundleTargetKey). + WithTargetMetadata( + map[string]string{"e2e-label": "test-value"}, + map[string]string{"e2e-annotation": "test-value"}, + ). + Build() + + createBundleWithCleanup(ctx, bundle) + + By("verifying target ConfigMap has custom labels and annotations") + Eventually(func(g Gomega) { + cm, err := k8sClientSet.CoreV1().ConfigMaps(testNS.Name).Get(ctx, bundleName, metav1.GetOptions{}) + g.Expect(err).ShouldNot(HaveOccurred()) + g.Expect(cm.Labels).Should(HaveKeyWithValue("e2e-label", "test-value")) + g.Expect(cm.Annotations).Should(HaveKeyWithValue("e2e-annotation", "test-value")) + }, highTimeout, fastPollInterval).Should(Succeed()) + }) + + It("should sync only to namespaces matching selector", func() { + bundleName := "bundle-ns-sel-" + randomStr(5) + selectorLabel := "bundle-selector-" + randomStr(5) + + By("creating a matching namespace") + matchNS := createNamespaceWithCleanup(ctx, "bundle-match-", map[string]string{selectorLabel: "true"}) + + By("creating a non-matching namespace") + noMatchNS := createNamespaceWithCleanup(ctx, "bundle-nomatch-", nil) + + bundle := newBundle(bundleName). + WithInLineSource(testCertPEM1). + WithConfigMapTarget(bundleTargetKey). + WithNamespaceSelector(map[string]string{selectorLabel: "true"}). + Build() + + createBundleWithCleanup(ctx, bundle) + + By("verifying ConfigMap exists in matching namespace") + err := waitForConfigMapTarget(ctx, bundleClient, bundleName, matchNS.Name, bundleTargetKey, testCertPEM1, highTimeout) + Expect(err).ShouldNot(HaveOccurred()) + + By("verifying ConfigMap does NOT exist in non-matching namespace") + Consistently(func() bool { + _, err := k8sClientSet.CoreV1().ConfigMaps(noMatchNS.Name).Get(ctx, bundleName, metav1.GetOptions{}) + return apierrors.IsNotFound(err) + }, "30s", fastPollInterval).Should(BeTrue()) + }) + + It("should update targets when inline source changes", func() { + bundleName := "bundle-update-" + randomStr(5) + bundle := newBundle(bundleName). + WithInLineSource(testCertPEM1). + WithConfigMapTarget(bundleTargetKey). + Build() + + createBundleWithCleanup(ctx, bundle) + + By("verifying initial sync") + err := waitForConfigMapTarget(ctx, bundleClient, bundleName, testNS.Name, bundleTargetKey, testCertPEM1, highTimeout) + Expect(err).ShouldNot(HaveOccurred()) + + By("updating Bundle inline source") + Eventually(func() error { + var current trustapi.Bundle + if err := bundleClient.Get(ctx, crclient.ObjectKey{Name: bundleName}, ¤t); err != nil { + return err + } + current.Spec.Sources[0].InLine = &testCertPEM2 + return bundleClient.Update(ctx, ¤t) + }, lowTimeout, fastPollInterval).Should(Succeed()) + + By("verifying target reflects updated data") + err = waitForConfigMapTarget(ctx, bundleClient, bundleName, testNS.Name, bundleTargetKey, testCertPEM2, highTimeout) + Expect(err).ShouldNot(HaveOccurred()) + }) + + It("should remove targets when Bundle is deleted", func() { + bundleName := "bundle-delete-" + randomStr(5) + bundle := newBundle(bundleName). + WithInLineSource(testCertPEM1). + WithConfigMapTarget(bundleTargetKey). + Build() + + Expect(bundleClient.Create(ctx, bundle)).ShouldNot(HaveOccurred()) + + By("verifying target is synced") + err := waitForConfigMapTarget(ctx, bundleClient, bundleName, testNS.Name, bundleTargetKey, testCertPEM1, highTimeout) + Expect(err).ShouldNot(HaveOccurred()) + + By("deleting the Bundle") + deleteBundle(ctx, bundleName) + + By("verifying targets are removed") + err = waitForTargetRemoved(ctx, bundleClient, bundleName, testNS.Name, lowTimeout) + Expect(err).ShouldNot(HaveOccurred()) + }) + + It("should report error in Bundle status when targeting Secret without SecretTargets enabled", func() { + bundleName := "bundle-no-secret-" + randomStr(5) + bundle := newBundle(bundleName). + WithInLineSource(testCertPEM1). + WithSecretTarget(bundleTargetKey). + Build() + + createBundleWithCleanup(ctx, bundle) + + By("verifying Bundle status condition shows not synced") + verifyBundleNeverSynced(ctx, bundleName) + + By("verifying no Secret is created in test namespace") + _, err := k8sClientSet.CoreV1().Secrets(testNS.Name).Get(ctx, bundleName, metav1.GetOptions{}) + Expect(apierrors.IsNotFound(err)).Should(BeTrue()) + }) + + It("should report error in Bundle status when using useDefaultCAs without DefaultCAPackage", func() { + bundleName := "bundle-no-default-ca-" + randomStr(5) + bundle := newBundle(bundleName). + WithUseDefaultCAs(). + WithConfigMapTarget(bundleTargetKey). + Build() + + createBundleWithCleanup(ctx, bundle) + + By("verifying Bundle status does not reach Synced=True") + verifyBundleNeverSynced(ctx, bundleName) + }) + + It("should not sync sources that exist outside the trust namespace", func() { + bundleName := "bundle-wrong-ns-" + randomStr(5) + sourceCMName := "src-wrong-ns-" + randomStr(5) + sourceSecretName := "src-secret-wrong-ns-" + randomStr(5) + + By(fmt.Sprintf("creating source ConfigMap and Secret in test namespace %q instead of trust namespace %q", testNS.Name, trustManagerNamespace)) + createSourceConfigMap(ctx, testNS.Name, sourceCMName, bundleSourceKey, testCertPEM1) + createSourceSecret(ctx, testNS.Name, sourceSecretName, bundleSourceKey, testCertPEM2) + + bundle := newBundle(bundleName). + WithConfigMapSource(sourceCMName, bundleSourceKey). + WithSecretSource(sourceSecretName, bundleSourceKey). + WithConfigMapTarget(bundleTargetKey). + Build() + + createBundleWithCleanup(ctx, bundle) + + By("verifying Bundle does not reach Synced=True because sources are not in trust namespace") + verifyBundleNeverSynced(ctx, bundleName) + + By("verifying no target ConfigMap is created in test namespace") + _, err := k8sClientSet.CoreV1().ConfigMaps(testNS.Name).Get(ctx, bundleName, metav1.GetOptions{}) + Expect(apierrors.IsNotFound(err)).Should(BeTrue()) + }) + }) + + // ===== Group 2: SecretTargets enabled ===== + Context("with SecretTargets enabled", Ordered, func() { + const ( + bundleSecretTarget = "bundle-secret-tgt" + bundleDualTarget = "bundle-dual-tgt" + bundleCMToSecretTarget = "bundle-cm-to-secret" + bundleSecretDrift = "bundle-secret-drift" + bundleSecretDisable = "bundle-secret-disable" + ) + + BeforeAll(func() { + createTrustManager(ctx, newTrustManagerCR().WithSecretTargets( + v1alpha1.SecretTargetsPolicyCustom, + []string{bundleSecretTarget, bundleDualTarget, bundleCMToSecretTarget, bundleSecretDrift, bundleSecretDisable}, + )) + }) + AfterAll(func() { deleteTrustManager(ctx) }) + + It("should sync inline source to Secret target", func() { + bundle := newBundle(bundleSecretTarget). + WithInLineSource(testCertPEM1). + WithSecretTarget(bundleTargetKey). + Build() + + createBundleWithCleanup(ctx, bundle) + + By("verifying Secret target is synced in test namespace") + err := waitForSecretTarget(ctx, bundleClient, bundleSecretTarget, testNS.Name, bundleTargetKey, testCertPEM1, highTimeout) + Expect(err).ShouldNot(HaveOccurred()) + + verifyBundleSynced(ctx, bundleSecretTarget) + }) + + It("should sync to both ConfigMap and Secret targets", func() { + bundle := newBundle(bundleDualTarget). + WithInLineSource(testCertPEM1). + WithConfigMapTarget(bundleTargetKey). + WithSecretTarget(bundleTargetKey). + Build() + + createBundleWithCleanup(ctx, bundle) + + By("verifying ConfigMap target is synced") + err := waitForConfigMapTarget(ctx, bundleClient, bundleDualTarget, testNS.Name, bundleTargetKey, testCertPEM1, highTimeout) + Expect(err).ShouldNot(HaveOccurred()) + + By("verifying Secret target is synced") + err = waitForSecretTarget(ctx, bundleClient, bundleDualTarget, testNS.Name, bundleTargetKey, testCertPEM1, highTimeout) + Expect(err).ShouldNot(HaveOccurred()) + }) + + It("should sync ConfigMap source to Secret target", func() { + sourceCMName := "bundle-cm-secret-src-" + randomStr(5) + + By("creating source ConfigMap in trust namespace") + createSourceConfigMap(ctx, trustManagerNamespace, sourceCMName, bundleSourceKey, testCertPEM1) + + bundle := newBundle(bundleCMToSecretTarget). + WithConfigMapSource(sourceCMName, bundleSourceKey). + WithSecretTarget(bundleTargetKey). + Build() + + createBundleWithCleanup(ctx, bundle) + + By("verifying Secret target contains source ConfigMap data") + err := waitForSecretTarget(ctx, bundleClient, bundleCMToSecretTarget, testNS.Name, bundleTargetKey, testCertPEM1, highTimeout) + Expect(err).ShouldNot(HaveOccurred()) + + verifyBundleSynced(ctx, bundleCMToSecretTarget) + }) + + It("should restore Secret target when tampered", func() { + bundle := newBundle(bundleSecretDrift). + WithInLineSource(testCertPEM1). + WithSecretTarget(bundleTargetKey). + Build() + + createBundleWithCleanup(ctx, bundle) + + By("verifying Secret target is synced") + err := waitForSecretTarget(ctx, bundleClient, bundleSecretDrift, testNS.Name, bundleTargetKey, testCertPEM1, highTimeout) + Expect(err).ShouldNot(HaveOccurred()) + + By("tampering with the target Secret data") + targetSecret, err := k8sClientSet.CoreV1().Secrets(testNS.Name).Get(ctx, bundleSecretDrift, metav1.GetOptions{}) + Expect(err).ShouldNot(HaveOccurred()) + targetSecret.Data[bundleTargetKey] = []byte("tampered-data") + _, err = k8sClientSet.CoreV1().Secrets(testNS.Name).Update(ctx, targetSecret, metav1.UpdateOptions{}) + Expect(err).ShouldNot(HaveOccurred()) + + By("verifying trust-manager restores the target Secret") + err = waitForSecretTarget(ctx, bundleClient, bundleSecretDrift, testNS.Name, bundleTargetKey, testCertPEM1, highTimeout) + Expect(err).ShouldNot(HaveOccurred()) + }) + + It("should not sync Secret when Bundle name is not in authorizedSecrets list", func() { + bundleName := "bundle-not-authorized" + bundle := newBundle(bundleName). + WithInLineSource(testCertPEM1). + WithSecretTarget(bundleTargetKey). + Build() + + createBundleWithCleanup(ctx, bundle) + + By("verifying Bundle status does not reach Synced=True") + verifyBundleNeverSynced(ctx, bundleName) + + By(fmt.Sprintf("verifying no Secret named %q exists in test namespace", bundleName)) + _, err := k8sClientSet.CoreV1().Secrets(testNS.Name).Get(ctx, bundleName, metav1.GetOptions{}) + Expect(apierrors.IsNotFound(err)).Should(BeTrue()) + }) + + It("should report SecretTargetsDisabled on existing synced Bundle after disabling secretTargets", func() { + bundle := newBundle(bundleSecretDisable). + WithInLineSource(testCertPEM1). + WithSecretTarget(bundleTargetKey). + Build() + + createBundleWithCleanup(ctx, bundle) + + By("verifying Secret target syncs while feature is enabled") + err := waitForSecretTarget(ctx, bundleClient, bundleSecretDisable, testNS.Name, bundleTargetKey, testCertPEM1, highTimeout) + Expect(err).ShouldNot(HaveOccurred()) + verifyBundleSynced(ctx, bundleSecretDisable) + + By("disabling secretTargets on TrustManager CR") + Eventually(func() error { + tm, err := trustManagerClient().Get(ctx, "cluster", metav1.GetOptions{}) + if err != nil { + return err + } + tm.Spec.TrustManagerConfig.SecretTargets = v1alpha1.SecretTargetsConfig{ + Policy: v1alpha1.SecretTargetsPolicyDisabled, + } + _, err = trustManagerClient().Update(ctx, tm, metav1.UpdateOptions{}) + return err + }, lowTimeout, fastPollInterval).Should(Succeed()) + + waitForTrustManagerReady(ctx) + + By("verifying Bundle status transitions to Synced=False") + err = waitForBundleCondition(ctx, bundleClient, bundleSecretDisable, trustapi.BundleConditionSynced, metav1.ConditionFalse, highTimeout) + Expect(err).ShouldNot(HaveOccurred()) + }) + }) + + // ===== Group 3: DefaultCAPackage enabled ===== + Context("with DefaultCAPackage enabled", Ordered, func() { + BeforeAll(func() { + createTrustManager(ctx, newTrustManagerCR().WithDefaultCAPackage(v1alpha1.DefaultCAPackagePolicyEnabled)) + + By("waiting for default CA package ConfigMap to be created") + err := pollTillConfigMapAvailable(ctx, k8sClientSet, trustManagerNamespace, defaultCAPackageConfigMapName) + Expect(err).ShouldNot(HaveOccurred()) + }) + AfterAll(func() { deleteTrustManager(ctx) }) + + It("should sync useDefaultCAs source to ConfigMap target", func() { + bundleName := "bundle-default-cas-" + randomStr(5) + bundle := newBundle(bundleName). + WithUseDefaultCAs(). + WithConfigMapTarget(bundleTargetKey). + Build() + + createBundleWithCleanup(ctx, bundle) + + By("verifying ConfigMap target contains PEM certificates from default CAs") + Eventually(func(g Gomega) { + cm, err := k8sClientSet.CoreV1().ConfigMaps(testNS.Name).Get(ctx, bundleName, metav1.GetOptions{}) + g.Expect(err).ShouldNot(HaveOccurred()) + data, ok := cm.Data[bundleTargetKey] + g.Expect(ok).Should(BeTrue(), "target ConfigMap should contain key %q", bundleTargetKey) + g.Expect(data).ShouldNot(BeEmpty()) + g.Expect(containsPEMCertificates(data)).Should(BeTrue(), "target data should contain valid PEM certificates") + }, highTimeout, slowPollInterval).Should(Succeed()) + + verifyBundleSynced(ctx, bundleName) + }) + + It("should include default CAs alongside explicit inline source", func() { + bundleName := "bundle-cas-inline-" + randomStr(5) + bundle := newBundle(bundleName). + WithInLineSource(testCertPEM1). + WithUseDefaultCAs(). + WithConfigMapTarget(bundleTargetKey). + Build() + + createBundleWithCleanup(ctx, bundle) + + By("verifying target contains the inline certificate") + err := waitForConfigMapTarget(ctx, bundleClient, bundleName, testNS.Name, bundleTargetKey, testCertPEM1, highTimeout) + Expect(err).ShouldNot(HaveOccurred()) + + By("verifying target also contains default CA certificates") + Eventually(func(g Gomega) { + cm, err := k8sClientSet.CoreV1().ConfigMaps(testNS.Name).Get(ctx, bundleName, metav1.GetOptions{}) + g.Expect(err).ShouldNot(HaveOccurred()) + data := cm.Data[bundleTargetKey] + g.Expect(strings.Contains(data, testCertPEM1)).Should(BeTrue(), "should contain inline cert") + g.Expect(strings.Count(data, "-----BEGIN CERTIFICATE-----")).Should(BeNumerically(">", 1), + "should contain multiple certificates (inline + default CAs)") + }, highTimeout, slowPollInterval).Should(Succeed()) + }) + }) + + // ===== Group 4: Combined SecretTargets + DefaultCAPackage ===== + Context("with SecretTargets and DefaultCAPackage enabled", Ordered, func() { + const bundleCombined = "bundle-combined" + + BeforeAll(func() { + createTrustManager(ctx, newTrustManagerCR(). + WithSecretTargets(v1alpha1.SecretTargetsPolicyCustom, []string{bundleCombined}). + WithDefaultCAPackage(v1alpha1.DefaultCAPackagePolicyEnabled)) + + By("waiting for default CA package ConfigMap to be created") + err := pollTillConfigMapAvailable(ctx, k8sClientSet, trustManagerNamespace, defaultCAPackageConfigMapName) + Expect(err).ShouldNot(HaveOccurred()) + }) + AfterAll(func() { deleteTrustManager(ctx) }) + + It("should sync useDefaultCAs and inline sources to both ConfigMap and Secret targets", func() { + bundle := newBundle(bundleCombined). + WithInLineSource(testCertPEM1). + WithUseDefaultCAs(). + WithConfigMapTarget(bundleTargetKey). + WithSecretTarget(bundleTargetKey). + Build() + + createBundleWithCleanup(ctx, bundle) + + By("verifying ConfigMap target contains inline cert and default CAs") + Eventually(func(g Gomega) { + cm, err := k8sClientSet.CoreV1().ConfigMaps(testNS.Name).Get(ctx, bundleCombined, metav1.GetOptions{}) + g.Expect(err).ShouldNot(HaveOccurred()) + data := cm.Data[bundleTargetKey] + g.Expect(strings.Contains(data, testCertPEM1)).Should(BeTrue(), "ConfigMap should contain inline cert") + g.Expect(strings.Count(data, "-----BEGIN CERTIFICATE-----")).Should(BeNumerically(">", 1)) + }, highTimeout, slowPollInterval).Should(Succeed()) + + By("verifying Secret target contains inline cert and default CAs") + Eventually(func(g Gomega) { + secret, err := k8sClientSet.CoreV1().Secrets(testNS.Name).Get(ctx, bundleCombined, metav1.GetOptions{}) + g.Expect(err).ShouldNot(HaveOccurred()) + data := string(secret.Data[bundleTargetKey]) + g.Expect(strings.Contains(data, testCertPEM1)).Should(BeTrue(), "Secret should contain inline cert") + g.Expect(strings.Count(data, "-----BEGIN CERTIFICATE-----")).Should(BeNumerically(">", 1)) + }, highTimeout, slowPollInterval).Should(Succeed()) + + verifyBundleSynced(ctx, bundleCombined) + }) + }) + + // ===== Group 5: Custom TrustNamespace ===== + Context("with custom trustNamespace", Ordered, func() { + var customTrustNS *corev1.Namespace + + BeforeAll(func() { + By("creating custom trust namespace") + customTrustNS = createNamespaceWithCleanup(ctx, "custom-trust-ns-", nil) + + createTrustManager(ctx, newTrustManagerCR().WithTrustNamespace(customTrustNS.Name)) + + By(fmt.Sprintf("verifying deployment has --trust-namespace=%s", customTrustNS.Name)) + Eventually(func(g Gomega) { + dep, err := k8sClientSet.AppsV1().Deployments(trustManagerNamespace).Get(ctx, trustManagerDeploymentName, metav1.GetOptions{}) + g.Expect(err).ShouldNot(HaveOccurred()) + g.Expect(dep.Spec.Template.Spec.Containers).ShouldNot(BeEmpty()) + g.Expect(dep.Spec.Template.Spec.Containers[0].Args).Should( + ContainElement(fmt.Sprintf("--trust-namespace=%s", customTrustNS.Name)), + ) + }, lowTimeout, fastPollInterval).Should(Succeed()) + }) + + AfterAll(func() { deleteTrustManager(ctx) }) + + It("should sync ConfigMap source from custom trust namespace to target", func() { + bundleName := "bundle-custom-ns-" + randomStr(5) + sourceCMName := "src-custom-ns-" + randomStr(5) + + By(fmt.Sprintf("creating source ConfigMap in custom trust namespace %q", customTrustNS.Name)) + createSourceConfigMap(ctx, customTrustNS.Name, sourceCMName, bundleSourceKey, testCertPEM1) + + bundle := newBundle(bundleName). + WithConfigMapSource(sourceCMName, bundleSourceKey). + WithConfigMapTarget(bundleTargetKey). + Build() + + createBundleWithCleanup(ctx, bundle) + + By("verifying ConfigMap target is synced in test namespace") + err := waitForConfigMapTarget(ctx, bundleClient, bundleName, testNS.Name, bundleTargetKey, testCertPEM1, highTimeout) + Expect(err).ShouldNot(HaveOccurred()) + + verifyBundleSynced(ctx, bundleName) + }) + + It("should sync Secret source from custom trust namespace to target", func() { + bundleName := "bundle-secret-custom-ns-" + randomStr(5) + sourceSecretName := "src-secret-custom-ns-" + randomStr(5) + + By(fmt.Sprintf("creating source Secret in custom trust namespace %q", customTrustNS.Name)) + createSourceSecret(ctx, customTrustNS.Name, sourceSecretName, bundleSourceKey, testCertPEM1) + + bundle := newBundle(bundleName). + WithSecretSource(sourceSecretName, bundleSourceKey). + WithConfigMapTarget(bundleTargetKey). + Build() + + createBundleWithCleanup(ctx, bundle) + + By("verifying ConfigMap target is synced in test namespace") + err := waitForConfigMapTarget(ctx, bundleClient, bundleName, testNS.Name, bundleTargetKey, testCertPEM1, highTimeout) + Expect(err).ShouldNot(HaveOccurred()) + + verifyBundleSynced(ctx, bundleName) + }) + + It("should not sync sources from default namespace when custom trust namespace is configured", func() { + bundleName := "bundle-default-ns-miss-" + randomStr(5) + sourceCMName := "src-default-ns-miss-" + randomStr(5) + sourceSecretName := "src-secret-default-miss-" + randomStr(5) + + By(fmt.Sprintf("creating source ConfigMap and Secret in default namespace %q (not the custom trust namespace %q)", trustManagerNamespace, customTrustNS.Name)) + createSourceConfigMap(ctx, trustManagerNamespace, sourceCMName, bundleSourceKey, testCertPEM1) + createSourceSecret(ctx, trustManagerNamespace, sourceSecretName, bundleSourceKey, testCertPEM2) + + bundle := newBundle(bundleName). + WithConfigMapSource(sourceCMName, bundleSourceKey). + WithSecretSource(sourceSecretName, bundleSourceKey). + WithConfigMapTarget(bundleTargetKey). + Build() + + createBundleWithCleanup(ctx, bundle) + + By("verifying Bundle does not reach Synced=True because sources are not in custom trust namespace") + verifyBundleNeverSynced(ctx, bundleName) + + By("verifying no target ConfigMap is created in test namespace") + _, err := k8sClientSet.CoreV1().ConfigMaps(testNS.Name).Get(ctx, bundleName, metav1.GetOptions{}) + Expect(apierrors.IsNotFound(err)).Should(BeTrue()) + }) + }) + + // ===== Group 6: FilterExpiredCertificates ===== + Context("with FilterExpiredCertificates enabled", Ordered, func() { + var ( + filterBundleName string + sourceCMName string + ) + + BeforeAll(func() { + createTrustManager(ctx, newTrustManagerCR(). + WithFilterExpiredCertificates(v1alpha1.FilterExpiredCertificatesPolicyEnabled)) + + sourceCMName = "filter-src-cm-" + randomStr(5) + combinedPEM := testCertPEM1 + expiredCertPEM + + By("creating source ConfigMap with valid + expired certs in trust namespace") + createSourceConfigMap(ctx, trustManagerNamespace, sourceCMName, bundleSourceKey, combinedPEM) + }) + AfterAll(func() { deleteTrustManager(ctx) }) + + It("should exclude expired certificates from ConfigMap target when using ConfigMap source", func() { + filterBundleName = "bundle-filter-expired-" + randomStr(5) + + bundle := newBundle(filterBundleName). + WithConfigMapSource(sourceCMName, bundleSourceKey). + WithConfigMapTarget(bundleTargetKey). + Build() + + createBundleWithCleanup(ctx, bundle) + + By("verifying target contains the valid certificate") + err := waitForConfigMapTarget(ctx, bundleClient, filterBundleName, testNS.Name, bundleTargetKey, testCertPEM1, highTimeout) + Expect(err).ShouldNot(HaveOccurred()) + + By("verifying target does NOT contain the expired certificate") + Eventually(func(g Gomega) { + cm, err := k8sClientSet.CoreV1().ConfigMaps(testNS.Name).Get(ctx, filterBundleName, metav1.GetOptions{}) + g.Expect(err).ShouldNot(HaveOccurred()) + data := cm.Data[bundleTargetKey] + g.Expect(strings.Contains(data, strings.TrimSpace(testCertPEM1))).Should(BeTrue(), "should contain valid cert") + g.Expect(strings.Contains(data, strings.TrimSpace(expiredCertPEM))).Should(BeFalse(), "should not contain expired cert") + }, highTimeout, fastPollInterval).Should(Succeed()) + + verifyBundleSynced(ctx, filterBundleName) + }) + + It("should re-sync same Bundle with expired certs included after disabling filter", func() { + By("disabling filterExpiredCertificates on TrustManager CR") + Eventually(func() error { + tm, err := trustManagerClient().Get(ctx, "cluster", metav1.GetOptions{}) + if err != nil { + return err + } + tm.Spec.TrustManagerConfig.FilterExpiredCertificates = v1alpha1.FilterExpiredCertificatesPolicyDisabled + _, err = trustManagerClient().Update(ctx, tm, metav1.UpdateOptions{}) + return err + }, lowTimeout, fastPollInterval).Should(Succeed()) + + waitForTrustManagerReady(ctx) + + By("verifying the same Bundle's target now includes the expired certificate") + Eventually(func(g Gomega) { + cm, err := k8sClientSet.CoreV1().ConfigMaps(testNS.Name).Get(ctx, filterBundleName, metav1.GetOptions{}) + g.Expect(err).ShouldNot(HaveOccurred()) + data := cm.Data[bundleTargetKey] + g.Expect(strings.Contains(data, strings.TrimSpace(testCertPEM1))).Should(BeTrue(), "should contain valid cert") + g.Expect(strings.Contains(data, strings.TrimSpace(expiredCertPEM))).Should(BeTrue(), "should contain expired cert after disabling filter") + }, highTimeout, fastPollInterval).Should(Succeed()) + + verifyBundleSynced(ctx, filterBundleName) + }) + }) +}) diff --git a/test/e2e/trustmanager_helpers_test.go b/test/e2e/trustmanager_helpers_test.go new file mode 100644 index 000000000..4ae38b952 --- /dev/null +++ b/test/e2e/trustmanager_helpers_test.go @@ -0,0 +1,360 @@ +//go:build e2e +// +build e2e + +package e2e + +import ( + "context" + "encoding/pem" + "strings" + "time" + + trustapi "github.com/cert-manager/trust-manager/pkg/apis/trust/v1alpha1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "github.com/openshift/cert-manager-operator/api/operator/v1alpha1" + operatorclientv1alpha1 "github.com/openshift/cert-manager-operator/pkg/operator/clientset/versioned/typed/operator/v1alpha1" + + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/utils/ptr" + crclient "sigs.k8s.io/controller-runtime/pkg/client" +) + +// --------------------------------------------------------------------------- +// TrustManager CR builder +// --------------------------------------------------------------------------- + +type trustManagerCRBuilder struct { + tm *v1alpha1.TrustManager +} + +func newTrustManagerCR() *trustManagerCRBuilder { + return &trustManagerCRBuilder{ + tm: &v1alpha1.TrustManager{ + ObjectMeta: metav1.ObjectMeta{Name: "cluster"}, + Spec: v1alpha1.TrustManagerSpec{ + TrustManagerConfig: v1alpha1.TrustManagerConfig{}, + }, + }, + } +} + +func (b *trustManagerCRBuilder) WithResources(resources corev1.ResourceRequirements) *trustManagerCRBuilder { + b.tm.Spec.TrustManagerConfig.Resources = resources + return b +} + +func (b *trustManagerCRBuilder) WithTolerations(tolerations []corev1.Toleration) *trustManagerCRBuilder { + b.tm.Spec.TrustManagerConfig.Tolerations = tolerations + return b +} + +func (b *trustManagerCRBuilder) WithNodeSelector(nodeSelector map[string]string) *trustManagerCRBuilder { + b.tm.Spec.TrustManagerConfig.NodeSelector = nodeSelector + return b +} + +func (b *trustManagerCRBuilder) WithAffinity(affinity *corev1.Affinity) *trustManagerCRBuilder { + b.tm.Spec.TrustManagerConfig.Affinity = affinity + return b +} + +func (b *trustManagerCRBuilder) WithLabels(labels map[string]string) *trustManagerCRBuilder { + b.tm.Spec.ControllerConfig.Labels = labels + return b +} + +func (b *trustManagerCRBuilder) WithAnnotations(annotations map[string]string) *trustManagerCRBuilder { + b.tm.Spec.ControllerConfig.Annotations = annotations + return b +} + +func (b *trustManagerCRBuilder) WithTrustNamespace(trustNamespace string) *trustManagerCRBuilder { + b.tm.Spec.TrustManagerConfig.TrustNamespace = trustNamespace + return b +} + +func (b *trustManagerCRBuilder) WithSecretTargets(policy v1alpha1.SecretTargetsPolicy, authorizedSecrets []string) *trustManagerCRBuilder { + b.tm.Spec.TrustManagerConfig.SecretTargets = v1alpha1.SecretTargetsConfig{ + Policy: policy, + AuthorizedSecrets: authorizedSecrets, + } + return b +} + +func (b *trustManagerCRBuilder) WithDefaultCAPackage(policy v1alpha1.DefaultCAPackagePolicy) *trustManagerCRBuilder { + b.tm.Spec.TrustManagerConfig.DefaultCAPackage.Policy = policy + return b +} + +func (b *trustManagerCRBuilder) WithFilterExpiredCertificates(policy v1alpha1.FilterExpiredCertificatesPolicy) *trustManagerCRBuilder { + b.tm.Spec.TrustManagerConfig.FilterExpiredCertificates = policy + return b +} + +func (b *trustManagerCRBuilder) Build() *v1alpha1.TrustManager { + return b.tm +} + +// --------------------------------------------------------------------------- +// TrustManager CR helpers +// --------------------------------------------------------------------------- + +func trustManagerClient() operatorclientv1alpha1.TrustManagerInterface { + return certmanageroperatorclient.OperatorV1alpha1().TrustManagers() +} + +func waitForTrustManagerReady(ctx context.Context) v1alpha1.TrustManagerStatus { + By("waiting for TrustManager CR to be ready") + status, err := pollTillTrustManagerAvailable(ctx, trustManagerClient(), "cluster") + Expect(err).Should(BeNil()) + return status +} + +func createTrustManager(ctx context.Context, b *trustManagerCRBuilder) { + By("creating TrustManager CR") + _, err := trustManagerClient().Create(ctx, b.Build(), metav1.CreateOptions{}) + Expect(err).ShouldNot(HaveOccurred()) + waitForTrustManagerReady(ctx) +} + +func deleteTrustManager(ctx context.Context) { + By("deleting TrustManager CR") + _ = trustManagerClient().Delete(ctx, "cluster", metav1.DeleteOptions{}) + Eventually(func() bool { + _, err := trustManagerClient().Get(ctx, "cluster", metav1.GetOptions{}) + return apierrors.IsNotFound(err) + }, lowTimeout, fastPollInterval).Should(BeTrue()) +} + +// --------------------------------------------------------------------------- +// Bundle builder +// --------------------------------------------------------------------------- + +// bundleBuilder provides a fluent API for constructing trust.cert-manager.io/v1alpha1 Bundle objects. +type bundleBuilder struct { + bundle *trustapi.Bundle +} + +func newBundle(name string) *bundleBuilder { + return &bundleBuilder{ + bundle: &trustapi.Bundle{ + ObjectMeta: metav1.ObjectMeta{Name: name}, + Spec: trustapi.BundleSpec{}, + }, + } +} + +func (b *bundleBuilder) WithInLineSource(pemData string) *bundleBuilder { + b.bundle.Spec.Sources = append(b.bundle.Spec.Sources, trustapi.BundleSource{InLine: &pemData}) + return b +} + +func (b *bundleBuilder) WithConfigMapSource(name, key string) *bundleBuilder { + b.bundle.Spec.Sources = append(b.bundle.Spec.Sources, trustapi.BundleSource{ + ConfigMap: &trustapi.SourceObjectKeySelector{Name: name, Key: key}, + }) + return b +} + +func (b *bundleBuilder) WithSecretSource(name, key string) *bundleBuilder { + b.bundle.Spec.Sources = append(b.bundle.Spec.Sources, trustapi.BundleSource{ + Secret: &trustapi.SourceObjectKeySelector{Name: name, Key: key}, + }) + return b +} + +func (b *bundleBuilder) WithUseDefaultCAs() *bundleBuilder { + b.bundle.Spec.Sources = append(b.bundle.Spec.Sources, trustapi.BundleSource{UseDefaultCAs: ptr.To(true)}) + return b +} + +func (b *bundleBuilder) WithConfigMapTarget(key string) *bundleBuilder { + b.bundle.Spec.Target.ConfigMap = &trustapi.TargetTemplate{Key: key} + return b +} + +func (b *bundleBuilder) WithSecretTarget(key string) *bundleBuilder { + b.bundle.Spec.Target.Secret = &trustapi.TargetTemplate{Key: key} + return b +} + +func (b *bundleBuilder) WithTargetMetadata(labels, annotations map[string]string) *bundleBuilder { + meta := &trustapi.TargetMetadata{Labels: labels, Annotations: annotations} + if b.bundle.Spec.Target.ConfigMap != nil { + b.bundle.Spec.Target.ConfigMap.Metadata = meta + } + if b.bundle.Spec.Target.Secret != nil { + b.bundle.Spec.Target.Secret.Metadata = meta + } + return b +} + +func (b *bundleBuilder) WithNamespaceSelector(matchLabels map[string]string) *bundleBuilder { + b.bundle.Spec.Target.NamespaceSelector = &metav1.LabelSelector{MatchLabels: matchLabels} + return b +} + +func (b *bundleBuilder) Build() *trustapi.Bundle { + return b.bundle +} + +// --------------------------------------------------------------------------- +// Bundle helpers +// --------------------------------------------------------------------------- + +// waitForBundleCondition polls until the Bundle has a status condition matching +// the given type and status, or until timeout. +func waitForBundleCondition(ctx context.Context, cl crclient.Client, bundleName, conditionType string, conditionStatus metav1.ConditionStatus, timeout time.Duration) error { + return wait.PollUntilContextTimeout(ctx, fastPollInterval, timeout, true, func(context.Context) (bool, error) { + var bundle trustapi.Bundle + if err := cl.Get(ctx, crclient.ObjectKey{Name: bundleName}, &bundle); err != nil { + if apierrors.IsNotFound(err) { + return false, nil + } + return false, err + } + for _, c := range bundle.Status.Conditions { + if c.Type == conditionType && c.Status == conditionStatus { + return true, nil + } + } + return false, nil + }) +} + +// waitForConfigMapTarget polls until a ConfigMap with the Bundle name exists in the +// given namespace and its data key contains the expected content. +func waitForConfigMapTarget(ctx context.Context, cl crclient.Client, bundleName, namespace, key, expectedContent string, timeout time.Duration) error { + return wait.PollUntilContextTimeout(ctx, fastPollInterval, timeout, true, func(context.Context) (bool, error) { + var cm corev1.ConfigMap + if err := cl.Get(ctx, crclient.ObjectKey{Namespace: namespace, Name: bundleName}, &cm); err != nil { + if apierrors.IsNotFound(err) { + return false, nil + } + return false, err + } + data, ok := cm.Data[key] + if !ok { + return false, nil + } + if expectedContent != "" { + return strings.Contains(strings.TrimSpace(data), strings.TrimSpace(expectedContent)), nil + } + return len(data) > 0, nil + }) +} + +// waitForSecretTarget polls until a Secret with the Bundle name exists in the +// given namespace and its data key contains the expected content. +func waitForSecretTarget(ctx context.Context, cl crclient.Client, bundleName, namespace, key, expectedContent string, timeout time.Duration) error { + return wait.PollUntilContextTimeout(ctx, fastPollInterval, timeout, true, func(context.Context) (bool, error) { + var secret corev1.Secret + if err := cl.Get(ctx, crclient.ObjectKey{Namespace: namespace, Name: bundleName}, &secret); err != nil { + if apierrors.IsNotFound(err) { + return false, nil + } + return false, err + } + data, ok := secret.Data[key] + if !ok { + return false, nil + } + if expectedContent != "" { + return strings.Contains(strings.TrimSpace(string(data)), strings.TrimSpace(expectedContent)), nil + } + return len(data) > 0, nil + }) +} + +// waitForTargetRemoved polls until the target ConfigMap or Secret with the +// Bundle name no longer exists in the given namespace. +func waitForTargetRemoved(ctx context.Context, cl crclient.Client, bundleName, namespace string, timeout time.Duration) error { + return wait.PollUntilContextTimeout(ctx, fastPollInterval, timeout, true, func(context.Context) (bool, error) { + var cm corev1.ConfigMap + cmErr := cl.Get(ctx, crclient.ObjectKey{Namespace: namespace, Name: bundleName}, &cm) + var secret corev1.Secret + secretErr := cl.Get(ctx, crclient.ObjectKey{Namespace: namespace, Name: bundleName}, &secret) + return apierrors.IsNotFound(cmErr) && apierrors.IsNotFound(secretErr), nil + }) +} + +// containsPEMCertificates returns true if the data contains at least one +// valid PEM-encoded CERTIFICATE block. +func containsPEMCertificates(data string) bool { + block, _ := pem.Decode([]byte(data)) + return block != nil && block.Type == "CERTIFICATE" +} + +func deleteBundle(ctx context.Context, name string) { + var bundle trustapi.Bundle + bundle.Name = name + _ = bundleClient.Delete(ctx, &bundle) + Eventually(func() bool { + err := bundleClient.Get(ctx, crclient.ObjectKey{Name: name}, &trustapi.Bundle{}) + return apierrors.IsNotFound(err) + }, lowTimeout, fastPollInterval).Should(BeTrue()) +} + +func createBundleWithCleanup(ctx context.Context, bundle *trustapi.Bundle) { + Expect(bundleClient.Create(ctx, bundle)).ShouldNot(HaveOccurred()) + DeferCleanup(func() { deleteBundle(ctx, bundle.Name) }) +} + +func createNamespaceWithCleanup(ctx context.Context, prefix string, labels map[string]string) *corev1.Namespace { + ns, err := k8sClientSet.CoreV1().Namespaces().Create(ctx, &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{GenerateName: prefix, Labels: labels}, + }, metav1.CreateOptions{}) + Expect(err).ShouldNot(HaveOccurred()) + DeferCleanup(func() { + _ = k8sClientSet.CoreV1().Namespaces().Delete(ctx, ns.Name, metav1.DeleteOptions{}) + }) + return ns +} + +func createSourceConfigMap(ctx context.Context, namespace, name, key, data string) { + _, err := k8sClientSet.CoreV1().ConfigMaps(namespace).Create(ctx, &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{Name: name}, + Data: map[string]string{key: data}, + }, metav1.CreateOptions{}) + Expect(err).ShouldNot(HaveOccurred()) + DeferCleanup(func() { + _ = k8sClientSet.CoreV1().ConfigMaps(namespace).Delete(ctx, name, metav1.DeleteOptions{}) + }) +} + +func createSourceSecret(ctx context.Context, namespace, name, key, data string) { + _, err := k8sClientSet.CoreV1().Secrets(namespace).Create(ctx, &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{Name: name}, + Data: map[string][]byte{key: []byte(data)}, + }, metav1.CreateOptions{}) + Expect(err).ShouldNot(HaveOccurred()) + DeferCleanup(func() { + _ = k8sClientSet.CoreV1().Secrets(namespace).Delete(ctx, name, metav1.DeleteOptions{}) + }) +} + +func verifyBundleSynced(ctx context.Context, bundleName string) { + By("verifying Bundle status shows Synced") + err := waitForBundleCondition(ctx, bundleClient, bundleName, trustapi.BundleConditionSynced, metav1.ConditionTrue, lowTimeout) + Expect(err).ShouldNot(HaveOccurred()) +} + +func verifyBundleNeverSynced(ctx context.Context, bundleName string) { + Consistently(func() bool { + var b trustapi.Bundle + if err := bundleClient.Get(ctx, crclient.ObjectKey{Name: bundleName}, &b); err != nil { + return false + } + for _, c := range b.Status.Conditions { + if c.Type == trustapi.BundleConditionSynced && c.Status == metav1.ConditionTrue { + return false + } + } + return true + }, "60s", fastPollInterval).Should(BeTrue()) +} diff --git a/test/e2e/trustmanager_test.go b/test/e2e/trustmanager_test.go index b749eb483..cf019f6ff 100644 --- a/test/e2e/trustmanager_test.go +++ b/test/e2e/trustmanager_test.go @@ -5,6 +5,7 @@ package e2e import ( "context" + "crypto/x509" "fmt" "slices" @@ -12,6 +13,7 @@ import ( . "github.com/onsi/gomega" "github.com/openshift/cert-manager-operator/api/operator/v1alpha1" + testutils "github.com/openshift/cert-manager-operator/pkg/controller/istiocsr" operatorclientv1alpha1 "github.com/openshift/cert-manager-operator/pkg/operator/clientset/versioned/typed/operator/v1alpha1" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" @@ -57,12 +59,6 @@ const ( trustedCABundleKey = "ca-bundle.crt" ) -var ( - trustManagerClient = func() operatorclientv1alpha1.TrustManagerInterface { - return certmanageroperatorclient.OperatorV1alpha1().TrustManagers() - } -) - // Cluster must have an allowed feature set (e.g. TechPreviewNoUpgrade). TrustManager is deployed and reconciled. var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:TrustManager", "TechPreview"), func() { var ( @@ -73,19 +69,6 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru originalOperatorLogLevel string ) - waitForTrustManagerReady := func() v1alpha1.TrustManagerStatus { - By("waiting for TrustManager CR to be ready") - status, err := pollTillTrustManagerAvailable(ctx, trustManagerClient(), "cluster") - Expect(err).Should(BeNil()) - return status - } - - createTrustManager := func(b *trustManagerCRBuilder) { - _, err := trustManagerClient().Create(ctx, b.Build(), metav1.CreateOptions{}) - Expect(err).ShouldNot(HaveOccurred()) - waitForTrustManagerReady() - } - BeforeAll(trustManagerBeforeAll(ctx, &clientset, &originalUnsupportedAddonFeatures, &originalOperatorLogLevel)) AfterAll(trustManagerAfterAll(ctx, &originalUnsupportedAddonFeatures, &originalOperatorLogLevel)) @@ -100,7 +83,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru Context("resource creation", func() { It("should create all resources managed by the controller with correct labels", func() { - createTrustManager(newTrustManagerCR()) + createTrustManager(ctx, newTrustManagerCR()) // Namespace-scoped resources By("verifying ServiceAccount") @@ -203,7 +186,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru Context("resource deletion and recreation", func() { It("should recreate resources managed by the controller when deleted externally", func() { - createTrustManager(newTrustManagerCR()) + createTrustManager(ctx, newTrustManagerCR()) // Namespace-scoped resources By("deleting and verifying recreation of ServiceAccount") @@ -319,7 +302,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru Context("label drift reconciliation", func() { It("should restore labels when modified externally on managed resources", func() { - createTrustManager(newTrustManagerCR()) + createTrustManager(ctx, newTrustManagerCR()) By("modifying ServiceAccount labels externally") sa, err := clientset.CoreV1().ServiceAccounts(trustManagerNamespace).Get(ctx, trustManagerServiceAccountName, metav1.GetOptions{}) @@ -371,7 +354,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru Context("managed label removal reconciliation", func() { It("should restore the managed label when removed externally from resources", func() { - createTrustManager(newTrustManagerCR()) + createTrustManager(ctx, newTrustManagerCR()) // The "app" label is the managed resource label used by the predicate // to filter watch events. Removing it tests that the predicate checks @@ -427,7 +410,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru Context("deployment configuration", func() { It("should have deployment available with correct configuration", func() { - createTrustManager(newTrustManagerCR()) + createTrustManager(ctx, newTrustManagerCR()) By("waiting for trust-manager deployment to become available") err := pollTillDeploymentAvailable(ctx, clientset, trustManagerNamespace, trustManagerDeploymentName) @@ -448,7 +431,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru }) It("should update deployment args when log level changes", func() { - createTrustManager(newTrustManagerCR()) + createTrustManager(ctx, newTrustManagerCR()) err := pollTillDeploymentAvailable(ctx, clientset, trustManagerNamespace, trustManagerDeploymentName) Expect(err).ShouldNot(HaveOccurred()) @@ -474,7 +457,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru }) It("should apply custom resource requirements to deployment", func() { - createTrustManager(newTrustManagerCR().WithResources(corev1.ResourceRequirements{ + createTrustManager(ctx, newTrustManagerCR().WithResources(corev1.ResourceRequirements{ Requests: corev1.ResourceList{ corev1.ResourceCPU: resource.MustParse("50m"), corev1.ResourceMemory: resource.MustParse("64Mi"), @@ -499,7 +482,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru }) It("should apply custom tolerations to deployment", func() { - createTrustManager(newTrustManagerCR().WithTolerations([]corev1.Toleration{ + createTrustManager(ctx, newTrustManagerCR().WithTolerations([]corev1.Toleration{ { Key: "test-key", Operator: corev1.TolerationOpEqual, @@ -525,7 +508,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru }) It("should apply custom nodeSelector to deployment", func() { - createTrustManager(newTrustManagerCR().WithNodeSelector(map[string]string{ + createTrustManager(ctx, newTrustManagerCR().WithNodeSelector(map[string]string{ "test-node-label": "test-value", })) @@ -538,7 +521,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru }) It("should apply custom affinity to deployment", func() { - createTrustManager(newTrustManagerCR().WithAffinity(&corev1.Affinity{ + createTrustManager(ctx, newTrustManagerCR().WithAffinity(&corev1.Affinity{ PodAntiAffinity: &corev1.PodAntiAffinity{ PreferredDuringSchedulingIgnoredDuringExecution: []corev1.WeightedPodAffinityTerm{ { @@ -574,7 +557,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru customTrustNS := createUniqueNamespace("custom-trust-ns") createAndDestroyTestNamespace(ctx, clientset, customTrustNS) - createTrustManager(newTrustManagerCR().WithTrustNamespace(customTrustNS)) + createTrustManager(ctx, newTrustManagerCR().WithTrustNamespace(customTrustNS)) By("verifying deployment has correct --trust-namespace arg") Eventually(func(g Gomega) { @@ -586,7 +569,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru }) It("should add secret-targets-enabled arg when secretTargets policy is Custom", func() { - createTrustManager(newTrustManagerCR().WithSecretTargets(v1alpha1.SecretTargetsPolicyCustom, []string{"test-secret"})) + createTrustManager(ctx, newTrustManagerCR().WithSecretTargets(v1alpha1.SecretTargetsPolicyCustom, []string{"test-secret"})) By("verifying deployment args contain --secret-targets-enabled=true") Eventually(func(g Gomega) { @@ -598,7 +581,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru }) It("should not have secret-targets-enabled arg when secretTargets is Disabled", func() { - createTrustManager(newTrustManagerCR()) + createTrustManager(ctx, newTrustManagerCR()) By("verifying deployment args do not contain --secret-targets-enabled=true") Eventually(func(g Gomega) { @@ -609,8 +592,31 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru }, lowTimeout, fastPollInterval).Should(Succeed()) }) - // TODO: Add test for other deployment configuration options - // (e.g. filter expired certificates policy; custom trust namespace is covered above.) + It("should add filter-expired-certificates arg when filterExpiredCertificates is Enabled", func() { + createTrustManager(ctx, newTrustManagerCR(). + WithFilterExpiredCertificates(v1alpha1.FilterExpiredCertificatesPolicyEnabled)) + + By("verifying deployment args contain --filter-expired-certificates=true") + Eventually(func(g Gomega) { + dep, err := clientset.AppsV1().Deployments(trustManagerNamespace).Get(ctx, trustManagerDeploymentName, metav1.GetOptions{}) + g.Expect(err).ShouldNot(HaveOccurred()) + g.Expect(dep.Spec.Template.Spec.Containers).ShouldNot(BeEmpty()) + g.Expect(dep.Spec.Template.Spec.Containers[0].Args).Should(ContainElement("--filter-expired-certificates=true")) + }, lowTimeout, fastPollInterval).Should(Succeed()) + }) + + It("should not have filter-expired-certificates arg when filterExpiredCertificates is Disabled", func() { + createTrustManager(ctx, newTrustManagerCR()) + + By("verifying deployment args do not contain --filter-expired-certificates=true") + Eventually(func(g Gomega) { + dep, err := clientset.AppsV1().Deployments(trustManagerNamespace).Get(ctx, trustManagerDeploymentName, metav1.GetOptions{}) + g.Expect(err).ShouldNot(HaveOccurred()) + g.Expect(dep.Spec.Template.Spec.Containers).ShouldNot(BeEmpty()) + g.Expect(dep.Spec.Template.Spec.Containers[0].Args).ShouldNot(ContainElement("--filter-expired-certificates=true")) + }, lowTimeout, fastPollInterval).Should(Succeed()) + }) + }) // ------------------------------------------------------------------------- @@ -619,7 +625,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru Context("default CA package configuration", func() { It("should reconcile deployment when default CA package policy transitions between Disabled and Enabled", func() { - createTrustManager(newTrustManagerCR()) + createTrustManager(ctx, newTrustManagerCR()) By("verifying no default CA package ConfigMap exists") Eventually(func(g Gomega) { @@ -668,7 +674,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru return err }, lowTimeout, fastPollInterval).Should(Succeed()) - waitForTrustManagerReady() + waitForTrustManagerReady(ctx) By("verifying the CNO-injected CA bundle ConfigMap exists in operator namespace") Eventually(func(g Gomega) { @@ -750,7 +756,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru return err }, lowTimeout, fastPollInterval).Should(Succeed()) - waitForTrustManagerReady() + waitForTrustManagerReady(ctx) By("verifying deployment does not have --default-package-location arg after disabling") Eventually(func(g Gomega) { @@ -791,7 +797,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru }) It("should reconcile ConfigMap data drift when CA package ConfigMap is tampered", func() { - createTrustManager(newTrustManagerCR().WithDefaultCAPackage(v1alpha1.DefaultCAPackagePolicyEnabled)) + createTrustManager(ctx, newTrustManagerCR().WithDefaultCAPackage(v1alpha1.DefaultCAPackagePolicyEnabled)) var originalData string By("reading original CA package ConfigMap data") @@ -817,6 +823,173 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru g.Expect(cm.Data["cert-manager-package-openshift.json"]).Should(Equal(originalData)) }, lowTimeout, fastPollInterval).Should(Succeed()) }) + + It("should propagate CNO CA bundle update to package ConfigMap and restart pod", func() { + const openshiftConfigNS = "openshift-config" + const userCABundleName = "user-ca-bundle" + + createTrustManager(ctx, newTrustManagerCR().WithDefaultCAPackage(v1alpha1.DefaultCAPackagePolicyEnabled)) + + // --- Capture baseline state --- + + var originalHash string + By("reading original hash annotation from pod template") + Eventually(func(g Gomega) { + dep, err := clientset.AppsV1().Deployments(trustManagerNamespace).Get(ctx, trustManagerDeploymentName, metav1.GetOptions{}) + g.Expect(err).ShouldNot(HaveOccurred()) + g.Expect(dep.Spec.Template.Annotations).Should(HaveKey(defaultCAPackageHashAnnotation)) + originalHash = dep.Spec.Template.Annotations[defaultCAPackageHashAnnotation] + g.Expect(originalHash).ShouldNot(BeEmpty()) + }, lowTimeout, fastPollInterval).Should(Succeed()) + + var originalPkgData string + By("reading original package ConfigMap data") + Eventually(func(g Gomega) { + cm, err := clientset.CoreV1().ConfigMaps(trustManagerNamespace).Get(ctx, defaultCAPackageConfigMapName, metav1.GetOptions{}) + g.Expect(err).ShouldNot(HaveOccurred()) + originalPkgData = cm.Data["cert-manager-package-openshift.json"] + g.Expect(originalPkgData).ShouldNot(BeEmpty()) + }, lowTimeout, fastPollInterval).Should(Succeed()) + + var originalInjectedData string + By("reading original CNO-injected CA bundle ConfigMap data") + Eventually(func(g Gomega) { + cm, err := clientset.CoreV1().ConfigMaps(operatorNamespace).Get(ctx, trustedCABundleConfigMapName, metav1.GetOptions{}) + g.Expect(err).ShouldNot(HaveOccurred()) + originalInjectedData = cm.Data[trustedCABundleKey] + }, lowTimeout, fastPollInterval).Should(Succeed()) + + // --- Save original Proxy and user-ca-bundle state for cleanup --- + + By("saving original Proxy trustedCA and user-ca-bundle state") + proxy, err := configClient.Proxies().Get(ctx, "cluster", metav1.GetOptions{}) + Expect(err).ShouldNot(HaveOccurred()) + originalTrustedCAName := proxy.Spec.TrustedCA.Name + + existingUserCA, userCAErr := clientset.CoreV1().ConfigMaps(openshiftConfigNS).Get(ctx, userCABundleName, metav1.GetOptions{}) + userCABundleExisted := userCAErr == nil + var originalUserCAData string + if userCABundleExisted { + originalUserCAData = existingUserCA.Data["ca-bundle.crt"] + } + + // --- Register cleanup to restore original cluster state --- + + DeferCleanup(func() { + By("[cleanup] restoring original Proxy trustedCA reference") + if originalTrustedCAName != userCABundleName { + Eventually(func() error { + p, err := configClient.Proxies().Get(ctx, "cluster", metav1.GetOptions{}) + if err != nil { + return err + } + p.Spec.TrustedCA.Name = originalTrustedCAName + _, err = configClient.Proxies().Update(ctx, p, metav1.UpdateOptions{}) + return err + }, lowTimeout, fastPollInterval).Should(Succeed()) + } + + By("[cleanup] restoring original user-ca-bundle ConfigMap") + if userCABundleExisted { + Eventually(func() error { + cm, err := clientset.CoreV1().ConfigMaps(openshiftConfigNS).Get(ctx, userCABundleName, metav1.GetOptions{}) + if err != nil { + return err + } + cm.Data["ca-bundle.crt"] = originalUserCAData + _, err = clientset.CoreV1().ConfigMaps(openshiftConfigNS).Update(ctx, cm, metav1.UpdateOptions{}) + return err + }, lowTimeout, fastPollInterval).Should(Succeed()) + } else { + _ = clientset.CoreV1().ConfigMaps(openshiftConfigNS).Delete(ctx, userCABundleName, metav1.DeleteOptions{}) + } + + By("[cleanup] waiting for CNO to restore the injected CA bundle") + Eventually(func(g Gomega) { + cm, err := clientset.CoreV1().ConfigMaps(operatorNamespace).Get(ctx, trustedCABundleConfigMapName, metav1.GetOptions{}) + g.Expect(err).ShouldNot(HaveOccurred()) + g.Expect(cm.Data[trustedCABundleKey]).Should(Equal(originalInjectedData), + "injected CA bundle should be restored to original state") + }, highTimeout, slowPollInterval).Should(Succeed()) + }) + + // --- Modify the cluster-wide trust bundle via Proxy CR --- + + testCACert := testutils.GenerateCertificate( + "e2e-proxy-test-ca", + []string{"cert-manager-operator-e2e"}, + func(cert *x509.Certificate) { + cert.IsCA = true + cert.KeyUsage |= x509.KeyUsageCertSign + }, + ) + + By("creating/updating user-ca-bundle ConfigMap in openshift-config namespace") + if userCABundleExisted { + Eventually(func() error { + cm, err := clientset.CoreV1().ConfigMaps(openshiftConfigNS).Get(ctx, userCABundleName, metav1.GetOptions{}) + if err != nil { + return err + } + cm.Data["ca-bundle.crt"] = cm.Data["ca-bundle.crt"] + "\n" + testCACert + _, err = clientset.CoreV1().ConfigMaps(openshiftConfigNS).Update(ctx, cm, metav1.UpdateOptions{}) + return err + }, lowTimeout, fastPollInterval).Should(Succeed()) + } else { + _, err := clientset.CoreV1().ConfigMaps(openshiftConfigNS).Create(ctx, &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: userCABundleName, + Namespace: openshiftConfigNS, + }, + Data: map[string]string{ + "ca-bundle.crt": testCACert, + }, + }, metav1.CreateOptions{}) + Expect(err).ShouldNot(HaveOccurred()) + } + + if originalTrustedCAName != userCABundleName { + By("updating Proxy/cluster to reference user-ca-bundle") + Eventually(func() error { + p, err := configClient.Proxies().Get(ctx, "cluster", metav1.GetOptions{}) + if err != nil { + return err + } + p.Spec.TrustedCA.Name = userCABundleName + _, err = configClient.Proxies().Update(ctx, p, metav1.UpdateOptions{}) + return err + }, lowTimeout, fastPollInterval).Should(Succeed()) + } + + // --- Wait for CNO propagation --- + + By("waiting for CNO to propagate updated CA bundle to operator namespace") + Eventually(func(g Gomega) { + cm, err := clientset.CoreV1().ConfigMaps(operatorNamespace).Get(ctx, trustedCABundleConfigMapName, metav1.GetOptions{}) + g.Expect(err).ShouldNot(HaveOccurred()) + g.Expect(cm.Data[trustedCABundleKey]).ShouldNot(Equal(originalInjectedData), + "CNO should have updated the injected CA bundle") + }, highTimeout, slowPollInterval).Should(Succeed()) + + // --- Verify operator propagated the change --- + + By("verifying package ConfigMap in operand namespace is updated with new content") + Eventually(func(g Gomega) { + cm, err := clientset.CoreV1().ConfigMaps(trustManagerNamespace).Get(ctx, defaultCAPackageConfigMapName, metav1.GetOptions{}) + g.Expect(err).ShouldNot(HaveOccurred()) + g.Expect(cm.Data["cert-manager-package-openshift.json"]).ShouldNot(Equal(originalPkgData), + "package ConfigMap should reflect the updated CA bundle") + }, highTimeout, fastPollInterval).Should(Succeed()) + + By("verifying pod template hash annotation changed (triggers rolling restart)") + Eventually(func(g Gomega) { + dep, err := clientset.AppsV1().Deployments(trustManagerNamespace).Get(ctx, trustManagerDeploymentName, metav1.GetOptions{}) + g.Expect(err).ShouldNot(HaveOccurred()) + g.Expect(dep.Spec.Template.Annotations).Should(HaveKey(defaultCAPackageHashAnnotation)) + g.Expect(dep.Spec.Template.Annotations[defaultCAPackageHashAnnotation]).ShouldNot(Equal(originalHash), + "hash annotation should have changed after CA bundle update") + }, highTimeout, fastPollInterval).Should(Succeed()) + }) }) // ------------------------------------------------------------------------- @@ -825,7 +998,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru Context("RBAC configuration", func() { It("should configure ClusterRoleBinding with correct subjects and roleRef", func() { - createTrustManager(newTrustManagerCR()) + createTrustManager(ctx, newTrustManagerCR()) By("verifying ClusterRoleBinding references correct ClusterRole and ServiceAccount") Eventually(func(g Gomega) { @@ -842,7 +1015,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru }) It("should configure trust namespace RoleBinding with correct subjects and roleRef", func() { - createTrustManager(newTrustManagerCR()) + createTrustManager(ctx, newTrustManagerCR()) By("verifying trust namespace RoleBinding references correct Role and ServiceAccount") Eventually(func(g Gomega) { @@ -859,7 +1032,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru }) It("should configure leader election RoleBinding with correct subjects and roleRef", func() { - createTrustManager(newTrustManagerCR()) + createTrustManager(ctx, newTrustManagerCR()) By("verifying leader election RoleBinding references correct Role and ServiceAccount") Eventually(func(g Gomega) { @@ -881,7 +1054,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru createAndDestroyTestNamespace(ctx, clientset, customTrustNS) By("creating TrustManager CR with custom trust namespace") - createTrustManager(newTrustManagerCR().WithTrustNamespace(customTrustNS)) + createTrustManager(ctx, newTrustManagerCR().WithTrustNamespace(customTrustNS)) By("verifying Role is created in custom trust namespace") Eventually(func(g Gomega) { @@ -910,7 +1083,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru createAndDestroyTestNamespace(ctx, clientset, customTrustNS) By("creating TrustManager CR with custom trust namespace") - createTrustManager(newTrustManagerCR().WithTrustNamespace(customTrustNS)) + createTrustManager(ctx, newTrustManagerCR().WithTrustNamespace(customTrustNS)) By("verifying leader election Role is in operand namespace") Eventually(func(g Gomega) { @@ -930,7 +1103,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru }) It("should have no secret rules on ClusterRole when secretTargets is Disabled", func() { - createTrustManager(newTrustManagerCR()) + createTrustManager(ctx, newTrustManagerCR()) By("verifying ClusterRole has no secret rules") Eventually(func(g Gomega) { @@ -942,7 +1115,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru It("should add secret read and scoped write rules to ClusterRole when secretTargets is Custom", func() { authorizedSecrets := []string{"bundle-secret-a", "bundle-secret-b"} - createTrustManager(newTrustManagerCR().WithSecretTargets(v1alpha1.SecretTargetsPolicyCustom, authorizedSecrets)) + createTrustManager(ctx, newTrustManagerCR().WithSecretTargets(v1alpha1.SecretTargetsPolicyCustom, authorizedSecrets)) By("verifying ClusterRole has secret read rule") Eventually(func(g Gomega) { @@ -967,8 +1140,10 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru }, lowTimeout, fastPollInterval).Should(Succeed()) }) - It("should update ClusterRole rules when secretTargets policy changes from Disabled to Custom", func() { - createTrustManager(newTrustManagerCR()) + It("should update ClusterRole rules when secretTargets policy transitions between Disabled and Custom", func() { + createTrustManager(ctx, newTrustManagerCR()) + + // --- Disabled → Custom --- By("verifying ClusterRole initially has no secret rules") Eventually(func(g Gomega) { @@ -1000,10 +1175,35 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru g.Expect(writeRule).ShouldNot(BeNil(), "expected secret write rule after enabling secretTargets") g.Expect(writeRule.ResourceNames).Should(ConsistOf("updated-secret")) }, lowTimeout, fastPollInterval).Should(Succeed()) + + // --- Custom → Disabled --- + + By("updating TrustManager CR to disable secretTargets") + Eventually(func() error { + tm, err := trustManagerClient().Get(ctx, "cluster", metav1.GetOptions{}) + if err != nil { + return err + } + tm.Spec.TrustManagerConfig.SecretTargets = v1alpha1.SecretTargetsConfig{ + Policy: v1alpha1.SecretTargetsPolicyDisabled, + } + _, err = trustManagerClient().Update(ctx, tm, metav1.UpdateOptions{}) + return err + }, lowTimeout, fastPollInterval).Should(Succeed()) + + waitForTrustManagerReady(ctx) + + By("verifying ClusterRole no longer has secret rules after disabling") + Eventually(func(g Gomega) { + cr, err := clientset.RbacV1().ClusterRoles().Get(ctx, trustManagerClusterRoleName, metav1.GetOptions{}) + g.Expect(err).ShouldNot(HaveOccurred()) + g.Expect(hasSecretRule(cr.Rules)).Should(BeFalse(), + "ClusterRole should not have secret rules after disabling secretTargets") + }, lowTimeout, fastPollInterval).Should(Succeed()) }) It("should update ClusterRole resourceNames when authorizedSecrets list changes", func() { - createTrustManager(newTrustManagerCR(). + createTrustManager(ctx, newTrustManagerCR(). WithSecretTargets(v1alpha1.SecretTargetsPolicyCustom, []string{"secret-a", "secret-b"})) By("verifying ClusterRole has initial authorized secrets") @@ -1048,7 +1248,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru Context("webhook and certificate configuration", func() { It("should configure webhook with cert-manager CA injection annotation", func() { - createTrustManager(newTrustManagerCR()) + createTrustManager(ctx, newTrustManagerCR()) expectedAnnotation := fmt.Sprintf("%s/%s", trustManagerNamespace, trustManagerCertificateName) @@ -1061,7 +1261,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru }) It("should configure webhook service reference correctly", func() { - createTrustManager(newTrustManagerCR()) + createTrustManager(ctx, newTrustManagerCR()) By("verifying webhook service references are correct") Eventually(func(g Gomega) { @@ -1078,7 +1278,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru }) It("should have Issuer become ready", func() { - createTrustManager(newTrustManagerCR()) + createTrustManager(ctx, newTrustManagerCR()) By("waiting for trust-manager Issuer to become ready") err := waitForIssuerReadiness(ctx, trustManagerIssuerName, trustManagerNamespace) @@ -1086,7 +1286,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru }) It("should have Certificate become ready and create TLS secret", func() { - createTrustManager(newTrustManagerCR()) + createTrustManager(ctx, newTrustManagerCR()) By("waiting for trust-manager Certificate to become ready") err := waitForCertificateReadiness(ctx, trustManagerCertificateName, trustManagerNamespace) @@ -1103,7 +1303,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru }) It("should configure Certificate with correct spec fields", func() { - createTrustManager(newTrustManagerCR()) + createTrustManager(ctx, newTrustManagerCR()) expectedDNSName := fmt.Sprintf("%s.%s.svc", trustManagerServiceName, trustManagerNamespace) @@ -1126,7 +1326,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru Context("status reporting", func() { It("should report trust-manager image in status", func() { - createTrustManager(newTrustManagerCR()) + createTrustManager(ctx, newTrustManagerCR()) By("verifying TrustManager status has image set") Eventually(func(g Gomega) { @@ -1137,7 +1337,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru }) It("should report trust namespace in status", func() { - createTrustManager(newTrustManagerCR()) + createTrustManager(ctx, newTrustManagerCR()) By("verifying TrustManager status has default trust namespace set") Eventually(func(g Gomega) { @@ -1152,7 +1352,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru customTrustNS := createUniqueNamespace("custom-trust-ns-status") createAndDestroyTestNamespace(ctx, clientset, customTrustNS) - createTrustManager(newTrustManagerCR().WithTrustNamespace(customTrustNS)) + createTrustManager(ctx, newTrustManagerCR().WithTrustNamespace(customTrustNS)) By("verifying TrustManager status has custom trust namespace set") Eventually(func(g Gomega) { @@ -1163,7 +1363,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru }) It("should report secretTargets policy in status", func() { - createTrustManager(newTrustManagerCR().WithSecretTargets(v1alpha1.SecretTargetsPolicyCustom, []string{"status-test-secret"})) + createTrustManager(ctx, newTrustManagerCR().WithSecretTargets(v1alpha1.SecretTargetsPolicyCustom, []string{"status-test-secret"})) By("verifying TrustManager status reflects Custom secretTargets policy") Eventually(func(g Gomega) { @@ -1174,7 +1374,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru }) It("should report default CA package policy in status", func() { - createTrustManager(newTrustManagerCR().WithDefaultCAPackage(v1alpha1.DefaultCAPackagePolicyEnabled)) + createTrustManager(ctx, newTrustManagerCR().WithDefaultCAPackage(v1alpha1.DefaultCAPackagePolicyEnabled)) By("verifying status reports Enabled policy") Eventually(func(g Gomega) { @@ -1202,8 +1402,17 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru }, lowTimeout, fastPollInterval).Should(Succeed()) }) - // TODO: Add test for status reporting when custom configuration is applied - // (e.g. filter expired certificates policy; secret targets, default CA package, and trust namespace are covered above.) + It("should report filterExpiredCertificates policy in status", func() { + createTrustManager(ctx, newTrustManagerCR(). + WithFilterExpiredCertificates(v1alpha1.FilterExpiredCertificatesPolicyEnabled)) + + By("verifying status reports Enabled policy") + Eventually(func(g Gomega) { + tm, err := trustManagerClient().Get(ctx, "cluster", metav1.GetOptions{}) + g.Expect(err).ShouldNot(HaveOccurred()) + g.Expect(tm.Status.FilterExpiredCertificatesPolicy).Should(Equal(v1alpha1.FilterExpiredCertificatesPolicyEnabled)) + }, lowTimeout, fastPollInterval).Should(Succeed()) + }) }) // ------------------------------------------------------------------------- @@ -1213,7 +1422,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru Context("trust namespace configuration", func() { It("should reject updates that change spec.trustNamespace", func() { By("creating TrustManager with explicit trust namespace") - createTrustManager(newTrustManagerCR().WithTrustNamespace("cert-manager")) + createTrustManager(ctx, newTrustManagerCR().WithTrustNamespace("cert-manager")) By("attempting to mutate spec.trustNamespace (field is immutable once set)") tm, err := trustManagerClient().Get(ctx, "cluster", metav1.GetOptions{}) @@ -1273,7 +1482,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru Expect(err).ShouldNot(HaveOccurred()) By("waiting for TrustManager to recover (Ready=True, not Degraded)") - waitForTrustManagerReady() + waitForTrustManagerReady(ctx) }) }) @@ -1284,7 +1493,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru Context("custom labels and annotations", func() { It("should apply custom labels from controllerConfig to all managed resources", func() { By("creating TrustManager CR with custom labels") - createTrustManager(newTrustManagerCR().WithLabels(map[string]string{ + createTrustManager(ctx, newTrustManagerCR().WithLabels(map[string]string{ "custom-label": "custom-value", })) @@ -1340,7 +1549,7 @@ var _ = Describe("TrustManager", Ordered, Label("Platform:Generic", "Feature:Tru It("should apply custom annotations from controllerConfig to managed resources", func() { By("creating TrustManager CR with custom annotations") - createTrustManager(newTrustManagerCR().WithAnnotations(map[string]string{ + createTrustManager(ctx, newTrustManagerCR().WithAnnotations(map[string]string{ "custom-annotation": "annotation-value", })) diff --git a/test/e2e/utils_test.go b/test/e2e/utils_test.go index d59cc5fbb..1170ca1fd 100644 --- a/test/e2e/utils_test.go +++ b/test/e2e/utils_test.go @@ -27,7 +27,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" . "github.com/onsi/ginkgo/v2" - "github.com/onsi/gomega" + . "github.com/onsi/gomega" opv1 "github.com/openshift/api/operator/v1" configv1 "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1" operatorv1 "github.com/openshift/client-go/operator/clientset/versioned/typed/operator/v1" @@ -103,73 +103,6 @@ var serviceMonitorGVR = schema.GroupVersionResource{ Resource: "servicemonitors", } -type trustManagerCRBuilder struct { - tm *v1alpha1.TrustManager -} - -func newTrustManagerCR() *trustManagerCRBuilder { - return &trustManagerCRBuilder{ - tm: &v1alpha1.TrustManager{ - ObjectMeta: metav1.ObjectMeta{Name: "cluster"}, - Spec: v1alpha1.TrustManagerSpec{ - TrustManagerConfig: v1alpha1.TrustManagerConfig{}, - }, - }, - } -} - -func (b *trustManagerCRBuilder) WithResources(resources corev1.ResourceRequirements) *trustManagerCRBuilder { - b.tm.Spec.TrustManagerConfig.Resources = resources - return b -} - -func (b *trustManagerCRBuilder) WithTolerations(tolerations []corev1.Toleration) *trustManagerCRBuilder { - b.tm.Spec.TrustManagerConfig.Tolerations = tolerations - return b -} - -func (b *trustManagerCRBuilder) WithNodeSelector(nodeSelector map[string]string) *trustManagerCRBuilder { - b.tm.Spec.TrustManagerConfig.NodeSelector = nodeSelector - return b -} - -func (b *trustManagerCRBuilder) WithAffinity(affinity *corev1.Affinity) *trustManagerCRBuilder { - b.tm.Spec.TrustManagerConfig.Affinity = affinity - return b -} - -func (b *trustManagerCRBuilder) WithLabels(labels map[string]string) *trustManagerCRBuilder { - b.tm.Spec.ControllerConfig.Labels = labels - return b -} - -func (b *trustManagerCRBuilder) WithAnnotations(annotations map[string]string) *trustManagerCRBuilder { - b.tm.Spec.ControllerConfig.Annotations = annotations - return b -} - -func (b *trustManagerCRBuilder) WithTrustNamespace(trustNamespace string) *trustManagerCRBuilder { - b.tm.Spec.TrustManagerConfig.TrustNamespace = trustNamespace - return b -} - -func (b *trustManagerCRBuilder) WithSecretTargets(policy v1alpha1.SecretTargetsPolicy, authorizedSecrets []string) *trustManagerCRBuilder { - b.tm.Spec.TrustManagerConfig.SecretTargets = v1alpha1.SecretTargetsConfig{ - Policy: policy, - AuthorizedSecrets: authorizedSecrets, - } - return b -} - -func (b *trustManagerCRBuilder) WithDefaultCAPackage(policy v1alpha1.DefaultCAPackagePolicy) *trustManagerCRBuilder { - b.tm.Spec.TrustManagerConfig.DefaultCAPackage.Policy = policy - return b -} - -func (b *trustManagerCRBuilder) Build() *v1alpha1.TrustManager { - return b.tm -} - func verifyDeploymentGenerationIsNotEmpty(client *certmanoperatorclient.Clientset, deployments []metav1.ObjectMeta) error { var wg sync.WaitGroup var lastFetchedGenerationStatus []opv1.GenerationStatus @@ -1090,7 +1023,7 @@ func verifyCertificateRenewed(ctx context.Context, secretName, namespace string, func createUniqueNamespace(prefix string) string { var b [4]byte _, err := cryptorand.Read(b[:]) - gomega.Expect(err).NotTo(gomega.HaveOccurred()) + Expect(err).NotTo(HaveOccurred()) name := fmt.Sprintf("%s-%s", prefix, hex.EncodeToString(b[:])) if len(name) > 63 { return name[:63] @@ -1100,10 +1033,10 @@ func createUniqueNamespace(prefix string) string { // waitNamespaceDeleted polls until the namespace is gone. func waitNamespaceDeleted(ctx context.Context, clientset *kubernetes.Clientset, name string) { - gomega.Eventually(func() bool { + Eventually(func() bool { _, err := clientset.CoreV1().Namespaces().Get(ctx, name, metav1.GetOptions{}) return apierrors.IsNotFound(err) - }, lowTimeout, fastPollInterval).Should(gomega.BeTrue()) + }, lowTimeout, fastPollInterval).Should(BeTrue()) } // createAndDestroyTestNamespace creates a namespace with the given name and registers DeferCleanup @@ -1112,7 +1045,7 @@ func createAndDestroyTestNamespace(ctx context.Context, clientset *kubernetes.Cl _, err := clientset.CoreV1().Namespaces().Create(ctx, &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{Name: name}, }, metav1.CreateOptions{}) - gomega.Expect(err).NotTo(gomega.HaveOccurred()) + Expect(err).NotTo(HaveOccurred()) DeferCleanup(func() { By("cleaning up test namespace") _ = clientset.CoreV1().Namespaces().Delete(ctx, name, metav1.DeleteOptions{}) diff --git a/test/go.mod b/test/go.mod index f97ab0d91..866b8d04b 100644 --- a/test/go.mod +++ b/test/go.mod @@ -13,6 +13,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/iam v1.52.1 github.com/aws/aws-sdk-go-v2/service/sts v1.38.6 github.com/cert-manager/cert-manager v1.19.4 + github.com/cert-manager/trust-manager v0.20.3 github.com/ghodss/yaml v1.0.0 github.com/google/go-cmp v0.7.0 github.com/google/uuid v1.6.0 @@ -150,7 +151,7 @@ require ( sigs.k8s.io/gateway-api v1.4.0 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.1 // indirect ) replace github.com/openshift/cert-manager-operator => ../ diff --git a/test/go.sum b/test/go.sum index d2881a84e..c14dfafbb 100644 --- a/test/go.sum +++ b/test/go.sum @@ -64,6 +64,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/cert-manager/trust-manager v0.20.3 h1:7jV9KwYDP/Lv61/dsdMvJKYLmdCxKinemakGEMftJgw= +github.com/cert-manager/trust-manager v0.20.3/go.mod h1:QwfQi2YsYL+8ApRuUBhthasrUM+zD1bT/POgnJltqaI= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -428,7 +430,7 @@ sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 h1:IpInykpT6ceI+QxKBbEflcR5E sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco= -sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.1 h1:JrhdFMqOd/+3ByqlP2I45kTOZmTRLBUm5pvRjeheg7E= +sigs.k8s.io/structured-merge-diff/v6 v6.3.1/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/tools/go.mod b/tools/go.mod index 72c485107..21757b4b7 100644 --- a/tools/go.mod +++ b/tools/go.mod @@ -83,7 +83,7 @@ require ( github.com/fzipp/gocyclo v0.6.0 // indirect github.com/ghostiam/protogetter v0.3.17 // indirect github.com/go-critic/go-critic v0.14.2 // indirect - github.com/go-errors/errors v1.4.2 // indirect + github.com/go-errors/errors v1.5.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/zapr v1.3.0 // indirect github.com/go-openapi/jsonpointer v0.22.1 // indirect @@ -292,7 +292,7 @@ require ( sigs.k8s.io/kustomize/cmd/config v0.20.1 // indirect sigs.k8s.io/kustomize/kyaml v0.20.1 // indirect sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.3.1 // indirect sigs.k8s.io/yaml v1.6.0 // indirect ) diff --git a/tools/go.sum b/tools/go.sum index 6a7065a63..73f4bfca2 100644 --- a/tools/go.sum +++ b/tools/go.sum @@ -150,8 +150,8 @@ github.com/go-bindata/go-bindata v3.1.2+incompatible h1:5vjJMVhowQdPzjE1LdxyFF7Y github.com/go-bindata/go-bindata v3.1.2+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo= github.com/go-critic/go-critic v0.14.2 h1:PMvP5f+LdR8p6B29npvChUXbD1vrNlKDf60NJtgMBOo= github.com/go-critic/go-critic v0.14.2/go.mod h1:xwntfW6SYAd7h1OqDzmN6hBX/JxsEKl5up/Y2bsxgVQ= -github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= -github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= +github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk= +github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= @@ -814,7 +814,7 @@ sigs.k8s.io/kustomize/kyaml v0.20.1 h1:PCMnA2mrVbRP3NIB6v9kYCAc38uvFLVs8j/CD567A sigs.k8s.io/kustomize/kyaml v0.20.1/go.mod h1:0EmkQHRUsJxY8Ug9Niig1pUMSCGHxQ5RklbpV/Ri6po= sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= -sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco= -sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= +sigs.k8s.io/structured-merge-diff/v6 v6.3.1 h1:JrhdFMqOd/+3ByqlP2I45kTOZmTRLBUm5pvRjeheg7E= +sigs.k8s.io/structured-merge-diff/v6 v6.3.1/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE= sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs= sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4= diff --git a/vendor/github.com/cert-manager/trust-manager/LICENSE b/vendor/github.com/cert-manager/trust-manager/LICENSE new file mode 100644 index 000000000..261eeb9e9 --- /dev/null +++ b/vendor/github.com/cert-manager/trust-manager/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/github.com/cert-manager/trust-manager/LICENSES b/vendor/github.com/cert-manager/trust-manager/LICENSES new file mode 100644 index 000000000..a8f820154 --- /dev/null +++ b/vendor/github.com/cert-manager/trust-manager/LICENSES @@ -0,0 +1,128 @@ +This LICENSES file is generated by the `licenses` module in makefile-modules[0]. + +The licenses below the "---" are determined by the go-licenses tool[1]. + +The aim of this file is to collect the licenses of all dependencies, and provide +a single source of truth for licenses used by this project. + +## For Developers + +If CI reports that this file is out of date, you should be careful to check that the +new licenses are acceptable for this project before running `make generate-go-licenses` +to update this file. + +Acceptable licenses are those allowlisted by the CNCF[2]. + +You MUST NOT add any new dependencies whose licenses are not allowlisted by the CNCF, +or which do not have an explicit license exception[3]. + +## For Users + +If this file was included in a release artifact, it is a snapshot of the licenses of all dependencies at the time of the release. + +You can retrieve the actual license text by following these steps: + +1. Find the dependency name in this file +2. Go to the source code repository of this project, and go to the tag corresponding to this release. +3. Find the exact version of the dependency in the `go.mod` file +4. Search for the dependency at the correct version in the [Go package index](https://pkg.go.dev/). + +## Links + +[0]: https://github.com/cert-manager/makefile-modules/ +[1]: https://github.com/google/go-licenses +[2]: https://github.com/cncf/foundation/blob/db4179134ebe7fa00b140a050c19147db808b6fa/policies-guidance/allowed-third-party-license-policy.md#cncf-allowlist-license-policy +[3]: https://github.com/cncf/foundation/blob/db4179134ebe7fa00b140a050c19147db808b6fa/license-exceptions/README.md + +--- + +github.com/Masterminds/semver/v3,MIT +github.com/beorn7/perks/quantile,MIT +github.com/blang/semver/v4,MIT +github.com/cert-manager/trust-manager,Apache-2.0 +github.com/cespare/xxhash/v2,MIT +github.com/davecgh/go-spew/spew,ISC +github.com/emicklei/go-restful/v3,MIT +github.com/evanphx/json-patch/v5,BSD-3-Clause +github.com/fsnotify/fsnotify,BSD-3-Clause +github.com/fxamacker/cbor/v2,MIT +github.com/go-errors/errors,MIT +github.com/go-logr/logr,Apache-2.0 +github.com/go-logr/zapr,Apache-2.0 +github.com/go-openapi/jsonpointer,Apache-2.0 +github.com/go-openapi/jsonreference,Apache-2.0 +github.com/go-openapi/swag,Apache-2.0 +github.com/gogo/protobuf,BSD-3-Clause +github.com/google/btree,Apache-2.0 +github.com/google/gnostic-models,Apache-2.0 +github.com/google/go-cmp/cmp,BSD-3-Clause +github.com/google/uuid,BSD-3-Clause +github.com/gregjones/httpcache,MIT +github.com/josharian/intern,MIT +github.com/json-iterator/go,MIT +github.com/liggitt/tabwriter,BSD-3-Clause +github.com/mailru/easyjson,MIT +github.com/moby/term,Apache-2.0 +github.com/modern-go/concurrent,Apache-2.0 +github.com/modern-go/reflect2,Apache-2.0 +github.com/monochromegane/go-gitignore,MIT +github.com/munnerz/goautoneg,BSD-3-Clause +github.com/onsi/ginkgo/v2,MIT +github.com/onsi/gomega,MIT +github.com/pavlo-v-chernykh/keystore-go/v4,MIT +github.com/peterbourgon/diskv,MIT +github.com/pkg/errors,BSD-2-Clause +github.com/pmezard/go-difflib/difflib,BSD-3-Clause +github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil,BSD-3-Clause +github.com/prometheus/client_golang/prometheus,Apache-2.0 +github.com/prometheus/client_model/go,Apache-2.0 +github.com/prometheus/common,Apache-2.0 +github.com/prometheus/procfs,Apache-2.0 +github.com/spf13/cobra,Apache-2.0 +github.com/spf13/pflag,BSD-3-Clause +github.com/x448/float16,MIT +github.com/xlab/treeprint,MIT +go.uber.org/multierr,MIT +go.uber.org/zap,MIT +go.yaml.in/yaml/v2,Apache-2.0 +go.yaml.in/yaml/v3,MIT +golang.org/x/crypto/pbkdf2,BSD-3-Clause +golang.org/x/mod/semver,BSD-3-Clause +golang.org/x/net,BSD-3-Clause +golang.org/x/oauth2,BSD-3-Clause +golang.org/x/sync/errgroup,BSD-3-Clause +golang.org/x/sys/unix,BSD-3-Clause +golang.org/x/term,BSD-3-Clause +golang.org/x/text,BSD-3-Clause +golang.org/x/time/rate,BSD-3-Clause +golang.org/x/tools,BSD-3-Clause +gomodules.xyz/jsonpatch/v2,Apache-2.0 +google.golang.org/protobuf,BSD-3-Clause +gopkg.in/evanphx/json-patch.v4,BSD-3-Clause +gopkg.in/inf.v0,BSD-3-Clause +gopkg.in/yaml.v3,MIT +k8s.io/api,Apache-2.0 +k8s.io/apiextensions-apiserver/pkg,Apache-2.0 +k8s.io/apimachinery/pkg,Apache-2.0 +k8s.io/apimachinery/third_party/forked/golang,BSD-3-Clause +k8s.io/cli-runtime/pkg,Apache-2.0 +k8s.io/client-go,Apache-2.0 +k8s.io/client-go/third_party/forked/golang/template,BSD-3-Clause +k8s.io/component-base/cli/flag,Apache-2.0 +k8s.io/klog/v2,Apache-2.0 +k8s.io/kube-openapi/pkg,Apache-2.0 +k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json,BSD-3-Clause +k8s.io/kube-openapi/pkg/validation/spec,Apache-2.0 +k8s.io/utils,Apache-2.0 +k8s.io/utils/internal/third_party/forked/golang,BSD-3-Clause +sigs.k8s.io/controller-runtime,Apache-2.0 +sigs.k8s.io/json,Apache-2.0 +sigs.k8s.io/json,BSD-3-Clause +sigs.k8s.io/kustomize/api,Apache-2.0 +sigs.k8s.io/kustomize/kyaml,Apache-2.0 +sigs.k8s.io/randfill,Apache-2.0 +sigs.k8s.io/structured-merge-diff/v6,Apache-2.0 +sigs.k8s.io/yaml,MIT +sigs.k8s.io/yaml,Apache-2.0 +sigs.k8s.io/yaml,BSD-3-Clause +software.sslmate.com/src/go-pkcs12,BSD-3-Clause diff --git a/vendor/github.com/cert-manager/trust-manager/pkg/apis/trust/doc.go b/vendor/github.com/cert-manager/trust-manager/pkg/apis/trust/doc.go new file mode 100644 index 000000000..4ac14a33d --- /dev/null +++ b/vendor/github.com/cert-manager/trust-manager/pkg/apis/trust/doc.go @@ -0,0 +1,19 @@ +/* +Copyright 2021 The cert-manager Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package trust + +const GroupName = "trust.cert-manager.io" diff --git a/vendor/github.com/cert-manager/trust-manager/pkg/apis/trust/v1alpha1/conversion.go b/vendor/github.com/cert-manager/trust-manager/pkg/apis/trust/v1alpha1/conversion.go new file mode 100644 index 000000000..6a28c8713 --- /dev/null +++ b/vendor/github.com/cert-manager/trust-manager/pkg/apis/trust/v1alpha1/conversion.go @@ -0,0 +1,294 @@ +/* +Copyright 2025 The cert-manager Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + "slices" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + apimachineryconversion "k8s.io/apimachinery/pkg/conversion" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/conversion" + + trustv1alpha2 "github.com/cert-manager/trust-manager/pkg/apis/trustmanager/v1alpha2" +) + +const annotationKeyJKSKey = "internal.trust-manager.io/jks-key" + +func (src *Bundle) ConvertTo(dstRaw conversion.Hub) error { + dst := dstRaw.(*trustv1alpha2.ClusterBundle) + dst.ObjectMeta = src.ObjectMeta + + scheme := runtime.NewScheme() + if err := localSchemeBuilder.AddToScheme(scheme); err != nil { + return err + } + converter := scheme.Converter() + + meta := &apimachineryconversion.Meta{ + Context: dst, + } + if err := converter.Convert(&src.Spec, &dst.Spec, meta); err != nil { + return err + } + if err := converter.Convert(&src.Status, &dst.Status, meta); err != nil { + return err + } + + // Remove empty sources, as some source fields are "promoted" to spec in ClusterBundle. + dst.Spec.Sources = slices.DeleteFunc(dst.Spec.Sources, func(bs trustv1alpha2.BundleSource) bool { + return bs == trustv1alpha2.BundleSource{} + }) + + return nil +} + +func Convert_v1alpha1_BundleSource_To_v1alpha2_BundleSource(in *BundleSource, out *trustv1alpha2.BundleSource, scope apimachineryconversion.Scope) error { + var sourceObjectKeySelector *SourceObjectKeySelector + if in.ConfigMap != nil { + out.Kind = trustv1alpha2.ConfigMapKind + sourceObjectKeySelector = in.ConfigMap + } + if in.Secret != nil { + out.Kind = trustv1alpha2.SecretKind + sourceObjectKeySelector = in.Secret + } + if sourceObjectKeySelector != nil { + out.Name = sourceObjectKeySelector.Name + out.Selector = sourceObjectKeySelector.Selector + out.Key = sourceObjectKeySelector.Key + if sourceObjectKeySelector.IncludeAllKeys { + out.Key = "*" + } + } + + if in.InLine != nil { + obj := scope.Meta().Context.(*trustv1alpha2.ClusterBundle) + obj.Spec.InLineCAs = in.InLine + } + if in.UseDefaultCAs != nil { + obj := scope.Meta().Context.(*trustv1alpha2.ClusterBundle) + obj.Spec.IncludeDefaultCAs = in.UseDefaultCAs + } + + return nil +} + +func Convert_v1alpha1_BundleTarget_To_v1alpha2_BundleTarget(in *BundleTarget, out *trustv1alpha2.BundleTarget, scope apimachineryconversion.Scope) error { + if err := autoConvert_v1alpha1_BundleTarget_To_v1alpha2_BundleTarget(in, out, scope); err != nil { + return err + } + + // No targets defined; we are done + if *out == (trustv1alpha2.BundleTarget{}) { + return nil + } + + if in.AdditionalFormats != nil { + appendTargetKV := func(tkv trustv1alpha2.TargetKeyValue) { + if in.ConfigMap != nil { + out.ConfigMap.Data = append(out.ConfigMap.Data, tkv) + } + if in.Secret != nil { + out.Secret.Data = append(out.Secret.Data, tkv) + } + } + + if in.AdditionalFormats.JKS != nil { + targetKV := trustv1alpha2.TargetKeyValue{ + Key: in.AdditionalFormats.JKS.Key, + Format: trustv1alpha2.BundleFormatPKCS12, + PKCS12: trustv1alpha2.PKCS12{ + Password: in.AdditionalFormats.JKS.Password, + }, + } + appendTargetKV(targetKV) + + obj := scope.Meta().Context.(*trustv1alpha2.ClusterBundle) + if obj.Annotations == nil { + obj.Annotations = map[string]string{} + } + obj.Annotations[annotationKeyJKSKey] = targetKV.Key + } + if in.AdditionalFormats.PKCS12 != nil { + targetKV := trustv1alpha2.TargetKeyValue{ + Key: in.AdditionalFormats.PKCS12.Key, + Format: trustv1alpha2.BundleFormatPKCS12, + PKCS12: trustv1alpha2.PKCS12{}, + } + if err := Convert_v1alpha1_PKCS12_To_v1alpha2_PKCS12(in.AdditionalFormats.PKCS12, &targetKV.PKCS12, scope); err != nil { + return err + } + appendTargetKV(targetKV) + } + } + + if in.NamespaceSelector == nil { + // NamespaceSelector is required in v1alpha2 + out.NamespaceSelector = &metav1.LabelSelector{} + } + return nil +} + +func Convert_v1alpha1_TargetTemplate_To_v1alpha2_KeyValueTarget(in *TargetTemplate, out *trustv1alpha2.KeyValueTarget, scope apimachineryconversion.Scope) error { + out.Data = []trustv1alpha2.TargetKeyValue{{Key: in.Key}} + if in.Metadata != nil { + out.Metadata = &trustv1alpha2.TargetMetadata{} + if err := Convert_v1alpha1_TargetMetadata_To_v1alpha2_TargetMetadata(in.Metadata, out.Metadata, scope); err != nil { + return err + } + } + return nil +} + +func Convert_v1alpha1_PKCS12_To_v1alpha2_PKCS12(in *PKCS12, out *trustv1alpha2.PKCS12, _ apimachineryconversion.Scope) error { + out.Password = in.Password + out.Profile = trustv1alpha2.PKCS12Profile(in.Profile) + if out.Profile == "" { + // Default profile changed from LegacyRC2 to LegacyDES in v1alpha2 + out.Profile = trustv1alpha2.LegacyRC2PKCS12Profile + } + return nil +} + +func (dst *Bundle) ConvertFrom(srcRaw conversion.Hub) error { + src := srcRaw.(*trustv1alpha2.ClusterBundle) + dst.ObjectMeta = src.ObjectMeta + + scheme := runtime.NewScheme() + if err := localSchemeBuilder.AddToScheme(scheme); err != nil { + return err + } + converter := scheme.Converter() + + meta := &apimachineryconversion.Meta{ + Context: dst, + } + if err := converter.Convert(&src.Spec, &dst.Spec, meta); err != nil { + return err + } + if err := converter.Convert(&src.Status, &dst.Status, meta); err != nil { + return err + } + return nil +} + +func Convert_v1alpha2_BundleSpec_To_v1alpha1_BundleSpec(in *trustv1alpha2.BundleSpec, out *BundleSpec, scope apimachineryconversion.Scope) error { + if err := autoConvert_v1alpha2_BundleSpec_To_v1alpha1_BundleSpec(in, out, scope); err != nil { + return err + } + + if in.InLineCAs != nil { + out.Sources = append(out.Sources, BundleSource{InLine: in.InLineCAs}) + } + if in.IncludeDefaultCAs != nil { + out.Sources = append(out.Sources, BundleSource{UseDefaultCAs: in.IncludeDefaultCAs}) + } + + return nil +} + +func Convert_v1alpha2_BundleSource_To_v1alpha1_BundleSource(in *trustv1alpha2.BundleSource, out *BundleSource, _ apimachineryconversion.Scope) error { + key := in.Key + includeAllKeys := false + if in.Key == "*" { + key = "" + includeAllKeys = true + } + sourceObjectKeySelector := &SourceObjectKeySelector{ + Name: in.Name, + Selector: in.Selector, + Key: key, + IncludeAllKeys: includeAllKeys, + } + switch in.Kind { + case trustv1alpha2.ConfigMapKind: + out.ConfigMap = sourceObjectKeySelector + case trustv1alpha2.SecretKind: + out.Secret = sourceObjectKeySelector + } + return nil +} + +func Convert_v1alpha2_BundleTarget_To_v1alpha1_BundleTarget(in *trustv1alpha2.BundleTarget, out *BundleTarget, scope apimachineryconversion.Scope) error { + if err := autoConvert_v1alpha2_BundleTarget_To_v1alpha1_BundleTarget(in, out, scope); err != nil { + return err + } + + var targetKeyValues []trustv1alpha2.TargetKeyValue + if in.Secret != nil { + targetKeyValues = append(targetKeyValues, in.Secret.Data...) + } + if in.ConfigMap != nil { + targetKeyValues = append(targetKeyValues, in.ConfigMap.Data...) + } + + obj := scope.Meta().Context.(*Bundle) + + var jks *JKS + var pkcs12 *PKCS12 + for _, tkv := range targetKeyValues { + if tkv.Format == trustv1alpha2.BundleFormatPKCS12 { + if k, ok := obj.Annotations[annotationKeyJKSKey]; ok && k == tkv.Key { + jks = &JKS{} + jks.Key = tkv.Key + jks.Password = tkv.PKCS12.Password + } else { + pkcs12 = &PKCS12{} + pkcs12.Key = tkv.Key + pkcs12.Password = tkv.PKCS12.Password + pkcs12.Profile = PKCS12Profile(tkv.PKCS12.Profile) + if pkcs12.Profile == "" { + // Default profile changed from LegacyRC2 to LegacyDES in v1alpha1->v1alpha2 + pkcs12.Profile = LegacyDESPKCS12Profile + } + } + } + if jks != nil && pkcs12 != nil { + break + } + } + if jks != nil || pkcs12 != nil { + out.AdditionalFormats = &AdditionalFormats{ + JKS: jks, + PKCS12: pkcs12, + } + } + + delete(obj.Annotations, annotationKeyJKSKey) + if len(obj.Annotations) == 0 { + obj.Annotations = nil + } + + return nil +} + +func Convert_v1alpha2_KeyValueTarget_To_v1alpha1_TargetTemplate(in *trustv1alpha2.KeyValueTarget, out *TargetTemplate, scope apimachineryconversion.Scope) error { + for _, tkv := range in.Data { + if tkv.Format == "" || tkv.Format == trustv1alpha2.BundleFormatPEM { + out.Key = tkv.Key + break + } + } + if in.Metadata != nil { + out.Metadata = &TargetMetadata{} + if err := Convert_v1alpha2_TargetMetadata_To_v1alpha1_TargetMetadata(in.Metadata, out.Metadata, scope); err != nil { + return err + } + } + return nil +} diff --git a/vendor/github.com/cert-manager/trust-manager/pkg/apis/trust/v1alpha1/doc.go b/vendor/github.com/cert-manager/trust-manager/pkg/apis/trust/v1alpha1/doc.go new file mode 100644 index 000000000..07ba1f977 --- /dev/null +++ b/vendor/github.com/cert-manager/trust-manager/pkg/apis/trust/v1alpha1/doc.go @@ -0,0 +1,22 @@ +/* +Copyright 2021 The cert-manager Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +kubebuilder:object:generate=true +// +groupName=trust.cert-manager.io +// +kubebuilder:ac:generate=true +// +kubebuilder:ac:output:package=../../../applyconfigurations +// +k8s:conversion-gen=github.com/cert-manager/trust-manager/pkg/apis/trustmanager/v1alpha2 +package v1alpha1 diff --git a/vendor/github.com/cert-manager/trust-manager/pkg/apis/trust/v1alpha1/register.go b/vendor/github.com/cert-manager/trust-manager/pkg/apis/trust/v1alpha1/register.go new file mode 100644 index 000000000..18e504494 --- /dev/null +++ b/vendor/github.com/cert-manager/trust-manager/pkg/apis/trust/v1alpha1/register.go @@ -0,0 +1,47 @@ +/* +Copyright 2021 The cert-manager Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + + "github.com/cert-manager/trust-manager/pkg/apis/trust" +) + +var ( + // SchemeGroupVersion is group version used to register these objects. + SchemeGroupVersion = schema.GroupVersion{Group: trust.GroupName, Version: "v1alpha1"} + + // schemeBuilder is used to add go types to the GroupVersionKind scheme. + schemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + + localSchemeBuilder = schemeBuilder + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = schemeBuilder.AddToScheme +) + +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &Bundle{}, + &BundleList{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/vendor/github.com/cert-manager/trust-manager/pkg/apis/trust/v1alpha1/types_bundle.go b/vendor/github.com/cert-manager/trust-manager/pkg/apis/trust/v1alpha1/types_bundle.go new file mode 100644 index 000000000..afe22fec6 --- /dev/null +++ b/vendor/github.com/cert-manager/trust-manager/pkg/apis/trust/v1alpha1/types_bundle.go @@ -0,0 +1,303 @@ +/* +Copyright 2021 The cert-manager Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var BundleKind = "Bundle" + +var BundleLabelKey = "trust.cert-manager.io/bundle" +var BundleHashAnnotationKey = "trust.cert-manager.io/hash" + +// +kubebuilder:object:root=true +// +kubebuilder:printcolumn:name="ConfigMap Target",type="string",JSONPath=".spec.target.configMap.key",description="Bundle ConfigMap Target Key" +// +kubebuilder:printcolumn:name="Secret Target",type="string",JSONPath=".spec.target.secret.key",description="Bundle Secret Target Key" +// +kubebuilder:printcolumn:name="Synced",type="string",JSONPath=`.status.conditions[?(@.type == "Synced")].status`,description="Bundle has been synced" +// +kubebuilder:printcolumn:name="Reason",type="string",JSONPath=`.status.conditions[?(@.type == "Synced")].reason`,description="Reason Bundle has Synced status" +// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Timestamp Bundle was created" +// +kubebuilder:subresource:status +// +kubebuilder:resource:scope=Cluster +// +genclient +// +genclient:nonNamespaced + +type Bundle struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata"` + + // Desired state of the Bundle resource. + Spec BundleSpec `json:"spec"` + + // Status of the Bundle. This is set and managed automatically. + // +optional + Status BundleStatus `json:"status,omitzero"` +} + +// +kubebuilder:object:root=true +type BundleList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata"` + + Items []Bundle `json:"items"` +} + +// BundleSpec defines the desired state of a Bundle. +type BundleSpec struct { + // Sources is a set of references to data whose data will sync to the target. + // +listType=atomic + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:validation:MaxItems=100 + Sources []BundleSource `json:"sources"` + + // Target is the target location in all namespaces to sync source data to. + // +optional + Target BundleTarget `json:"target,omitzero"` +} + +// BundleSource is the set of sources whose data will be appended and synced to +// the BundleTarget in all Namespaces. +// +structType=atomic +type BundleSource struct { + // ConfigMap is a reference (by name) to a ConfigMap's `data` key(s), or to a + // list of ConfigMap's `data` key(s) using label selector, in the trust Namespace. + // +optional + ConfigMap *SourceObjectKeySelector `json:"configMap,omitempty"` + + // Secret is a reference (by name) to a Secret's `data` key(s), or to a + // list of Secret's `data` key(s) using label selector, in the trust Namespace. + // +optional + Secret *SourceObjectKeySelector `json:"secret,omitempty"` + + // InLine is a simple string to append as the source data. + // +optional + InLine *string `json:"inLine,omitempty"` + + // UseDefaultCAs, when true, requests the default CA bundle to be used as a source. + // Default CAs are available if trust-manager was installed via Helm + // or was otherwise set up to include a package-injecting init container by using the + // "--default-package-location" flag when starting the trust-manager controller. + // If default CAs were not configured at start-up, any request to use the default + // CAs will fail. + // The version of the default CA package which is used for a Bundle is stored in the + // defaultCAPackageVersion field of the Bundle's status field. + // +optional + UseDefaultCAs *bool `json:"useDefaultCAs,omitempty"` +} + +// BundleTarget is the target resource that the Bundle will sync all source +// data to. +type BundleTarget struct { + // ConfigMap is the target ConfigMap in Namespaces that all Bundle source + // data will be synced to. + // +optional + ConfigMap *TargetTemplate `json:"configMap,omitempty"` + + // Secret is the target Secret that all Bundle source data will be synced to. + // Using Secrets as targets is only supported if enabled at trust-manager startup. + // By default, trust-manager has no permissions for writing to secrets and can only read secrets in the trust namespace. + // +optional + Secret *TargetTemplate `json:"secret,omitempty"` + + // AdditionalFormats specifies any additional formats to write to the target + // +optional + AdditionalFormats *AdditionalFormats `json:"additionalFormats,omitempty"` + + // NamespaceSelector will, if set, only sync the target resource in + // Namespaces which match the selector. + // +optional + NamespaceSelector *metav1.LabelSelector `json:"namespaceSelector,omitempty"` +} + +// AdditionalFormats specifies any additional formats to write to the target +type AdditionalFormats struct { + // JKS requests a JKS-formatted binary trust bundle to be written to the target. + // The bundle has "changeit" as the default password. + // For more information refer to this link https://cert-manager.io/docs/faq/#keystore-passwords + // Format is deprecated: Writing JKS is subject for removal. Please migrate to PKCS12. + // PKCS#12 trust stores created by trust-manager are compatible with Java. + // +optional + JKS *JKS `json:"jks,omitempty"` + // PKCS12 requests a PKCS12-formatted binary trust bundle to be written to the target. + // + // The bundle is by default created without a password. + // For more information refer to this link https://cert-manager.io/docs/faq/#keystore-passwords + // +optional + PKCS12 *PKCS12 `json:"pkcs12,omitempty"` +} + +// JKS specifies additional target JKS files +// +structType=atomic +type JKS struct { + KeySelector `json:",inline"` + + // Password for JKS trust store + //+optional + //+kubebuilder:validation:MinLength=1 + //+kubebuilder:validation:MaxLength=128 + //+kubebuilder:default=changeit + Password *string `json:"password"` +} + +// PKCS12 specifies additional target PKCS#12 files +// +structType=atomic +type PKCS12 struct { + KeySelector `json:",inline"` + + // Password for PKCS12 trust store + //+optional + //+kubebuilder:validation:MaxLength=128 + //+kubebuilder:default="" + Password *string `json:"password,omitempty"` + + // Profile specifies the certificate encryption algorithms and the HMAC algorithm + // used to create the PKCS12 trust store. + // + // If provided, allowed values are: + // `LegacyRC2`: Deprecated. Not supported by default in OpenSSL 3 or Java 20. + // `LegacyDES`: Less secure algorithm. Use this option for maximal compatibility. + // `Modern2023`: Secure algorithm. Use this option in case you have to always use secure algorithms (e.g. because of company policy). + // + // Default value is `LegacyRC2` for backward compatibility. + // +optional + Profile PKCS12Profile `json:"profile,omitempty"` +} + +// +kubebuilder:validation:Enum=LegacyRC2;LegacyDES;Modern2023 +type PKCS12Profile string + +const ( + // see: https://pkg.go.dev/software.sslmate.com/src/go-pkcs12#LegacyRC2 + LegacyRC2PKCS12Profile PKCS12Profile = "LegacyRC2" + + // see: https://pkg.go.dev/software.sslmate.com/src/go-pkcs12#LegacyDES + LegacyDESPKCS12Profile PKCS12Profile = "LegacyDES" + + // see: https://pkg.go.dev/software.sslmate.com/src/go-pkcs12#Modern2023 + Modern2023PKCS12Profile PKCS12Profile = "Modern2023" +) + +// SourceObjectKeySelector is a reference to a source object and its `data` key(s) +// in the trust Namespace. +// +structType=atomic +type SourceObjectKeySelector struct { + // Name is the name of the source object in the trust Namespace. + // This field must be left empty when `selector` is set + //+optional + // +kubebuilder:validation:MinLength=1 + Name string `json:"name,omitempty"` + + // Selector is the label selector to use to fetch a list of objects. Must not be set + // when `Name` is set. + //+optional + Selector *metav1.LabelSelector `json:"selector,omitempty"` + + // Key of the entry in the object's `data` field to be used. + //+optional + // +kubebuilder:validation:MinLength=1 + Key string `json:"key,omitempty"` + + // IncludeAllKeys is a flag to include all keys in the object's `data` field to be used. False by default. + // This field must not be true when `Key` is set. + //+optional + IncludeAllKeys bool `json:"includeAllKeys,omitempty"` +} + +// TargetTemplate defines the form of the Kubernetes Secret or ConfigMap bundle targets. +type TargetTemplate struct { + // Key is the key of the entry in the object's `data` field to be used. + // +kubebuilder:validation:MinLength=1 + Key string `json:"key"` + + // Metadata is an optional set of labels and annotations to be copied to the target. + // +optional + Metadata *TargetMetadata `json:"metadata,omitempty"` +} + +// GetAnnotations returns the annotations to be copied to the target or an empty map if there are no annotations. +func (t *TargetTemplate) GetAnnotations() map[string]string { + if t == nil || t.Metadata == nil { + return nil + } + return t.Metadata.Annotations +} + +// GetLabels returns the labels to be copied to the target or an empty map if there are no labels. +func (t *TargetTemplate) GetLabels() map[string]string { + if t == nil || t.Metadata == nil { + return nil + } + return t.Metadata.Labels +} + +// KeySelector is a reference to a key for some map data object. +type KeySelector struct { + // Key is the key of the entry in the object's `data` field to be used. + // +kubebuilder:validation:MinLength=1 + Key string `json:"key"` +} + +// TargetMetadata defines the default labels and annotations +// to be copied to the Kubernetes Secret or ConfigMap bundle targets. +type TargetMetadata struct { + // Annotations is a key value map to be copied to the target. + // +optional + Annotations map[string]string `json:"annotations,omitempty"` + + // Labels is a key value map to be copied to the target. + // +optional + Labels map[string]string `json:"labels,omitempty"` +} + +// BundleStatus defines the observed state of the Bundle. +type BundleStatus struct { + // List of status conditions to indicate the status of the Bundle. + // Known condition types are `Bundle`. + // +listType=map + // +listMapKey=type + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty"` + + // DefaultCAPackageVersion, if set and non-empty, indicates the version information + // which was retrieved when the set of default CAs was requested in the bundle + // source. This should only be set if useDefaultCAs was set to "true" on a source, + // and will be the same for the same version of a bundle with identical certificates. + // +optional + DefaultCAPackageVersion *string `json:"defaultCAVersion,omitempty"` +} + +const ( + // DefaultJKSPassword is the default password that Java uses; it's a Java convention to use this exact password. + // Since we're not storing anything secret in the JKS files we generate, this password is not a meaningful security measure + // but seems often to be expected by applications consuming JKS files + DefaultJKSPassword = "changeit" + // DefaultPKCS12Password is the empty string, that will create a password-less PKCS12 truststore. + // Password-less PKCS is the new default Java truststore from Java 18. + // By password-less, it means the certificates are not encrypted, and it contains no MacData for integrity check. + DefaultPKCS12Password = "" + + // BundleConditionSynced indicates that the Bundle has successfully synced + // all source bundle data to the Bundle target in all Namespaces. + BundleConditionSynced string = "Synced" + // BundleConditionDeprecated is a condition type used in migration from Bundle to ClusterBundle. + BundleConditionDeprecated string = "Deprecated" + // BundleConditionMigrated indicates that the Bundle has been successfully migrated + // to ClusterBundle by user. The user has taken ownership of the migrated ClusterBundle, + // and the obsolete Bundle can now be safely deleted by user. + BundleConditionMigrated string = "Migrated" +) diff --git a/vendor/github.com/cert-manager/trust-manager/pkg/apis/trust/v1alpha1/zz_generated.conversion.go b/vendor/github.com/cert-manager/trust-manager/pkg/apis/trust/v1alpha1/zz_generated.conversion.go new file mode 100644 index 000000000..964774b72 --- /dev/null +++ b/vendor/github.com/cert-manager/trust-manager/pkg/apis/trust/v1alpha1/zz_generated.conversion.go @@ -0,0 +1,276 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The cert-manager Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +// Code generated by conversion-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + unsafe "unsafe" + + v1alpha2 "github.com/cert-manager/trust-manager/pkg/apis/trustmanager/v1alpha2" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + conversion "k8s.io/apimachinery/pkg/conversion" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +func init() { + localSchemeBuilder.Register(RegisterConversions) +} + +// RegisterConversions adds conversion functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterConversions(s *runtime.Scheme) error { + if err := s.AddGeneratedConversionFunc((*BundleSpec)(nil), (*v1alpha2.BundleSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_BundleSpec_To_v1alpha2_BundleSpec(a.(*BundleSpec), b.(*v1alpha2.BundleSpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*BundleStatus)(nil), (*v1alpha2.BundleStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_BundleStatus_To_v1alpha2_BundleStatus(a.(*BundleStatus), b.(*v1alpha2.BundleStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1alpha2.BundleStatus)(nil), (*BundleStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha2_BundleStatus_To_v1alpha1_BundleStatus(a.(*v1alpha2.BundleStatus), b.(*BundleStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1alpha2.PKCS12)(nil), (*PKCS12)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha2_PKCS12_To_v1alpha1_PKCS12(a.(*v1alpha2.PKCS12), b.(*PKCS12), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*TargetMetadata)(nil), (*v1alpha2.TargetMetadata)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_TargetMetadata_To_v1alpha2_TargetMetadata(a.(*TargetMetadata), b.(*v1alpha2.TargetMetadata), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*v1alpha2.TargetMetadata)(nil), (*TargetMetadata)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha2_TargetMetadata_To_v1alpha1_TargetMetadata(a.(*v1alpha2.TargetMetadata), b.(*TargetMetadata), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*BundleSource)(nil), (*v1alpha2.BundleSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_BundleSource_To_v1alpha2_BundleSource(a.(*BundleSource), b.(*v1alpha2.BundleSource), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*BundleTarget)(nil), (*v1alpha2.BundleTarget)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_BundleTarget_To_v1alpha2_BundleTarget(a.(*BundleTarget), b.(*v1alpha2.BundleTarget), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*PKCS12)(nil), (*v1alpha2.PKCS12)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_PKCS12_To_v1alpha2_PKCS12(a.(*PKCS12), b.(*v1alpha2.PKCS12), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*TargetTemplate)(nil), (*v1alpha2.KeyValueTarget)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_TargetTemplate_To_v1alpha2_KeyValueTarget(a.(*TargetTemplate), b.(*v1alpha2.KeyValueTarget), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*v1alpha2.BundleSource)(nil), (*BundleSource)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha2_BundleSource_To_v1alpha1_BundleSource(a.(*v1alpha2.BundleSource), b.(*BundleSource), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*v1alpha2.BundleSpec)(nil), (*BundleSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha2_BundleSpec_To_v1alpha1_BundleSpec(a.(*v1alpha2.BundleSpec), b.(*BundleSpec), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*v1alpha2.BundleTarget)(nil), (*BundleTarget)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha2_BundleTarget_To_v1alpha1_BundleTarget(a.(*v1alpha2.BundleTarget), b.(*BundleTarget), scope) + }); err != nil { + return err + } + if err := s.AddConversionFunc((*v1alpha2.KeyValueTarget)(nil), (*TargetTemplate)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha2_KeyValueTarget_To_v1alpha1_TargetTemplate(a.(*v1alpha2.KeyValueTarget), b.(*TargetTemplate), scope) + }); err != nil { + return err + } + return nil +} + +func autoConvert_v1alpha1_BundleSource_To_v1alpha2_BundleSource(in *BundleSource, out *v1alpha2.BundleSource, s conversion.Scope) error { + // WARNING: in.ConfigMap requires manual conversion: does not exist in peer-type + // WARNING: in.Secret requires manual conversion: does not exist in peer-type + // WARNING: in.InLine requires manual conversion: does not exist in peer-type + // WARNING: in.UseDefaultCAs requires manual conversion: does not exist in peer-type + return nil +} + +func autoConvert_v1alpha2_BundleSource_To_v1alpha1_BundleSource(in *v1alpha2.BundleSource, out *BundleSource, s conversion.Scope) error { + // WARNING: in.SourceReference requires manual conversion: does not exist in peer-type + // WARNING: in.Key requires manual conversion: does not exist in peer-type + return nil +} + +func autoConvert_v1alpha1_BundleSpec_To_v1alpha2_BundleSpec(in *BundleSpec, out *v1alpha2.BundleSpec, s conversion.Scope) error { + if in.Sources != nil { + in, out := &in.Sources, &out.Sources + *out = make([]v1alpha2.BundleSource, len(*in)) + for i := range *in { + if err := Convert_v1alpha1_BundleSource_To_v1alpha2_BundleSource(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Sources = nil + } + if err := Convert_v1alpha1_BundleTarget_To_v1alpha2_BundleTarget(&in.Target, &out.Target, s); err != nil { + return err + } + return nil +} + +// Convert_v1alpha1_BundleSpec_To_v1alpha2_BundleSpec is an autogenerated conversion function. +func Convert_v1alpha1_BundleSpec_To_v1alpha2_BundleSpec(in *BundleSpec, out *v1alpha2.BundleSpec, s conversion.Scope) error { + return autoConvert_v1alpha1_BundleSpec_To_v1alpha2_BundleSpec(in, out, s) +} + +func autoConvert_v1alpha2_BundleSpec_To_v1alpha1_BundleSpec(in *v1alpha2.BundleSpec, out *BundleSpec, s conversion.Scope) error { + if in.Sources != nil { + in, out := &in.Sources, &out.Sources + *out = make([]BundleSource, len(*in)) + for i := range *in { + if err := Convert_v1alpha2_BundleSource_To_v1alpha1_BundleSource(&(*in)[i], &(*out)[i], s); err != nil { + return err + } + } + } else { + out.Sources = nil + } + // WARNING: in.IncludeDefaultCAs requires manual conversion: does not exist in peer-type + // WARNING: in.InLineCAs requires manual conversion: does not exist in peer-type + if err := Convert_v1alpha2_BundleTarget_To_v1alpha1_BundleTarget(&in.Target, &out.Target, s); err != nil { + return err + } + return nil +} + +func autoConvert_v1alpha1_BundleStatus_To_v1alpha2_BundleStatus(in *BundleStatus, out *v1alpha2.BundleStatus, s conversion.Scope) error { + out.Conditions = *(*[]v1.Condition)(unsafe.Pointer(&in.Conditions)) + out.DefaultCAPackageVersion = (*string)(unsafe.Pointer(in.DefaultCAPackageVersion)) + return nil +} + +// Convert_v1alpha1_BundleStatus_To_v1alpha2_BundleStatus is an autogenerated conversion function. +func Convert_v1alpha1_BundleStatus_To_v1alpha2_BundleStatus(in *BundleStatus, out *v1alpha2.BundleStatus, s conversion.Scope) error { + return autoConvert_v1alpha1_BundleStatus_To_v1alpha2_BundleStatus(in, out, s) +} + +func autoConvert_v1alpha2_BundleStatus_To_v1alpha1_BundleStatus(in *v1alpha2.BundleStatus, out *BundleStatus, s conversion.Scope) error { + out.Conditions = *(*[]v1.Condition)(unsafe.Pointer(&in.Conditions)) + out.DefaultCAPackageVersion = (*string)(unsafe.Pointer(in.DefaultCAPackageVersion)) + return nil +} + +// Convert_v1alpha2_BundleStatus_To_v1alpha1_BundleStatus is an autogenerated conversion function. +func Convert_v1alpha2_BundleStatus_To_v1alpha1_BundleStatus(in *v1alpha2.BundleStatus, out *BundleStatus, s conversion.Scope) error { + return autoConvert_v1alpha2_BundleStatus_To_v1alpha1_BundleStatus(in, out, s) +} + +func autoConvert_v1alpha1_BundleTarget_To_v1alpha2_BundleTarget(in *BundleTarget, out *v1alpha2.BundleTarget, s conversion.Scope) error { + if in.ConfigMap != nil { + in, out := &in.ConfigMap, &out.ConfigMap + *out = new(v1alpha2.KeyValueTarget) + if err := Convert_v1alpha1_TargetTemplate_To_v1alpha2_KeyValueTarget(*in, *out, s); err != nil { + return err + } + } else { + out.ConfigMap = nil + } + if in.Secret != nil { + in, out := &in.Secret, &out.Secret + *out = new(v1alpha2.KeyValueTarget) + if err := Convert_v1alpha1_TargetTemplate_To_v1alpha2_KeyValueTarget(*in, *out, s); err != nil { + return err + } + } else { + out.Secret = nil + } + // WARNING: in.AdditionalFormats requires manual conversion: does not exist in peer-type + out.NamespaceSelector = (*v1.LabelSelector)(unsafe.Pointer(in.NamespaceSelector)) + return nil +} + +func autoConvert_v1alpha2_BundleTarget_To_v1alpha1_BundleTarget(in *v1alpha2.BundleTarget, out *BundleTarget, s conversion.Scope) error { + if in.ConfigMap != nil { + in, out := &in.ConfigMap, &out.ConfigMap + *out = new(TargetTemplate) + if err := Convert_v1alpha2_KeyValueTarget_To_v1alpha1_TargetTemplate(*in, *out, s); err != nil { + return err + } + } else { + out.ConfigMap = nil + } + if in.Secret != nil { + in, out := &in.Secret, &out.Secret + *out = new(TargetTemplate) + if err := Convert_v1alpha2_KeyValueTarget_To_v1alpha1_TargetTemplate(*in, *out, s); err != nil { + return err + } + } else { + out.Secret = nil + } + out.NamespaceSelector = (*v1.LabelSelector)(unsafe.Pointer(in.NamespaceSelector)) + return nil +} + +func autoConvert_v1alpha1_PKCS12_To_v1alpha2_PKCS12(in *PKCS12, out *v1alpha2.PKCS12, s conversion.Scope) error { + // WARNING: in.KeySelector requires manual conversion: does not exist in peer-type + out.Password = (*string)(unsafe.Pointer(in.Password)) + out.Profile = v1alpha2.PKCS12Profile(in.Profile) + return nil +} + +func autoConvert_v1alpha2_PKCS12_To_v1alpha1_PKCS12(in *v1alpha2.PKCS12, out *PKCS12, s conversion.Scope) error { + out.Password = (*string)(unsafe.Pointer(in.Password)) + out.Profile = PKCS12Profile(in.Profile) + return nil +} + +// Convert_v1alpha2_PKCS12_To_v1alpha1_PKCS12 is an autogenerated conversion function. +func Convert_v1alpha2_PKCS12_To_v1alpha1_PKCS12(in *v1alpha2.PKCS12, out *PKCS12, s conversion.Scope) error { + return autoConvert_v1alpha2_PKCS12_To_v1alpha1_PKCS12(in, out, s) +} + +func autoConvert_v1alpha1_TargetMetadata_To_v1alpha2_TargetMetadata(in *TargetMetadata, out *v1alpha2.TargetMetadata, s conversion.Scope) error { + out.Annotations = *(*map[string]string)(unsafe.Pointer(&in.Annotations)) + out.Labels = *(*map[string]string)(unsafe.Pointer(&in.Labels)) + return nil +} + +// Convert_v1alpha1_TargetMetadata_To_v1alpha2_TargetMetadata is an autogenerated conversion function. +func Convert_v1alpha1_TargetMetadata_To_v1alpha2_TargetMetadata(in *TargetMetadata, out *v1alpha2.TargetMetadata, s conversion.Scope) error { + return autoConvert_v1alpha1_TargetMetadata_To_v1alpha2_TargetMetadata(in, out, s) +} + +func autoConvert_v1alpha2_TargetMetadata_To_v1alpha1_TargetMetadata(in *v1alpha2.TargetMetadata, out *TargetMetadata, s conversion.Scope) error { + out.Annotations = *(*map[string]string)(unsafe.Pointer(&in.Annotations)) + out.Labels = *(*map[string]string)(unsafe.Pointer(&in.Labels)) + return nil +} + +// Convert_v1alpha2_TargetMetadata_To_v1alpha1_TargetMetadata is an autogenerated conversion function. +func Convert_v1alpha2_TargetMetadata_To_v1alpha1_TargetMetadata(in *v1alpha2.TargetMetadata, out *TargetMetadata, s conversion.Scope) error { + return autoConvert_v1alpha2_TargetMetadata_To_v1alpha1_TargetMetadata(in, out, s) +} diff --git a/vendor/github.com/cert-manager/trust-manager/pkg/apis/trust/v1alpha1/zz_generated.deepcopy.go b/vendor/github.com/cert-manager/trust-manager/pkg/apis/trust/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 000000000..8a012d704 --- /dev/null +++ b/vendor/github.com/cert-manager/trust-manager/pkg/apis/trust/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,356 @@ +//go:build !ignore_autogenerated + +/* +Copyright The cert-manager Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AdditionalFormats) DeepCopyInto(out *AdditionalFormats) { + *out = *in + if in.JKS != nil { + in, out := &in.JKS, &out.JKS + *out = new(JKS) + (*in).DeepCopyInto(*out) + } + if in.PKCS12 != nil { + in, out := &in.PKCS12, &out.PKCS12 + *out = new(PKCS12) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AdditionalFormats. +func (in *AdditionalFormats) DeepCopy() *AdditionalFormats { + if in == nil { + return nil + } + out := new(AdditionalFormats) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Bundle) DeepCopyInto(out *Bundle) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Bundle. +func (in *Bundle) DeepCopy() *Bundle { + if in == nil { + return nil + } + out := new(Bundle) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Bundle) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BundleList) DeepCopyInto(out *BundleList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Bundle, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BundleList. +func (in *BundleList) DeepCopy() *BundleList { + if in == nil { + return nil + } + out := new(BundleList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *BundleList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BundleSource) DeepCopyInto(out *BundleSource) { + *out = *in + if in.ConfigMap != nil { + in, out := &in.ConfigMap, &out.ConfigMap + *out = new(SourceObjectKeySelector) + (*in).DeepCopyInto(*out) + } + if in.Secret != nil { + in, out := &in.Secret, &out.Secret + *out = new(SourceObjectKeySelector) + (*in).DeepCopyInto(*out) + } + if in.InLine != nil { + in, out := &in.InLine, &out.InLine + *out = new(string) + **out = **in + } + if in.UseDefaultCAs != nil { + in, out := &in.UseDefaultCAs, &out.UseDefaultCAs + *out = new(bool) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BundleSource. +func (in *BundleSource) DeepCopy() *BundleSource { + if in == nil { + return nil + } + out := new(BundleSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BundleSpec) DeepCopyInto(out *BundleSpec) { + *out = *in + if in.Sources != nil { + in, out := &in.Sources, &out.Sources + *out = make([]BundleSource, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + in.Target.DeepCopyInto(&out.Target) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BundleSpec. +func (in *BundleSpec) DeepCopy() *BundleSpec { + if in == nil { + return nil + } + out := new(BundleSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BundleStatus) DeepCopyInto(out *BundleStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.DefaultCAPackageVersion != nil { + in, out := &in.DefaultCAPackageVersion, &out.DefaultCAPackageVersion + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BundleStatus. +func (in *BundleStatus) DeepCopy() *BundleStatus { + if in == nil { + return nil + } + out := new(BundleStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BundleTarget) DeepCopyInto(out *BundleTarget) { + *out = *in + if in.ConfigMap != nil { + in, out := &in.ConfigMap, &out.ConfigMap + *out = new(TargetTemplate) + (*in).DeepCopyInto(*out) + } + if in.Secret != nil { + in, out := &in.Secret, &out.Secret + *out = new(TargetTemplate) + (*in).DeepCopyInto(*out) + } + if in.AdditionalFormats != nil { + in, out := &in.AdditionalFormats, &out.AdditionalFormats + *out = new(AdditionalFormats) + (*in).DeepCopyInto(*out) + } + if in.NamespaceSelector != nil { + in, out := &in.NamespaceSelector, &out.NamespaceSelector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BundleTarget. +func (in *BundleTarget) DeepCopy() *BundleTarget { + if in == nil { + return nil + } + out := new(BundleTarget) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *JKS) DeepCopyInto(out *JKS) { + *out = *in + out.KeySelector = in.KeySelector + if in.Password != nil { + in, out := &in.Password, &out.Password + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JKS. +func (in *JKS) DeepCopy() *JKS { + if in == nil { + return nil + } + out := new(JKS) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KeySelector) DeepCopyInto(out *KeySelector) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeySelector. +func (in *KeySelector) DeepCopy() *KeySelector { + if in == nil { + return nil + } + out := new(KeySelector) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PKCS12) DeepCopyInto(out *PKCS12) { + *out = *in + out.KeySelector = in.KeySelector + if in.Password != nil { + in, out := &in.Password, &out.Password + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PKCS12. +func (in *PKCS12) DeepCopy() *PKCS12 { + if in == nil { + return nil + } + out := new(PKCS12) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SourceObjectKeySelector) DeepCopyInto(out *SourceObjectKeySelector) { + *out = *in + if in.Selector != nil { + in, out := &in.Selector, &out.Selector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SourceObjectKeySelector. +func (in *SourceObjectKeySelector) DeepCopy() *SourceObjectKeySelector { + if in == nil { + return nil + } + out := new(SourceObjectKeySelector) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TargetMetadata) DeepCopyInto(out *TargetMetadata) { + *out = *in + if in.Annotations != nil { + in, out := &in.Annotations, &out.Annotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TargetMetadata. +func (in *TargetMetadata) DeepCopy() *TargetMetadata { + if in == nil { + return nil + } + out := new(TargetMetadata) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TargetTemplate) DeepCopyInto(out *TargetTemplate) { + *out = *in + if in.Metadata != nil { + in, out := &in.Metadata, &out.Metadata + *out = new(TargetMetadata) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TargetTemplate. +func (in *TargetTemplate) DeepCopy() *TargetTemplate { + if in == nil { + return nil + } + out := new(TargetTemplate) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/github.com/cert-manager/trust-manager/pkg/apis/trustmanager/doc.go b/vendor/github.com/cert-manager/trust-manager/pkg/apis/trustmanager/doc.go new file mode 100644 index 000000000..6a9d44d56 --- /dev/null +++ b/vendor/github.com/cert-manager/trust-manager/pkg/apis/trustmanager/doc.go @@ -0,0 +1,19 @@ +/* +Copyright 2021 The cert-manager Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package trustmanager + +const GroupName = "trust-manager.io" diff --git a/vendor/github.com/cert-manager/trust-manager/pkg/apis/trustmanager/v1alpha2/conversion.go b/vendor/github.com/cert-manager/trust-manager/pkg/apis/trustmanager/v1alpha2/conversion.go new file mode 100644 index 000000000..40f6d701b --- /dev/null +++ b/vendor/github.com/cert-manager/trust-manager/pkg/apis/trustmanager/v1alpha2/conversion.go @@ -0,0 +1,19 @@ +/* +Copyright 2025 The cert-manager Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha2 + +func (in *ClusterBundle) Hub() {} diff --git a/vendor/github.com/cert-manager/trust-manager/pkg/apis/trustmanager/v1alpha2/doc.go b/vendor/github.com/cert-manager/trust-manager/pkg/apis/trustmanager/v1alpha2/doc.go new file mode 100644 index 000000000..b4445167a --- /dev/null +++ b/vendor/github.com/cert-manager/trust-manager/pkg/apis/trustmanager/v1alpha2/doc.go @@ -0,0 +1,21 @@ +/* +Copyright 2021 The cert-manager Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// +kubebuilder:object:generate=true +// +groupName=trust-manager.io +// +kubebuilder:ac:generate=true +// +kubebuilder:ac:output:package=../../../applyconfigurations +package v1alpha2 diff --git a/vendor/github.com/cert-manager/trust-manager/pkg/apis/trustmanager/v1alpha2/register.go b/vendor/github.com/cert-manager/trust-manager/pkg/apis/trustmanager/v1alpha2/register.go new file mode 100644 index 000000000..786f27e7c --- /dev/null +++ b/vendor/github.com/cert-manager/trust-manager/pkg/apis/trustmanager/v1alpha2/register.go @@ -0,0 +1,45 @@ +/* +Copyright 2021 The cert-manager Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha2 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + + "github.com/cert-manager/trust-manager/pkg/apis/trustmanager" +) + +var ( + // SchemeGroupVersion is group version used to register these objects. + SchemeGroupVersion = schema.GroupVersion{Group: trustmanager.GroupName, Version: "v1alpha2"} + + // schemeBuilder is used to add go types to the GroupVersionKind scheme. + schemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = schemeBuilder.AddToScheme +) + +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &ClusterBundle{}, + &ClusterBundleList{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/vendor/github.com/cert-manager/trust-manager/pkg/apis/trustmanager/v1alpha2/types_cluster_bundle.go b/vendor/github.com/cert-manager/trust-manager/pkg/apis/trustmanager/v1alpha2/types_cluster_bundle.go new file mode 100644 index 000000000..60a3c6ad6 --- /dev/null +++ b/vendor/github.com/cert-manager/trust-manager/pkg/apis/trustmanager/v1alpha2/types_cluster_bundle.go @@ -0,0 +1,285 @@ +/* +Copyright 2021 The cert-manager Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha2 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var ClusterBundleKind = "ClusterBundle" + +var BundleLabelKey = "trust-manager.io/bundle" +var BundleHashAnnotationKey = "trust-manager.io/hash" + +// +kubebuilder:object:root=true +// +kubebuilder:printcolumn:name="ConfigMap Target",type="string",JSONPath=".spec.target.configMap.key",description="Bundle ConfigMap Target Key" +// +kubebuilder:printcolumn:name="Secret Target",type="string",JSONPath=".spec.target.secret.key",description="Bundle Secret Target Key" +// +kubebuilder:printcolumn:name="Synced",type="string",JSONPath=`.status.conditions[?(@.type == "Synced")].status`,description="Bundle has been synced" +// +kubebuilder:printcolumn:name="Reason",type="string",JSONPath=`.status.conditions[?(@.type == "Synced")].reason`,description="Reason Bundle has Synced status" +// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="Timestamp Bundle was created" +// +kubebuilder:subresource:status +// +kubebuilder:resource:scope=Cluster +// +genclient +// +genclient:nonNamespaced + +type ClusterBundle struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata"` + + // Desired state of the Bundle resource. + Spec BundleSpec `json:"spec"` + + // Status of the Bundle. This is set and managed automatically. + // +optional + Status BundleStatus `json:"status,omitzero"` +} + +// +kubebuilder:object:root=true +type ClusterBundleList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata"` + + Items []ClusterBundle `json:"items"` +} + +// BundleSpec defines the desired state of a Bundle. +type BundleSpec struct { + // Sources is a set of references to data whose data will sync to the target. + // +listType=atomic + // +optional + // +kubebuilder:validation:MinItems=0 + // +kubebuilder:validation:MaxItems=100 + Sources []BundleSource `json:"sources,omitempty"` + + // IncludeDefaultCAs, when true, requests the default CA bundle to be used as a source. + // Default CAs are available if trust-manager was installed via Helm + // or was otherwise set up to include a package-injecting init container by using the + // "--default-package-location" flag when starting the trust-manager controller. + // If default CAs were not configured at start-up, any request to use the default + // CAs will fail. + // The version of the default CA package which is used for a Bundle is stored in the + // defaultCAPackageVersion field of the Bundle's status field. + // +optional + IncludeDefaultCAs *bool `json:"includeDefaultCAs,omitempty"` + + // InLine is a simple string to append as the source data. + // +optional + InLineCAs *string `json:"inLineCAs,omitempty"` + + // Target is the target location in all namespaces to sync source data to. + // +optional + Target BundleTarget `json:"target,omitzero"` +} + +// BundleSource is the set of sources whose data will be appended and synced to +// the BundleTarget in all Namespaces. +// +structType=atomic +type BundleSource struct { + SourceReference `json:",inline"` + + // Key(s) of the entry in the object's `data` field to be used. + // Wildcards "*" in Key matches any sequence characters. + // A Key containing only "*" will match all data fields. + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:Pattern=`^[0-9A-Za-z_.\-*]+$` + Key string `json:"key"` +} + +// BundleTarget is the target resource that the Bundle will sync all source +// data to. +// +kubebuilder:validation:XValidation:rule="[has(self.configMap), has(self.secret)].exists(x,x)", message="any of the following fields must be provided: [configMap, secret]" +type BundleTarget struct { + // ConfigMap is the target ConfigMap in Namespaces that all Bundle source data will be synced to. + // +optional + ConfigMap *KeyValueTarget `json:"configMap,omitempty"` + + // Secret is the target Secret in Namespaces that all Bundle source data will be synced to. + // Using Secrets as targets is only supported if enabled at trust-manager startup. + // By default, trust-manager has no permissions for writing to secrets and can only read secrets in the trust namespace. + // +optional + Secret *KeyValueTarget `json:"secret,omitempty"` + + // NamespaceSelector specifies the namespaces where target resources will be synced. + NamespaceSelector *metav1.LabelSelector `json:"namespaceSelector"` +} + +// PKCS12 specifies configs for target PKCS#12 files. +// +structType=atomic +type PKCS12 struct { + // Password for PKCS12 trust store. + // By default, no password is used (password-less PKCS#12). + //+optional + //+kubebuilder:validation:MaxLength=128 + Password *string `json:"password,omitempty"` + + // Profile specifies the certificate encryption algorithms and the HMAC algorithm + // used to create the PKCS12 trust store. + // + // If provided, allowed values are: + // `LegacyRC2`: Deprecated. Not supported by default in OpenSSL 3 or Java 20. + // `LegacyDES`: Less secure algorithm. Use this option for maximal compatibility. + // `Modern2023`: Secure algorithm. Use this option in case you have to always use secure algorithms (e.g. because of company policy). + // + // Default value is `LegacyDES`. + // +optional + Profile PKCS12Profile `json:"profile,omitempty"` +} + +// +kubebuilder:validation:Enum=LegacyRC2;LegacyDES;Modern2023 +type PKCS12Profile string + +const ( + // see: https://pkg.go.dev/software.sslmate.com/src/go-pkcs12#LegacyRC2 + LegacyRC2PKCS12Profile PKCS12Profile = "LegacyRC2" + + // see: https://pkg.go.dev/software.sslmate.com/src/go-pkcs12#LegacyDES + LegacyDESPKCS12Profile PKCS12Profile = "LegacyDES" + + // see: https://pkg.go.dev/software.sslmate.com/src/go-pkcs12#Modern2023 + Modern2023PKCS12Profile PKCS12Profile = "Modern2023" + + ConfigMapKind string = "ConfigMap" + + SecretKind string = "Secret" +) + +// SourceReference is a reference to a source object. +// +structType=atomic +// +kubebuilder:validation:XValidation:rule="[has(self.name), has(self.selector)].exists_one(x,x)", message="exactly one of the following fields must be provided: [name, selector]" +type SourceReference struct { + // Kind is the kind of the source object. + // +kubebuilder:validation:Enum=ConfigMap;Secret + Kind string `json:"kind"` + + // Name is the name of the source object in the trust Namespace. + // This field must be left empty when `selector` is set + //+optional + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=253 + Name string `json:"name,omitempty"` + + // Selector is the label selector to use to fetch a list of objects. Must not be set + // when `Name` is set. + //+optional + Selector *metav1.LabelSelector `json:"selector,omitempty"` +} + +// KeyValueTarget is the specification of key value target resources as ConfigMaps and Secrets. +type KeyValueTarget struct { + // Data is the specification of the object's `data` field. + // +listType=map + // +listMapKey=key + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:validation:MaxItems=10 + Data []TargetKeyValue `json:"data"` + + // Metadata is an optional set of labels and annotations to be copied to the target. + // +optional + Metadata *TargetMetadata `json:"metadata,omitempty"` +} + +// GetAnnotations returns the annotations to be copied to the target or an empty map if there are no annotations. +func (t *KeyValueTarget) GetAnnotations() map[string]string { + if t == nil || t.Metadata == nil { + return nil + } + return t.Metadata.Annotations +} + +// GetLabels returns the labels to be copied to the target or an empty map if there are no labels. +func (t *KeyValueTarget) GetLabels() map[string]string { + if t == nil || t.Metadata == nil { + return nil + } + return t.Metadata.Labels +} + +// TargetKeyValue is the specification of a key with value in a key-value target resource. +// +structType=atomic +// +kubebuilder:validation:XValidation:rule="!has(self.password) || (has(self.format) && self.format == 'PKCS12')", reason=FieldValueForbidden, fieldPath=".password", message="may only be set when format is 'PKCS12'" +// +kubebuilder:validation:XValidation:rule="!has(self.profile) || (has(self.format) && self.format == 'PKCS12')", reason=FieldValueForbidden, fieldPath=".profile", message="may only be set when format is 'PKCS12'" +type TargetKeyValue struct { + // Key is the key of the entry in the object's `data` field to be used. + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:Pattern=`^[0-9A-Za-z_.\-]+$` + Key string `json:"key"` + + // Format defines the format of the target value. + // The default format is PEM. + //+optional + Format BundleFormat `json:"format,omitempty"` + + // PKCS12 specifies configs for PKCS#12 files. + // May only be used when format is PKCS12. + // +optional + PKCS12 `json:",inline"` +} + +// BundleFormat defines the trust bundle format. +// +kubebuilder:validation:Enum=PEM;PKCS12 +type BundleFormat string + +const ( + BundleFormatPEM BundleFormat = "PEM" + + BundleFormatPKCS12 BundleFormat = "PKCS12" +) + +// TargetMetadata defines the default labels and annotations +// to be copied to the Kubernetes Secret or ConfigMap bundle targets. +type TargetMetadata struct { + // Annotations is a key value map to be copied to the target. + // +optional + // +kubebuilder:validation:XValidation:rule="self.all(k, !k.startsWith('trust-manager.io/'))", reason=FieldValueForbidden, message="must not use forbidden domains as prefixes (e.g., trust-manager.io)" + Annotations map[string]string `json:"annotations,omitempty"` + + // Labels is a key value map to be copied to the target. + // +optional + // +kubebuilder:validation:XValidation:rule="self.all(k, !k.startsWith('trust-manager.io/'))", reason=FieldValueForbidden, message="must not use forbidden domains as prefixes (e.g., trust-manager.io)" + Labels map[string]string `json:"labels,omitempty"` +} + +// BundleStatus defines the observed state of the Bundle. +type BundleStatus struct { + // List of status conditions to indicate the status of the Bundle. + // Known condition types are `Bundle`. + // +listType=map + // +listMapKey=type + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty"` + + // DefaultCAPackageVersion, if set and non-empty, indicates the version information + // which was retrieved when the set of default CAs was requested in the bundle + // source. This should only be set if useDefaultCAs was set to "true" on a source, + // and will be the same for the same version of a bundle with identical certificates. + // +optional + DefaultCAPackageVersion *string `json:"defaultCAVersion,omitempty"` +} + +const ( + // DefaultPKCS12Password is the empty string, that will create a password-less PKCS12 truststore. + // Password-less PKCS is the new default Java truststore from Java 18. + // By password-less, it means the certificates are not encrypted, and it contains no MacData for integrity check. + DefaultPKCS12Password = "" + + // BundleConditionSynced indicates that the Bundle has successfully synced + // all source bundle data to the Bundle target in all Namespaces. + BundleConditionSynced string = "Synced" + + BundleMigratedAnnotation string = "trust-manager.io/migrated" +) diff --git a/vendor/github.com/cert-manager/trust-manager/pkg/apis/trustmanager/v1alpha2/zz_generated.deepcopy.go b/vendor/github.com/cert-manager/trust-manager/pkg/apis/trustmanager/v1alpha2/zz_generated.deepcopy.go new file mode 100644 index 000000000..ea9248ad9 --- /dev/null +++ b/vendor/github.com/cert-manager/trust-manager/pkg/apis/trustmanager/v1alpha2/zz_generated.deepcopy.go @@ -0,0 +1,303 @@ +//go:build !ignore_autogenerated + +/* +Copyright The cert-manager Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BundleSource) DeepCopyInto(out *BundleSource) { + *out = *in + in.SourceReference.DeepCopyInto(&out.SourceReference) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BundleSource. +func (in *BundleSource) DeepCopy() *BundleSource { + if in == nil { + return nil + } + out := new(BundleSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BundleSpec) DeepCopyInto(out *BundleSpec) { + *out = *in + if in.Sources != nil { + in, out := &in.Sources, &out.Sources + *out = make([]BundleSource, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.IncludeDefaultCAs != nil { + in, out := &in.IncludeDefaultCAs, &out.IncludeDefaultCAs + *out = new(bool) + **out = **in + } + if in.InLineCAs != nil { + in, out := &in.InLineCAs, &out.InLineCAs + *out = new(string) + **out = **in + } + in.Target.DeepCopyInto(&out.Target) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BundleSpec. +func (in *BundleSpec) DeepCopy() *BundleSpec { + if in == nil { + return nil + } + out := new(BundleSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BundleStatus) DeepCopyInto(out *BundleStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.DefaultCAPackageVersion != nil { + in, out := &in.DefaultCAPackageVersion, &out.DefaultCAPackageVersion + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BundleStatus. +func (in *BundleStatus) DeepCopy() *BundleStatus { + if in == nil { + return nil + } + out := new(BundleStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BundleTarget) DeepCopyInto(out *BundleTarget) { + *out = *in + if in.ConfigMap != nil { + in, out := &in.ConfigMap, &out.ConfigMap + *out = new(KeyValueTarget) + (*in).DeepCopyInto(*out) + } + if in.Secret != nil { + in, out := &in.Secret, &out.Secret + *out = new(KeyValueTarget) + (*in).DeepCopyInto(*out) + } + if in.NamespaceSelector != nil { + in, out := &in.NamespaceSelector, &out.NamespaceSelector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BundleTarget. +func (in *BundleTarget) DeepCopy() *BundleTarget { + if in == nil { + return nil + } + out := new(BundleTarget) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterBundle) DeepCopyInto(out *ClusterBundle) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterBundle. +func (in *ClusterBundle) DeepCopy() *ClusterBundle { + if in == nil { + return nil + } + out := new(ClusterBundle) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterBundle) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterBundleList) DeepCopyInto(out *ClusterBundleList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ClusterBundle, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterBundleList. +func (in *ClusterBundleList) DeepCopy() *ClusterBundleList { + if in == nil { + return nil + } + out := new(ClusterBundleList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterBundleList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *KeyValueTarget) DeepCopyInto(out *KeyValueTarget) { + *out = *in + if in.Data != nil { + in, out := &in.Data, &out.Data + *out = make([]TargetKeyValue, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Metadata != nil { + in, out := &in.Metadata, &out.Metadata + *out = new(TargetMetadata) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KeyValueTarget. +func (in *KeyValueTarget) DeepCopy() *KeyValueTarget { + if in == nil { + return nil + } + out := new(KeyValueTarget) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PKCS12) DeepCopyInto(out *PKCS12) { + *out = *in + if in.Password != nil { + in, out := &in.Password, &out.Password + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PKCS12. +func (in *PKCS12) DeepCopy() *PKCS12 { + if in == nil { + return nil + } + out := new(PKCS12) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SourceReference) DeepCopyInto(out *SourceReference) { + *out = *in + if in.Selector != nil { + in, out := &in.Selector, &out.Selector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SourceReference. +func (in *SourceReference) DeepCopy() *SourceReference { + if in == nil { + return nil + } + out := new(SourceReference) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TargetKeyValue) DeepCopyInto(out *TargetKeyValue) { + *out = *in + in.PKCS12.DeepCopyInto(&out.PKCS12) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TargetKeyValue. +func (in *TargetKeyValue) DeepCopy() *TargetKeyValue { + if in == nil { + return nil + } + out := new(TargetKeyValue) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TargetMetadata) DeepCopyInto(out *TargetMetadata) { + *out = *in + if in.Annotations != nil { + in, out := &in.Annotations, &out.Annotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TargetMetadata. +func (in *TargetMetadata) DeepCopy() *TargetMetadata { + if in == nil { + return nil + } + out := new(TargetMetadata) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/github.com/go-errors/errors/.travis.yml b/vendor/github.com/go-errors/errors/.travis.yml index 77a6bccf7..1dc296026 100644 --- a/vendor/github.com/go-errors/errors/.travis.yml +++ b/vendor/github.com/go-errors/errors/.travis.yml @@ -2,7 +2,6 @@ language: go go: - "1.8.x" - - "1.10.x" - - "1.13.x" - - "1.14.x" + - "1.11.x" - "1.16.x" + - "1.21.x" diff --git a/vendor/github.com/go-errors/errors/README.md b/vendor/github.com/go-errors/errors/README.md index 3d7852594..558bc883e 100644 --- a/vendor/github.com/go-errors/errors/README.md +++ b/vendor/github.com/go-errors/errors/README.md @@ -9,7 +9,7 @@ This is particularly useful when you want to understand the state of execution when an error was returned unexpectedly. It provides the type \*Error which implements the standard golang error -interface, so you can use this library interchangably with code that is +interface, so you can use this library interchangeably with code that is expecting a normal error return. Usage @@ -80,3 +80,5 @@ This package is licensed under the MIT license, see LICENSE.MIT for details. * v1.4.0 *BREAKING* v1.4.0 reverted all changes from v1.3.0 and is identical to v1.2.0 * v1.4.1 no code change, but now without an unnecessary cover.out file. * v1.4.2 performance improvement to ErrorStack() to avoid unnecessary work https://github.com/go-errors/errors/pull/40 +* v1.5.0 add errors.Join() and errors.Unwrap() copying the stdlib https://github.com/go-errors/errors/pull/40 +* v1.5.1 fix build on go1.13..go1.19 (broken by adding Join and Unwrap with wrong build constraints) diff --git a/vendor/github.com/go-errors/errors/error_1_13.go b/vendor/github.com/go-errors/errors/error_1_13.go index 0af2fc806..34ab3e00e 100644 --- a/vendor/github.com/go-errors/errors/error_1_13.go +++ b/vendor/github.com/go-errors/errors/error_1_13.go @@ -1,3 +1,4 @@ +//go:build go1.13 // +build go1.13 package errors @@ -6,14 +7,17 @@ import ( baseErrors "errors" ) -// find error in any wrapped error +// As finds the first error in err's tree that matches target, and if one is found, sets +// target to that error value and returns true. Otherwise, it returns false. +// +// For more information see stdlib errors.As. func As(err error, target interface{}) bool { return baseErrors.As(err, target) } // Is detects whether the error is equal to a given error. Errors // are considered equal by this function if they are matched by errors.Is -// or if their contained errors are matched through errors.Is +// or if their contained errors are matched through errors.Is. func Is(e error, original error) bool { if baseErrors.Is(e, original) { return true diff --git a/vendor/github.com/go-errors/errors/error_backward.go b/vendor/github.com/go-errors/errors/error_backward.go index 80b0695e7..ff14c4bfa 100644 --- a/vendor/github.com/go-errors/errors/error_backward.go +++ b/vendor/github.com/go-errors/errors/error_backward.go @@ -1,3 +1,4 @@ +//go:build !go1.13 // +build !go1.13 package errors @@ -55,3 +56,70 @@ func Is(e error, original error) bool { return false } + +// Disclaimer: functions Join and Unwrap are copied from the stdlib errors +// package v1.21.0. + +// Join returns an error that wraps the given errors. +// Any nil error values are discarded. +// Join returns nil if every value in errs is nil. +// The error formats as the concatenation of the strings obtained +// by calling the Error method of each element of errs, with a newline +// between each string. +// +// A non-nil error returned by Join implements the Unwrap() []error method. +func Join(errs ...error) error { + n := 0 + for _, err := range errs { + if err != nil { + n++ + } + } + if n == 0 { + return nil + } + e := &joinError{ + errs: make([]error, 0, n), + } + for _, err := range errs { + if err != nil { + e.errs = append(e.errs, err) + } + } + return e +} + +type joinError struct { + errs []error +} + +func (e *joinError) Error() string { + var b []byte + for i, err := range e.errs { + if i > 0 { + b = append(b, '\n') + } + b = append(b, err.Error()...) + } + return string(b) +} + +func (e *joinError) Unwrap() []error { + return e.errs +} + +// Unwrap returns the result of calling the Unwrap method on err, if err's +// type contains an Unwrap method returning error. +// Otherwise, Unwrap returns nil. +// +// Unwrap only calls a method of the form "Unwrap() error". +// In particular Unwrap does not unwrap errors returned by [Join]. +func Unwrap(err error) error { + u, ok := err.(interface { + Unwrap() error + }) + if !ok { + return nil + } + return u.Unwrap() +} diff --git a/vendor/github.com/go-errors/errors/join_unwrap_1_20.go b/vendor/github.com/go-errors/errors/join_unwrap_1_20.go new file mode 100644 index 000000000..44df35ece --- /dev/null +++ b/vendor/github.com/go-errors/errors/join_unwrap_1_20.go @@ -0,0 +1,32 @@ +//go:build go1.20 +// +build go1.20 + +package errors + +import baseErrors "errors" + +// Join returns an error that wraps the given errors. +// Any nil error values are discarded. +// Join returns nil if every value in errs is nil. +// The error formats as the concatenation of the strings obtained +// by calling the Error method of each element of errs, with a newline +// between each string. +// +// A non-nil error returned by Join implements the Unwrap() []error method. +// +// For more information see stdlib errors.Join. +func Join(errs ...error) error { + return baseErrors.Join(errs...) +} + +// Unwrap returns the result of calling the Unwrap method on err, if err's +// type contains an Unwrap method returning error. +// Otherwise, Unwrap returns nil. +// +// Unwrap only calls a method of the form "Unwrap() error". +// In particular Unwrap does not unwrap errors returned by [Join]. +// +// For more information see stdlib errors.Unwrap. +func Unwrap(err error) error { + return baseErrors.Unwrap(err) +} diff --git a/vendor/github.com/go-errors/errors/join_unwrap_backward.go b/vendor/github.com/go-errors/errors/join_unwrap_backward.go new file mode 100644 index 000000000..50c766976 --- /dev/null +++ b/vendor/github.com/go-errors/errors/join_unwrap_backward.go @@ -0,0 +1,71 @@ +//go:build !go1.20 +// +build !go1.20 + +package errors + +// Disclaimer: functions Join and Unwrap are copied from the stdlib errors +// package v1.21.0. + +// Join returns an error that wraps the given errors. +// Any nil error values are discarded. +// Join returns nil if every value in errs is nil. +// The error formats as the concatenation of the strings obtained +// by calling the Error method of each element of errs, with a newline +// between each string. +// +// A non-nil error returned by Join implements the Unwrap() []error method. +func Join(errs ...error) error { + n := 0 + for _, err := range errs { + if err != nil { + n++ + } + } + if n == 0 { + return nil + } + e := &joinError{ + errs: make([]error, 0, n), + } + for _, err := range errs { + if err != nil { + e.errs = append(e.errs, err) + } + } + return e +} + +type joinError struct { + errs []error +} + +func (e *joinError) Error() string { + var b []byte + for i, err := range e.errs { + if i > 0 { + b = append(b, '\n') + } + b = append(b, err.Error()...) + } + return string(b) +} + +func (e *joinError) Unwrap() []error { + return e.errs +} + +// Unwrap returns the result of calling the Unwrap method on err, if err's +// type contains an Unwrap method returning error. +// Otherwise, Unwrap returns nil. +// +// Unwrap only calls a method of the form "Unwrap() error". +// In particular Unwrap does not unwrap errors returned by [Join]. +func Unwrap(err error) error { + u, ok := err.(interface { + Unwrap() error + }) + if !ok { + return nil + } + return u.Unwrap() +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 5073ad921..9a43376a0 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -368,6 +368,12 @@ github.com/cert-manager/cert-manager/pkg/client/clientset/versioned github.com/cert-manager/cert-manager/pkg/client/clientset/versioned/scheme github.com/cert-manager/cert-manager/pkg/client/clientset/versioned/typed/acme/v1 github.com/cert-manager/cert-manager/pkg/client/clientset/versioned/typed/certmanager/v1 +# github.com/cert-manager/trust-manager v0.20.3 +## explicit; go 1.24.0 +github.com/cert-manager/trust-manager/pkg/apis/trust +github.com/cert-manager/trust-manager/pkg/apis/trust/v1alpha1 +github.com/cert-manager/trust-manager/pkg/apis/trustmanager +github.com/cert-manager/trust-manager/pkg/apis/trustmanager/v1alpha2 # github.com/cespare/xxhash/v2 v2.3.0 ## explicit; go 1.11 github.com/cespare/xxhash/v2 @@ -490,7 +496,7 @@ github.com/go-critic/go-critic/checkers/internal/astwalk github.com/go-critic/go-critic/checkers/internal/lintutil github.com/go-critic/go-critic/checkers/rulesdata github.com/go-critic/go-critic/linter -# github.com/go-errors/errors v1.4.2 +# github.com/go-errors/errors v1.5.1 ## explicit; go 1.14 github.com/go-errors/errors # github.com/go-logr/logr v1.4.3 @@ -3380,7 +3386,7 @@ sigs.k8s.io/kustomize/kyaml/yaml/walk ## explicit; go 1.18 sigs.k8s.io/randfill sigs.k8s.io/randfill/bytesource -# sigs.k8s.io/structured-merge-diff/v6 v6.3.0 +# sigs.k8s.io/structured-merge-diff/v6 v6.3.1 ## explicit; go 1.23 sigs.k8s.io/structured-merge-diff/v6/fieldpath sigs.k8s.io/structured-merge-diff/v6/merge diff --git a/vendor/sigs.k8s.io/structured-merge-diff/v6/schema/elements.go b/vendor/sigs.k8s.io/structured-merge-diff/v6/schema/elements.go index 5d3707a5b..c8138a654 100644 --- a/vendor/sigs.k8s.io/structured-merge-diff/v6/schema/elements.go +++ b/vendor/sigs.k8s.io/structured-merge-diff/v6/schema/elements.go @@ -18,6 +18,7 @@ package schema import ( "sync" + "sync/atomic" ) // Schema is a list of named types. @@ -28,7 +29,7 @@ type Schema struct { Types []TypeDef `yaml:"types,omitempty"` once sync.Once - m map[string]TypeDef + m atomic.Pointer[map[string]TypeDef] lock sync.Mutex // Cached results of resolving type references to atoms. Only stores @@ -144,26 +145,28 @@ type Map struct { ElementRelationship ElementRelationship `yaml:"elementRelationship,omitempty"` once sync.Once - m map[string]StructField + m atomic.Pointer[map[string]StructField] } // FindField is a convenience function that returns the referenced StructField, // if it exists, or (nil, false) if it doesn't. func (m *Map) FindField(name string) (StructField, bool) { m.once.Do(func() { - m.m = make(map[string]StructField, len(m.Fields)) + mm := make(map[string]StructField, len(m.Fields)) for _, field := range m.Fields { - m.m[field.Name] = field + mm[field.Name] = field } + m.m.Store(&mm) }) - sf, ok := m.m[name] + sf, ok := (*m.m.Load())[name] return sf, ok } -// CopyInto this instance of Map into the other -// If other is nil this method does nothing. -// If other is already initialized, overwrites it with this instance -// Warning: Not thread safe +// CopyInto clones this instance of Map into dst +// +// If dst is nil this method does nothing. +// If dst is already initialized, overwrites it with this instance. +// Warning: Not thread safe. Only use dst after this function returns. func (m *Map) CopyInto(dst *Map) { if dst == nil { return @@ -175,12 +178,13 @@ func (m *Map) CopyInto(dst *Map) { dst.Unions = m.Unions dst.ElementRelationship = m.ElementRelationship - if m.m != nil { + mm := m.m.Load() + if mm != nil { // If cache is non-nil then the once token had been consumed. // Must reset token and use it again to ensure same semantics. dst.once = sync.Once{} dst.once.Do(func() { - dst.m = m.m + dst.m.Store(mm) }) } } @@ -274,12 +278,13 @@ type List struct { // if it exists, or (nil, false) if it doesn't. func (s *Schema) FindNamedType(name string) (TypeDef, bool) { s.once.Do(func() { - s.m = make(map[string]TypeDef, len(s.Types)) + sm := make(map[string]TypeDef, len(s.Types)) for _, t := range s.Types { - s.m[t.Name] = t + sm[t.Name] = t } + s.m.Store(&sm) }) - t, ok := s.m[name] + t, ok := (*s.m.Load())[name] return t, ok } @@ -352,10 +357,11 @@ func (s *Schema) Resolve(tr TypeRef) (Atom, bool) { return result, true } -// Clones this instance of Schema into the other -// If other is nil this method does nothing. -// If other is already initialized, overwrites it with this instance -// Warning: Not thread safe +// CopyInto clones this instance of Schema into dst +// +// If dst is nil this method does nothing. +// If dst is already initialized, overwrites it with this instance. +// Warning: Not thread safe. Only use dst after this function returns. func (s *Schema) CopyInto(dst *Schema) { if dst == nil { return @@ -364,12 +370,13 @@ func (s *Schema) CopyInto(dst *Schema) { // Schema type is considered immutable so sharing references dst.Types = s.Types - if s.m != nil { + sm := s.m.Load() + if sm != nil { // If cache is non-nil then the once token had been consumed. // Must reset token and use it again to ensure same semantics. dst.once = sync.Once{} dst.once.Do(func() { - dst.m = s.m + dst.m.Store(sm) }) } } diff --git a/vendor/sigs.k8s.io/structured-merge-diff/v6/typed/remove.go b/vendor/sigs.k8s.io/structured-merge-diff/v6/typed/remove.go index 86de5105d..0db1734f9 100644 --- a/vendor/sigs.k8s.io/structured-merge-diff/v6/typed/remove.go +++ b/vendor/sigs.k8s.io/structured-merge-diff/v6/typed/remove.go @@ -58,6 +58,10 @@ func (w *removingWalker) doList(t *schema.List) (errs ValidationErrors) { defer w.allocator.Free(l) // If list is null or empty just return if l == nil || l.Length() == 0 { + // For extraction, we just return the value as is (which is nil or empty). For extraction the difference matters. + if w.shouldExtract { + w.out = w.value.Unstructured() + } return nil } @@ -71,6 +75,7 @@ func (w *removingWalker) doList(t *schema.List) (errs ValidationErrors) { } var newItems []interface{} + hadMatches := false iter := l.RangeUsing(w.allocator) defer w.allocator.Free(iter) for iter.Next() { @@ -80,24 +85,40 @@ func (w *removingWalker) doList(t *schema.List) (errs ValidationErrors) { path, _ := fieldpath.MakePath(pe) // save items on the path when we shouldExtract // but ignore them when we are removing (i.e. !w.shouldExtract) - if w.toRemove.Has(path) { - if w.shouldExtract { - newItems = append(newItems, removeItemsWithSchema(item, w.toRemove, w.schema, t.ElementType, w.shouldExtract).Unstructured()) - } else { - continue + isExactPathMatch := w.toRemove.Has(path) + isPrefixMatch := !w.toRemove.WithPrefix(pe).Empty() + if w.shouldExtract { + if isPrefixMatch { + item = removeItemsWithSchema(item, w.toRemove.WithPrefix(pe), w.schema, t.ElementType, w.shouldExtract) + } + if isExactPathMatch || isPrefixMatch { + newItems = append(newItems, item.Unstructured()) } - } - if subset := w.toRemove.WithPrefix(pe); !subset.Empty() { - item = removeItemsWithSchema(item, subset, w.schema, t.ElementType, w.shouldExtract) } else { - // don't save items not on the path when we shouldExtract. - if w.shouldExtract { + if isExactPathMatch { continue } + if isPrefixMatch { + // Removing nested items within this list item and preserve if it becomes empty + hadMatches = true + wasMap := item.IsMap() + wasList := item.IsList() + item = removeItemsWithSchema(item, w.toRemove.WithPrefix(pe), w.schema, t.ElementType, w.shouldExtract) + // If item returned null but we're removing items within the structure(not the item itself), + // preserve the empty container structure + if item.IsNull() && !w.shouldExtract { + if wasMap { + item = value.NewValueInterface(map[string]interface{}{}) + } else if wasList { + item = value.NewValueInterface([]interface{}{}) + } + } + } + newItems = append(newItems, item.Unstructured()) } - newItems = append(newItems, item.Unstructured()) } - if len(newItems) > 0 { + // Preserve empty lists (non-nil) instead of converting to null when items were matched and removed + if len(newItems) > 0 || (hadMatches && !w.shouldExtract) { w.out = newItems } return nil @@ -113,6 +134,10 @@ func (w *removingWalker) doMap(t *schema.Map) ValidationErrors { } // If map is null or empty just return if m == nil || m.Empty() { + // For extraction, we just return the value as is (which is nil or empty). For extraction the difference matters. + if w.shouldExtract { + w.out = w.value.Unstructured() + } return nil } @@ -131,6 +156,7 @@ func (w *removingWalker) doMap(t *schema.Map) ValidationErrors { } newMap := map[string]interface{}{} + hadMatches := false m.Iterate(func(k string, val value.Value) bool { pe := fieldpath.PathElement{FieldName: &k} path, _ := fieldpath.MakePath(pe) @@ -148,7 +174,19 @@ func (w *removingWalker) doMap(t *schema.Map) ValidationErrors { return true } if subset := w.toRemove.WithPrefix(pe); !subset.Empty() { + hadMatches = true + wasMap := val.IsMap() + wasList := val.IsList() val = removeItemsWithSchema(val, subset, w.schema, fieldType, w.shouldExtract) + // If val returned null but we're removing items within the structure (not the field itself), + // preserve the empty container structure + if val.IsNull() && !w.shouldExtract { + if wasMap { + val = value.NewValueInterface(map[string]interface{}{}) + } else if wasList { + val = value.NewValueInterface([]interface{}{}) + } + } } else { // don't save values not on the path when we shouldExtract. if w.shouldExtract { @@ -158,7 +196,8 @@ func (w *removingWalker) doMap(t *schema.Map) ValidationErrors { newMap[k] = val.Unstructured() return true }) - if len(newMap) > 0 { + // Preserve empty maps (non-nil) instead of converting to null when items were matched and removed + if len(newMap) > 0 || (hadMatches && !w.shouldExtract) { w.out = newMap } return nil