From 4e1588c7b94ae2291e5f95fb63f3c74316a314b4 Mon Sep 17 00:00:00 2001 From: Evan Hearne Date: Thu, 16 Jul 2026 16:11:08 +0100 Subject: [PATCH 1/5] update openshift/api to access auth proxy config --- go.mod | 10 +- go.sum | 8 +- .../github.com/openshift/api/.golangci.yaml | 4 + vendor/github.com/openshift/api/Makefile | 4 +- .../openshift/api/apps/.codegen.yaml | 2 + .../openshift/api/authorization/.codegen.yaml | 2 + .../openshift/api/build/.codegen.yaml | 2 + .../openshift/api/cloudnetwork/.codegen.yaml | 2 + .../api/config/v1/types_infrastructure.go | 1 - .../openshift/api/config/v1/types_ingress.go | 36 +++ .../openshift/api/config/v1/types_network.go | 3 + .../api/config/v1/zz_generated.deepcopy.go | 11 +- ..._generated.featuregated-crd-manifests.yaml | 4 +- .../v1/zz_generated.swagger_doc_generated.go | 5 +- .../v1alpha1/types_cluster_monitoring.go | 66 +++-- .../config/v1alpha1/zz_generated.deepcopy.go | 7 +- .../zz_generated.swagger_doc_generated.go | 15 +- vendor/github.com/openshift/api/features.md | 7 +- .../openshift/api/features/features.go | 42 ++- .../openshift/api/image/.codegen.yaml | 5 + .../api/machineconfiguration/v1/register.go | 2 + .../v1/types_internalreleaseimage.go | 159 +++++++++++ .../v1/zz_generated.deepcopy.go | 151 ++++++++++ ..._generated.featuregated-crd-manifests.yaml | 25 +- .../v1/zz_generated.model_name.go | 30 ++ .../v1/zz_generated.swagger_doc_generated.go | 59 ++++ .../openshift/api/network/.codegen.yaml | 5 +- .../api/networkoperator/.codegen.yaml | 2 + .../openshift/api/oauth/.codegen.yaml | 2 + .../api/operator/v1/types_authentication.go | 88 ++++++ .../operator/v1/types_csi_cluster_driver.go | 20 +- .../operator/v1/types_ingresscontroller.go | 53 ++++ .../api/operator/v1/zz_generated.deepcopy.go | 39 +++ ..._generated.featuregated-crd-manifests.yaml | 2 + .../operator/v1/zz_generated.model_name.go | 10 + .../v1/zz_generated.swagger_doc_generated.go | 35 ++- .../api/operator/v1alpha1/types_clusterapi.go | 15 +- .../github.com/openshift/api/osin/v1/types.go | 5 + .../v1/zz_generated.swagger_doc_generated.go | 1 + .../openshift/api/project/.codegen.yaml | 2 + .../openshift/api/quota/.codegen.yaml | 2 + .../openshift/api/route/.codegen.yaml | 2 + .../openshift/api/samples/.codegen.yaml | 2 + .../openshift/api/security/.codegen.yaml | 2 + .../openshift/api/template/.codegen.yaml | 2 + .../openshift/api/user/.codegen.yaml | 2 + .../encoding/protodelim/protodelim.go | 9 +- .../protobuf/encoding/protojson/decode.go | 12 + .../encoding/protojson/well_known_types.go | 5 +- .../protobuf/encoding/prototext/decode.go | 18 ++ .../protobuf/internal/descfmt/stringer.go | 269 +++++++++--------- .../internal/editionssupport/editions.go | 2 +- .../protobuf/internal/encoding/tag/tag.go | 11 +- .../protobuf/internal/encoding/text/decode.go | 115 +++++--- .../protobuf/internal/filedesc/desc.go | 53 ++-- .../protobuf/internal/filedesc/desc_init.go | 14 + .../protobuf/internal/filedesc/desc_lazy.go | 42 ++- .../protobuf/internal/filedesc/editions.go | 12 +- .../protobuf/internal/genid/descriptor_gen.go | 1 + .../protobuf/internal/impl/codec_map.go | 6 + .../protobuf/internal/impl/decode.go | 3 +- .../protobuf/internal/impl/validate.go | 26 ++ .../protobuf/internal/version/version.go | 4 +- .../protobuf/proto/decode.go | 10 +- .../protobuf/reflect/protodesc/desc.go | 29 +- .../protobuf/reflect/protodesc/desc_init.go | 3 + .../protobuf/reflect/protodesc/editions.go | 4 +- .../protobuf/reflect/protodesc/proto.go | 37 ++- .../types/descriptorpb/descriptor.pb.go | 13 +- .../types/known/timestamppb/timestamp.pb.go | 13 +- vendor/modules.txt | 10 +- 71 files changed, 1348 insertions(+), 326 deletions(-) create mode 100644 vendor/github.com/openshift/api/apps/.codegen.yaml create mode 100644 vendor/github.com/openshift/api/authorization/.codegen.yaml create mode 100644 vendor/github.com/openshift/api/build/.codegen.yaml create mode 100644 vendor/github.com/openshift/api/machineconfiguration/v1/types_internalreleaseimage.go create mode 100644 vendor/github.com/openshift/api/project/.codegen.yaml create mode 100644 vendor/github.com/openshift/api/quota/.codegen.yaml create mode 100644 vendor/github.com/openshift/api/security/.codegen.yaml create mode 100644 vendor/github.com/openshift/api/template/.codegen.yaml create mode 100644 vendor/github.com/openshift/api/user/.codegen.yaml diff --git a/go.mod b/go.mod index 83c2a87b5eaa..d5cdaadaf9e8 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/openshift/origin -go 1.25.0 +go 1.26.0 require ( cloud.google.com/go/storage v1.56.0 @@ -65,7 +65,7 @@ require ( github.com/opencontainers/go-digest v1.0.0 github.com/openshift-eng/openshift-tests-extension v0.0.0-20260127124016-0fed2b824818 github.com/openshift-kni/commatrix v0.0.5-0.20251111204857-e5a931eff73f - github.com/openshift/api v0.0.0-20260629123346-784126000268 + github.com/openshift/api v0.0.0-20260715165912-72066cc9718b github.com/openshift/apiserver-library-go v0.0.0-20260303173613-cd3676268d31 github.com/openshift/build-machinery-go v0.0.0-20250530140348-dc5b2804eeee github.com/openshift/client-go v0.0.0-20260629081241-b769428f4111 @@ -106,9 +106,9 @@ require ( gopkg.in/src-d/go-git.v4 v4.13.1 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 - k8s.io/api v0.35.1 + k8s.io/api v0.36.2 k8s.io/apiextensions-apiserver v0.35.1 - k8s.io/apimachinery v0.35.1 + k8s.io/apimachinery v0.36.2 k8s.io/apiserver v0.35.1 k8s.io/cli-runtime v0.33.4 k8s.io/client-go v0.35.1 @@ -407,7 +407,7 @@ require ( google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250826171959-ef028d996bc1 // indirect - google.golang.org/protobuf v1.36.8 // indirect + google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/go-jose/go-jose.v2 v2.6.3 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/go.sum b/go.sum index 2a82ef591d20..f7004a878160 100644 --- a/go.sum +++ b/go.sum @@ -903,8 +903,8 @@ github.com/openshift-eng/openshift-tests-extension v0.0.0-20260127124016-0fed2b8 github.com/openshift-eng/openshift-tests-extension v0.0.0-20260127124016-0fed2b824818/go.mod h1:6gkP5f2HL0meusT0Aim8icAspcD1cG055xxBZ9yC68M= github.com/openshift-kni/commatrix v0.0.5-0.20251111204857-e5a931eff73f h1:E72Zoc+JImPehBrXkgaCbIDbSFuItvyX6RCaZ0FQE5k= github.com/openshift-kni/commatrix v0.0.5-0.20251111204857-e5a931eff73f/go.mod h1:cDVdp0eda7EHE6tLuSeo4IqPWdAX/KJK+ogBirIGtsI= -github.com/openshift/api v0.0.0-20260629123346-784126000268 h1:s2Z/n/ihnmPddz89PnLMkcOgjoe28VlkuDOMUu7y3uI= -github.com/openshift/api v0.0.0-20260629123346-784126000268/go.mod h1:Jm45pE7O6/G0tYYhiLzNyZykTjmf9BfhsKYuGfLLwTE= +github.com/openshift/api v0.0.0-20260715165912-72066cc9718b h1:gN3SihCYEwoIksD+f24wHhwiEgvaV0RxNjgmkDvBBeg= +github.com/openshift/api v0.0.0-20260715165912-72066cc9718b/go.mod h1:k6qH5QOVa5GDln2VVm8Jz4NV3Z7R2SATHFLwGS6Wh3M= github.com/openshift/apiserver-library-go v0.0.0-20260303173613-cd3676268d31 h1:oYPQMrkzyk002L5aN8I2tkUHTEu9lsVrc1qiJmHJdXU= github.com/openshift/apiserver-library-go v0.0.0-20260303173613-cd3676268d31/go.mod h1:mnTsMMTtXSPBQzqBp5HXBjLvliveKenRADFQy9m5jc0= github.com/openshift/build-machinery-go v0.0.0-20250530140348-dc5b2804eeee h1:+Sp5GGnjHDhT/a/nQ1xdp43UscBMr7G5wxsYotyhzJ4= @@ -1623,8 +1623,8 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc= -google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af h1:+5/Sw3GsDNlEmu7TfklWKPdQ0Ykja5VEmq2i817+jbI= +google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/vendor/github.com/openshift/api/.golangci.yaml b/vendor/github.com/openshift/api/.golangci.yaml index 53c9b4009e37..e4e5b97612b2 100644 --- a/vendor/github.com/openshift/api/.golangci.yaml +++ b/vendor/github.com/openshift/api/.golangci.yaml @@ -106,6 +106,10 @@ linters: # This regex must always be updated in tandem with the regex in .golangci.go-validated.yaml that prevents `optionalfields` from being applied to the files in the path. path: machine/v1beta1/(types_awsprovider.go|types_azureprovider.go|types_gcpprovider.go|types_vsphereprovider.go)|machine/v1alpha1/types_openstack.go text: "optionalfields" + - linters: + - kubeapilinter + # osin/v1 types are config file APIs, not CRDs — validation is handled in Go code at config load time. + path: osin/v1/types.go - linters: - kubeapilinter # Silence norefs lint for `Ref` field in ClusterAPI as it refers to an OCI image reference, not a kube object reference. diff --git a/vendor/github.com/openshift/api/Makefile b/vendor/github.com/openshift/api/Makefile index 8b85144eafad..b6c0de378c75 100644 --- a/vendor/github.com/openshift/api/Makefile +++ b/vendor/github.com/openshift/api/Makefile @@ -4,7 +4,7 @@ all: build update: update-non-codegen update-codegen RUNTIME ?= podman -RUNTIME_IMAGE_NAME ?= registry.ci.openshift.org/openshift/release:rhel-9-release-golang-1.25-openshift-4.22 +RUNTIME_IMAGE_NAME ?= registry.ci.openshift.org/openshift/release:rhel-9-release-golang-1.26-openshift-5.0 EXCLUDE_DIRS := _output/ dependencymagnet/ hack/ third_party/ tls/ tools/ vendor/ tests/ GO_PACKAGES :=$(addsuffix ...,$(addprefix ./,$(filter-out $(EXCLUDE_DIRS), $(wildcard */)))) @@ -220,7 +220,7 @@ write-available-featuresets: .PHONY: clean clean: - rm -f render write-available-featuresets models-schema + rm -f render write-available-featuresets rm -rf tools/_output VERSION ?= $(shell git describe --always --abbrev=7) diff --git a/vendor/github.com/openshift/api/apps/.codegen.yaml b/vendor/github.com/openshift/api/apps/.codegen.yaml new file mode 100644 index 000000000000..f7a37129a0a0 --- /dev/null +++ b/vendor/github.com/openshift/api/apps/.codegen.yaml @@ -0,0 +1,2 @@ +protobuf: + disabled: false diff --git a/vendor/github.com/openshift/api/authorization/.codegen.yaml b/vendor/github.com/openshift/api/authorization/.codegen.yaml new file mode 100644 index 000000000000..f7a37129a0a0 --- /dev/null +++ b/vendor/github.com/openshift/api/authorization/.codegen.yaml @@ -0,0 +1,2 @@ +protobuf: + disabled: false diff --git a/vendor/github.com/openshift/api/build/.codegen.yaml b/vendor/github.com/openshift/api/build/.codegen.yaml new file mode 100644 index 000000000000..f7a37129a0a0 --- /dev/null +++ b/vendor/github.com/openshift/api/build/.codegen.yaml @@ -0,0 +1,2 @@ +protobuf: + disabled: false diff --git a/vendor/github.com/openshift/api/cloudnetwork/.codegen.yaml b/vendor/github.com/openshift/api/cloudnetwork/.codegen.yaml index e69de29bb2d1..f7a37129a0a0 100644 --- a/vendor/github.com/openshift/api/cloudnetwork/.codegen.yaml +++ b/vendor/github.com/openshift/api/cloudnetwork/.codegen.yaml @@ -0,0 +1,2 @@ +protobuf: + disabled: false diff --git a/vendor/github.com/openshift/api/config/v1/types_infrastructure.go b/vendor/github.com/openshift/api/config/v1/types_infrastructure.go index e8aaa810f5d3..5d9f10374eb7 100644 --- a/vendor/github.com/openshift/api/config/v1/types_infrastructure.go +++ b/vendor/github.com/openshift/api/config/v1/types_infrastructure.go @@ -660,7 +660,6 @@ type AzurePlatformStatus struct { // // +default={"dnsType": "PlatformDefault"} // +kubebuilder:default={"dnsType": "PlatformDefault"} - // +openshift:enable:FeatureGate=AzureClusterHostedDNSInstall // +optional CloudLoadBalancerConfig *CloudLoadBalancerConfig `json:"cloudLoadBalancerConfig,omitempty"` diff --git a/vendor/github.com/openshift/api/config/v1/types_ingress.go b/vendor/github.com/openshift/api/config/v1/types_ingress.go index 26e0ebf2184b..bb461e2f3e24 100644 --- a/vendor/github.com/openshift/api/config/v1/types_ingress.go +++ b/vendor/github.com/openshift/api/config/v1/types_ingress.go @@ -64,10 +64,12 @@ type IngressSpec struct { // To determine the set of configurable Routes, look at namespace and name of entries in the // .status.componentRoutes list, where participating operators write the status of // configurable routes. + // A maximum of 250 component routes may be configured. // +optional // +listType=map // +listMapKey=namespace // +listMapKey=name + // +kubebuilder:validation:MaxItems=250 ComponentRoutes []ComponentRouteSpec `json:"componentRoutes,omitempty"` // requiredHSTSPolicies specifies HSTS policies that are required to be set on newly created or updated routes @@ -164,6 +166,14 @@ const ( Classic AWSLBType = "Classic" ) +// LabelValue is the value part of a Kubernetes label. +// A label value must be either empty or 1-63 characters, consisting of +// alphanumeric characters, '-', '_', or '.', starting and ending with +// an alphanumeric character. +// +kubebuilder:validation:MaxLength=63 +// +kubebuilder:validation:XValidation:rule="!format.labelValue().validate(self).hasValue()",message="label values must be valid Kubernetes label values (at most 63 characters, alphanumeric, '-', '_', or '.', must start and end with alphanumeric)" +type LabelValue string + // ConsumingUser is an alias for string which we add validation to. Currently only service accounts are supported. // +kubebuilder:validation:Pattern="^system:serviceaccount:[a-z0-9]([-a-z0-9]*[a-z0-9])?:[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$" // +kubebuilder:validation:MinLength=1 @@ -245,6 +255,32 @@ type ComponentRouteSpec struct { // the Secret specification for a serving certificate will not be needed. // +optional ServingCertKeyPairSecret SecretNameReference `json:"servingCertKeyPairSecret"` + + // labels defines additional labels to be applied to the route created + // for the component. These labels are used by the IngressController to + // determine which routes it should manage. Changing labels may cause the + // route to be reassigned to a different IngressController. + // When omitted, no additional labels are applied to the component route. + // When specified, labels must contain at least one entry, up to a maximum of 8. + // Label keys must be valid qualified names, consisting of a name segment and + // an optional prefix separated by a slash (/). The name segment must be at most + // 63 characters in length and must consist only of alphanumeric characters, + // dashes (-), underscores (_), and dots (.), and must start and end with + // alphanumeric characters. The prefix, if specified, must be a DNS subdomain: + // at most 253 characters in length, consisting of dot-separated segments where + // each segment starts and ends with an alphanumeric character. + // Label values must be either empty or 1-63 characters, consisting of + // alphanumeric characters, dashes (-), underscores (_), or dots (.), + // starting and ending with an alphanumeric character. + // Keys with the "kubernetes.io/", "k8s.io/", and "openshift.io/" prefixes are reserved and may not be used. + // +openshift:enable:FeatureGate=IngressComponentRouteLabels + // +optional + // +mapType=granular + // +kubebuilder:validation:MinProperties=1 + // +kubebuilder:validation:MaxProperties=8 + // +kubebuilder:validation:XValidation:rule="self.all(key, !format.qualifiedName().validate(key).hasValue())",message="label keys must be valid qualified names, consisting of an optional DNS subdomain prefix of up to 253 characters followed by a slash and a name segment of 1-63 characters, that consists only of alphanumeric characters, dashes, underscores, and dots, and must start and end with an alphanumeric character" + // +kubebuilder:validation:XValidation:rule="self.all(key, !key.startsWith('kubernetes.io/') && !key.startsWith('k8s.io/') && !key.startsWith('openshift.io/'))",message="kubernetes.io/, k8s.io/, and openshift.io/ prefixed label keys are reserved and may not be used" + Labels map[string]LabelValue `json:"labels,omitempty"` } // ComponentRouteStatus contains information allowing configuration of a route's hostname and serving certificate. diff --git a/vendor/github.com/openshift/api/config/v1/types_network.go b/vendor/github.com/openshift/api/config/v1/types_network.go index 5e2eb9337263..80b022de9fda 100644 --- a/vendor/github.com/openshift/api/config/v1/types_network.go +++ b/vendor/github.com/openshift/api/config/v1/types_network.go @@ -331,6 +331,9 @@ type NetworkObservabilitySpec struct { // Valid values are "InstallAndEnable" and "NoAction". // When set to "InstallAndEnable", ensure that network observability will be installed and enabled on the cluster. If already installed, no action taken, but if it gets uninstalled, it will install it again. // When set to "NoAction", nothing will be done regarding Network observability. + // During the installation of NetworkObservability, the platform checks for any existing manual installations. + // If a successful installation using the OLMv0 or OLMv1 API is detected, it will be used. + // If the platform cannot determine how the current version was installed, or if the existing installation is incomplete, the installation process will stop. // +required InstallationPolicy NetworkObservabilityInstallationPolicy `json:"installationPolicy,omitempty"` } diff --git a/vendor/github.com/openshift/api/config/v1/zz_generated.deepcopy.go b/vendor/github.com/openshift/api/config/v1/zz_generated.deepcopy.go index 3c75062bb7aa..4b194b226a42 100644 --- a/vendor/github.com/openshift/api/config/v1/zz_generated.deepcopy.go +++ b/vendor/github.com/openshift/api/config/v1/zz_generated.deepcopy.go @@ -1640,6 +1640,13 @@ func (in *ComponentOverride) DeepCopy() *ComponentOverride { func (in *ComponentRouteSpec) DeepCopyInto(out *ComponentRouteSpec) { *out = *in out.ServingCertKeyPairSecret = in.ServingCertKeyPairSecret + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]LabelValue, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } return } @@ -3914,7 +3921,9 @@ func (in *IngressSpec) DeepCopyInto(out *IngressSpec) { if in.ComponentRoutes != nil { in, out := &in.ComponentRoutes, &out.ComponentRoutes *out = make([]ComponentRouteSpec, len(*in)) - copy(*out, *in) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } if in.RequiredHSTSPolicies != nil { in, out := &in.RequiredHSTSPolicies, &out.RequiredHSTSPolicies diff --git a/vendor/github.com/openshift/api/config/v1/zz_generated.featuregated-crd-manifests.yaml b/vendor/github.com/openshift/api/config/v1/zz_generated.featuregated-crd-manifests.yaml index 5426057a8858..76f78df82d1d 100644 --- a/vendor/github.com/openshift/api/config/v1/zz_generated.featuregated-crd-manifests.yaml +++ b/vendor/github.com/openshift/api/config/v1/zz_generated.featuregated-crd-manifests.yaml @@ -396,7 +396,6 @@ infrastructures.config.openshift.io: FeatureGates: - AWSClusterHostedDNSInstall - AWSDualStackInstall - - AzureClusterHostedDNSInstall - AzureDualStackInstall - DualReplica - DyanmicServiceEndpointIBMCloud @@ -427,7 +426,8 @@ ingresses.config.openshift.io: CRDName: ingresses.config.openshift.io Capability: "" Category: "" - FeatureGates: [] + FeatureGates: + - IngressComponentRouteLabels FilenameOperatorName: config-operator FilenameOperatorOrdering: "01" FilenameRunLevel: "0000_10" diff --git a/vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go b/vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go index b321d3d7e183..631f11a1b292 100644 --- a/vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go +++ b/vendor/github.com/openshift/api/config/v1/zz_generated.swagger_doc_generated.go @@ -2283,6 +2283,7 @@ var map_ComponentRouteSpec = map[string]string{ "name": "name is the logical name of the route to customize.\n\nThe namespace and name of this componentRoute must match a corresponding entry in the list of status.componentRoutes if the route is to be customized.", "hostname": "hostname is the hostname that should be used by the route.", "servingCertKeyPairSecret": "servingCertKeyPairSecret is a reference to a secret of type `kubernetes.io/tls` in the openshift-config namespace. The serving cert/key pair must match and will be used by the operator to fulfill the intent of serving with this name. If the custom hostname uses the default routing suffix of the cluster, the Secret specification for a serving certificate will not be needed.", + "labels": "labels defines additional labels to be applied to the route created for the component. These labels are used by the IngressController to determine which routes it should manage. Changing labels may cause the route to be reassigned to a different IngressController. When omitted, no additional labels are applied to the component route. When specified, labels must contain at least one entry, up to a maximum of 8. Label keys must be valid qualified names, consisting of a name segment and an optional prefix separated by a slash (/). The name segment must be at most 63 characters in length and must consist only of alphanumeric characters, dashes (-), underscores (_), and dots (.), and must start and end with alphanumeric characters. The prefix, if specified, must be a DNS subdomain: at most 253 characters in length, consisting of dot-separated segments where each segment starts and ends with an alphanumeric character. Label values must be either empty or 1-63 characters, consisting of alphanumeric characters, dashes (-), underscores (_), or dots (.), starting and ending with an alphanumeric character. Keys with the \"kubernetes.io/\", \"k8s.io/\", and \"openshift.io/\" prefixes are reserved and may not be used.", } func (ComponentRouteSpec) SwaggerDoc() map[string]string { @@ -2337,7 +2338,7 @@ func (IngressPlatformSpec) SwaggerDoc() map[string]string { var map_IngressSpec = map[string]string{ "domain": "domain is used to generate a default host name for a route when the route's host name is empty. The generated host name will follow this pattern: \"..\".\n\nIt is also used as the default wildcard domain suffix for ingress. The default ingresscontroller domain will follow this pattern: \"*.\".\n\nOnce set, changing domain is not currently supported.", "appsDomain": "appsDomain is an optional domain to use instead of the one specified in the domain field when a Route is created without specifying an explicit host. If appsDomain is nonempty, this value is used to generate default host values for Route. Unlike domain, appsDomain may be modified after installation. This assumes a new ingresscontroller has been setup with a wildcard certificate.", - "componentRoutes": "componentRoutes is an optional list of routes that are managed by OpenShift components that a cluster-admin is able to configure the hostname and serving certificate for. The namespace and name of each route in this list should match an existing entry in the status.componentRoutes list.\n\nTo determine the set of configurable Routes, look at namespace and name of entries in the .status.componentRoutes list, where participating operators write the status of configurable routes.", + "componentRoutes": "componentRoutes is an optional list of routes that are managed by OpenShift components that a cluster-admin is able to configure the hostname and serving certificate for. The namespace and name of each route in this list should match an existing entry in the status.componentRoutes list.\n\nTo determine the set of configurable Routes, look at namespace and name of entries in the .status.componentRoutes list, where participating operators write the status of configurable routes. A maximum of 250 component routes may be configured.", "requiredHSTSPolicies": "requiredHSTSPolicies specifies HSTS policies that are required to be set on newly created or updated routes matching the domainPattern/s and namespaceSelector/s that are specified in the policy. Each requiredHSTSPolicy must have at least a domainPattern and a maxAge to validate a route HSTS Policy route annotation, and affect route admission.\n\nA candidate route is checked for HSTS Policies if it has the HSTS Policy route annotation: \"haproxy.router.openshift.io/hsts_header\" E.g. haproxy.router.openshift.io/hsts_header: max-age=31536000;preload;includeSubDomains\n\n- For each candidate route, if it matches a requiredHSTSPolicy domainPattern and optional namespaceSelector, then the maxAge, preloadPolicy, and includeSubdomainsPolicy must be valid to be admitted. Otherwise, the route is rejected. - The first match, by domainPattern and optional namespaceSelector, in the ordering of the RequiredHSTSPolicies determines the route's admission status. - If the candidate route doesn't match any requiredHSTSPolicy domainPattern and optional namespaceSelector, then it may use any HSTS Policy annotation.\n\nThe HSTS policy configuration may be changed after routes have already been created. An update to a previously admitted route may then fail if the updated route does not conform to the updated HSTS policy configuration. However, changing the HSTS policy configuration will not cause a route that is already admitted to stop working.\n\nNote that if there are no RequiredHSTSPolicies, any HSTS Policy annotation on the route is valid.", "loadBalancer": "loadBalancer contains the load balancer details in general which are not only specific to the underlying infrastructure provider of the current cluster and are required for Ingress Controller to work on OpenShift.", } @@ -2645,7 +2646,7 @@ func (NetworkMigration) SwaggerDoc() map[string]string { var map_NetworkObservabilitySpec = map[string]string{ "": "NetworkObservabilitySpec defines the configuration for network observability installation", - "installationPolicy": "installationPolicy controls whether network observability is installed during cluster deployment. Valid values are \"InstallAndEnable\" and \"NoAction\". When set to \"InstallAndEnable\", ensure that network observability will be installed and enabled on the cluster. If already installed, no action taken, but if it gets uninstalled, it will install it again. When set to \"NoAction\", nothing will be done regarding Network observability.", + "installationPolicy": "installationPolicy controls whether network observability is installed during cluster deployment. Valid values are \"InstallAndEnable\" and \"NoAction\". When set to \"InstallAndEnable\", ensure that network observability will be installed and enabled on the cluster. If already installed, no action taken, but if it gets uninstalled, it will install it again. When set to \"NoAction\", nothing will be done regarding Network observability. During the installation of NetworkObservability, the platform checks for any existing manual installations. If a successful installation using the OLMv0 or OLMv1 API is detected, it will be used. If the platform cannot determine how the current version was installed, or if the existing installation is incomplete, the installation process will stop.", } func (NetworkObservabilitySpec) SwaggerDoc() map[string]string { diff --git a/vendor/github.com/openshift/api/config/v1alpha1/types_cluster_monitoring.go b/vendor/github.com/openshift/api/config/v1alpha1/types_cluster_monitoring.go index ca2f0216a946..d4846fd1cdb7 100644 --- a/vendor/github.com/openshift/api/config/v1alpha1/types_cluster_monitoring.go +++ b/vendor/github.com/openshift/api/config/v1alpha1/types_cluster_monitoring.go @@ -1552,7 +1552,7 @@ type RemoteWriteSpec struct { Name string `json:"name,omitempty"` // authorization defines the authorization method for the remote write endpoint. // When omitted, no authorization is performed. - // When set, type must be one of BearerToken, BasicAuth, OAuth2, SigV4, SafeAuthorization, or ServiceAccount; the corresponding nested config must be set (ServiceAccount has no config). + // When set, type must be one of Authorization, BasicAuth, OAuth2, SigV4, or ServiceAccount; the corresponding nested config must be set (ServiceAccount has no config). // +optional AuthorizationConfig RemoteWriteAuthorization `json:"authorization,omitzero"` // headers specifies the custom HTTP headers to be sent along with each remote write request. @@ -1654,39 +1654,49 @@ type BasicAuth struct { } // RemoteWriteAuthorizationType defines the authorization method for remote write endpoints. -// +kubebuilder:validation:Enum=BearerToken;BasicAuth;OAuth2;SigV4;SafeAuthorization;ServiceAccount +// +kubebuilder:validation:Enum=Authorization;BasicAuth;OAuth2;SigV4;ServiceAccount type RemoteWriteAuthorizationType string const ( - // RemoteWriteAuthorizationTypeBearerToken indicates bearer token from a secret. - RemoteWriteAuthorizationTypeBearerToken RemoteWriteAuthorizationType = "BearerToken" + // RemoteWriteAuthorizationTypeAuthorization indicates authorization credentials from a secret. + // The secret key contains the credentials (e.g. a Bearer token). Use the authorization field. + RemoteWriteAuthorizationTypeAuthorization RemoteWriteAuthorizationType = "Authorization" // RemoteWriteAuthorizationTypeBasicAuth indicates HTTP basic authentication. RemoteWriteAuthorizationTypeBasicAuth RemoteWriteAuthorizationType = "BasicAuth" // RemoteWriteAuthorizationTypeOAuth2 indicates OAuth2 client credentials. RemoteWriteAuthorizationTypeOAuth2 RemoteWriteAuthorizationType = "OAuth2" // RemoteWriteAuthorizationTypeSigV4 indicates AWS Signature Version 4. RemoteWriteAuthorizationTypeSigV4 RemoteWriteAuthorizationType = "SigV4" - // RemoteWriteAuthorizationTypeSafeAuthorization indicates authorization from a secret (Prometheus SafeAuthorization pattern). - // The secret key contains the credentials (e.g. a Bearer token). Use the safeAuthorization field. - RemoteWriteAuthorizationTypeSafeAuthorization RemoteWriteAuthorizationType = "SafeAuthorization" // RemoteWriteAuthorizationTypeServiceAccount indicates use of the pod's service account token for machine identity. // No additional field is required; the operator configures the token path. RemoteWriteAuthorizationTypeServiceAccount RemoteWriteAuthorizationType = "ServiceAccount" + + // --- TOMBSTONE --- + // RemoteWriteAuthorizationTypeBearerToken was a constant for bearer token authentication from a secret. + // It has been removed in favor of RemoteWriteAuthorizationTypeAuthorization. The constant name is reserved to prevent reuse. + // + // RemoteWriteAuthorizationTypeBearerToken RemoteWriteAuthorizationType = "BearerToken" + + // --- TOMBSTONE --- + // RemoteWriteAuthorizationTypeSafeAuthorization was a constant for authorization credentials from a secret (Prometheus SafeAuthorization pattern). + // It has been removed in favor of RemoteWriteAuthorizationTypeAuthorization. The constant name is reserved to prevent reuse. + // + // RemoteWriteAuthorizationTypeSafeAuthorization RemoteWriteAuthorizationType = "SafeAuthorization" ) // RemoteWriteAuthorization defines the authorization method for a remote write endpoint. -// Exactly one of the nested configs must be set according to the type discriminator. -// +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'BearerToken' ? has(self.bearerToken) : !has(self.bearerToken)",message="bearerToken is required when type is BearerToken, and forbidden otherwise" +// Nested config requirements depend on the type discriminator: Authorization requires authorization, +// BasicAuth requires basicAuth, OAuth2 requires oauth2, SigV4 requires sigv4, and ServiceAccount forbids all nested configs. +// +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'Authorization' ? has(self.authorization) : !has(self.authorization)",message="authorization is required when type is Authorization, and forbidden otherwise" // +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'BasicAuth' ? has(self.basicAuth) : !has(self.basicAuth)",message="basicAuth is required when type is BasicAuth, and forbidden otherwise" // +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'OAuth2' ? has(self.oauth2) : !has(self.oauth2)",message="oauth2 is required when type is OAuth2, and forbidden otherwise" // +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'SigV4' ? has(self.sigv4) : !has(self.sigv4)",message="sigv4 is required when type is SigV4, and forbidden otherwise" -// +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'SafeAuthorization' ? has(self.safeAuthorization) : !has(self.safeAuthorization)",message="safeAuthorization is required when type is SafeAuthorization, and forbidden otherwise" // +union type RemoteWriteAuthorization struct { // type specifies the authorization method to use. - // Allowed values are BearerToken, BasicAuth, OAuth2, SigV4, SafeAuthorization, ServiceAccount. + // Allowed values are Authorization, BasicAuth, OAuth2, SigV4, and ServiceAccount. // - // When set to BearerToken, the bearer token is read from a Secret referenced by the bearerToken field. + // When set to Authorization, credentials are read from a single Secret key. The secret key typically contains a Bearer token. Use the authorization field. // // When set to BasicAuth, HTTP basic authentication is used; the basicAuth field (username and password from Secrets) must be set. // @@ -1694,22 +1704,16 @@ type RemoteWriteAuthorization struct { // // When set to SigV4, AWS Signature Version 4 is used for authentication; the sigv4 field must be set. // - // When set to SafeAuthorization, credentials are read from a single Secret key (Prometheus SafeAuthorization pattern). The secret key typically contains a Bearer token. Use the safeAuthorization field. - // // When set to ServiceAccount, the pod's service account token is used for machine identity. No additional field is required; the operator configures the token path. // +unionDiscriminator // +required Type RemoteWriteAuthorizationType `json:"type,omitempty"` - // safeAuthorization defines the secret reference containing the credentials for authentication (e.g. Bearer token). - // Required when type is "SafeAuthorization", and forbidden otherwise. Maps to Prometheus SafeAuthorization. The secret must exist in the openshift-monitoring namespace. - // +unionMember - // +optional - SafeAuthorization *v1.SecretKeySelector `json:"safeAuthorization,omitempty"` - // bearerToken defines the secret reference containing the bearer token. - // Required when type is "BearerToken", and forbidden otherwise. - // +unionMember + // authorization defines the secret reference containing the authorization credentials (e.g. Bearer token). + // Required when type is "Authorization", and forbidden otherwise. + // The secret must exist in the openshift-monitoring namespace. + // +unionMember=Authorization // +optional - BearerToken SecretKeySelector `json:"bearerToken,omitempty,omitzero"` + Authorization SecretKeySelector `json:"authorization,omitempty,omitzero"` // basicAuth defines HTTP basic authentication credentials. // Required when type is "BasicAuth", and forbidden otherwise. // +unionMember @@ -1725,6 +1729,22 @@ type RemoteWriteAuthorization struct { // +unionMember // +optional Sigv4 Sigv4 `json:"sigv4,omitempty,omitzero"` + + // --- TOMBSTONE --- + // bearerToken was a field for bearer token authentication from a secret. + // It has been removed in favor of authorization. The field name is reserved to prevent reuse. + // + // +unionMember + // +optional + // BearerToken SecretKeySelector `json:"bearerToken,omitempty,omitzero"` + + // --- TOMBSTONE --- + // safeAuthorization was a field for authorization credentials from a secret (Prometheus SafeAuthorization pattern). + // It has been removed in favor of authorization. The field name is reserved to prevent reuse. + // + // +unionMember + // +optional + // SafeAuthorization *v1.SecretKeySelector `json:"safeAuthorization,omitempty"` } // MetadataConfigSendPolicy defines whether to send metadata with platform defaults or with custom settings. diff --git a/vendor/github.com/openshift/api/config/v1alpha1/zz_generated.deepcopy.go b/vendor/github.com/openshift/api/config/v1alpha1/zz_generated.deepcopy.go index 7313338a3b98..12dd0cd31274 100644 --- a/vendor/github.com/openshift/api/config/v1alpha1/zz_generated.deepcopy.go +++ b/vendor/github.com/openshift/api/config/v1alpha1/zz_generated.deepcopy.go @@ -1755,12 +1755,7 @@ func (in *RelabelConfig) DeepCopy() *RelabelConfig { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RemoteWriteAuthorization) DeepCopyInto(out *RemoteWriteAuthorization) { *out = *in - if in.SafeAuthorization != nil { - in, out := &in.SafeAuthorization, &out.SafeAuthorization - *out = new(v1.SecretKeySelector) - (*in).DeepCopyInto(*out) - } - out.BearerToken = in.BearerToken + out.Authorization = in.Authorization out.BasicAuth = in.BasicAuth in.OAuth2.DeepCopyInto(&out.OAuth2) out.Sigv4 = in.Sigv4 diff --git a/vendor/github.com/openshift/api/config/v1alpha1/zz_generated.swagger_doc_generated.go b/vendor/github.com/openshift/api/config/v1alpha1/zz_generated.swagger_doc_generated.go index 2194d79def9b..8f6cda1915a8 100644 --- a/vendor/github.com/openshift/api/config/v1alpha1/zz_generated.swagger_doc_generated.go +++ b/vendor/github.com/openshift/api/config/v1alpha1/zz_generated.swagger_doc_generated.go @@ -619,13 +619,12 @@ func (RelabelConfig) SwaggerDoc() map[string]string { } var map_RemoteWriteAuthorization = map[string]string{ - "": "RemoteWriteAuthorization defines the authorization method for a remote write endpoint. Exactly one of the nested configs must be set according to the type discriminator.", - "type": "type specifies the authorization method to use. Allowed values are BearerToken, BasicAuth, OAuth2, SigV4, SafeAuthorization, ServiceAccount.\n\nWhen set to BearerToken, the bearer token is read from a Secret referenced by the bearerToken field.\n\nWhen set to BasicAuth, HTTP basic authentication is used; the basicAuth field (username and password from Secrets) must be set.\n\nWhen set to OAuth2, OAuth2 client credentials flow is used; the oauth2 field (clientId, clientSecret, tokenUrl) must be set.\n\nWhen set to SigV4, AWS Signature Version 4 is used for authentication; the sigv4 field must be set.\n\nWhen set to SafeAuthorization, credentials are read from a single Secret key (Prometheus SafeAuthorization pattern). The secret key typically contains a Bearer token. Use the safeAuthorization field.\n\nWhen set to ServiceAccount, the pod's service account token is used for machine identity. No additional field is required; the operator configures the token path.", - "safeAuthorization": "safeAuthorization defines the secret reference containing the credentials for authentication (e.g. Bearer token). Required when type is \"SafeAuthorization\", and forbidden otherwise. Maps to Prometheus SafeAuthorization. The secret must exist in the openshift-monitoring namespace.", - "bearerToken": "bearerToken defines the secret reference containing the bearer token. Required when type is \"BearerToken\", and forbidden otherwise.", - "basicAuth": "basicAuth defines HTTP basic authentication credentials. Required when type is \"BasicAuth\", and forbidden otherwise.", - "oauth2": "oauth2 defines OAuth2 client credentials authentication. Required when type is \"OAuth2\", and forbidden otherwise.", - "sigv4": "sigv4 defines AWS Signature Version 4 authentication. Required when type is \"SigV4\", and forbidden otherwise.", + "": "RemoteWriteAuthorization defines the authorization method for a remote write endpoint. Nested config requirements depend on the type discriminator: Authorization requires authorization, BasicAuth requires basicAuth, OAuth2 requires oauth2, SigV4 requires sigv4, and ServiceAccount forbids all nested configs.", + "type": "type specifies the authorization method to use. Allowed values are Authorization, BasicAuth, OAuth2, SigV4, and ServiceAccount.\n\nWhen set to Authorization, credentials are read from a single Secret key. The secret key typically contains a Bearer token. Use the authorization field.\n\nWhen set to BasicAuth, HTTP basic authentication is used; the basicAuth field (username and password from Secrets) must be set.\n\nWhen set to OAuth2, OAuth2 client credentials flow is used; the oauth2 field (clientId, clientSecret, tokenUrl) must be set.\n\nWhen set to SigV4, AWS Signature Version 4 is used for authentication; the sigv4 field must be set.\n\nWhen set to ServiceAccount, the pod's service account token is used for machine identity. No additional field is required; the operator configures the token path.", + "authorization": "authorization defines the secret reference containing the authorization credentials (e.g. Bearer token). Required when type is \"Authorization\", and forbidden otherwise. The secret must exist in the openshift-monitoring namespace.", + "basicAuth": "basicAuth defines HTTP basic authentication credentials. Required when type is \"BasicAuth\", and forbidden otherwise.", + "oauth2": "oauth2 defines OAuth2 client credentials authentication. Required when type is \"OAuth2\", and forbidden otherwise.", + "sigv4": "sigv4 defines AWS Signature Version 4 authentication. Required when type is \"SigV4\", and forbidden otherwise.", } func (RemoteWriteAuthorization) SwaggerDoc() map[string]string { @@ -636,7 +635,7 @@ var map_RemoteWriteSpec = map[string]string{ "": "RemoteWriteSpec represents configuration for remote write endpoints.", "url": "url is the URL of the remote write endpoint. Must be a valid URL with http or https scheme and a non-empty hostname. Query parameters, fragments, and user information (e.g. user:password@host) are not allowed. Empty string is invalid. Must be between 1 and 2048 characters in length.", "name": "name is a required identifier for this remote write configuration (name is the list key for the remoteWrite list). This name is used in metrics and logging to differentiate remote write queues. Must contain only alphanumeric characters, hyphens, and underscores. Must be between 1 and 63 characters in length.", - "authorization": "authorization defines the authorization method for the remote write endpoint. When omitted, no authorization is performed. When set, type must be one of BearerToken, BasicAuth, OAuth2, SigV4, SafeAuthorization, or ServiceAccount; the corresponding nested config must be set (ServiceAccount has no config).", + "authorization": "authorization defines the authorization method for the remote write endpoint. When omitted, no authorization is performed. When set, type must be one of Authorization, BasicAuth, OAuth2, SigV4, or ServiceAccount; the corresponding nested config must be set (ServiceAccount has no config).", "headers": "headers specifies the custom HTTP headers to be sent along with each remote write request. Sending custom headers makes the configuration of a proxy in between optional and helps the receiver recognize the given source better. Clients MAY allow users to send custom HTTP headers; they MUST NOT allow users to configure them in such a way as to send reserved headers. Headers set by Prometheus cannot be overwritten. When omitted, no custom headers are sent. Maximum of 50 headers can be specified. Each header name must be unique. Each header name must contain only alphanumeric characters, hyphens, and underscores, and must not be a reserved Prometheus header (Host, Authorization, Content-Encoding, Content-Type, X-Prometheus-Remote-Write-Version, User-Agent, Connection, Keep-Alive, Proxy-Authenticate, Proxy-Authorization, WWW-Authenticate).", "metadataConfig": "metadataConfig configures the sending of series metadata to remote storage. When omitted, no metadata is sent. When set to sendPolicy: Default, metadata is sent using platform-chosen defaults (e.g. send interval 30 seconds). When set to sendPolicy: Custom, metadata is sent using the settings in the custom field (e.g. custom.sendIntervalSeconds).", "proxyUrl": "proxyUrl defines an optional proxy URL. If the cluster-wide proxy is enabled, it replaces the proxyUrl setting. The cluster-wide proxy supports both HTTP and HTTPS proxies, with HTTPS taking precedence. When omitted, no proxy is used. Must be a valid URL with http or https scheme. Must be between 1 and 2048 characters in length.", diff --git a/vendor/github.com/openshift/api/features.md b/vendor/github.com/openshift/api/features.md index dcf231b6e89f..c78d402696af 100644 --- a/vendor/github.com/openshift/api/features.md +++ b/vendor/github.com/openshift/api/features.md @@ -10,13 +10,14 @@ | MachineAPIOperatorDisableMachineHealthCheckController| | | | | | | | | | MultiArchInstallAzure| | | | | | | | | | ShortCertRotation| | | | | | | | | +| KarpenterOperator| | | | Enabled | | | | | | MutableTopology| | | | Enabled | | | | | +| AuthenticationComponentProxy| | | | Enabled | | | | Enabled | | ClusterAPIComputeInstall| | | Enabled | Enabled | | | | | | ClusterAPIControlPlaneInstall| | | Enabled | Enabled | | | | | | ClusterUpdatePreflight| | | Enabled | Enabled | | | | | | ConfidentialCluster| | | Enabled | Enabled | | | | | | Example2| | | Enabled | Enabled | | | | | -| ExternalOIDCExternalClaimsSourcing| | | Enabled | Enabled | | | | | | MachineAPIMigrationVSphere| | | Enabled | Enabled | | | | | | NetworkConnect| | | Enabled | Enabled | | | | | | NewOLMBoxCutterRuntime| | | | Enabled | | | | Enabled | @@ -58,6 +59,7 @@ | DyanmicServiceEndpointIBMCloud| | | Enabled | Enabled | | | Enabled | Enabled | | EtcdBackendQuota| | | Enabled | Enabled | | | Enabled | Enabled | | Example| | | Enabled | Enabled | | | Enabled | Enabled | +| ExternalOIDCExternalClaimsSourcing| | | Enabled | Enabled | | | Enabled | Enabled | | ExternalOIDCWithUpstreamParity| | | Enabled | Enabled | | | Enabled | Enabled | | ExternalSnapshotMetadata| | | Enabled | Enabled | | | Enabled | Enabled | | GCPCustomAPIEndpoints| | | Enabled | Enabled | | | Enabled | Enabled | @@ -65,7 +67,9 @@ | GCPDualStackInstall| | | Enabled | Enabled | | | Enabled | Enabled | | HyperShiftOnlyDynamicResourceAllocation| Enabled | | Enabled | | Enabled | | Enabled | | | ImageModeStatusReporting| | | Enabled | Enabled | | | Enabled | Enabled | +| IngressComponentRouteLabels| | | Enabled | Enabled | | | Enabled | Enabled | | IngressControllerDynamicConfigurationManager| | | Enabled | Enabled | | | Enabled | Enabled | +| IngressControllerMultipleHAProxyVersions| | | Enabled | Enabled | | | Enabled | Enabled | | IrreconcilableMachineConfig| | | Enabled | Enabled | | | Enabled | Enabled | | KMSEncryption| | | Enabled | Enabled | | | Enabled | Enabled | | MachineAPIMigration| | | Enabled | Enabled | | | Enabled | Enabled | @@ -93,7 +97,6 @@ | OSStreams| | Enabled | Enabled | Enabled | | Enabled | Enabled | Enabled | | AWSClusterHostedDNSInstall| Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | | AWSServiceLBNetworkSecurityGroup| Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | -| AzureClusterHostedDNSInstall| Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | | AzureWorkloadIdentity| Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | | BootImageSkewEnforcement| Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | | BuildCSIVolumes| Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | Enabled | diff --git a/vendor/github.com/openshift/api/features/features.go b/vendor/github.com/openshift/api/features/features.go index 4a5484803fed..b45bef770563 100644 --- a/vendor/github.com/openshift/api/features/features.go +++ b/vendor/github.com/openshift/api/features/features.go @@ -272,14 +272,6 @@ var ( enable(inTechPreviewNoUpgrade(), inDevPreviewNoUpgrade()). mustRegister() - FeatureGateAzureClusterHostedDNSInstall = newFeatureGate("AzureClusterHostedDNSInstall"). - reportProblemsToJiraComponent("Installer"). - contactPerson("sadasu"). - productScope(ocpSpecific). - enhancementPR("https://github.com/openshift/enhancements/pull/1468"). - enable(inDefault(), inOKD(), inTechPreviewNoUpgrade(), inDevPreviewNoUpgrade()). - mustRegister() - FeatureGateMixedCPUsAllocation = newFeatureGate("MixedCPUsAllocation"). reportProblemsToJiraComponent("NodeTuningOperator"). contactPerson("titzhak"). @@ -368,6 +360,14 @@ var ( enable(inDefault(), inOKD(), inTechPreviewNoUpgrade(), inDevPreviewNoUpgrade()). mustRegister() + FeatureGateAuthenticationComponentProxy = newFeatureGate("AuthenticationComponentProxy"). + reportProblemsToJiraComponent("authentication"). + contactPerson("liouk"). + productScope(ocpSpecific). + enhancementPR("https://github.com/openshift/enhancements/pull/2015"). + enable(inClusterProfile(SelfManaged), inTechPreviewNoUpgrade(), inDevPreviewNoUpgrade()). + mustRegister() + FeatureGateExternalOIDCWithAdditionalClaimMappings = newFeatureGate("ExternalOIDCWithUIDAndExtraClaimMappings"). reportProblemsToJiraComponent("authentication"). contactPerson("bpalmer"). @@ -389,7 +389,7 @@ var ( contactPerson("bpalmer"). productScope(ocpSpecific). enhancementPR("https://github.com/openshift/enhancements/pull/1907"). - enable(inDevPreviewNoUpgrade()). + enable(inDevPreviewNoUpgrade(), inTechPreviewNoUpgrade()). mustRegister() FeatureGateExample = newFeatureGate("Example"). @@ -666,6 +666,22 @@ var ( enable(inDevPreviewNoUpgrade(), inTechPreviewNoUpgrade()). mustRegister() + FeatureGateIngressComponentRouteLabels = newFeatureGate("IngressComponentRouteLabels"). + reportProblemsToJiraComponent("Management Console"). + contactPerson("leoli"). + productScope(ocpSpecific). + enhancementPR("https://github.com/openshift/enhancements/pull/2033"). + enable(inDevPreviewNoUpgrade(), inTechPreviewNoUpgrade()). + mustRegister() + + FeatureGateIngressControllerMultipleHAProxyVersions = newFeatureGate("IngressControllerMultipleHAProxyVersions"). + reportProblemsToJiraComponent("Networking/router"). + contactPerson("miciah"). + productScope(ocpSpecific). + enhancementPR("https://github.com/openshift/enhancements/pull/1965"). + enable(inDevPreviewNoUpgrade(), inTechPreviewNoUpgrade()). + mustRegister() + FeatureGateMinimumKubeletVersion = newFeatureGate("MinimumKubeletVersion"). reportProblemsToJiraComponent("Node"). contactPerson("haircommander"). @@ -1036,4 +1052,12 @@ var ( enhancementPR("https://github.com/openshift/enhancements/pull/2010"). enable(inTechPreviewNoUpgrade(), inDevPreviewNoUpgrade()). mustRegister() + + FeatureGateKarpenterOperator = newFeatureGate("KarpenterOperator"). + reportProblemsToJiraComponent("Karpenter"). + contactPerson("maxcao13"). + productScope(ocpSpecific). + enhancementPR("https://github.com/openshift/enhancements/pull/2007"). + enable(inClusterProfile(SelfManaged), inDevPreviewNoUpgrade()). + mustRegister() ) diff --git a/vendor/github.com/openshift/api/image/.codegen.yaml b/vendor/github.com/openshift/api/image/.codegen.yaml index ffa2c8d9b2ee..a2d9bd2000b3 100644 --- a/vendor/github.com/openshift/api/image/.codegen.yaml +++ b/vendor/github.com/openshift/api/image/.codegen.yaml @@ -1,2 +1,7 @@ swaggerdocs: commentPolicy: Warn +protobuf: + disabled: false + disabledVersions: + - "1.0" + - pre012 diff --git a/vendor/github.com/openshift/api/machineconfiguration/v1/register.go b/vendor/github.com/openshift/api/machineconfiguration/v1/register.go index d52f6480e87e..1a7252834b54 100644 --- a/vendor/github.com/openshift/api/machineconfiguration/v1/register.go +++ b/vendor/github.com/openshift/api/machineconfiguration/v1/register.go @@ -28,6 +28,8 @@ func addKnownTypes(scheme *runtime.Scheme) error { &ContainerRuntimeConfigList{}, &ControllerConfig{}, &ControllerConfigList{}, + &InternalReleaseImage{}, + &InternalReleaseImageList{}, &KubeletConfig{}, &KubeletConfigList{}, &MachineConfig{}, diff --git a/vendor/github.com/openshift/api/machineconfiguration/v1/types_internalreleaseimage.go b/vendor/github.com/openshift/api/machineconfiguration/v1/types_internalreleaseimage.go new file mode 100644 index 000000000000..261d31333743 --- /dev/null +++ b/vendor/github.com/openshift/api/machineconfiguration/v1/types_internalreleaseimage.go @@ -0,0 +1,159 @@ +package v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +genclient +// +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +kubebuilder:object:root=true +// +kubebuilder:resource:path=internalreleaseimages,scope=Cluster +// +kubebuilder:subresource:status +// +openshift:api-approved.openshift.io=https://github.com/openshift/api/pull/2510 +// +openshift:file-pattern=cvoRunLevel=0000_80,operatorName=machine-config,operatorOrdering=01 +// +openshift:enable:FeatureGate=NoRegistryClusterInstall +// +kubebuilder:metadata:labels=openshift.io/operator-managed= +// +kubebuilder:validation:XValidation:rule="self.metadata.name == 'cluster'",message="internalreleaseimage is a singleton, .metadata.name must be 'cluster'" + +// InternalReleaseImage is used to keep track and manage a set +// of release bundles (OCP and OLM operators images) that are stored +// into the control planes nodes. +// This is a singleton resource with 'cluster' as the only valid name. +// +// Compatibility level 1: Stable within a major release for a minimum of 12 months or 3 minor releases (whichever is longer). +// +openshift:compatibility-gen:level=1 +type InternalReleaseImage struct { + metav1.TypeMeta `json:",inline"` + + // metadata is the standard object's metadata. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + // +required + metav1.ObjectMeta `json:"metadata,omitempty"` + + // spec describes the configuration of this internal release image. + // +required + Spec InternalReleaseImageSpec `json:"spec,omitzero"` + + // status describes the last observed state of this internal release image. + // +optional + Status InternalReleaseImageStatus `json:"status,omitzero"` +} + +// InternalReleaseImageSpec defines the desired state of a InternalReleaseImage. +type InternalReleaseImageSpec struct { + // releases is a list of release bundle identifiers that the user wants to + // add/remove to/from the control plane nodes. + // Entries must be unique, keyed on the name field. + // releases must contain at least one entry and must not exceed 16 entries. + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:validation:MaxItems=16 + // +listType=map + // +listMapKey=name + // +required + Releases []InternalReleaseImageRef `json:"releases,omitempty"` +} + +// InternalReleaseImageRef is used to provide a simple reference for a release +// bundle. Currently it contains only the name field. +type InternalReleaseImageRef struct { + // name indicates the desired release bundle identifier. This field is required and must be between 1 and 64 characters long. + // The expected name format is ocp-release-bundle--. + // +required + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=64 + // +kubebuilder:validation:XValidation:rule=`self.matches('^ocp-release-bundle-[0-9]+\\.[0-9]+\\.[0-9]+-[A-Za-z0-9._-]+$')`,message="must be ocp-release-bundle-- and <= 64 chars" + Name string `json:"name,omitempty"` +} + +// InternalReleaseImageStatus describes the current state of a InternalReleaseImage. +type InternalReleaseImageStatus struct { + // conditions represent the observations of the InternalReleaseImage controller current state. + // Valid types are: Degraded. + // If Degraded is true, that means something has gone wrong in the controller. + // The conditions list must contain at most 5 entries. + // +listType=map + // +listMapKey=type + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:validation:MaxItems=5 + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty"` + // releases is a list of the release bundles currently owned and managed by the + // cluster. + // A release bundle content could be safely pulled only when its Conditions field + // contains at least an Available entry set to "True" and Degraded to "False". + // Entries must be unique, keyed on the name field. + // releases must contain at least one entry and must not exceed 32 entries. + // +listType=map + // +listMapKey=name + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:validation:MaxItems=32 + // +required + Releases []InternalReleaseImageBundleStatus `json:"releases,omitempty"` +} + +// InternalReleaseImageStatusConditionType describes the possible states for InternalReleaseImageStatus. +// +enum +type InternalReleaseImageStatusConditionType string + +const ( + // InternalReleaseImageStatusConditionTypeDegraded describes a failure in the controller. + InternalReleaseImageStatusConditionTypeDegraded InternalReleaseImageStatusConditionType = "Degraded" +) + +// InternalReleaseImageBundleStatus describes the observed state of a single release bundle managed by the cluster. +type InternalReleaseImageBundleStatus struct { + // conditions represent the observations of an internal release image current state. Valid types are: + // Mounted, Installing, Available, Removing and Degraded. + // + // If Mounted is true, that means that a valid ISO has been discovered and mounted on one of the cluster nodes. + // If Installing is true, that means that a new release bundle is currently being copied on one (or more) cluster nodes, and not yet completed. + // If Available is true, it means that the release has been previously installed on all the cluster nodes, and it can be used. + // If Removing is true, it means that a release deletion is in progress on one (or more) cluster nodes, and not yet completed. + // If Degraded is true, that means something has gone wrong (possibly on one or more cluster nodes). + // + // In general, after installing a new release bundle, it is required to wait for the Conditions "Available" to become "True" (and all + // the other conditions to be equal to "False") before being able to pull its content. + // When present, conditions must contain at least 1 entry and must not exceed 5 entries. + // + // +listType=map + // +listMapKey=type + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:validation:MaxItems=5 + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty"` + // name indicates the desired release bundle identifier. This field is required and must be between 1 and 64 characters long. + // The expected name format is ocp-release-bundle--. + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=64 + // +kubebuilder:validation:XValidation:rule=`self.matches('^ocp-release-bundle-[0-9]+\\.[0-9]+\\.[0-9]+-[A-Za-z0-9._-]+$')`,message="must be ocp-release-bundle-- and <= 64 chars" + // +required + Name string `json:"name,omitempty"` + // image is an OCP release image referenced by digest. + // The format of the image pull spec is: host[:port][/namespace]/name@sha256:, + // where the digest must be 64 characters long, and consist only of lowercase hexadecimal characters, a-f and 0-9. + // The length of the whole spec must be between 1 to 447 characters. + // The field is optional, and it will be provided after a release has been successfully installed. + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=447 + // +kubebuilder:validation:XValidation:rule=`(self.split('@').size() == 2 && self.split('@')[1].matches('^sha256:[a-f0-9]{64}$'))`,message="the OCI Image reference must end with a valid '@sha256:' suffix, where '' is 64 characters long" + // +kubebuilder:validation:XValidation:rule=`(self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?/([a-zA-Z0-9-_]{0,61}/)?[a-zA-Z0-9-_.]*?$'))`,message="the OCI Image name should follow the host[:port][/namespace]/name format, resembling a valid URL without the scheme" + // +optional + Image string `json:"image,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// InternalReleaseImageList is a list of InternalReleaseImage resources +// +// Compatibility level 1: Stable within a major release for a minimum of 12 months or 3 minor releases (whichever is longer). +// +openshift:compatibility-gen:level=1 +type InternalReleaseImageList struct { + metav1.TypeMeta `json:",inline"` + + // metadata is the standard list's metadata. + // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata + metav1.ListMeta `json:"metadata"` + + Items []InternalReleaseImage `json:"items"` +} diff --git a/vendor/github.com/openshift/api/machineconfiguration/v1/zz_generated.deepcopy.go b/vendor/github.com/openshift/api/machineconfiguration/v1/zz_generated.deepcopy.go index 9b738f8622d4..4a69ea1e9d76 100644 --- a/vendor/github.com/openshift/api/machineconfiguration/v1/zz_generated.deepcopy.go +++ b/vendor/github.com/openshift/api/machineconfiguration/v1/zz_generated.deepcopy.go @@ -510,6 +510,157 @@ func (in *ImageSecretObjectReference) DeepCopy() *ImageSecretObjectReference { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InternalReleaseImage) DeepCopyInto(out *InternalReleaseImage) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InternalReleaseImage. +func (in *InternalReleaseImage) DeepCopy() *InternalReleaseImage { + if in == nil { + return nil + } + out := new(InternalReleaseImage) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *InternalReleaseImage) 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 *InternalReleaseImageBundleStatus) DeepCopyInto(out *InternalReleaseImageBundleStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]metav1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InternalReleaseImageBundleStatus. +func (in *InternalReleaseImageBundleStatus) DeepCopy() *InternalReleaseImageBundleStatus { + if in == nil { + return nil + } + out := new(InternalReleaseImageBundleStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InternalReleaseImageList) DeepCopyInto(out *InternalReleaseImageList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]InternalReleaseImage, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InternalReleaseImageList. +func (in *InternalReleaseImageList) DeepCopy() *InternalReleaseImageList { + if in == nil { + return nil + } + out := new(InternalReleaseImageList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *InternalReleaseImageList) 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 *InternalReleaseImageRef) DeepCopyInto(out *InternalReleaseImageRef) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InternalReleaseImageRef. +func (in *InternalReleaseImageRef) DeepCopy() *InternalReleaseImageRef { + if in == nil { + return nil + } + out := new(InternalReleaseImageRef) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InternalReleaseImageSpec) DeepCopyInto(out *InternalReleaseImageSpec) { + *out = *in + if in.Releases != nil { + in, out := &in.Releases, &out.Releases + *out = make([]InternalReleaseImageRef, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InternalReleaseImageSpec. +func (in *InternalReleaseImageSpec) DeepCopy() *InternalReleaseImageSpec { + if in == nil { + return nil + } + out := new(InternalReleaseImageSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *InternalReleaseImageStatus) DeepCopyInto(out *InternalReleaseImageStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]metav1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Releases != nil { + in, out := &in.Releases, &out.Releases + *out = make([]InternalReleaseImageBundleStatus, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new InternalReleaseImageStatus. +func (in *InternalReleaseImageStatus) DeepCopy() *InternalReleaseImageStatus { + if in == nil { + return nil + } + out := new(InternalReleaseImageStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *IrreconcilableChangeDiff) DeepCopyInto(out *IrreconcilableChangeDiff) { *out = *in diff --git a/vendor/github.com/openshift/api/machineconfiguration/v1/zz_generated.featuregated-crd-manifests.yaml b/vendor/github.com/openshift/api/machineconfiguration/v1/zz_generated.featuregated-crd-manifests.yaml index b22dc29f5da5..6eb9f97c6a76 100644 --- a/vendor/github.com/openshift/api/machineconfiguration/v1/zz_generated.featuregated-crd-manifests.yaml +++ b/vendor/github.com/openshift/api/machineconfiguration/v1/zz_generated.featuregated-crd-manifests.yaml @@ -32,7 +32,6 @@ controllerconfigs.machineconfiguration.openshift.io: - AWSClusterHostedDNSInstall - AWSDualStackInstall - AWSEuropeanSovereignCloudInstall - - AzureClusterHostedDNSInstall - AzureDualStackInstall - DualReplica - DyanmicServiceEndpointIBMCloud @@ -57,6 +56,30 @@ controllerconfigs.machineconfiguration.openshift.io: TopLevelFeatureGates: [] Version: v1 +internalreleaseimages.machineconfiguration.openshift.io: + Annotations: {} + ApprovedPRNumber: https://github.com/openshift/api/pull/2510 + CRDName: internalreleaseimages.machineconfiguration.openshift.io + Capability: "" + Category: "" + FeatureGates: + - NoRegistryClusterInstall + FilenameOperatorName: machine-config + FilenameOperatorOrdering: "01" + FilenameRunLevel: "0000_80" + GroupName: machineconfiguration.openshift.io + HasStatus: true + KindName: InternalReleaseImage + Labels: + openshift.io/operator-managed: "" + PluralName: internalreleaseimages + PrinterColumns: [] + Scope: Cluster + ShortNames: null + TopLevelFeatureGates: + - NoRegistryClusterInstall + Version: v1 + kubeletconfigs.machineconfiguration.openshift.io: Annotations: {} ApprovedPRNumber: https://github.com/openshift/api/pull/1453 diff --git a/vendor/github.com/openshift/api/machineconfiguration/v1/zz_generated.model_name.go b/vendor/github.com/openshift/api/machineconfiguration/v1/zz_generated.model_name.go index 1315ccb99e24..8ee36a9e964e 100644 --- a/vendor/github.com/openshift/api/machineconfiguration/v1/zz_generated.model_name.go +++ b/vendor/github.com/openshift/api/machineconfiguration/v1/zz_generated.model_name.go @@ -95,6 +95,36 @@ func (in ImageSecretObjectReference) OpenAPIModelName() string { return "com.github.openshift.api.machineconfiguration.v1.ImageSecretObjectReference" } +// OpenAPIModelName returns the OpenAPI model name for this type. +func (in InternalReleaseImage) OpenAPIModelName() string { + return "com.github.openshift.api.machineconfiguration.v1.InternalReleaseImage" +} + +// OpenAPIModelName returns the OpenAPI model name for this type. +func (in InternalReleaseImageBundleStatus) OpenAPIModelName() string { + return "com.github.openshift.api.machineconfiguration.v1.InternalReleaseImageBundleStatus" +} + +// OpenAPIModelName returns the OpenAPI model name for this type. +func (in InternalReleaseImageList) OpenAPIModelName() string { + return "com.github.openshift.api.machineconfiguration.v1.InternalReleaseImageList" +} + +// OpenAPIModelName returns the OpenAPI model name for this type. +func (in InternalReleaseImageRef) OpenAPIModelName() string { + return "com.github.openshift.api.machineconfiguration.v1.InternalReleaseImageRef" +} + +// OpenAPIModelName returns the OpenAPI model name for this type. +func (in InternalReleaseImageSpec) OpenAPIModelName() string { + return "com.github.openshift.api.machineconfiguration.v1.InternalReleaseImageSpec" +} + +// OpenAPIModelName returns the OpenAPI model name for this type. +func (in InternalReleaseImageStatus) OpenAPIModelName() string { + return "com.github.openshift.api.machineconfiguration.v1.InternalReleaseImageStatus" +} + // OpenAPIModelName returns the OpenAPI model name for this type. func (in IrreconcilableChangeDiff) OpenAPIModelName() string { return "com.github.openshift.api.machineconfiguration.v1.IrreconcilableChangeDiff" diff --git a/vendor/github.com/openshift/api/machineconfiguration/v1/zz_generated.swagger_doc_generated.go b/vendor/github.com/openshift/api/machineconfiguration/v1/zz_generated.swagger_doc_generated.go index 7369c02db0c9..aac65c9acbc9 100644 --- a/vendor/github.com/openshift/api/machineconfiguration/v1/zz_generated.swagger_doc_generated.go +++ b/vendor/github.com/openshift/api/machineconfiguration/v1/zz_generated.swagger_doc_generated.go @@ -410,6 +410,65 @@ func (PoolSynchronizerStatus) SwaggerDoc() map[string]string { return map_PoolSynchronizerStatus } +var map_InternalReleaseImage = map[string]string{ + "": "InternalReleaseImage is used to keep track and manage a set of release bundles (OCP and OLM operators images) that are stored into the control planes nodes. This is a singleton resource with 'cluster' as the only valid name.\n\nCompatibility level 1: Stable within a major release for a minimum of 12 months or 3 minor releases (whichever is longer).", + "metadata": "metadata is the standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", + "spec": "spec describes the configuration of this internal release image.", + "status": "status describes the last observed state of this internal release image.", +} + +func (InternalReleaseImage) SwaggerDoc() map[string]string { + return map_InternalReleaseImage +} + +var map_InternalReleaseImageBundleStatus = map[string]string{ + "": "InternalReleaseImageBundleStatus describes the observed state of a single release bundle managed by the cluster.", + "conditions": "conditions represent the observations of an internal release image current state. Valid types are: Mounted, Installing, Available, Removing and Degraded.\n\nIf Mounted is true, that means that a valid ISO has been discovered and mounted on one of the cluster nodes. If Installing is true, that means that a new release bundle is currently being copied on one (or more) cluster nodes, and not yet completed. If Available is true, it means that the release has been previously installed on all the cluster nodes, and it can be used. If Removing is true, it means that a release deletion is in progress on one (or more) cluster nodes, and not yet completed. If Degraded is true, that means something has gone wrong (possibly on one or more cluster nodes).\n\nIn general, after installing a new release bundle, it is required to wait for the Conditions \"Available\" to become \"True\" (and all the other conditions to be equal to \"False\") before being able to pull its content. When present, conditions must contain at least 1 entry and must not exceed 5 entries.", + "name": "name indicates the desired release bundle identifier. This field is required and must be between 1 and 64 characters long. The expected name format is ocp-release-bundle--.", + "image": "image is an OCP release image referenced by digest. The format of the image pull spec is: host[:port][/namespace]/name@sha256:, where the digest must be 64 characters long, and consist only of lowercase hexadecimal characters, a-f and 0-9. The length of the whole spec must be between 1 to 447 characters. The field is optional, and it will be provided after a release has been successfully installed.", +} + +func (InternalReleaseImageBundleStatus) SwaggerDoc() map[string]string { + return map_InternalReleaseImageBundleStatus +} + +var map_InternalReleaseImageList = map[string]string{ + "": "InternalReleaseImageList is a list of InternalReleaseImage resources\n\nCompatibility level 1: Stable within a major release for a minimum of 12 months or 3 minor releases (whichever is longer).", + "metadata": "metadata is the standard list's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", +} + +func (InternalReleaseImageList) SwaggerDoc() map[string]string { + return map_InternalReleaseImageList +} + +var map_InternalReleaseImageRef = map[string]string{ + "": "InternalReleaseImageRef is used to provide a simple reference for a release bundle. Currently it contains only the name field.", + "name": "name indicates the desired release bundle identifier. This field is required and must be between 1 and 64 characters long. The expected name format is ocp-release-bundle--.", +} + +func (InternalReleaseImageRef) SwaggerDoc() map[string]string { + return map_InternalReleaseImageRef +} + +var map_InternalReleaseImageSpec = map[string]string{ + "": "InternalReleaseImageSpec defines the desired state of a InternalReleaseImage.", + "releases": "releases is a list of release bundle identifiers that the user wants to add/remove to/from the control plane nodes. Entries must be unique, keyed on the name field. releases must contain at least one entry and must not exceed 16 entries.", +} + +func (InternalReleaseImageSpec) SwaggerDoc() map[string]string { + return map_InternalReleaseImageSpec +} + +var map_InternalReleaseImageStatus = map[string]string{ + "": "InternalReleaseImageStatus describes the current state of a InternalReleaseImage.", + "conditions": "conditions represent the observations of the InternalReleaseImage controller current state. Valid types are: Degraded. If Degraded is true, that means something has gone wrong in the controller. The conditions list must contain at most 5 entries.", + "releases": "releases is a list of the release bundles currently owned and managed by the cluster. A release bundle content could be safely pulled only when its Conditions field contains at least an Available entry set to \"True\" and Degraded to \"False\". Entries must be unique, keyed on the name field. releases must contain at least one entry and must not exceed 32 entries.", +} + +func (InternalReleaseImageStatus) SwaggerDoc() map[string]string { + return map_InternalReleaseImageStatus +} + var map_IrreconcilableChangeDiff = map[string]string{ "": "IrreconcilableChangeDiff holds an individual diff between the initial install-time MachineConfig and the latest applied one caused by the presence of irreconcilable changes.", "fieldPath": "fieldPath is a required reference to the path in the latest rendered MachineConfig that differs from this nodes configuration. Must not be empty and must not exceed 70 characters in length. Must begin with the prefix 'spec.' and only contain alphanumeric characters, square brackets ('[]'), or dots ('.').", diff --git a/vendor/github.com/openshift/api/network/.codegen.yaml b/vendor/github.com/openshift/api/network/.codegen.yaml index ab56605cdcad..e9a0f1897632 100644 --- a/vendor/github.com/openshift/api/network/.codegen.yaml +++ b/vendor/github.com/openshift/api/network/.codegen.yaml @@ -1 +1,4 @@ -schemapatch: +protobuf: + disabled: false + disabledVersions: + - v1alpha1 diff --git a/vendor/github.com/openshift/api/networkoperator/.codegen.yaml b/vendor/github.com/openshift/api/networkoperator/.codegen.yaml index ffa2c8d9b2ee..f10357951b3f 100644 --- a/vendor/github.com/openshift/api/networkoperator/.codegen.yaml +++ b/vendor/github.com/openshift/api/networkoperator/.codegen.yaml @@ -1,2 +1,4 @@ swaggerdocs: commentPolicy: Warn +protobuf: + disabled: false diff --git a/vendor/github.com/openshift/api/oauth/.codegen.yaml b/vendor/github.com/openshift/api/oauth/.codegen.yaml index ffa2c8d9b2ee..f10357951b3f 100644 --- a/vendor/github.com/openshift/api/oauth/.codegen.yaml +++ b/vendor/github.com/openshift/api/oauth/.codegen.yaml @@ -1,2 +1,4 @@ swaggerdocs: commentPolicy: Warn +protobuf: + disabled: false diff --git a/vendor/github.com/openshift/api/operator/v1/types_authentication.go b/vendor/github.com/openshift/api/operator/v1/types_authentication.go index 4d0e9f6d6826..55fc62a79150 100644 --- a/vendor/github.com/openshift/api/operator/v1/types_authentication.go +++ b/vendor/github.com/openshift/api/operator/v1/types_authentication.go @@ -33,6 +33,94 @@ type Authentication struct { type AuthenticationSpec struct { OperatorSpec `json:",inline"` + + // proxy configures proxy settings for outbound connections made + // by the authentication stack. When set, it replaces the + // cluster-wide proxy (proxy.config.openshift.io/cluster) + // entirely for authentication — individual fields are not + // inherited from the cluster-wide configuration. When omitted, + // the cluster-wide proxy is used if configured; otherwise no + // proxy is used. + // +openshift:enable:FeatureGate=AuthenticationComponentProxy + // +optional + Proxy AuthenticationProxyConfig `json:"proxy,omitzero"` +} + +// AuthenticationProxyConfig holds proxy configuration scoped to +// authentication components (the OAuth server and the cluster +// authentication operator). +// +kubebuilder:validation:MinProperties=1 +// +kubebuilder:validation:XValidation:rule="has(self.httpProxy) || has(self.httpsProxy)",message="at least one of httpProxy or httpsProxy must be specified" +type AuthenticationProxyConfig struct { + // httpProxy is the URL of the proxy for HTTP requests. + // Must be a valid URL with http or https scheme, a non-empty + // hostname, and no path, query parameters, or fragment. + // Userinfo (e.g. user:password@host) is allowed for proxy + // authentication. Maximum length is 2048 characters. + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=2048 + // +kubebuilder:validation:XValidation:rule="isURL(self)",message="httpProxy must be a valid URL" + // +kubebuilder:validation:XValidation:rule="!isURL(self) || url(self).getScheme() in ['http', 'https']",message="httpProxy must use http or https scheme" + // +kubebuilder:validation:XValidation:rule="!isURL(self) || size(url(self).getHostname()) > 0",message="httpProxy must contain a hostname" + // +kubebuilder:validation:XValidation:rule="!isURL(self) || url(self).getEscapedPath() == '' || url(self).getEscapedPath() == '/'",message="httpProxy must not contain a path" + // +kubebuilder:validation:XValidation:rule="!isURL(self) || url(self).getQuery().size() == 0",message="httpProxy must not contain query parameters" + // +kubebuilder:validation:XValidation:rule="!self.matches('.*#.*')",message="httpProxy must not contain a fragment" + // +optional + HTTPProxy string `json:"httpProxy,omitempty"` + + // httpsProxy is the URL of the proxy for HTTPS requests. + // Must be a valid URL with http or https scheme, a non-empty + // hostname, and no path, query parameters, or fragment. + // Userinfo (e.g. user:password@host) is allowed for proxy + // authentication. Maximum length is 2048 characters. + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=2048 + // +kubebuilder:validation:XValidation:rule="isURL(self)",message="httpsProxy must be a valid URL" + // +kubebuilder:validation:XValidation:rule="!isURL(self) || url(self).getScheme() in ['http', 'https']",message="httpsProxy must use http or https scheme" + // +kubebuilder:validation:XValidation:rule="!isURL(self) || size(url(self).getHostname()) > 0",message="httpsProxy must contain a hostname" + // +kubebuilder:validation:XValidation:rule="!isURL(self) || url(self).getEscapedPath() == '' || url(self).getEscapedPath() == '/'",message="httpsProxy must not contain a path" + // +kubebuilder:validation:XValidation:rule="!isURL(self) || url(self).getQuery().size() == 0",message="httpsProxy must not contain query parameters" + // +kubebuilder:validation:XValidation:rule="!self.matches('.*#.*')",message="httpsProxy must not contain a fragment" + // +optional + HTTPSProxy string `json:"httpsProxy,omitempty"` + + // noProxy is a list of hostnames and/or CIDRs and/or IPs for which + // the proxy should not be used. Must contain at least one entry + // when set. Each entry must be between 1 and 253 characters long + // and at most 64 entries are allowed. Duplicate + // entries are not permitted. Entries that are not valid hostnames, + // CIDRs, or IPs are silently ignored. Cluster-internal defaults + // (.cluster.local, .svc, 127.0.0.1, localhost) are always appended + // automatically and do not need to be included. + // +listType=set + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:validation:MaxItems=64 + // +kubebuilder:validation:items:MinLength=1 + // +kubebuilder:validation:items:MaxLength=253 + // +optional + NoProxy []string `json:"noProxy,omitempty"` + + // trustedCA is a reference to a ConfigMap in the openshift-config + // namespace containing a CA certificate bundle under the key + // "ca-bundle.crt". This bundle is appended to the system trust store + // used by authentication components for proxy TLS connections. + // When omitted, only the system trust store is used. + // +optional + TrustedCA AuthenticationConfigMapReference `json:"trustedCA,omitzero"` +} + +// AuthenticationConfigMapReference references a ConfigMap in the +// openshift-config namespace. +type AuthenticationConfigMapReference struct { + // name is the metadata.name of the referenced ConfigMap. + // Must be a valid DNS subdomain name (RFC 1123): at most 253 + // characters, only lowercase alphanumeric characters, '-' or + // '.', starting and ending with an alphanumeric character. + // +kubebuilder:validation:MinLength=1 + // +kubebuilder:validation:MaxLength=253 + // +kubebuilder:validation:XValidation:rule="!format.dns1123Subdomain().validate(self).hasValue()",message="name must be a valid DNS subdomain name: contain no more than 253 characters, contain only lowercase alphanumeric characters, '-' or '.', and start and end with an alphanumeric character" + // +required + Name string `json:"name,omitempty"` } type AuthenticationStatus struct { diff --git a/vendor/github.com/openshift/api/operator/v1/types_csi_cluster_driver.go b/vendor/github.com/openshift/api/operator/v1/types_csi_cluster_driver.go index 51ecab70c8c5..fca2c808d34b 100644 --- a/vendor/github.com/openshift/api/operator/v1/types_csi_cluster_driver.go +++ b/vendor/github.com/openshift/api/operator/v1/types_csi_cluster_driver.go @@ -506,16 +506,28 @@ type SecretsStoreSecretRotation struct { // CustomSecretRotation holds configuration for custom secret rotation behavior. // +kubebuilder:validation:MinProperties=1 type CustomSecretRotation struct { - // rotationPollIntervalSeconds is the minimum time in seconds between secret - // rotation attempts. The driver skips provider calls if less than this interval - // has elapsed since the last successful rotation. + // minimumRefreshAge is the minimum time in seconds between secret + // rotation attempts. Each time kubelet calls NodePublishVolume, the driver + // checks whether this interval has elapsed since the last successful provider + // call. If it has, the driver contacts the secret provider to fetch the latest + // secret values and updates the mounted volume. + // Setting this value below the kubelet syncFrequency (default: 1 minute) + // has no additional effect on the actual rotation cadence. // Must be at least 1 second and no more than 31560000 seconds (~1 year). // When omitted, this means no opinion and the platform is left to choose a // reasonable default, which is subject to change over time. // +kubebuilder:validation:Minimum=1 // +kubebuilder:validation:Maximum=31560000 // +optional - RotationPollIntervalSeconds int32 `json:"rotationPollIntervalSeconds,omitempty"` + MinimumRefreshAge int32 `json:"minimumRefreshAge,omitempty"` + + // --- TOMBSTONE --- + // rotationPollIntervalSeconds was the previous name for minimumRefreshAge. + // The field has been renamed to better reflect its semantics. + // The JSON key is reserved to prevent reuse. + // + // +optional + // RotationPollIntervalSeconds int32 `json:"rotationPollIntervalSeconds,omitempty"` } // SecretsStoreTokenRequest specifies a service account token audience configuration diff --git a/vendor/github.com/openshift/api/operator/v1/types_ingresscontroller.go b/vendor/github.com/openshift/api/operator/v1/types_ingresscontroller.go index 52bfdede3e83..2d442d4b41ab 100644 --- a/vendor/github.com/openshift/api/operator/v1/types_ingresscontroller.go +++ b/vendor/github.com/openshift/api/operator/v1/types_ingresscontroller.go @@ -385,6 +385,31 @@ type IngressControllerSpec struct { // +kubebuilder:default:="Continue" // +default="Continue" ClosedClientConnectionPolicy IngressControllerClosedClientConnectionPolicy `json:"closedClientConnectionPolicy,omitempty"` + + // haproxyVersion specifies the HAProxy version to use for this + // IngressController. + // + // OpenShift 5.0 introduces HAProxy 3.2 as its default version and supports + // HAProxy 2.8 from OpenShift 4.22 for migration purposes. When an OpenShift + // release introduces a new default HAProxy version, that HAProxy version + // becomes available as a pinnable value in subsequent OpenShift releases, + // providing a smooth migration path for administrators who want to defer + // HAProxy upgrades. + // + // Valid values for OpenShift 5.0: + // - Unset (default): Uses HAProxy 3.2 (the default for OpenShift 5.0) + // - "3.2": Explicitly pins HAProxy 3.2 for preservation during cluster + // upgrades to future OpenShift releases + // - "2.8": Uses HAProxy 2.8 from OpenShift 4.22 (migration support, will + // be dropped in the next OpenShift release) + // + // If a specific HAProxy version is set and would become unsupported in a + // target cluster upgrade, a preflight check will block the cluster upgrade + // until this field is updated to unset or a supported version. + // + // +optional + // +openshift:enable:FeatureGate=IngressControllerMultipleHAProxyVersions + HAProxyVersion HAProxyVersion `json:"haproxyVersion,omitempty"` } // httpCompressionPolicy turns on compression for the specified MIME types. @@ -2263,6 +2288,19 @@ type IngressControllerStatus struct { // routeSelector is the actual routeSelector in use. // +optional RouteSelector *metav1.LabelSelector `json:"routeSelector,omitempty"` + + // effectiveHAProxyVersion reports the HAProxy version currently in use by + // this IngressController. This reflects the resolved value of the + // spec.haproxyVersion field. When omitted, the effective value has not yet + // been resolved by the operator or the feature is not enabled for this cluster. + // + // Examples for OpenShift 5.0: + // - "3.2": Using HAProxy 3.2 + // - "2.8": Using HAProxy 2.8 + // + // +optional + // +openshift:enable:FeatureGate=IngressControllerMultipleHAProxyVersions + EffectiveHAProxyVersion HAProxyVersion `json:"effectiveHAProxyVersion,omitempty"` } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object @@ -2331,3 +2369,18 @@ const ( // server's response regardless of the client having closed the connection. IngressControllerClosedClientConnectionPolicyContinue IngressControllerClosedClientConnectionPolicy = "Continue" ) + +// HAProxyVersion is a string representing a HAProxy minor version in "X.Y" +// format. The allowed values are constrained by enum validation and vary by +// OpenShift release. +// +// +kubebuilder:validation:Enum="2.8";"3.2" +type HAProxyVersion string + +const ( + // HAProxyVersion28 represents HAProxy 2.8, shipped with OpenShift 4.22. + HAProxyVersion28 HAProxyVersion = "2.8" + + // HAProxyVersion32 represents HAProxy 3.2, introduced in OpenShift 5.0. + HAProxyVersion32 HAProxyVersion = "3.2" +) diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.deepcopy.go b/vendor/github.com/openshift/api/operator/v1/zz_generated.deepcopy.go index 0a6726b19983..3c244a9867ea 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.deepcopy.go +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.deepcopy.go @@ -285,6 +285,22 @@ func (in *Authentication) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AuthenticationConfigMapReference) DeepCopyInto(out *AuthenticationConfigMapReference) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthenticationConfigMapReference. +func (in *AuthenticationConfigMapReference) DeepCopy() *AuthenticationConfigMapReference { + if in == nil { + return nil + } + out := new(AuthenticationConfigMapReference) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AuthenticationList) DeepCopyInto(out *AuthenticationList) { *out = *in @@ -318,10 +334,33 @@ func (in *AuthenticationList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AuthenticationProxyConfig) DeepCopyInto(out *AuthenticationProxyConfig) { + *out = *in + if in.NoProxy != nil { + in, out := &in.NoProxy, &out.NoProxy + *out = make([]string, len(*in)) + copy(*out, *in) + } + out.TrustedCA = in.TrustedCA + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthenticationProxyConfig. +func (in *AuthenticationProxyConfig) DeepCopy() *AuthenticationProxyConfig { + if in == nil { + return nil + } + out := new(AuthenticationProxyConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AuthenticationSpec) DeepCopyInto(out *AuthenticationSpec) { *out = *in in.OperatorSpec.DeepCopyInto(&out.OperatorSpec) + in.Proxy.DeepCopyInto(&out.Proxy) return } diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.featuregated-crd-manifests.yaml b/vendor/github.com/openshift/api/operator/v1/zz_generated.featuregated-crd-manifests.yaml index 9edb02ec6e31..aab9e3564fef 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.featuregated-crd-manifests.yaml +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.featuregated-crd-manifests.yaml @@ -6,6 +6,7 @@ authentications.operator.openshift.io: Capability: "" Category: "" FeatureGates: + - AuthenticationComponentProxy - KMSEncryption FilenameOperatorName: authentication FilenameOperatorOrdering: "01" @@ -179,6 +180,7 @@ ingresscontrollers.operator.openshift.io: Category: "" FeatureGates: - IngressControllerDynamicConfigurationManager + - IngressControllerMultipleHAProxyVersions - TLSGroupPreferences FilenameOperatorName: ingress FilenameOperatorOrdering: "00" diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.model_name.go b/vendor/github.com/openshift/api/operator/v1/zz_generated.model_name.go index c6a047d2cebf..271665a7ecab 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.model_name.go +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.model_name.go @@ -65,11 +65,21 @@ func (in Authentication) OpenAPIModelName() string { return "com.github.openshift.api.operator.v1.Authentication" } +// OpenAPIModelName returns the OpenAPI model name for this type. +func (in AuthenticationConfigMapReference) OpenAPIModelName() string { + return "com.github.openshift.api.operator.v1.AuthenticationConfigMapReference" +} + // OpenAPIModelName returns the OpenAPI model name for this type. func (in AuthenticationList) OpenAPIModelName() string { return "com.github.openshift.api.operator.v1.AuthenticationList" } +// OpenAPIModelName returns the OpenAPI model name for this type. +func (in AuthenticationProxyConfig) OpenAPIModelName() string { + return "com.github.openshift.api.operator.v1.AuthenticationProxyConfig" +} + // OpenAPIModelName returns the OpenAPI model name for this type. func (in AuthenticationSpec) OpenAPIModelName() string { return "com.github.openshift.api.operator.v1.AuthenticationSpec" diff --git a/vendor/github.com/openshift/api/operator/v1/zz_generated.swagger_doc_generated.go b/vendor/github.com/openshift/api/operator/v1/zz_generated.swagger_doc_generated.go index a79189ffc209..114b5c7a689b 100644 --- a/vendor/github.com/openshift/api/operator/v1/zz_generated.swagger_doc_generated.go +++ b/vendor/github.com/openshift/api/operator/v1/zz_generated.swagger_doc_generated.go @@ -118,6 +118,15 @@ func (Authentication) SwaggerDoc() map[string]string { return map_Authentication } +var map_AuthenticationConfigMapReference = map[string]string{ + "": "AuthenticationConfigMapReference references a ConfigMap in the openshift-config namespace.", + "name": "name is the metadata.name of the referenced ConfigMap. Must be a valid DNS subdomain name (RFC 1123): at most 253 characters, only lowercase alphanumeric characters, '-' or '.', starting and ending with an alphanumeric character.", +} + +func (AuthenticationConfigMapReference) SwaggerDoc() map[string]string { + return map_AuthenticationConfigMapReference +} + var map_AuthenticationList = map[string]string{ "": "AuthenticationList is a collection of items\n\nCompatibility level 1: Stable within a major release for a minimum of 12 months or 3 minor releases (whichever is longer).", "metadata": "metadata is the standard list's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", @@ -127,6 +136,26 @@ func (AuthenticationList) SwaggerDoc() map[string]string { return map_AuthenticationList } +var map_AuthenticationProxyConfig = map[string]string{ + "": "AuthenticationProxyConfig holds proxy configuration scoped to authentication components (the OAuth server and the cluster authentication operator).", + "httpProxy": "httpProxy is the URL of the proxy for HTTP requests. Must be a valid URL with http or https scheme, a non-empty hostname, and no path, query parameters, or fragment. Userinfo (e.g. user:password@host) is allowed for proxy authentication. Maximum length is 2048 characters.", + "httpsProxy": "httpsProxy is the URL of the proxy for HTTPS requests. Must be a valid URL with http or https scheme, a non-empty hostname, and no path, query parameters, or fragment. Userinfo (e.g. user:password@host) is allowed for proxy authentication. Maximum length is 2048 characters.", + "noProxy": "noProxy is a list of hostnames and/or CIDRs and/or IPs for which the proxy should not be used. Must contain at least one entry when set. Each entry must be between 1 and 253 characters long and at most 64 entries are allowed. Duplicate entries are not permitted. Entries that are not valid hostnames, CIDRs, or IPs are silently ignored. Cluster-internal defaults (.cluster.local, .svc, 127.0.0.1, localhost) are always appended automatically and do not need to be included.", + "trustedCA": "trustedCA is a reference to a ConfigMap in the openshift-config namespace containing a CA certificate bundle under the key \"ca-bundle.crt\". This bundle is appended to the system trust store used by authentication components for proxy TLS connections. When omitted, only the system trust store is used.", +} + +func (AuthenticationProxyConfig) SwaggerDoc() map[string]string { + return map_AuthenticationProxyConfig +} + +var map_AuthenticationSpec = map[string]string{ + "proxy": "proxy configures proxy settings for outbound connections made by the authentication stack. When set, it replaces the cluster-wide proxy (proxy.config.openshift.io/cluster) entirely for authentication — individual fields are not inherited from the cluster-wide configuration. When omitted, the cluster-wide proxy is used if configured; otherwise no proxy is used.", +} + +func (AuthenticationSpec) SwaggerDoc() map[string]string { + return map_AuthenticationSpec +} + var map_AuthenticationStatus = map[string]string{ "oauthAPIServer": "oauthAPIServer holds status specific only to oauth-apiserver", } @@ -569,8 +598,8 @@ func (ClusterCSIDriverStatus) SwaggerDoc() map[string]string { } var map_CustomSecretRotation = map[string]string{ - "": "CustomSecretRotation holds configuration for custom secret rotation behavior.", - "rotationPollIntervalSeconds": "rotationPollIntervalSeconds is the minimum time in seconds between secret rotation attempts. The driver skips provider calls if less than this interval has elapsed since the last successful rotation. Must be at least 1 second and no more than 31560000 seconds (~1 year). When omitted, this means no opinion and the platform is left to choose a reasonable default, which is subject to change over time.", + "": "CustomSecretRotation holds configuration for custom secret rotation behavior.", + "minimumRefreshAge": "minimumRefreshAge is the minimum time in seconds between secret rotation attempts. Each time kubelet calls NodePublishVolume, the driver checks whether this interval has elapsed since the last successful provider call. If it has, the driver contacts the secret provider to fetch the latest secret values and updates the mounted volume. Setting this value below the kubelet syncFrequency (default: 1 minute) has no additional effect on the actual rotation cadence. Must be at least 1 second and no more than 31560000 seconds (~1 year). When omitted, this means no opinion and the platform is left to choose a reasonable default, which is subject to change over time.", } func (CustomSecretRotation) SwaggerDoc() map[string]string { @@ -1143,6 +1172,7 @@ var map_IngressControllerSpec = map[string]string{ "httpCompression": "httpCompression defines a policy for HTTP traffic compression. By default, there is no HTTP compression.", "idleConnectionTerminationPolicy": "idleConnectionTerminationPolicy maps directly to HAProxy's idle-close-on-response option and controls whether HAProxy keeps idle frontend connections open during a soft stop (router reload).\n\nAllowed values for this field are \"Immediate\" and \"Deferred\". The default value is \"Immediate\".\n\nWhen set to \"Immediate\", idle connections are closed immediately during router reloads. This ensures immediate propagation of route changes but may impact clients sensitive to connection resets.\n\nWhen set to \"Deferred\", HAProxy will maintain idle connections during a soft reload instead of closing them immediately. These connections remain open until any of the following occurs:\n\n - A new request is received on the connection, in which\n case HAProxy handles it in the old process and closes\n the connection after sending the response.\n\n - HAProxy's `timeout http-keep-alive` duration expires.\n By default this is 300 seconds, but it can be changed\n using httpKeepAliveTimeout tuning option.\n\n - The client's keep-alive timeout expires, causing the\n client to close the connection.\n\nSetting Deferred can help prevent errors in clients or load balancers that do not properly handle connection resets. Additionally, this option allows you to retain the pre-2.4 HAProxy behaviour: in HAProxy version 2.2 (OpenShift versions < 4.14), maintaining idle connections during a soft reload was the default behaviour, but starting with HAProxy 2.4, the default changed to closing idle connections immediately.\n\nImportant Consideration:\n\n - Using Deferred will result in temporary inconsistencies\n for the first request on each persistent connection\n after a route update and router reload. This request\n will be processed by the old HAProxy process using its\n old configuration. Subsequent requests will use the\n updated configuration.\n\nOperational Considerations:\n\n - Keeping idle connections open during reloads may lead\n to an accumulation of old HAProxy processes if\n connections remain idle for extended periods,\n especially in environments where frequent reloads\n occur.\n\n - Consider monitoring the number of HAProxy processes in\n the router pods when Deferred is set.\n\n - You may need to enable or adjust the\n `ingress.operator.openshift.io/hard-stop-after`\n duration (configured via an annotation on the\n IngressController resource) in environments with\n frequent reloads to prevent resource exhaustion.", "closedClientConnectionPolicy": "closedClientConnectionPolicy controls how the IngressController behaves when the client closes the TCP connection while the TLS handshake or HTTP request is in progress. This option maps directly to HAProxy’s \"abortonclose\" option.\n\nValid values are: \"Abort\" and \"Continue\". The default value is \"Continue\".\n\nWhen set to \"Abort\", the router will stop processing the TLS handshake if it is in progress, and it will not send an HTTP request to the backend server if the request has not yet been sent when the client closes the connection.\n\nWhen set to \"Continue\", the router will complete the TLS handshake if it is in progress, or send an HTTP request to the backend server and wait for the backend server's response, regardless of whether the client has closed the connection.\n\nSetting \"Abort\" can help free CPU resources otherwise spent on TLS computation for connections the client has already closed, and can reduce request queue size, thereby reducing the load on saturated backend servers.\n\nImportant Considerations:\n\n - The default policy (\"Continue\") is HTTP-compliant, and requests\n for aborted client connections will still be served.\n Use the \"Continue\" policy to allow a client to send a request\n and then immediately close its side of the connection while\n still receiving a response on the half-closed connection.\n\n - When clients use keep-alive connections, the most common case for premature\n closure is when the user wants to cancel the transfer or when a timeout\n occurs. In that case, the \"Abort\" policy may be used to reduce resource consumption.\n\n - Using RSA keys larger than 2048 bits can significantly slow down\n TLS computations. Consider using the \"Abort\" policy to reduce CPU usage.", + "haproxyVersion": "haproxyVersion specifies the HAProxy version to use for this IngressController.\n\nOpenShift 5.0 introduces HAProxy 3.2 as its default version and supports HAProxy 2.8 from OpenShift 4.22 for migration purposes. When an OpenShift release introduces a new default HAProxy version, that HAProxy version becomes available as a pinnable value in subsequent OpenShift releases, providing a smooth migration path for administrators who want to defer HAProxy upgrades.\n\nValid values for OpenShift 5.0: - Unset (default): Uses HAProxy 3.2 (the default for OpenShift 5.0) - \"3.2\": Explicitly pins HAProxy 3.2 for preservation during cluster\n upgrades to future OpenShift releases\n- \"2.8\": Uses HAProxy 2.8 from OpenShift 4.22 (migration support, will\n be dropped in the next OpenShift release)\n\nIf a specific HAProxy version is set and would become unsupported in a target cluster upgrade, a preflight check will block the cluster upgrade until this field is updated to unset or a supported version.", } func (IngressControllerSpec) SwaggerDoc() map[string]string { @@ -1160,6 +1190,7 @@ var map_IngressControllerStatus = map[string]string{ "observedGeneration": "observedGeneration is the most recent generation observed.", "namespaceSelector": "namespaceSelector is the actual namespaceSelector in use.", "routeSelector": "routeSelector is the actual routeSelector in use.", + "effectiveHAProxyVersion": "effectiveHAProxyVersion reports the HAProxy version currently in use by this IngressController. This reflects the resolved value of the spec.haproxyVersion field. When omitted, the effective value has not yet been resolved by the operator or the feature is not enabled for this cluster.\n\nExamples for OpenShift 5.0: - \"3.2\": Using HAProxy 3.2 - \"2.8\": Using HAProxy 2.8", } func (IngressControllerStatus) SwaggerDoc() map[string]string { diff --git a/vendor/github.com/openshift/api/operator/v1alpha1/types_clusterapi.go b/vendor/github.com/openshift/api/operator/v1alpha1/types_clusterapi.go index 719893f8a539..291cedc14558 100644 --- a/vendor/github.com/openshift/api/operator/v1alpha1/types_clusterapi.go +++ b/vendor/github.com/openshift/api/operator/v1alpha1/types_clusterapi.go @@ -244,13 +244,24 @@ type ClusterAPIInstallerComponentSource struct { Image ClusterAPIInstallerComponentImage `json:"image,omitzero"` } -// ImageDigestFormat is a type that conforms to the format host[:port][/namespace]/name@sha256:. +// The image name validation regex is derived from the OCI distribution reference: +// https://github.com/distribution/reference/blob/main/regexp.go +// It matches: domainAndPort "/" remoteName +// +// domainAndPort = (domainName | "[" ipv6 "]") [ ":" port ] +// domainName = label ("." label)* +// label = alphanumeric, may contain hyphens but must start/end with [a-zA-Z0-9] +// remoteName = pathComponent ("/" pathComponent)* +// pathComponent = [a-z0-9]+ separated by ".", "_", "__", or "-"+ + +// ImageDigestFormat is a type that conforms to the format host[:port][/namespace[/namespace...]]/name@sha256:. +// The host may be a dotted domain name (including IPv4 addresses like 192.168.1.1), or an IPv6 address in brackets (e.g. [fd00::1]). // The digest must be 64 characters long, and consist only of lowercase hexadecimal characters, a-f and 0-9. // The length of the field must be between 1 to 447 characters. // +kubebuilder:validation:MinLength=1 // +kubebuilder:validation:MaxLength=447 // +kubebuilder:validation:XValidation:rule=`(self.split('@').size() == 2 && self.split('@')[1].matches('^sha256:[a-f0-9]{64}$'))`,message="the OCI Image reference must end with a valid '@sha256:' suffix, where '' is 64 characters long" -// +kubebuilder:validation:XValidation:rule=`(self.split('@')[0].matches('^([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9-]+(:[0-9]{2,5})?/([a-zA-Z0-9-_]{0,61}/)?[a-zA-Z0-9-_.]*?$'))`,message="the OCI Image name should follow the host[:port][/namespace]/name format, resembling a valid URL without the scheme" +// +kubebuilder:validation:XValidation:rule=`(self.split('@')[0].matches('^(?:(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])(?:\\.(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]))*|\\[(?:[a-fA-F0-9:]+)\\])(?::[0-9]+)?/[a-z0-9]+(?:(?:[._]|__|[-]+)[a-z0-9]+)*(?:/[a-z0-9]+(?:(?:[._]|__|[-]+)[a-z0-9]+)*)*$'))`,message="the OCI Image name should follow the host[:port][/namespace[/namespace...]]/name format, where host is a domain name, IPv4, or IPv6 address in brackets" type ImageDigestFormat string // ClusterAPIInstallerComponentImage defines an image source for a component. diff --git a/vendor/github.com/openshift/api/osin/v1/types.go b/vendor/github.com/openshift/api/osin/v1/types.go index 35eb3ee8b016..3f3af3cfa541 100644 --- a/vendor/github.com/openshift/api/osin/v1/types.go +++ b/vendor/github.com/openshift/api/osin/v1/types.go @@ -80,6 +80,11 @@ type OAuthConfig struct { // templates allow you to customize pages like the login page. Templates *OAuthTemplates `json:"templates"` + + // proxyTrustedCA is an optional path to a PEM-encoded CA bundle used to + // verify connections to an HTTPS proxy during outbound IdP requests. + // When omitted, proxy connections use the system trust roots only. + ProxyTrustedCA string `json:"proxyTrustedCA,omitempty"` } // OAuthTemplates allow for customization of pages like the login page diff --git a/vendor/github.com/openshift/api/osin/v1/zz_generated.swagger_doc_generated.go b/vendor/github.com/openshift/api/osin/v1/zz_generated.swagger_doc_generated.go index 890928a7a4dc..6594af9451a0 100644 --- a/vendor/github.com/openshift/api/osin/v1/zz_generated.swagger_doc_generated.go +++ b/vendor/github.com/openshift/api/osin/v1/zz_generated.swagger_doc_generated.go @@ -154,6 +154,7 @@ var map_OAuthConfig = map[string]string{ "sessionConfig": "sessionConfig hold information about configuring sessions.", "tokenConfig": "tokenConfig contains options for authorization and access tokens", "templates": "templates allow you to customize pages like the login page.", + "proxyTrustedCA": "proxyTrustedCA is an optional path to a PEM-encoded CA bundle used to verify connections to an HTTPS proxy during outbound IdP requests. When omitted, proxy connections use the system trust roots only.", } func (OAuthConfig) SwaggerDoc() map[string]string { diff --git a/vendor/github.com/openshift/api/project/.codegen.yaml b/vendor/github.com/openshift/api/project/.codegen.yaml new file mode 100644 index 000000000000..f7a37129a0a0 --- /dev/null +++ b/vendor/github.com/openshift/api/project/.codegen.yaml @@ -0,0 +1,2 @@ +protobuf: + disabled: false diff --git a/vendor/github.com/openshift/api/quota/.codegen.yaml b/vendor/github.com/openshift/api/quota/.codegen.yaml new file mode 100644 index 000000000000..f7a37129a0a0 --- /dev/null +++ b/vendor/github.com/openshift/api/quota/.codegen.yaml @@ -0,0 +1,2 @@ +protobuf: + disabled: false diff --git a/vendor/github.com/openshift/api/route/.codegen.yaml b/vendor/github.com/openshift/api/route/.codegen.yaml index 65cf5d814ba9..b003a5d6c9da 100644 --- a/vendor/github.com/openshift/api/route/.codegen.yaml +++ b/vendor/github.com/openshift/api/route/.codegen.yaml @@ -1,3 +1,5 @@ schemapatch: swaggerdocs: commentPolicy: Warn +protobuf: + disabled: false diff --git a/vendor/github.com/openshift/api/samples/.codegen.yaml b/vendor/github.com/openshift/api/samples/.codegen.yaml index ffa2c8d9b2ee..f10357951b3f 100644 --- a/vendor/github.com/openshift/api/samples/.codegen.yaml +++ b/vendor/github.com/openshift/api/samples/.codegen.yaml @@ -1,2 +1,4 @@ swaggerdocs: commentPolicy: Warn +protobuf: + disabled: false diff --git a/vendor/github.com/openshift/api/security/.codegen.yaml b/vendor/github.com/openshift/api/security/.codegen.yaml new file mode 100644 index 000000000000..f7a37129a0a0 --- /dev/null +++ b/vendor/github.com/openshift/api/security/.codegen.yaml @@ -0,0 +1,2 @@ +protobuf: + disabled: false diff --git a/vendor/github.com/openshift/api/template/.codegen.yaml b/vendor/github.com/openshift/api/template/.codegen.yaml new file mode 100644 index 000000000000..f7a37129a0a0 --- /dev/null +++ b/vendor/github.com/openshift/api/template/.codegen.yaml @@ -0,0 +1,2 @@ +protobuf: + disabled: false diff --git a/vendor/github.com/openshift/api/user/.codegen.yaml b/vendor/github.com/openshift/api/user/.codegen.yaml new file mode 100644 index 000000000000..f7a37129a0a0 --- /dev/null +++ b/vendor/github.com/openshift/api/user/.codegen.yaml @@ -0,0 +1,2 @@ +protobuf: + disabled: false diff --git a/vendor/google.golang.org/protobuf/encoding/protodelim/protodelim.go b/vendor/google.golang.org/protobuf/encoding/protodelim/protodelim.go index 2ef36bbcf92a..ec63689e725a 100644 --- a/vendor/google.golang.org/protobuf/encoding/protodelim/protodelim.go +++ b/vendor/google.golang.org/protobuf/encoding/protodelim/protodelim.go @@ -10,6 +10,7 @@ import ( "encoding/binary" "fmt" "io" + "math" "google.golang.org/protobuf/encoding/protowire" "google.golang.org/protobuf/internal/errors" @@ -117,7 +118,13 @@ func (o UnmarshalOptions) UnmarshalFrom(r Reader, m proto.Message) error { if maxSize == 0 { maxSize = defaultMaxSize } - if maxSize != -1 && size > uint64(maxSize) { + if maxSize == -1 { + // No limit specified: Just check that size fits into an integer, + // otherwise the make([]byte, size) call below will panic. + if size > math.MaxInt { + return errors.Wrap(&SizeTooLargeError{Size: size, MaxSize: math.MaxInt}, "") + } + } else if size > uint64(maxSize) { return errors.Wrap(&SizeTooLargeError{Size: size, MaxSize: uint64(maxSize)}, "") } diff --git a/vendor/google.golang.org/protobuf/encoding/protojson/decode.go b/vendor/google.golang.org/protobuf/encoding/protojson/decode.go index 737d6876d5ef..1d6608dc7d5e 100644 --- a/vendor/google.golang.org/protobuf/encoding/protojson/decode.go +++ b/vendor/google.golang.org/protobuf/encoding/protojson/decode.go @@ -365,6 +365,10 @@ func unmarshalInt(tok json.Token, bitSize int) (protoreflect.Value, bool) { if err != nil { return protoreflect.Value{}, false } + // Ensure there is no non-number content in this string. + if next, err := dec.Read(); err != nil || next.Kind() != json.EOF { + return protoreflect.Value{}, false + } return getInt(tok, bitSize) } return protoreflect.Value{}, false @@ -397,6 +401,10 @@ func unmarshalUint(tok json.Token, bitSize int) (protoreflect.Value, bool) { if err != nil { return protoreflect.Value{}, false } + // Ensure there is no non-number content in this string. + if next, err := dec.Read(); err != nil || next.Kind() != json.EOF { + return protoreflect.Value{}, false + } return getUint(tok, bitSize) } return protoreflect.Value{}, false @@ -447,6 +455,10 @@ func unmarshalFloat(tok json.Token, bitSize int) (protoreflect.Value, bool) { if err != nil { return protoreflect.Value{}, false } + // Ensure there is no non-number content in this string. + if next, err := dec.Read(); err != nil || next.Kind() != json.EOF { + return protoreflect.Value{}, false + } return getFloat(tok, bitSize) } return protoreflect.Value{}, false diff --git a/vendor/google.golang.org/protobuf/encoding/protojson/well_known_types.go b/vendor/google.golang.org/protobuf/encoding/protojson/well_known_types.go index e9fe1039437a..d2eab469474a 100644 --- a/vendor/google.golang.org/protobuf/encoding/protojson/well_known_types.go +++ b/vendor/google.golang.org/protobuf/encoding/protojson/well_known_types.go @@ -52,7 +52,10 @@ func wellKnownTypeMarshaler(name protoreflect.FullName) marshalFunc { case genid.FieldMask_message_name: return encoder.marshalFieldMask case genid.Empty_message_name: - return encoder.marshalEmpty + // The spec explicitly specifies that the Empty message + // is not considered to have any special JSON mapping: + // https://protobuf.dev/programming-guides/json/#any + return nil } } return nil diff --git a/vendor/google.golang.org/protobuf/encoding/prototext/decode.go b/vendor/google.golang.org/protobuf/encoding/prototext/decode.go index b53805056a9a..20ec09e19481 100644 --- a/vendor/google.golang.org/protobuf/encoding/prototext/decode.go +++ b/vendor/google.golang.org/protobuf/encoding/prototext/decode.go @@ -8,6 +8,7 @@ import ( "fmt" "unicode/utf8" + "google.golang.org/protobuf/encoding/protowire" "google.golang.org/protobuf/internal/encoding/messageset" "google.golang.org/protobuf/internal/encoding/text" "google.golang.org/protobuf/internal/errors" @@ -49,12 +50,19 @@ type UnmarshalOptions struct { protoregistry.MessageTypeResolver protoregistry.ExtensionTypeResolver } + + // RecursionLimit limits how deeply messages may be nested. + // If zero, a default limit is applied. + RecursionLimit int } // Unmarshal reads the given []byte and populates the given [proto.Message] // using options in the UnmarshalOptions object. // The provided message must be mutable (e.g., a non-nil pointer to a message). func (o UnmarshalOptions) Unmarshal(b []byte, m proto.Message) error { + if o.RecursionLimit == 0 { + o.RecursionLimit = protowire.DefaultRecursionLimit + } return o.unmarshal(b, m) } @@ -102,8 +110,14 @@ func (d decoder) syntaxError(pos int, f string, x ...any) error { return errors.New(head+f, x...) } +var errRecursionDepth = errors.New("exceeded maximum recursion depth") + // unmarshalMessage unmarshals into the given protoreflect.Message. func (d decoder) unmarshalMessage(m protoreflect.Message, checkDelims bool) error { + if d.opts.RecursionLimit--; d.opts.RecursionLimit < 0 { + return errRecursionDepth + } + messageDesc := m.Descriptor() if !flags.ProtoLegacy && messageset.IsMessageSet(messageDesc) { return errors.New("no support for proto1 MessageSets") @@ -437,6 +451,10 @@ func (d decoder) unmarshalList(fd protoreflect.FieldDescriptor, list protoreflec // unmarshalMap unmarshals into given protoreflect.Map. A map value is a // textproto message containing {key: , value: }. func (d decoder) unmarshalMap(fd protoreflect.FieldDescriptor, mmap protoreflect.Map) error { + if d.opts.RecursionLimit--; d.opts.RecursionLimit < 0 { + return errRecursionDepth + } + // Determine ahead whether map entry is a scalar type or a message type in // order to call the appropriate unmarshalMapValue func inside // unmarshalMapEntry. diff --git a/vendor/google.golang.org/protobuf/internal/descfmt/stringer.go b/vendor/google.golang.org/protobuf/internal/descfmt/stringer.go index 87e46bd4dfb9..0b0dfacbe5a2 100644 --- a/vendor/google.golang.org/protobuf/internal/descfmt/stringer.go +++ b/vendor/google.golang.org/protobuf/internal/descfmt/stringer.go @@ -83,12 +83,13 @@ func formatListOpt(vs list, isRoot, allowMulti bool) string { case protoreflect.FileImports: for i := 0; i < vs.Len(); i++ { var rs records - rv := reflect.ValueOf(vs.Get(i)) - rs.Append(rv, []methodAndName{ - {rv.MethodByName("Path"), "Path"}, - {rv.MethodByName("Package"), "Package"}, - {rv.MethodByName("IsPublic"), "IsPublic"}, - {rv.MethodByName("IsWeak"), "IsWeak"}, + fi := vs.Get(i) + rv := reflect.ValueOf(fi) + rs.Append(rv, []attrAndName{ + {fi.Path(), "Path"}, + {fi.Package(), "Package"}, + {fi.IsPublic, "IsPublic"}, + {fi.IsWeak, "IsWeak"}, }...) ss = append(ss, "{"+rs.Join()+"}") } @@ -104,9 +105,9 @@ func formatListOpt(vs list, isRoot, allowMulti bool) string { } } -type methodAndName struct { - method reflect.Value - name string +type attrAndName struct { + attr any + name string } func FormatDesc(s fmt.State, r rune, t protoreflect.Descriptor) { @@ -126,58 +127,58 @@ func formatDescOpt(t protoreflect.Descriptor, isRoot, allowMulti bool, record fu start = rt.Name() + "{" } - _, isFile := t.(protoreflect.FileDescriptor) + fd, isFile := t.(protoreflect.FileDescriptor) rs := records{ allowMulti: allowMulti, record: record, } if t.IsPlaceholder() { if isFile { - rs.Append(rv, []methodAndName{ - {rv.MethodByName("Path"), "Path"}, - {rv.MethodByName("Package"), "Package"}, - {rv.MethodByName("IsPlaceholder"), "IsPlaceholder"}, + rs.Append(rv, []attrAndName{ + {fd.Path(), "Path"}, + {fd.Package(), "Package"}, + {fd.IsPlaceholder(), "IsPlaceholder"}, }...) } else { - rs.Append(rv, []methodAndName{ - {rv.MethodByName("FullName"), "FullName"}, - {rv.MethodByName("IsPlaceholder"), "IsPlaceholder"}, + rs.Append(rv, []attrAndName{ + {t.FullName(), "FullName"}, + {t.IsPlaceholder(), "IsPlaceholder"}, }...) } } else { switch { case isFile: - rs.Append(rv, methodAndName{rv.MethodByName("Syntax"), "Syntax"}) + rs.Append(rv, attrAndName{fd.Syntax(), "Syntax"}) case isRoot: - rs.Append(rv, []methodAndName{ - {rv.MethodByName("Syntax"), "Syntax"}, - {rv.MethodByName("FullName"), "FullName"}, + rs.Append(rv, []attrAndName{ + {t.Syntax(), "Syntax"}, + {t.FullName(), "FullName"}, }...) default: - rs.Append(rv, methodAndName{rv.MethodByName("Name"), "Name"}) + rs.Append(rv, attrAndName{t.Name(), "Name"}) } switch t := t.(type) { case protoreflect.FieldDescriptor: - accessors := []methodAndName{ - {rv.MethodByName("Number"), "Number"}, - {rv.MethodByName("Cardinality"), "Cardinality"}, - {rv.MethodByName("Kind"), "Kind"}, - {rv.MethodByName("HasJSONName"), "HasJSONName"}, - {rv.MethodByName("JSONName"), "JSONName"}, - {rv.MethodByName("HasPresence"), "HasPresence"}, - {rv.MethodByName("IsExtension"), "IsExtension"}, - {rv.MethodByName("IsPacked"), "IsPacked"}, - {rv.MethodByName("IsWeak"), "IsWeak"}, - {rv.MethodByName("IsList"), "IsList"}, - {rv.MethodByName("IsMap"), "IsMap"}, - {rv.MethodByName("MapKey"), "MapKey"}, - {rv.MethodByName("MapValue"), "MapValue"}, - {rv.MethodByName("HasDefault"), "HasDefault"}, - {rv.MethodByName("Default"), "Default"}, - {rv.MethodByName("ContainingOneof"), "ContainingOneof"}, - {rv.MethodByName("ContainingMessage"), "ContainingMessage"}, - {rv.MethodByName("Message"), "Message"}, - {rv.MethodByName("Enum"), "Enum"}, + accessors := []attrAndName{ + {t.Number(), "Number"}, + {t.Cardinality(), "Cardinality"}, + {t.Kind(), "Kind"}, + {t.HasJSONName(), "HasJSONName"}, + {t.JSONName(), "JSONName"}, + {t.HasPresence(), "HasPresence"}, + {t.IsExtension(), "IsExtension"}, + {t.IsPacked(), "IsPacked"}, + {t.IsWeak(), "IsWeak"}, + {t.IsList(), "IsList"}, + {t.IsMap(), "IsMap"}, + {t.MapKey(), "MapKey"}, + {t.MapValue(), "MapValue"}, + {t.HasDefault(), "HasDefault"}, + {t.Default(), "Default"}, + {t.ContainingOneof(), "ContainingOneof"}, + {t.ContainingMessage(), "ContainingMessage"}, + {t.Message(), "Message"}, + {t.Enum(), "Enum"}, } for _, s := range accessors { switch s.name { @@ -223,58 +224,54 @@ func formatDescOpt(t protoreflect.Descriptor, isRoot, allowMulti bool, record fu } case protoreflect.FileDescriptor: - rs.Append(rv, []methodAndName{ - {rv.MethodByName("Path"), "Path"}, - {rv.MethodByName("Package"), "Package"}, - {rv.MethodByName("Imports"), "Imports"}, - {rv.MethodByName("Messages"), "Messages"}, - {rv.MethodByName("Enums"), "Enums"}, - {rv.MethodByName("Extensions"), "Extensions"}, - {rv.MethodByName("Services"), "Services"}, + rs.Append(rv, []attrAndName{ + {t.Path(), "Path"}, + {t.Package(), "Package"}, + {t.Imports(), "Imports"}, + {t.Messages(), "Messages"}, + {t.Enums(), "Enums"}, + {t.Extensions(), "Extensions"}, + {t.Services(), "Services"}, }...) case protoreflect.MessageDescriptor: - rs.Append(rv, []methodAndName{ - {rv.MethodByName("IsMapEntry"), "IsMapEntry"}, - {rv.MethodByName("Fields"), "Fields"}, - {rv.MethodByName("Oneofs"), "Oneofs"}, - {rv.MethodByName("ReservedNames"), "ReservedNames"}, - {rv.MethodByName("ReservedRanges"), "ReservedRanges"}, - {rv.MethodByName("RequiredNumbers"), "RequiredNumbers"}, - {rv.MethodByName("ExtensionRanges"), "ExtensionRanges"}, - {rv.MethodByName("Messages"), "Messages"}, - {rv.MethodByName("Enums"), "Enums"}, - {rv.MethodByName("Extensions"), "Extensions"}, + rs.Append(rv, []attrAndName{ + {t.IsMapEntry(), "IsMapEntry"}, + {t.Fields(), "Fields"}, + {t.Oneofs(), "Oneofs"}, + {t.ReservedNames(), "ReservedNames"}, + {t.ReservedRanges(), "ReservedRanges"}, + {t.RequiredNumbers(), "RequiredNumbers"}, + {t.ExtensionRanges(), "ExtensionRanges"}, + {t.Messages(), "Messages"}, + {t.Enums(), "Enums"}, + {t.Extensions(), "Extensions"}, }...) case protoreflect.EnumDescriptor: - rs.Append(rv, []methodAndName{ - {rv.MethodByName("Values"), "Values"}, - {rv.MethodByName("ReservedNames"), "ReservedNames"}, - {rv.MethodByName("ReservedRanges"), "ReservedRanges"}, - {rv.MethodByName("IsClosed"), "IsClosed"}, + rs.Append(rv, []attrAndName{ + {t.Values(), "Values"}, + {t.ReservedNames(), "ReservedNames"}, + {t.ReservedRanges(), "ReservedRanges"}, + {t.IsClosed(), "IsClosed"}, }...) case protoreflect.EnumValueDescriptor: - rs.Append(rv, []methodAndName{ - {rv.MethodByName("Number"), "Number"}, - }...) + rs.Append(rv, attrAndName{t.Number(), "Number"}) case protoreflect.ServiceDescriptor: - rs.Append(rv, []methodAndName{ - {rv.MethodByName("Methods"), "Methods"}, - }...) + rs.Append(rv, attrAndName{t.Methods(), "Methods"}) case protoreflect.MethodDescriptor: - rs.Append(rv, []methodAndName{ - {rv.MethodByName("Input"), "Input"}, - {rv.MethodByName("Output"), "Output"}, - {rv.MethodByName("IsStreamingClient"), "IsStreamingClient"}, - {rv.MethodByName("IsStreamingServer"), "IsStreamingServer"}, + rs.Append(rv, []attrAndName{ + {t.Input(), "Input"}, + {t.Output(), "Output"}, + {t.IsStreamingClient(), "IsStreamingClient"}, + {t.IsStreamingServer(), "IsStreamingServer"}, }...) } - if m := rv.MethodByName("GoType"); m.IsValid() { - rs.Append(rv, methodAndName{m, "GoType"}) + if m, ok := t.(interface{ GoType() reflect.Type }); ok { + rs.Append(rv, attrAndName{m.GoType(), "GoType"}) } } return start + rs.Join() + end @@ -297,68 +294,66 @@ func (rs *records) AppendRecs(fieldName string, newRecs [2]string) { rs.recs = append(rs.recs, newRecs) } -func (rs *records) Append(v reflect.Value, accessors ...methodAndName) { - for _, a := range accessors { - if rs.record != nil { - rs.record(a.name) - } - var rv reflect.Value - if a.method.IsValid() { - rv = a.method.Call(nil)[0] - } - if v.Kind() == reflect.Struct && !rv.IsValid() { - rv = v.FieldByName(a.name) - } - if !rv.IsValid() { - panic(fmt.Sprintf("unknown accessor: %v.%s", v.Type(), a.name)) - } - if _, ok := rv.Interface().(protoreflect.Value); ok { - rv = rv.MethodByName("Interface").Call(nil)[0] - if !rv.IsNil() { - rv = rv.Elem() - } - } +func (rs *records) Append(v reflect.Value, results ...attrAndName) { + for _, r := range results { + rs.appendAttribute(v, r.name, r.attr) + } +} - // Ignore zero values. - var isZero bool - switch rv.Kind() { - case reflect.Interface, reflect.Slice: - isZero = rv.IsNil() - case reflect.Bool: - isZero = rv.Bool() == false - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - isZero = rv.Int() == 0 - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - isZero = rv.Uint() == 0 - case reflect.String: - isZero = rv.String() == "" - } - if n, ok := rv.Interface().(list); ok { - isZero = n.Len() == 0 - } - if isZero { - continue +func (rs *records) appendAttribute(val reflect.Value, name string, attrVal any) { + if rs.record != nil { + rs.record(name) + } + if attrVal == nil { + return + } + rv := reflect.ValueOf(attrVal) + if _, ok := rv.Interface().(protoreflect.Value); ok { + rv = rv.MethodByName("Interface").Call(nil)[0] + if !rv.IsNil() { + rv = rv.Elem() } + } - // Format the value. - var s string - v := rv.Interface() - switch v := v.(type) { - case list: - s = formatListOpt(v, false, rs.allowMulti) - case protoreflect.FieldDescriptor, protoreflect.OneofDescriptor, protoreflect.EnumValueDescriptor, protoreflect.MethodDescriptor: - s = string(v.(protoreflect.Descriptor).Name()) - case protoreflect.Descriptor: - s = string(v.FullName()) - case string: - s = strconv.Quote(v) - case []byte: - s = fmt.Sprintf("%q", v) - default: - s = fmt.Sprint(v) - } - rs.recs = append(rs.recs, [2]string{a.name, s}) + // Ignore zero values. + var isZero bool + switch rv.Kind() { + case reflect.Interface, reflect.Slice: + isZero = rv.IsNil() + case reflect.Bool: + isZero = rv.Bool() == false + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + isZero = rv.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + isZero = rv.Uint() == 0 + case reflect.String: + isZero = rv.String() == "" + } + if n, ok := rv.Interface().(list); ok { + isZero = n.Len() == 0 + } + if isZero { + return + } + + // Format the value. + var s string + v := rv.Interface() + switch v := v.(type) { + case list: + s = formatListOpt(v, false, rs.allowMulti) + case protoreflect.FieldDescriptor, protoreflect.OneofDescriptor, protoreflect.EnumValueDescriptor, protoreflect.MethodDescriptor: + s = string(v.(protoreflect.Descriptor).Name()) + case protoreflect.Descriptor: + s = string(v.FullName()) + case string: + s = strconv.Quote(v) + case []byte: + s = fmt.Sprintf("%q", v) + default: + s = fmt.Sprint(v) } + rs.recs = append(rs.recs, [2]string{name, s}) } func (rs *records) Join() string { diff --git a/vendor/google.golang.org/protobuf/internal/editionssupport/editions.go b/vendor/google.golang.org/protobuf/internal/editionssupport/editions.go index bf1aba0e851b..7b9f01afb087 100644 --- a/vendor/google.golang.org/protobuf/internal/editionssupport/editions.go +++ b/vendor/google.golang.org/protobuf/internal/editionssupport/editions.go @@ -9,7 +9,7 @@ import "google.golang.org/protobuf/types/descriptorpb" const ( Minimum = descriptorpb.Edition_EDITION_PROTO2 - Maximum = descriptorpb.Edition_EDITION_2023 + Maximum = descriptorpb.Edition_EDITION_2024 // MaximumKnown is the maximum edition that is known to Go Protobuf, but not // declared as supported. In other words: end users cannot use it, but diff --git a/vendor/google.golang.org/protobuf/internal/encoding/tag/tag.go b/vendor/google.golang.org/protobuf/internal/encoding/tag/tag.go index 669133d04dc9..c96e4483460a 100644 --- a/vendor/google.golang.org/protobuf/internal/encoding/tag/tag.go +++ b/vendor/google.golang.org/protobuf/internal/encoding/tag/tag.go @@ -32,7 +32,7 @@ var byteType = reflect.TypeOf(byte(0)) func Unmarshal(tag string, goType reflect.Type, evs protoreflect.EnumValueDescriptors) protoreflect.FieldDescriptor { f := new(filedesc.Field) f.L0.ParentFile = filedesc.SurrogateProto2 - f.L1.EditionFeatures = f.L0.ParentFile.L1.EditionFeatures + packed := false for len(tag) > 0 { i := strings.IndexByte(tag, ',') if i < 0 { @@ -108,7 +108,7 @@ func Unmarshal(tag string, goType reflect.Type, evs protoreflect.EnumValueDescri f.L1.StringName.InitJSON(jsonName) } case s == "packed": - f.L1.EditionFeatures.IsPacked = true + packed = true case strings.HasPrefix(s, "def="): // The default tag is special in that everything afterwards is the // default regardless of the presence of commas. @@ -121,6 +121,13 @@ func Unmarshal(tag string, goType reflect.Type, evs protoreflect.EnumValueDescri tag = strings.TrimPrefix(tag[i:], ",") } + // Update EditionFeatures after the loop and after we know whether this is + // a proto2 or proto3 field. + f.L1.EditionFeatures = f.L0.ParentFile.L1.EditionFeatures + if packed { + f.L1.EditionFeatures.IsPacked = true + } + // The generator uses the group message name instead of the field name. // We obtain the real field name by lowercasing the group name. if f.L1.Kind == protoreflect.GroupKind { diff --git a/vendor/google.golang.org/protobuf/internal/encoding/text/decode.go b/vendor/google.golang.org/protobuf/internal/encoding/text/decode.go index 099b2bf451b5..9aa7a9bb7760 100644 --- a/vendor/google.golang.org/protobuf/internal/encoding/text/decode.go +++ b/vendor/google.golang.org/protobuf/internal/encoding/text/decode.go @@ -424,27 +424,34 @@ func (d *Decoder) parseFieldName() (tok Token, err error) { return Token{}, d.newSyntaxError("invalid field name: %s", errId(d.in)) } -// parseTypeName parses Any type URL or extension field name. The name is -// enclosed in [ and ] characters. The C++ parser does not handle many legal URL -// strings. This implementation is more liberal and allows for the pattern -// ^[-_a-zA-Z0-9]+([./][-_a-zA-Z0-9]+)*`). Whitespaces and comments are allowed -// in between [ ], '.', '/' and the sub names. +// parseTypeName parses an Any type URL or an extension field name. The name is +// enclosed in [ and ] characters. We allow almost arbitrary type URL prefixes, +// closely following the text-format spec [1,2]. We implement "ExtensionName | +// AnyName" as follows (with some exceptions for backwards compatibility): +// +// char = [-_a-zA-Z0-9] +// url_char = char | [.~!$&'()*+,;=] | "%", hex, hex +// +// Ident = char, { char } +// TypeName = Ident, { ".", Ident } ; +// UrlPrefix = url_char, { url_char | "/" } ; +// ExtensionName = "[", TypeName, "]" ; +// AnyName = "[", UrlPrefix, "/", TypeName, "]" ; +// +// Additionally, we allow arbitrary whitespace and comments between [ and ]. +// +// [1] https://protobuf.dev/reference/protobuf/textformat-spec/#characters +// [2] https://protobuf.dev/reference/protobuf/textformat-spec/#field-names func (d *Decoder) parseTypeName() (Token, error) { - startPos := len(d.orig) - len(d.in) // Use alias s to advance first in order to use d.in for error handling. - // Caller already checks for [ as first character. + // Caller already checks for [ as first character (d.in[0] == '['). s := consume(d.in[1:], 0) if len(s) == 0 { return Token{}, ErrUnexpectedEOF } + // Collect everything between [ and ] in name. var name []byte - for len(s) > 0 && isTypeNameChar(s[0]) { - name = append(name, s[0]) - s = s[1:] - } - s = consume(s, 0) - var closed bool for len(s) > 0 && !closed { switch { @@ -452,23 +459,20 @@ func (d *Decoder) parseTypeName() (Token, error) { s = s[1:] closed = true - case s[0] == '/', s[0] == '.': - if len(name) > 0 && (name[len(name)-1] == '/' || name[len(name)-1] == '.') { - return Token{}, d.newSyntaxError("invalid type URL/extension field name: %s", - d.orig[startPos:len(d.orig)-len(s)+1]) - } + case s[0] == '/' || isTypeNameChar(s[0]) || isUrlExtraChar(s[0]): name = append(name, s[0]) - s = s[1:] - s = consume(s, 0) - for len(s) > 0 && isTypeNameChar(s[0]) { - name = append(name, s[0]) - s = s[1:] + s = consume(s[1:], 0) + + // URL percent-encoded chars + case s[0] == '%': + if len(s) < 3 || !isHexChar(s[1]) || !isHexChar(s[2]) { + return Token{}, d.parseTypeNameError(s, 3) } - s = consume(s, 0) + name = append(name, s[0], s[1], s[2]) + s = consume(s[3:], 0) default: - return Token{}, d.newSyntaxError( - "invalid type URL/extension field name: %s", d.orig[startPos:len(d.orig)-len(s)+1]) + return Token{}, d.parseTypeNameError(s, 1) } } @@ -476,15 +480,38 @@ func (d *Decoder) parseTypeName() (Token, error) { return Token{}, ErrUnexpectedEOF } - // First character cannot be '.'. Last character cannot be '.' or '/'. - size := len(name) - if size == 0 || name[0] == '.' || name[size-1] == '.' || name[size-1] == '/' { - return Token{}, d.newSyntaxError("invalid type URL/extension field name: %s", - d.orig[startPos:len(d.orig)-len(s)]) + // Split collected name on last '/' into urlPrefix and typeName (if '/' is + // present). + typeName := name + if i := bytes.LastIndexByte(name, '/'); i != -1 { + urlPrefix := name[:i] + typeName = name[i+1:] + + // urlPrefix may be empty (for backwards compatibility). + // If non-empty, it must not start with '/'. + if len(urlPrefix) > 0 && urlPrefix[0] == '/' { + return Token{}, d.parseTypeNameError(s, 0) + } } + // typeName must not be empty (note: "" splits to [""]) and all identifier + // parts must not be empty. + for _, ident := range bytes.Split(typeName, []byte{'.'}) { + if len(ident) == 0 { + return Token{}, d.parseTypeNameError(s, 0) + } + } + + // typeName must not contain any percent-encoded or special URL chars. + for _, b := range typeName { + if b == '%' || (b != '.' && isUrlExtraChar(b)) { + return Token{}, d.parseTypeNameError(s, 0) + } + } + + startPos := len(d.orig) - len(d.in) + endPos := len(d.orig) - len(s) d.in = s - endPos := len(d.orig) - len(d.in) d.consume(0) return Token{ @@ -496,16 +523,32 @@ func (d *Decoder) parseTypeName() (Token, error) { }, nil } +func (d *Decoder) parseTypeNameError(s []byte, numUnconsumedChars int) error { + return d.newSyntaxError( + "invalid type URL/extension field name: %s", + d.in[:len(d.in)-len(s)+min(numUnconsumedChars, len(s))], + ) +} + +func isHexChar(b byte) bool { + return ('0' <= b && b <= '9') || + ('a' <= b && b <= 'f') || + ('A' <= b && b <= 'F') +} + func isTypeNameChar(b byte) bool { - return (b == '-' || b == '_' || + return b == '-' || b == '_' || ('0' <= b && b <= '9') || ('a' <= b && b <= 'z') || - ('A' <= b && b <= 'Z')) + ('A' <= b && b <= 'Z') } -func isWhiteSpace(b byte) bool { +// isUrlExtraChar complements isTypeNameChar with extra characters that we allow +// in URLs but not in type names. Note that '/' is not included so that it can +// be treated specially. +func isUrlExtraChar(b byte) bool { switch b { - case ' ', '\n', '\r', '\t': + case '.', '~', '!', '$', '&', '(', ')', '*', '+', ',', ';', '=': return true default: return false diff --git a/vendor/google.golang.org/protobuf/internal/filedesc/desc.go b/vendor/google.golang.org/protobuf/internal/filedesc/desc.go index 688aabe434ef..c775e5832f01 100644 --- a/vendor/google.golang.org/protobuf/internal/filedesc/desc.go +++ b/vendor/google.golang.org/protobuf/internal/filedesc/desc.go @@ -32,6 +32,7 @@ const ( EditionProto3 Edition = 999 Edition2023 Edition = 1000 Edition2024 Edition = 1001 + EditionUnstable Edition = 9999 EditionUnsupported Edition = 100000 ) @@ -72,9 +73,10 @@ type ( EditionFeatures EditionFeatures } FileL2 struct { - Options func() protoreflect.ProtoMessage - Imports FileImports - Locations SourceLocations + Options func() protoreflect.ProtoMessage + Imports FileImports + OptionImports func() protoreflect.FileImports + Locations SourceLocations } // EditionFeatures is a frequently-instantiated struct, so please take care @@ -126,12 +128,9 @@ func (fd *File) ParentFile() protoreflect.FileDescriptor { return fd } func (fd *File) Parent() protoreflect.Descriptor { return nil } func (fd *File) Index() int { return 0 } func (fd *File) Syntax() protoreflect.Syntax { return fd.L1.Syntax } - -// Not exported and just used to reconstruct the original FileDescriptor proto -func (fd *File) Edition() int32 { return int32(fd.L1.Edition) } -func (fd *File) Name() protoreflect.Name { return fd.L1.Package.Name() } -func (fd *File) FullName() protoreflect.FullName { return fd.L1.Package } -func (fd *File) IsPlaceholder() bool { return false } +func (fd *File) Name() protoreflect.Name { return fd.L1.Package.Name() } +func (fd *File) FullName() protoreflect.FullName { return fd.L1.Package } +func (fd *File) IsPlaceholder() bool { return false } func (fd *File) Options() protoreflect.ProtoMessage { if f := fd.lazyInit().Options; f != nil { return f() @@ -150,6 +149,16 @@ func (fd *File) Format(s fmt.State, r rune) { descfmt.FormatD func (fd *File) ProtoType(protoreflect.FileDescriptor) {} func (fd *File) ProtoInternal(pragma.DoNotImplement) {} +// The next two are not part of the FileDescriptor interface. They are just used to reconstruct +// the original FileDescriptor proto. +func (fd *File) Edition() int32 { return int32(fd.L1.Edition) } +func (fd *File) OptionImports() protoreflect.FileImports { + if f := fd.lazyInit().OptionImports; f != nil { + return f() + } + return emptyFiles +} + func (fd *File) lazyInit() *FileL2 { if atomic.LoadUint32(&fd.once) == 0 { fd.lazyInitOnce() @@ -182,9 +191,9 @@ type ( L2 *EnumL2 // protected by fileDesc.once } EnumL1 struct { - eagerValues bool // controls whether EnumL2.Values is already populated - EditionFeatures EditionFeatures + Visibility int32 + eagerValues bool // controls whether EnumL2.Values is already populated } EnumL2 struct { Options func() protoreflect.ProtoMessage @@ -219,6 +228,11 @@ func (ed *Enum) ReservedNames() protoreflect.Names { return &ed.lazyInit() func (ed *Enum) ReservedRanges() protoreflect.EnumRanges { return &ed.lazyInit().ReservedRanges } func (ed *Enum) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, ed) } func (ed *Enum) ProtoType(protoreflect.EnumDescriptor) {} + +// This is not part of the EnumDescriptor interface. It is just used to reconstruct +// the original FileDescriptor proto. +func (ed *Enum) Visibility() int32 { return ed.L1.Visibility } + func (ed *Enum) lazyInit() *EnumL2 { ed.L0.ParentFile.lazyInit() // implicitly initializes L2 return ed.L2 @@ -244,13 +258,13 @@ type ( L2 *MessageL2 // protected by fileDesc.once } MessageL1 struct { - Enums Enums - Messages Messages - Extensions Extensions - IsMapEntry bool // promoted from google.protobuf.MessageOptions - IsMessageSet bool // promoted from google.protobuf.MessageOptions - + Enums Enums + Messages Messages + Extensions Extensions EditionFeatures EditionFeatures + Visibility int32 + IsMapEntry bool // promoted from google.protobuf.MessageOptions + IsMessageSet bool // promoted from google.protobuf.MessageOptions } MessageL2 struct { Options func() protoreflect.ProtoMessage @@ -319,6 +333,11 @@ func (md *Message) Messages() protoreflect.MessageDescriptors { return &md.L func (md *Message) Extensions() protoreflect.ExtensionDescriptors { return &md.L1.Extensions } func (md *Message) ProtoType(protoreflect.MessageDescriptor) {} func (md *Message) Format(s fmt.State, r rune) { descfmt.FormatDesc(s, r, md) } + +// This is not part of the MessageDescriptor interface. It is just used to reconstruct +// the original FileDescriptor proto. +func (md *Message) Visibility() int32 { return md.L1.Visibility } + func (md *Message) lazyInit() *MessageL2 { md.L0.ParentFile.lazyInit() // implicitly initializes L2 return md.L2 diff --git a/vendor/google.golang.org/protobuf/internal/filedesc/desc_init.go b/vendor/google.golang.org/protobuf/internal/filedesc/desc_init.go index d2f549497eb7..e91860f5a21a 100644 --- a/vendor/google.golang.org/protobuf/internal/filedesc/desc_init.go +++ b/vendor/google.golang.org/protobuf/internal/filedesc/desc_init.go @@ -284,6 +284,13 @@ func (ed *Enum) unmarshalSeed(b []byte, sb *strs.Builder, pf *File, pd protorefl case genid.EnumDescriptorProto_Value_field_number: numValues++ } + case protowire.VarintType: + v, m := protowire.ConsumeVarint(b) + b = b[m:] + switch num { + case genid.EnumDescriptorProto_Visibility_field_number: + ed.L1.Visibility = int32(v) + } default: m := protowire.ConsumeFieldValue(num, typ, b) b = b[m:] @@ -365,6 +372,13 @@ func (md *Message) unmarshalSeed(b []byte, sb *strs.Builder, pf *File, pd protor md.unmarshalSeedOptions(v) } prevField = num + case protowire.VarintType: + v, m := protowire.ConsumeVarint(b) + b = b[m:] + switch num { + case genid.DescriptorProto_Visibility_field_number: + md.L1.Visibility = int32(v) + } default: m := protowire.ConsumeFieldValue(num, typ, b) b = b[m:] diff --git a/vendor/google.golang.org/protobuf/internal/filedesc/desc_lazy.go b/vendor/google.golang.org/protobuf/internal/filedesc/desc_lazy.go index d4c94458bd99..78f02b1b4959 100644 --- a/vendor/google.golang.org/protobuf/internal/filedesc/desc_lazy.go +++ b/vendor/google.golang.org/protobuf/internal/filedesc/desc_lazy.go @@ -134,6 +134,7 @@ func (fd *File) unmarshalFull(b []byte) { var enumIdx, messageIdx, extensionIdx, serviceIdx int var rawOptions []byte + var optionImports []string fd.L2 = new(FileL2) for len(b) > 0 { num, typ, n := protowire.ConsumeTag(b) @@ -157,6 +158,8 @@ func (fd *File) unmarshalFull(b []byte) { imp = PlaceholderFile(path) } fd.L2.Imports = append(fd.L2.Imports, protoreflect.FileImport{FileDescriptor: imp}) + case genid.FileDescriptorProto_OptionDependency_field_number: + optionImports = append(optionImports, sb.MakeString(v)) case genid.FileDescriptorProto_EnumType_field_number: fd.L1.Enums.List[enumIdx].unmarshalFull(v, sb) enumIdx++ @@ -178,6 +181,23 @@ func (fd *File) unmarshalFull(b []byte) { } } fd.L2.Options = fd.builder.optionsUnmarshaler(&descopts.File, rawOptions) + if len(optionImports) > 0 { + var imps FileImports + var once sync.Once + fd.L2.OptionImports = func() protoreflect.FileImports { + once.Do(func() { + imps = make(FileImports, len(optionImports)) + for i, path := range optionImports { + imp, _ := fd.builder.FileRegistry.FindFileByPath(path) + if imp == nil { + imp = PlaceholderFile(path) + } + imps[i] = protoreflect.FileImport{FileDescriptor: imp} + } + }) + return &imps + } + } } func (ed *Enum) unmarshalFull(b []byte, sb *strs.Builder) { @@ -310,7 +330,6 @@ func (md *Message) unmarshalFull(b []byte, sb *strs.Builder) { md.L1.Extensions.List[extensionIdx].unmarshalFull(v, sb) extensionIdx++ case genid.DescriptorProto_Options_field_number: - md.unmarshalOptions(v) rawOptions = appendOptions(rawOptions, v) } default: @@ -336,27 +355,6 @@ func (md *Message) unmarshalFull(b []byte, sb *strs.Builder) { md.L2.Options = md.L0.ParentFile.builder.optionsUnmarshaler(&descopts.Message, rawOptions) } -func (md *Message) unmarshalOptions(b []byte) { - for len(b) > 0 { - num, typ, n := protowire.ConsumeTag(b) - b = b[n:] - switch typ { - case protowire.VarintType: - v, m := protowire.ConsumeVarint(b) - b = b[m:] - switch num { - case genid.MessageOptions_MapEntry_field_number: - md.L1.IsMapEntry = protowire.DecodeBool(v) - case genid.MessageOptions_MessageSetWireFormat_field_number: - md.L1.IsMessageSet = protowire.DecodeBool(v) - } - default: - m := protowire.ConsumeFieldValue(num, typ, b) - b = b[m:] - } - } -} - func unmarshalMessageReservedRange(b []byte) (r [2]protoreflect.FieldNumber) { for len(b) > 0 { num, typ, n := protowire.ConsumeTag(b) diff --git a/vendor/google.golang.org/protobuf/internal/filedesc/editions.go b/vendor/google.golang.org/protobuf/internal/filedesc/editions.go index a0aad2777f3f..66ba906806fc 100644 --- a/vendor/google.golang.org/protobuf/internal/filedesc/editions.go +++ b/vendor/google.golang.org/protobuf/internal/filedesc/editions.go @@ -13,8 +13,10 @@ import ( "google.golang.org/protobuf/reflect/protoreflect" ) -var defaultsCache = make(map[Edition]EditionFeatures) -var defaultsKeys = []Edition{} +var ( + defaultsCache = make(map[Edition]EditionFeatures) + defaultsKeys = []Edition{} +) func init() { unmarshalEditionDefaults(editiondefaults.Defaults) @@ -41,7 +43,7 @@ func unmarshalGoFeature(b []byte, parent EditionFeatures) EditionFeatures { b = b[m:] parent.StripEnumPrefix = int(v) default: - panic(fmt.Sprintf("unkown field number %d while unmarshalling GoFeatures", num)) + panic(fmt.Sprintf("unknown field number %d while unmarshalling GoFeatures", num)) } } return parent @@ -76,7 +78,7 @@ func unmarshalFeatureSet(b []byte, parent EditionFeatures) EditionFeatures { // DefaultSymbolVisibility is enforced in protoc, runtimes should not // inspect this value. default: - panic(fmt.Sprintf("unkown field number %d while unmarshalling FeatureSet", num)) + panic(fmt.Sprintf("unknown field number %d while unmarshalling FeatureSet", num)) } case protowire.BytesType: v, m := protowire.ConsumeBytes(b) @@ -150,7 +152,7 @@ func unmarshalEditionDefaults(b []byte) { _, m := protowire.ConsumeVarint(b) b = b[m:] default: - panic(fmt.Sprintf("unkown field number %d while unmarshalling EditionDefault", num)) + panic(fmt.Sprintf("unknown field number %d while unmarshalling EditionDefault", num)) } } } diff --git a/vendor/google.golang.org/protobuf/internal/genid/descriptor_gen.go b/vendor/google.golang.org/protobuf/internal/genid/descriptor_gen.go index 950a6a325a47..65aaf4d210af 100644 --- a/vendor/google.golang.org/protobuf/internal/genid/descriptor_gen.go +++ b/vendor/google.golang.org/protobuf/internal/genid/descriptor_gen.go @@ -26,6 +26,7 @@ const ( Edition_EDITION_PROTO3_enum_value = 999 Edition_EDITION_2023_enum_value = 1000 Edition_EDITION_2024_enum_value = 1001 + Edition_EDITION_UNSTABLE_enum_value = 9999 Edition_EDITION_1_TEST_ONLY_enum_value = 1 Edition_EDITION_2_TEST_ONLY_enum_value = 2 Edition_EDITION_99997_TEST_ONLY_enum_value = 99997 diff --git a/vendor/google.golang.org/protobuf/internal/impl/codec_map.go b/vendor/google.golang.org/protobuf/internal/impl/codec_map.go index 229c69801386..4a3bf393ef4c 100644 --- a/vendor/google.golang.org/protobuf/internal/impl/codec_map.go +++ b/vendor/google.golang.org/protobuf/internal/impl/codec_map.go @@ -113,6 +113,9 @@ func sizeMap(mapv reflect.Value, mapi *mapInfo, f *coderFieldInfo, opts marshalO } func consumeMap(b []byte, mapv reflect.Value, wtyp protowire.Type, mapi *mapInfo, f *coderFieldInfo, opts unmarshalOptions) (out unmarshalOutput, err error) { + if opts.depth--; opts.depth < 0 { + return out, errRecursionDepth + } if wtyp != protowire.BytesType { return out, errUnknown } @@ -170,6 +173,9 @@ func consumeMap(b []byte, mapv reflect.Value, wtyp protowire.Type, mapi *mapInfo } func consumeMapOfMessage(b []byte, mapv reflect.Value, wtyp protowire.Type, mapi *mapInfo, f *coderFieldInfo, opts unmarshalOptions) (out unmarshalOutput, err error) { + if opts.depth--; opts.depth < 0 { + return out, errRecursionDepth + } if wtyp != protowire.BytesType { return out, errUnknown } diff --git a/vendor/google.golang.org/protobuf/internal/impl/decode.go b/vendor/google.golang.org/protobuf/internal/impl/decode.go index e0dd21fa5f4f..1228b5c8c271 100644 --- a/vendor/google.golang.org/protobuf/internal/impl/decode.go +++ b/vendor/google.golang.org/protobuf/internal/impl/decode.go @@ -102,8 +102,7 @@ var errUnknown = errors.New("unknown") func (mi *MessageInfo) unmarshalPointer(b []byte, p pointer, groupTag protowire.Number, opts unmarshalOptions) (out unmarshalOutput, err error) { mi.init() - opts.depth-- - if opts.depth < 0 { + if opts.depth--; opts.depth < 0 { return out, errRecursionDepth } if flags.ProtoLegacy && mi.isMessageSet { diff --git a/vendor/google.golang.org/protobuf/internal/impl/validate.go b/vendor/google.golang.org/protobuf/internal/impl/validate.go index 7b2995dde5eb..99a1eb95f7c4 100644 --- a/vendor/google.golang.org/protobuf/internal/impl/validate.go +++ b/vendor/google.golang.org/protobuf/internal/impl/validate.go @@ -68,9 +68,13 @@ func Validate(mt protoreflect.MessageType, in protoiface.UnmarshalInput) (out pr if in.Resolver == nil { in.Resolver = protoregistry.GlobalTypes } + if in.Depth == 0 { + in.Depth = protowire.DefaultRecursionLimit + } o, st := mi.validate(in.Buf, 0, unmarshalOptions{ flags: in.Flags, resolver: in.Resolver, + depth: in.Depth, }) if o.initialized { out.Flags |= protoiface.UnmarshalInitialized @@ -257,6 +261,9 @@ func (mi *MessageInfo) validate(b []byte, groupTag protowire.Number, opts unmars states[0].typ = validationTypeGroup states[0].endGroup = groupTag } + if opts.depth--; opts.depth < 0 { + return out, ValidationInvalid + } initialized := true start := len(b) State: @@ -451,6 +458,13 @@ State: mi: vi.mi, tail: b, }) + if vi.typ == validationTypeMessage || + vi.typ == validationTypeGroup || + vi.typ == validationTypeMap { + if opts.depth--; opts.depth < 0 { + return out, ValidationInvalid + } + } b = v continue State case validationTypeRepeatedVarint: @@ -499,6 +513,9 @@ State: mi: vi.mi, endGroup: num, }) + if opts.depth--; opts.depth < 0 { + return out, ValidationInvalid + } continue State case flags.ProtoLegacy && vi.typ == validationTypeMessageSetItem: typeid, v, n, err := messageset.ConsumeFieldValue(b, false) @@ -521,6 +538,13 @@ State: mi: xvi.mi, tail: b[n:], }) + if xvi.typ == validationTypeMessage || + xvi.typ == validationTypeGroup || + xvi.typ == validationTypeMap { + if opts.depth--; opts.depth < 0 { + return out, ValidationInvalid + } + } b = v continue State } @@ -547,12 +571,14 @@ State: switch st.typ { case validationTypeMessage, validationTypeGroup: numRequiredFields = int(st.mi.numRequiredFields) + opts.depth++ case validationTypeMap: // If this is a map field with a message value that contains // required fields, require that the value be present. if st.mi != nil && st.mi.numRequiredFields > 0 { numRequiredFields = 1 } + opts.depth++ } // If there are more than 64 required fields, this check will // always fail and we will report that the message is potentially diff --git a/vendor/google.golang.org/protobuf/internal/version/version.go b/vendor/google.golang.org/protobuf/internal/version/version.go index 697d1c14f3c8..bfb2cfdea5b4 100644 --- a/vendor/google.golang.org/protobuf/internal/version/version.go +++ b/vendor/google.golang.org/protobuf/internal/version/version.go @@ -52,8 +52,8 @@ import ( const ( Major = 1 Minor = 36 - Patch = 8 - PreRelease = "" + Patch = 11 + PreRelease = "devel" ) // String formats the version string for this module in semver format. diff --git a/vendor/google.golang.org/protobuf/proto/decode.go b/vendor/google.golang.org/protobuf/proto/decode.go index 4cbf1aeaf79c..889d8511d275 100644 --- a/vendor/google.golang.org/protobuf/proto/decode.go +++ b/vendor/google.golang.org/protobuf/proto/decode.go @@ -121,9 +121,8 @@ func (o UnmarshalOptions) unmarshal(b []byte, m protoreflect.Message) (out proto out, err = methods.Unmarshal(in) } else { - o.RecursionLimit-- - if o.RecursionLimit < 0 { - return out, errors.New("exceeded max recursion depth") + if o.RecursionLimit--; o.RecursionLimit < 0 { + return out, errRecursionDepth } err = o.unmarshalMessageSlow(b, m) } @@ -220,6 +219,9 @@ func (o UnmarshalOptions) unmarshalSingular(b []byte, wtyp protowire.Type, m pro } func (o UnmarshalOptions) unmarshalMap(b []byte, wtyp protowire.Type, mapv protoreflect.Map, fd protoreflect.FieldDescriptor) (n int, err error) { + if o.RecursionLimit--; o.RecursionLimit < 0 { + return 0, errRecursionDepth + } if wtyp != protowire.BytesType { return 0, errUnknown } @@ -305,3 +307,5 @@ func (o UnmarshalOptions) unmarshalMap(b []byte, wtyp protowire.Type, mapv proto var errUnknown = errors.New("BUG: internal error (unknown)") var errDecode = errors.New("cannot parse invalid wire-format data") + +var errRecursionDepth = errors.New("exceeded maximum recursion depth") diff --git a/vendor/google.golang.org/protobuf/reflect/protodesc/desc.go b/vendor/google.golang.org/protobuf/reflect/protodesc/desc.go index 823dbf3ba6cd..40f17af4e3cb 100644 --- a/vendor/google.golang.org/protobuf/reflect/protodesc/desc.go +++ b/vendor/google.golang.org/protobuf/reflect/protodesc/desc.go @@ -108,7 +108,9 @@ func (o FileOptions) New(fd *descriptorpb.FileDescriptorProto, r Resolver) (prot if f.L1.Path == "" { return nil, errors.New("file path must be populated") } - if f.L1.Syntax == protoreflect.Editions && (fd.GetEdition() < editionssupport.Minimum || fd.GetEdition() > editionssupport.Maximum) { + if f.L1.Syntax == protoreflect.Editions && + (fd.GetEdition() < editionssupport.Minimum || fd.GetEdition() > editionssupport.Maximum) && + fd.GetEdition() != descriptorpb.Edition_EDITION_UNSTABLE { // Allow cmd/protoc-gen-go/testdata to use any edition for easier // testing of upcoming edition features. if !strings.HasPrefix(fd.GetName(), "cmd/protoc-gen-go/testdata/") { @@ -152,6 +154,31 @@ func (o FileOptions) New(fd *descriptorpb.FileDescriptorProto, r Resolver) (prot imp := &f.L2.Imports[i] imps.importPublic(imp.Imports()) } + optionImps := importSet{f.Path(): true} + if len(fd.GetOptionDependency()) > 0 { + optionImports := make(filedesc.FileImports, len(fd.GetOptionDependency())) + for i, path := range fd.GetOptionDependency() { + imp := &optionImports[i] + f, err := r.FindFileByPath(path) + if err == protoregistry.NotFound { + // We always allow option imports to be unresolvable. + f = filedesc.PlaceholderFile(path) + } else if err != nil { + return nil, errors.New("could not resolve import %q: %v", path, err) + } + imp.FileDescriptor = f + + if imps[imp.Path()] || optionImps[imp.Path()] { + return nil, errors.New("already imported %q", path) + } + // This needs to be a separate map so that we don't recognize non-options + // symbols coming from option imports. + optionImps[imp.Path()] = true + } + f.L2.OptionImports = func() protoreflect.FileImports { + return &optionImports + } + } // Handle source locations. f.L2.Locations.File = f diff --git a/vendor/google.golang.org/protobuf/reflect/protodesc/desc_init.go b/vendor/google.golang.org/protobuf/reflect/protodesc/desc_init.go index 9da34998b171..84a3228edb4a 100644 --- a/vendor/google.golang.org/protobuf/reflect/protodesc/desc_init.go +++ b/vendor/google.golang.org/protobuf/reflect/protodesc/desc_init.go @@ -29,6 +29,7 @@ func (r descsByName) initEnumDeclarations(eds []*descriptorpb.EnumDescriptorProt e.L2.Options = func() protoreflect.ProtoMessage { return opts } } e.L1.EditionFeatures = mergeEditionFeatures(parent, ed.GetOptions().GetFeatures()) + e.L1.Visibility = int32(ed.GetVisibility()) for _, s := range ed.GetReservedName() { e.L2.ReservedNames.List = append(e.L2.ReservedNames.List, protoreflect.Name(s)) } @@ -70,6 +71,7 @@ func (r descsByName) initMessagesDeclarations(mds []*descriptorpb.DescriptorProt return nil, err } m.L1.EditionFeatures = mergeEditionFeatures(parent, md.GetOptions().GetFeatures()) + m.L1.Visibility = int32(md.GetVisibility()) if opts := md.GetOptions(); opts != nil { opts = proto.Clone(opts).(*descriptorpb.MessageOptions) m.L2.Options = func() protoreflect.ProtoMessage { return opts } @@ -199,6 +201,7 @@ func (r descsByName) initExtensionDeclarations(xds []*descriptorpb.FieldDescript return nil, err } x.L1.EditionFeatures = mergeEditionFeatures(parent, xd.GetOptions().GetFeatures()) + x.L2.IsProto3Optional = xd.GetProto3Optional() if opts := xd.GetOptions(); opts != nil { opts = proto.Clone(opts).(*descriptorpb.FieldOptions) x.L2.Options = func() protoreflect.ProtoMessage { return opts } diff --git a/vendor/google.golang.org/protobuf/reflect/protodesc/editions.go b/vendor/google.golang.org/protobuf/reflect/protodesc/editions.go index 697a61b290eb..147b8c7398d5 100644 --- a/vendor/google.golang.org/protobuf/reflect/protodesc/editions.go +++ b/vendor/google.golang.org/protobuf/reflect/protodesc/editions.go @@ -46,6 +46,8 @@ func toEditionProto(ed filedesc.Edition) descriptorpb.Edition { return descriptorpb.Edition_EDITION_2023 case filedesc.Edition2024: return descriptorpb.Edition_EDITION_2024 + case filedesc.EditionUnstable: + return descriptorpb.Edition_EDITION_UNSTABLE default: panic(fmt.Sprintf("unknown value for edition: %v", ed)) } @@ -58,7 +60,7 @@ func getFeatureSetFor(ed filedesc.Edition) *descriptorpb.FeatureSet { return def } edpb := toEditionProto(ed) - if defaults.GetMinimumEdition() > edpb || defaults.GetMaximumEdition() < edpb { + if (defaults.GetMinimumEdition() > edpb || defaults.GetMaximumEdition() < edpb) && edpb != descriptorpb.Edition_EDITION_UNSTABLE { // This should never happen protodesc.(FileOptions).New would fail when // initializing the file descriptor. // This most likely means the embedded defaults were not updated. diff --git a/vendor/google.golang.org/protobuf/reflect/protodesc/proto.go b/vendor/google.golang.org/protobuf/reflect/protodesc/proto.go index 9b880aa8c961..6f91074e36a1 100644 --- a/vendor/google.golang.org/protobuf/reflect/protodesc/proto.go +++ b/vendor/google.golang.org/protobuf/reflect/protodesc/proto.go @@ -70,16 +70,27 @@ func ToFileDescriptorProto(file protoreflect.FileDescriptor) *descriptorpb.FileD if syntax := file.Syntax(); syntax != protoreflect.Proto2 && syntax.IsValid() { p.Syntax = proto.String(file.Syntax().String()) } + desc := file + if fileImportDesc, ok := file.(protoreflect.FileImport); ok { + desc = fileImportDesc.FileDescriptor + } if file.Syntax() == protoreflect.Editions { - desc := file - if fileImportDesc, ok := file.(protoreflect.FileImport); ok { - desc = fileImportDesc.FileDescriptor - } - if editionsInterface, ok := desc.(interface{ Edition() int32 }); ok { p.Edition = descriptorpb.Edition(editionsInterface.Edition()).Enum() } } + type hasOptionImports interface { + OptionImports() protoreflect.FileImports + } + if opts, ok := desc.(hasOptionImports); ok { + if optionImports := opts.OptionImports(); optionImports.Len() > 0 { + optionDeps := make([]string, optionImports.Len()) + for i := range optionImports.Len() { + optionDeps[i] = optionImports.Get(i).Path() + } + p.OptionDependency = optionDeps + } + } return p } @@ -123,6 +134,14 @@ func ToDescriptorProto(message protoreflect.MessageDescriptor) *descriptorpb.Des for i, names := 0, message.ReservedNames(); i < names.Len(); i++ { p.ReservedName = append(p.ReservedName, string(names.Get(i))) } + type hasVisibility interface { + Visibility() int32 + } + if vis, ok := message.(hasVisibility); ok { + if visibility := vis.Visibility(); visibility > 0 { + p.Visibility = descriptorpb.SymbolVisibility(visibility).Enum() + } + } return p } @@ -216,6 +235,14 @@ func ToEnumDescriptorProto(enum protoreflect.EnumDescriptor) *descriptorpb.EnumD for i, names := 0, enum.ReservedNames(); i < names.Len(); i++ { p.ReservedName = append(p.ReservedName, string(names.Get(i))) } + type hasVisibility interface { + Visibility() int32 + } + if vis, ok := enum.(hasVisibility); ok { + if visibility := vis.Visibility(); visibility > 0 { + p.Visibility = descriptorpb.SymbolVisibility(visibility).Enum() + } + } return p } diff --git a/vendor/google.golang.org/protobuf/types/descriptorpb/descriptor.pb.go b/vendor/google.golang.org/protobuf/types/descriptorpb/descriptor.pb.go index 4eacb523c33a..0b23faa957c9 100644 --- a/vendor/google.golang.org/protobuf/types/descriptorpb/descriptor.pb.go +++ b/vendor/google.golang.org/protobuf/types/descriptorpb/descriptor.pb.go @@ -69,6 +69,8 @@ const ( // comparison. Edition_EDITION_2023 Edition = 1000 Edition_EDITION_2024 Edition = 1001 + // A placeholder edition for developing and testing unscheduled features. + Edition_EDITION_UNSTABLE Edition = 9999 // Placeholder editions for testing feature resolution. These should not be // used or relied on outside of tests. Edition_EDITION_1_TEST_ONLY Edition = 1 @@ -91,6 +93,7 @@ var ( 999: "EDITION_PROTO3", 1000: "EDITION_2023", 1001: "EDITION_2024", + 9999: "EDITION_UNSTABLE", 1: "EDITION_1_TEST_ONLY", 2: "EDITION_2_TEST_ONLY", 99997: "EDITION_99997_TEST_ONLY", @@ -105,6 +108,7 @@ var ( "EDITION_PROTO3": 999, "EDITION_2023": 1000, "EDITION_2024": 1001, + "EDITION_UNSTABLE": 9999, "EDITION_1_TEST_ONLY": 1, "EDITION_2_TEST_ONLY": 2, "EDITION_99997_TEST_ONLY": 99997, @@ -4793,11 +4797,11 @@ const file_google_protobuf_descriptor_proto_rawDesc = "" + "\x18EnumValueDescriptorProto\x12\x12\n" + "\x04name\x18\x01 \x01(\tR\x04name\x12\x16\n" + "\x06number\x18\x02 \x01(\x05R\x06number\x12;\n" + - "\aoptions\x18\x03 \x01(\v2!.google.protobuf.EnumValueOptionsR\aoptions\"\xa7\x01\n" + + "\aoptions\x18\x03 \x01(\v2!.google.protobuf.EnumValueOptionsR\aoptions\"\xb5\x01\n" + "\x16ServiceDescriptorProto\x12\x12\n" + "\x04name\x18\x01 \x01(\tR\x04name\x12>\n" + "\x06method\x18\x02 \x03(\v2&.google.protobuf.MethodDescriptorProtoR\x06method\x129\n" + - "\aoptions\x18\x03 \x01(\v2\x1f.google.protobuf.ServiceOptionsR\aoptions\"\x89\x02\n" + + "\aoptions\x18\x03 \x01(\v2\x1f.google.protobuf.ServiceOptionsR\aoptionsJ\x04\b\x04\x10\x05R\x06stream\"\x89\x02\n" + "\x15MethodDescriptorProto\x12\x12\n" + "\x04name\x18\x01 \x01(\tR\x04name\x12\x1d\n" + "\n" + @@ -5033,14 +5037,15 @@ const file_google_protobuf_descriptor_proto_rawDesc = "" + "\bSemantic\x12\b\n" + "\x04NONE\x10\x00\x12\a\n" + "\x03SET\x10\x01\x12\t\n" + - "\x05ALIAS\x10\x02*\xa7\x02\n" + + "\x05ALIAS\x10\x02*\xbe\x02\n" + "\aEdition\x12\x13\n" + "\x0fEDITION_UNKNOWN\x10\x00\x12\x13\n" + "\x0eEDITION_LEGACY\x10\x84\a\x12\x13\n" + "\x0eEDITION_PROTO2\x10\xe6\a\x12\x13\n" + "\x0eEDITION_PROTO3\x10\xe7\a\x12\x11\n" + "\fEDITION_2023\x10\xe8\a\x12\x11\n" + - "\fEDITION_2024\x10\xe9\a\x12\x17\n" + + "\fEDITION_2024\x10\xe9\a\x12\x15\n" + + "\x10EDITION_UNSTABLE\x10\x8fN\x12\x17\n" + "\x13EDITION_1_TEST_ONLY\x10\x01\x12\x17\n" + "\x13EDITION_2_TEST_ONLY\x10\x02\x12\x1d\n" + "\x17EDITION_99997_TEST_ONLY\x10\x9d\x8d\x06\x12\x1d\n" + diff --git a/vendor/google.golang.org/protobuf/types/known/timestamppb/timestamp.pb.go b/vendor/google.golang.org/protobuf/types/known/timestamppb/timestamp.pb.go index 06d584c14bea..484c21fd536c 100644 --- a/vendor/google.golang.org/protobuf/types/known/timestamppb/timestamp.pb.go +++ b/vendor/google.golang.org/protobuf/types/known/timestamppb/timestamp.pb.go @@ -172,13 +172,14 @@ import ( // ) to obtain a formatter capable of generating timestamps in this format. type Timestamp struct { state protoimpl.MessageState `protogen:"open.v1"` - // Represents seconds of UTC time since Unix epoch - // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to - // 9999-12-31T23:59:59Z inclusive. + // Represents seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z. Must + // be between -315576000000 and 315576000000 inclusive (which corresponds to + // 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z). Seconds int64 `protobuf:"varint,1,opt,name=seconds,proto3" json:"seconds,omitempty"` - // Non-negative fractions of a second at nanosecond resolution. Negative - // second values with fractions must still have non-negative nanos values - // that count forward in time. Must be from 0 to 999,999,999 + // Non-negative fractions of a second at nanosecond resolution. This field is + // the nanosecond portion of the duration, not an alternative to seconds. + // Negative second values with fractions must still have non-negative nanos + // values that count forward in time. Must be between 0 and 999,999,999 // inclusive. Nanos int32 `protobuf:"varint,2,opt,name=nanos,proto3" json:"nanos,omitempty"` unknownFields protoimpl.UnknownFields diff --git a/vendor/modules.txt b/vendor/modules.txt index 09c432c4663c..480faf002ecb 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1601,8 +1601,8 @@ github.com/openshift-kni/commatrix/pkg/matrix-diff github.com/openshift-kni/commatrix/pkg/mcp github.com/openshift-kni/commatrix/pkg/types github.com/openshift-kni/commatrix/pkg/utils -# github.com/openshift/api v0.0.0-20260629123346-784126000268 -## explicit; go 1.25.0 +# github.com/openshift/api v0.0.0-20260715165912-72066cc9718b +## explicit; go 1.26.0 github.com/openshift/api github.com/openshift/api/annotations github.com/openshift/api/apiextensions @@ -2762,7 +2762,7 @@ google.golang.org/grpc/xds/internal/xdsclient/xdslbregistry google.golang.org/grpc/xds/internal/xdsclient/xdslbregistry/converter google.golang.org/grpc/xds/internal/xdsclient/xdsresource google.golang.org/grpc/xds/internal/xdsclient/xdsresource/version -# google.golang.org/protobuf v1.36.8 +# google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af ## explicit; go 1.23 google.golang.org/protobuf/encoding/protodelim google.golang.org/protobuf/encoding/protojson @@ -2884,7 +2884,7 @@ gopkg.in/yaml.v2 # gopkg.in/yaml.v3 v3.0.1 ## explicit gopkg.in/yaml.v3 -# k8s.io/api v0.35.1 => github.com/openshift/kubernetes/staging/src/k8s.io/api v0.0.0-20260305123649-d18f3f005eaa +# k8s.io/api v0.36.2 => github.com/openshift/kubernetes/staging/src/k8s.io/api v0.0.0-20260305123649-d18f3f005eaa ## explicit; go 1.25.0 k8s.io/api/admission/v1 k8s.io/api/admission/v1beta1 @@ -2996,7 +2996,7 @@ k8s.io/apiextensions-apiserver/pkg/registry/customresource/tableconvertor k8s.io/apiextensions-apiserver/pkg/registry/customresourcedefinition k8s.io/apiextensions-apiserver/test/integration k8s.io/apiextensions-apiserver/test/integration/fixtures -# k8s.io/apimachinery v0.35.1 => github.com/openshift/kubernetes/staging/src/k8s.io/apimachinery v0.0.0-20260305123649-d18f3f005eaa +# k8s.io/apimachinery v0.36.2 => github.com/openshift/kubernetes/staging/src/k8s.io/apimachinery v0.0.0-20260305123649-d18f3f005eaa ## explicit; go 1.25.0 k8s.io/apimachinery/pkg/api/apitesting k8s.io/apimachinery/pkg/api/equality From d4126634972c4369ea7091468f1b15ab1f1cd023 Mon Sep 17 00:00:00 2001 From: Evan Hearne Date: Thu, 16 Jul 2026 16:12:38 +0100 Subject: [PATCH 2/5] export reusable keycloak func/var --- .../authentication/keycloak_client.go | 30 +++--- .../authentication/keycloak_helpers.go | 40 ++++---- test/extended/authentication/oidc.go | 92 +++++++++---------- 3 files changed, 81 insertions(+), 81 deletions(-) diff --git a/test/extended/authentication/keycloak_client.go b/test/extended/authentication/keycloak_client.go index a91283139f30..8fa6821d1524 100644 --- a/test/extended/authentication/keycloak_client.go +++ b/test/extended/authentication/keycloak_client.go @@ -12,7 +12,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" ) -type keycloakClient struct { +type KeycloakClient struct { realm string client *http.Client adminURL *url.URL @@ -21,7 +21,7 @@ type keycloakClient struct { idToken string } -func keycloakClientFor(keycloakURL string) (*keycloakClient, error) { +func KeycloakClientFor(keycloakURL string) (*KeycloakClient, error) { baseURL, err := url.Parse(keycloakURL) if err != nil { return nil, fmt.Errorf("parsing url: %w", err) @@ -34,7 +34,7 @@ func keycloakClientFor(keycloakURL string) (*keycloakClient, error) { Proxy: http.ProxyFromEnvironment, } - return &keycloakClient{ + return &KeycloakClient{ realm: "master", client: &http.Client{ Transport: transport, @@ -47,7 +47,7 @@ type group struct { Name string `json:"name"` } -func (kc *keycloakClient) CreateGroup(name string) error { +func (kc *KeycloakClient) CreateGroup(name string) error { groupURL := kc.adminURL.JoinPath("groups") group := group{ @@ -95,11 +95,11 @@ const ( credentialTypePassword credentialType = "password" ) -func (kc *keycloakClient) CreateUser(username, password string, groups ...string) error { +func (kc *KeycloakClient) CreateUser(username, password string, groups ...string) error { return kc.CreateUserWithEmail(username, fmt.Sprintf("%s@payload.openshift.io", username), password, groups...) } -func (kc *keycloakClient) CreateUserWithEmail(username, email, password string, groups ...string) error { +func (kc *KeycloakClient) CreateUserWithEmail(username, email, password string, groups ...string) error { userURL := kc.adminURL.JoinPath("users") user := user{ @@ -143,7 +143,7 @@ type authenticationResponse struct { ErrorDescription string `json:"error_description,omitempty"` } -func (kc *keycloakClient) Authenticate(clientID, username, password string) error { +func (kc *KeycloakClient) Authenticate(clientID, username, password string) error { data := url.Values{} data.Set("username", username) data.Set("password", password) @@ -177,7 +177,7 @@ func (kc *keycloakClient) Authenticate(clientID, username, password string) erro return nil } -func (kc *keycloakClient) DoRequest(method, url, contentType string, authenticated bool, body io.Reader) (*http.Response, error) { +func (kc *KeycloakClient) DoRequest(method, url, contentType string, authenticated bool, body io.Reader) (*http.Response, error) { if len(kc.accessToken) == 0 && authenticated { panic("must authenticate before calling keycloakClient.DoRequest") } @@ -194,15 +194,15 @@ func (kc *keycloakClient) DoRequest(method, url, contentType string, authenticat return kc.client.Do(req) } -func (kc *keycloakClient) AccessToken() string { +func (kc *KeycloakClient) AccessToken() string { return kc.accessToken } -func (kc *keycloakClient) IdToken() string { +func (kc *KeycloakClient) IdToken() string { return kc.idToken } -func (kc *keycloakClient) ConfigureClient(clientId string) error { +func (kc *KeycloakClient) ConfigureClient(clientId string) error { client, err := kc.GetClientByClientID(clientId) if err != nil { return fmt.Errorf("getting client %q: %w", clientId, err) @@ -254,7 +254,7 @@ const ( booleanStringFalse booleanString = "false" ) -func (kc *keycloakClient) CreateClientGroupMapper(clientId, name, claim string) error { +func (kc *KeycloakClient) CreateClientGroupMapper(clientId, name, claim string) error { mappersURL := *kc.adminURL mappersURL.Path += fmt.Sprintf("/clients/%s/protocol-mappers/models", clientId) @@ -307,7 +307,7 @@ type audienceMapperConfig struct { LightweightClaim booleanString `json:"lightweight.claim"` } -func (kc *keycloakClient) CreateClientAudienceMapper(clientId, name string) error { +func (kc *KeycloakClient) CreateClientAudienceMapper(clientId, name string) error { mappersURL := *kc.adminURL mappersURL.Path += fmt.Sprintf("/clients/%s/protocol-mappers/models", clientId) @@ -350,7 +350,7 @@ type client struct { } // ListClients retrieves all clients -func (kc *keycloakClient) ListClients() ([]client, error) { +func (kc *KeycloakClient) ListClients() ([]client, error) { clientsURL := *kc.adminURL clientsURL.Path += "/clients" @@ -373,7 +373,7 @@ func (kc *keycloakClient) ListClients() ([]client, error) { return clients, err } -func (kc *keycloakClient) GetClientByClientID(clientID string) (*client, error) { +func (kc *KeycloakClient) GetClientByClientID(clientID string) (*client, error) { clients, err := kc.ListClients() if err != nil { return nil, err diff --git a/test/extended/authentication/keycloak_helpers.go b/test/extended/authentication/keycloak_helpers.go index a8c2465f6130..428791f0e7f7 100644 --- a/test/extended/authentication/keycloak_helpers.go +++ b/test/extended/authentication/keycloak_helpers.go @@ -24,7 +24,7 @@ import ( ) const ( - keycloakResourceName = "keycloak" + KeycloakResourceName = "keycloak" keycloakServingCertSecretName = "keycloak-serving-cert" keycloakLabelKey = "app" keycloakLabelValue = "keycloak" @@ -32,16 +32,16 @@ const ( // TODO: should this be an openshift image? keycloakImage = "quay.io/keycloak/keycloak:25.0" - keycloakAdminUsername = "admin" - keycloakAdminPassword = "password" + KeycloakAdminUsername = "admin" + KeycloakAdminPassword = "password" keycloakCertVolumeName = "certkeypair" keycloakCertMountPath = "/etc/x509/https" keycloakCertFile = "tls.crt" keycloakKeyFile = "tls.key" ) -func deployKeycloak(ctx context.Context, client *exutil.CLI, namespace string, logger logr.Logger) ([]removalFunc, error) { - cleanups := []removalFunc{} +func DeployKeycloak(ctx context.Context, client *exutil.CLI, namespace string, logger logr.Logger) ([]RemovalFunc, error) { + cleanups := []RemovalFunc{} corev1Client := client.AdminKubeClient().CoreV1() @@ -84,7 +84,7 @@ func deployKeycloak(ctx context.Context, client *exutil.CLI, namespace string, l return cleanups, waitForKeycloakAvailable(ctx, client, namespace, logger) } -func createKeycloakNamespace(ctx context.Context, client typedcorev1.NamespaceInterface, namespace string) (removalFunc, error) { +func createKeycloakNamespace(ctx context.Context, client typedcorev1.NamespaceInterface, namespace string) (RemovalFunc, error) { ns := &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ Name: namespace, @@ -101,10 +101,10 @@ func createKeycloakNamespace(ctx context.Context, client typedcorev1.NamespaceIn }, nil } -func createKeycloakServiceAccount(ctx context.Context, client typedcorev1.ServiceAccountInterface) (removalFunc, error) { +func createKeycloakServiceAccount(ctx context.Context, client typedcorev1.ServiceAccountInterface) (RemovalFunc, error) { sa := &corev1.ServiceAccount{ ObjectMeta: metav1.ObjectMeta{ - Name: keycloakResourceName, + Name: KeycloakResourceName, }, } sa.SetGroupVersionKind(corev1.SchemeGroupVersion.WithKind("ServiceAccount")) @@ -119,10 +119,10 @@ func createKeycloakServiceAccount(ctx context.Context, client typedcorev1.Servic }, nil } -func createKeycloakService(ctx context.Context, client typedcorev1.ServiceInterface) (*corev1.Service, removalFunc, error) { +func createKeycloakService(ctx context.Context, client typedcorev1.ServiceInterface) (*corev1.Service, RemovalFunc, error) { service := &corev1.Service{ ObjectMeta: metav1.ObjectMeta{ - Name: keycloakResourceName, + Name: KeycloakResourceName, Annotations: map[string]string{ "service.beta.openshift.io/serving-cert-secret-name": keycloakServingCertSecretName, }, @@ -149,7 +149,7 @@ func createKeycloakService(ctx context.Context, client typedcorev1.ServiceInterf }, nil } -func createKeycloakCAConfigMap(ctx context.Context, client typedcorev1.ConfigMapsGetter) (removalFunc, error) { +func createKeycloakCAConfigMap(ctx context.Context, client typedcorev1.ConfigMapsGetter) (RemovalFunc, error) { defaultIngressCACM, err := client.ConfigMaps("openshift-config-managed").Get(ctx, "default-ingress-cert", metav1.GetOptions{}) if err != nil { return nil, fmt.Errorf("getting configmap openshift-config-managed/default-ingress-cert: %w", err) @@ -159,7 +159,7 @@ func createKeycloakCAConfigMap(ctx context.Context, client typedcorev1.ConfigMap keycloakCACM := &corev1.ConfigMap{ ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf("%s-ca", keycloakResourceName), + Name: fmt.Sprintf("%s-ca", KeycloakResourceName), }, Data: map[string]string{ "ca-bundle.crt": data, @@ -177,10 +177,10 @@ func createKeycloakCAConfigMap(ctx context.Context, client typedcorev1.ConfigMap }, nil } -func createKeycloakDeployment(ctx context.Context, client typedappsv1.DeploymentInterface) (removalFunc, error) { +func createKeycloakDeployment(ctx context.Context, client typedappsv1.DeploymentInterface) (RemovalFunc, error) { deployment := &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ - Name: keycloakResourceName, + Name: KeycloakResourceName, Labels: keycloakLabels(), }, Spec: appsv1.DeploymentSpec{ @@ -190,7 +190,7 @@ func createKeycloakDeployment(ctx context.Context, client typedappsv1.Deployment Replicas: ptr.To(int32(1)), Template: corev1.PodTemplateSpec{ ObjectMeta: metav1.ObjectMeta{ - Name: keycloakResourceName, + Name: KeycloakResourceName, Labels: keycloakLabels(), }, Spec: corev1.PodSpec{ @@ -262,11 +262,11 @@ func keycloakEnvVars() []corev1.EnvVar { return []corev1.EnvVar{ { Name: "KEYCLOAK_ADMIN", - Value: keycloakAdminUsername, + Value: KeycloakAdminUsername, }, { Name: "KEYCLOAK_ADMIN_PASSWORD", - Value: keycloakAdminPassword, + Value: KeycloakAdminPassword, }, { Name: "KC_HEALTH_ENABLED", @@ -337,10 +337,10 @@ func keycloakContainers() []corev1.Container { } } -func createKeycloakRoute(ctx context.Context, service *corev1.Service, client typedroutev1.RouteInterface) (removalFunc, error) { +func createKeycloakRoute(ctx context.Context, service *corev1.Service, client typedroutev1.RouteInterface) (RemovalFunc, error) { route := &routev1.Route{ ObjectMeta: metav1.ObjectMeta{ - Name: keycloakResourceName, + Name: KeycloakResourceName, }, Spec: routev1.RouteSpec{ TLS: &routev1.TLSConfig{ @@ -381,7 +381,7 @@ func waitForKeycloakAvailable(ctx context.Context, client *exutil.CLI, namespace timeoutCtx, cancel := context.WithDeadline(ctx, time.Now().Add(10*time.Minute)) defer cancel() err := wait.PollUntilContextCancel(timeoutCtx, 10*time.Second, true, func(ctx context.Context) (done bool, err error) { - deploy, err := client.AdminKubeClient().AppsV1().Deployments(namespace).Get(ctx, keycloakResourceName, metav1.GetOptions{}) + deploy, err := client.AdminKubeClient().AppsV1().Deployments(namespace).Get(ctx, KeycloakResourceName, metav1.GetOptions{}) if err != nil { logger.Error(err, "getting keycloak deployment") return false, nil diff --git a/test/extended/authentication/oidc.go b/test/extended/authentication/oidc.go index adac86f08b57..7177f68f4714 100644 --- a/test/extended/authentication/oidc.go +++ b/test/extended/authentication/oidc.go @@ -49,8 +49,8 @@ var _ = g.Describe("[sig-auth][Suite:openshift/auth/external-oidc][Serial][Slow] oc.SetNamespace("oidc-e2e") ctx := context.TODO() - var cleanups []removalFunc - var keycloakCli *keycloakClient + var cleanups []RemovalFunc + var keycloakCli *KeycloakClient var username string var password string var group string @@ -70,17 +70,17 @@ var _ = g.Describe("[sig-auth][Suite:openshift/auth/external-oidc][Serial][Slow] testID := rand.String(8) keycloakNamespace = fmt.Sprintf("oidc-keycloak-%s", testID) - cleanups, err = deployKeycloak(ctx, oc, keycloakNamespace, g.GinkgoLogr) + cleanups, err = DeployKeycloak(ctx, oc, keycloakNamespace, g.GinkgoLogr) o.Expect(err).NotTo(o.HaveOccurred(), "should not encounter an error deploying keycloak") - kcURL, err := admittedURLForRoute(ctx, oc, keycloakResourceName, keycloakNamespace) + kcURL, err := AdmittedURLForRoute(ctx, oc, KeycloakResourceName, keycloakNamespace) o.Expect(err).NotTo(o.HaveOccurred(), "should not encounter an error getting keycloak route URL") - keycloakCli, err = keycloakClientFor(kcURL) + keycloakCli, err = KeycloakClientFor(kcURL) o.Expect(err).NotTo(o.HaveOccurred(), "should not encounter an error creating a keycloak client") // First authenticate as the admin keycloak user so we can add new groups and users - err = keycloakCli.Authenticate("admin-cli", keycloakAdminUsername, keycloakAdminPassword) + err = keycloakCli.Authenticate("admin-cli", KeycloakAdminUsername, KeycloakAdminPassword) o.Expect(err).NotTo(o.HaveOccurred(), "should not encounter an error authenticating as keycloak admin") o.Expect(keycloakCli.ConfigureClient("admin-cli")).NotTo(o.HaveOccurred(), "should not encounter an error configuring the admin-cli client") @@ -117,11 +117,11 @@ var _ = g.Describe("[sig-auth][Suite:openshift/auth/external-oidc][Serial][Slow] g.Describe("[OCPFeatureGate:ExternalOIDC]", g.Ordered, func() { g.BeforeAll(func() { - _, _, err := configureOIDCAuthentication(ctx, oc, keycloakNamespace, oidcClientSecret, nil) + _, _, err := ConfigureOIDCAuthentication(ctx, oc, keycloakNamespace, oidcClientSecret, nil) o.Expect(err).NotTo(o.HaveOccurred(), "should not encounter an error configuring OIDC authentication") - waitForRollout(ctx, oc) - waitForHealthyOIDCClients(ctx, oc) + WaitForRollout(ctx, oc) + WaitForHealthyOIDCClients(ctx, oc) }) g.Describe("external IdP is configured", g.Ordered, func() { @@ -232,11 +232,11 @@ var _ = g.Describe("[sig-auth][Suite:openshift/auth/external-oidc][Serial][Slow] gomega.Expect(err).NotTo(o.HaveOccurred(), "should be able to create a SelfSubjectReview") }).WithTimeout(5 * time.Minute).WithPolling(10 * time.Second).Should(o.Succeed()) - err, modified := resetAuthentication(ctx, oc, originalAuth) + err, modified := ResetAuthentication(ctx, oc, originalAuth) o.Expect(err).NotTo(o.HaveOccurred(), "should not encounter an error reverting authentication to original state") if modified { - waitForRollout(ctx, oc) + WaitForRollout(ctx, oc) } }) @@ -304,11 +304,11 @@ var _ = g.Describe("[sig-auth][Suite:openshift/auth/external-oidc][Serial][Slow] g.Describe("external IdP is configured", func() { g.Describe("without specified UID or Extra claim mappings", func() { g.BeforeAll(func() { - _, _, err := configureOIDCAuthentication(ctx, oc, keycloakNamespace, oidcClientSecret, nil) + _, _, err := ConfigureOIDCAuthentication(ctx, oc, keycloakNamespace, oidcClientSecret, nil) o.Expect(err).NotTo(o.HaveOccurred(), "should not encounter an error configuring OIDC authentication") - waitForRollout(ctx, oc) - waitForHealthyOIDCClients(ctx, oc) + WaitForRollout(ctx, oc) + WaitForHealthyOIDCClients(ctx, oc) }) g.It("should default UID to the 'sub' claim in the access token from the IdP", func() { @@ -333,7 +333,7 @@ var _ = g.Describe("[sig-auth][Suite:openshift/auth/external-oidc][Serial][Slow] g.Describe("with valid specified UID or Extra claim mappings", func() { g.BeforeAll(func() { - _, _, err := configureOIDCAuthentication(ctx, oc, keycloakNamespace, oidcClientSecret, func(o *configv1.OIDCProvider) { + _, _, err := ConfigureOIDCAuthentication(ctx, oc, keycloakNamespace, oidcClientSecret, func(o *configv1.OIDCProvider) { o.ClaimMappings.UID = &configv1.TokenClaimOrExpressionMapping{ Expression: "claims.preferred_username.upperAscii()", } @@ -347,8 +347,8 @@ var _ = g.Describe("[sig-auth][Suite:openshift/auth/external-oidc][Serial][Slow] }) o.Expect(err).NotTo(o.HaveOccurred(), "should not encounter an error configuring OIDC authentication") - waitForRollout(ctx, oc) - waitForHealthyOIDCClients(ctx, oc) + WaitForRollout(ctx, oc) + WaitForHealthyOIDCClients(ctx, oc) }) g.Describe("checking cluster identity mapping", g.Ordered, func() { @@ -383,7 +383,7 @@ var _ = g.Describe("[sig-auth][Suite:openshift/auth/external-oidc][Serial][Slow] g.Describe("with invalid specified UID or Extra claim mappings", func() { g.It("should reject admission when UID claim expression is not compilable CEL", func() { - _, _, err := configureOIDCAuthentication(ctx, oc, keycloakNamespace, oidcClientSecret, func(o *configv1.OIDCProvider) { + _, _, err := ConfigureOIDCAuthentication(ctx, oc, keycloakNamespace, oidcClientSecret, func(o *configv1.OIDCProvider) { o.ClaimMappings.UID = &configv1.TokenClaimOrExpressionMapping{ Expression: "!@&*#^", } @@ -392,7 +392,7 @@ var _ = g.Describe("[sig-auth][Suite:openshift/auth/external-oidc][Serial][Slow] }) g.It("should reject admission when Extra claim expression is not compilable CEL", func() { - _, _, err := configureOIDCAuthentication(ctx, oc, keycloakNamespace, oidcClientSecret, func(o *configv1.OIDCProvider) { + _, _, err := ConfigureOIDCAuthentication(ctx, oc, keycloakNamespace, oidcClientSecret, func(o *configv1.OIDCProvider) { o.ClaimMappings.Extra = []configv1.ExtraMapping{ { Key: "payload/test", @@ -435,8 +435,8 @@ var _ = g.Describe("[sig-auth][Suite:openshift/auth/external-oidc][Serial][Slow] o.Expect(keycloakCli.CreateUserWithEmail(invalidClaimValidation, invalidClaimValidationEmail, invalidClaimValidationPassword, group)).To(o.Succeed(), "should be able to create invalidClaimValidation") // Configure OIDC provider with all new features - _, _, err := configureOIDCAuthentication(ctx, oc, keycloakNamespace, oidcClientSecret, func(provider *configv1.OIDCProvider) { - idpUrl, err := admittedURLForRoute(ctx, oc, keycloakResourceName, keycloakNamespace) + _, _, err := ConfigureOIDCAuthentication(ctx, oc, keycloakNamespace, oidcClientSecret, func(provider *configv1.OIDCProvider) { + idpUrl, err := AdmittedURLForRoute(ctx, oc, KeycloakResourceName, keycloakNamespace) o.Expect(err).NotTo(o.HaveOccurred(), "should not encounter an error getting keycloak route URL") // Set custom discoveryURL (different from issuerURL) @@ -481,8 +481,8 @@ var _ = g.Describe("[sig-auth][Suite:openshift/auth/external-oidc][Serial][Slow] }) o.Expect(err).NotTo(o.HaveOccurred(), "should not encounter an error configuring OIDC authentication") - waitForRollout(ctx, oc) - waitForHealthyOIDCClients(ctx, oc) + WaitForRollout(ctx, oc) + WaitForHealthyOIDCClients(ctx, oc) }) g.It("should authenticate successfully with custom discoveryURL, AND-logic userValidationRules, and CEL-type claimValidationRules", func() { @@ -580,8 +580,8 @@ var _ = g.Describe("[sig-auth][Suite:openshift/auth/external-oidc][Serial][Slow] o.Expect(keycloakCli.CreateUserWithEmail(invalidExprGroups, invalidExprGroupsEmail, invalidExprGroupsPassword, otherGroup)).To(o.Succeed(), "should be able to create invalidExprGroups") // Configure OIDC provider with CEL expression-based claim mappings - _, _, err := configureOIDCAuthentication(ctx, oc, keycloakNamespace, oidcClientSecret, func(provider *configv1.OIDCProvider) { - idpUrl, err := admittedURLForRoute(ctx, oc, keycloakResourceName, keycloakNamespace) + _, _, err := ConfigureOIDCAuthentication(ctx, oc, keycloakNamespace, oidcClientSecret, func(provider *configv1.OIDCProvider) { + idpUrl, err := AdmittedURLForRoute(ctx, oc, KeycloakResourceName, keycloakNamespace) o.Expect(err).NotTo(o.HaveOccurred(), "should not encounter an error getting keycloak route URL") // Set custom discoveryURL @@ -631,8 +631,8 @@ var _ = g.Describe("[sig-auth][Suite:openshift/auth/external-oidc][Serial][Slow] }) o.Expect(err).NotTo(o.HaveOccurred(), "should not encounter an error configuring OIDC authentication with CEL expression mappings") - waitForRollout(ctx, oc) - waitForHealthyOIDCClients(ctx, oc) + WaitForRollout(ctx, oc) + WaitForHealthyOIDCClients(ctx, oc) }) g.It("should authenticate with CEL expression claim mappings (with omitted prefix configurations), userValidationRules, and claimValidationRules", func() { @@ -709,7 +709,7 @@ var _ = g.Describe("[sig-auth][Suite:openshift/auth/external-oidc][Serial][Slow] g.It("should reject invalid CEL expressions in admission", func() { // Test invalid CEL expression in userValidationRules - _, _, err := configureOIDCAuthentication(ctx, oc, keycloakNamespace, oidcClientSecret, func(provider *configv1.OIDCProvider) { + _, _, err := ConfigureOIDCAuthentication(ctx, oc, keycloakNamespace, oidcClientSecret, func(provider *configv1.OIDCProvider) { provider.UserValidationRules = []configv1.TokenUserValidationRule{ { Expression: "!@#$%^&*()", @@ -720,7 +720,7 @@ var _ = g.Describe("[sig-auth][Suite:openshift/auth/external-oidc][Serial][Slow] o.Expect(err).To(o.HaveOccurred(), "should encounter an error with invalid CEL expression") // Test non-boolean CEL expression in userValidationRules - _, _, err = configureOIDCAuthentication(ctx, oc, keycloakNamespace, oidcClientSecret, func(provider *configv1.OIDCProvider) { + _, _, err = ConfigureOIDCAuthentication(ctx, oc, keycloakNamespace, oidcClientSecret, func(provider *configv1.OIDCProvider) { provider.UserValidationRules = []configv1.TokenUserValidationRule{ { Expression: "user.username", @@ -731,7 +731,7 @@ var _ = g.Describe("[sig-auth][Suite:openshift/auth/external-oidc][Serial][Slow] o.Expect(err).To(o.HaveOccurred(), "should encounter an error with non-boolean CEL expression") // Test invalid CEL expression in claimValidationRules - _, _, err = configureOIDCAuthentication(ctx, oc, keycloakNamespace, oidcClientSecret, func(provider *configv1.OIDCProvider) { + _, _, err = ConfigureOIDCAuthentication(ctx, oc, keycloakNamespace, oidcClientSecret, func(provider *configv1.OIDCProvider) { provider.ClaimValidationRules = []configv1.TokenClaimValidationRule{ { Type: configv1.TokenValidationRuleTypeCEL, @@ -745,13 +745,13 @@ var _ = g.Describe("[sig-auth][Suite:openshift/auth/external-oidc][Serial][Slow] o.Expect(err).To(o.HaveOccurred(), "should encounter an error with invalid CEL expression in claimValidationRules") // Test invalid CEL expression in claimMappings.username.expression - _, _, err = configureOIDCAuthentication(ctx, oc, keycloakNamespace, oidcClientSecret, func(provider *configv1.OIDCProvider) { + _, _, err = ConfigureOIDCAuthentication(ctx, oc, keycloakNamespace, oidcClientSecret, func(provider *configv1.OIDCProvider) { provider.ClaimMappings.Username.Expression = "!@#$%^&*()" }) o.Expect(err).To(o.HaveOccurred(), "should encounter an error with invalid CEL expression in username mapping") // Test invalid CEL expression in claimMappings.groups.expression - _, _, err = configureOIDCAuthentication(ctx, oc, keycloakNamespace, oidcClientSecret, func(provider *configv1.OIDCProvider) { + _, _, err = ConfigureOIDCAuthentication(ctx, oc, keycloakNamespace, oidcClientSecret, func(provider *configv1.OIDCProvider) { provider.ClaimMappings.Groups.TokenClaimMapping.Expression = "!@#$%^&*()" }) o.Expect(err).To(o.HaveOccurred(), "should encounter an error with invalid CEL expression in groups mapping") @@ -759,25 +759,25 @@ var _ = g.Describe("[sig-auth][Suite:openshift/auth/external-oidc][Serial][Slow] }) g.AfterAll(func() { - err, modified := resetAuthentication(ctx, oc, originalAuth) + err, modified := ResetAuthentication(ctx, oc, originalAuth) o.Expect(err).NotTo(o.HaveOccurred(), "should not encounter an error reverting authentication to original state") // Only if we modified the Authentication resource during the reset should we wait for a rollout if modified { - waitForRollout(ctx, oc) + WaitForRollout(ctx, oc) } - err = removeResources(ctx, cleanups...) + err = RemoveResources(ctx, cleanups...) o.Expect(err).NotTo(o.HaveOccurred(), "should not encounter an error cleaning up keycloak resources") }) }) -type removalFunc func(context.Context) error +type RemovalFunc func(context.Context) error -func removeResources(ctx context.Context, removalFuncs ...removalFunc) error { +func RemoveResources(ctx context.Context, RemovalFuncs ...RemovalFunc) error { errs := []error{} - for _, removal := range removalFuncs { + for _, removal := range RemovalFuncs { if removal == nil { continue } @@ -788,7 +788,7 @@ func removeResources(ctx context.Context, removalFuncs ...removalFunc) error { return errors.FilterOut(errors.NewAggregate(errs), apierrors.IsNotFound) } -func configureOIDCAuthentication(ctx context.Context, client *exutil.CLI, keycloakNS, oidcClientSecret string, modifier func(*configv1.OIDCProvider)) (*configv1.Authentication, *configv1.Authentication, error) { +func ConfigureOIDCAuthentication(ctx context.Context, client *exutil.CLI, keycloakNS, oidcClientSecret string, modifier func(*configv1.OIDCProvider)) (*configv1.Authentication, *configv1.Authentication, error) { authConfig, err := client.AdminConfigClient().ConfigV1().Authentications().Get(ctx, "cluster", metav1.GetOptions{}) if err != nil { return nil, nil, fmt.Errorf("getting authentications.config.openshift.io/cluster: %w", err) @@ -797,7 +797,7 @@ func configureOIDCAuthentication(ctx context.Context, client *exutil.CLI, keyclo original := authConfig.DeepCopy() modified := authConfig.DeepCopy() - oidcProvider, err := generateOIDCProvider(ctx, client, keycloakNS, oidcClientSecret) + oidcProvider, err := GenerateOIDCProvider(ctx, client, keycloakNS, oidcClientSecret) if err != nil { return nil, nil, fmt.Errorf("generating OIDC provider: %w", err) } @@ -818,7 +818,7 @@ func configureOIDCAuthentication(ctx context.Context, client *exutil.CLI, keyclo return original, modified, nil } -func generateOIDCProvider(ctx context.Context, client *exutil.CLI, namespace, oidcClientSecret string) (*configv1.OIDCProvider, error) { +func GenerateOIDCProvider(ctx context.Context, client *exutil.CLI, namespace, oidcClientSecret string) (*configv1.OIDCProvider, error) { idpName := "keycloak" caBundle := "keycloak-ca" audiences := []configv1.TokenAudience{ @@ -827,7 +827,7 @@ func generateOIDCProvider(ctx context.Context, client *exutil.CLI, namespace, oi usernameClaim := "email" groupsClaim := "groups" - idpUrl, err := admittedURLForRoute(ctx, client, keycloakResourceName, namespace) + idpUrl, err := AdmittedURLForRoute(ctx, client, KeycloakResourceName, namespace) if err != nil { return nil, fmt.Errorf("getting issuer URL: %w", err) } @@ -876,7 +876,7 @@ func generateOIDCProvider(ctx context.Context, client *exutil.CLI, namespace, oi }, nil } -func admittedURLForRoute(ctx context.Context, client *exutil.CLI, routeName, namespace string) (string, error) { +func AdmittedURLForRoute(ctx context.Context, client *exutil.CLI, routeName, namespace string) (string, error) { var admittedURL string timeoutCtx, cancel := context.WithTimeout(ctx, 5*time.Minute) @@ -901,7 +901,7 @@ func admittedURLForRoute(ctx context.Context, client *exutil.CLI, routeName, nam return fmt.Sprintf("https://%s", admittedURL), err } -func resetAuthentication(ctx context.Context, client *exutil.CLI, original *configv1.Authentication) (error, bool) { +func ResetAuthentication(ctx context.Context, client *exutil.CLI, original *configv1.Authentication) (error, bool) { if original == nil { return nil, false } @@ -936,7 +936,7 @@ func resetAuthentication(ctx context.Context, client *exutil.CLI, original *conf return err, modified } -func waitForRollout(ctx context.Context, client *exutil.CLI) { +func WaitForRollout(ctx context.Context, client *exutil.CLI) { kasCli := client.AdminOperatorClient().OperatorV1().KubeAPIServers() // First wait for KAS NodeInstallerProgressing condition to flip to "True". @@ -989,7 +989,7 @@ func checkKubeAPIServerCondition(ctx context.Context, kasCli operatorv1client.Ku return nil } -func waitForHealthyOIDCClients(ctx context.Context, client *exutil.CLI) { +func WaitForHealthyOIDCClients(ctx context.Context, client *exutil.CLI) { o.Eventually(func(gomega o.Gomega) { authn, err := client.AdminConfigClient().ConfigV1().Authentications().Get(ctx, "cluster", metav1.GetOptions{}) gomega.Expect(err).NotTo(o.HaveOccurred()) From df906b4b800c7b9bf27d9546a6b4b77530909184 Mon Sep 17 00:00:00 2001 From: Evan Hearne Date: Thu, 16 Jul 2026 16:13:54 +0100 Subject: [PATCH 3/5] test OIDC login through component proxy --- test/extended/oauth/oidc_proxy.go | 152 ++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 test/extended/oauth/oidc_proxy.go diff --git a/test/extended/oauth/oidc_proxy.go b/test/extended/oauth/oidc_proxy.go new file mode 100644 index 000000000000..6045c21f9fac --- /dev/null +++ b/test/extended/oauth/oidc_proxy.go @@ -0,0 +1,152 @@ +package oauth + +import ( + "context" + "fmt" + "io" + "time" + + g "github.com/onsi/ginkgo/v2" + o "github.com/onsi/gomega" + + configv1 "github.com/openshift/api/config/v1" + operatorv1 "github.com/openshift/api/operator/v1" + "github.com/openshift/library-go/pkg/oauth/tokenrequest" + "github.com/openshift/library-go/pkg/oauth/tokenrequest/challengehandlers" + exauth "github.com/openshift/origin/test/extended/authentication" + exutil "github.com/openshift/origin/test/extended/util" + exoperator "github.com/openshift/origin/test/extended/util/operator" + authnv1 "k8s.io/api/authentication/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "k8s.io/apimachinery/pkg/util/rand" +) + +var _ = g.Describe("[sig-auth][Feature:AuthenticationComponentProxy] OIDC login component proxy", g.Ordered, func() { + var cleanups []exauth.RemovalFunc + var authConfig *operatorv1.Authentication + var original *operatorv1.Authentication + + var keycloakCli *exauth.KeycloakClient + var username string + var password string + var group string + + ns := "oidc-oauth-login-flow" + oc := exutil.NewCLIWithoutNamespace(ns) + ctx := context.TODO() + + g.BeforeAll(func() { + featureGates, err := oc.AdminConfigClient().ConfigV1().FeatureGates().Get(ctx, "cluster", metav1.GetOptions{}) + o.Expect(err).NotTo(o.HaveOccurred()) + + if featureGates.Spec.FeatureSet != configv1.TechPreviewNoUpgrade { + g.Skip(fmt.Sprintf("tests should only run if behind %s featureset", configv1.TechPreviewNoUpgrade)) + } + + authConfig, err = oc.AdminOperatorClient().OperatorV1().Authentications().Get(ctx, "cluster", metav1.GetOptions{}) + o.Expect(err).NotTo(o.HaveOccurred(), "should be able to get authentications.operator.openshift.io/cluster") + + original = authConfig.DeepCopy() + + // We assume keycloak has been deployed and tests done previously that it works fine. + kcUrl, err := exauth.AdmittedURLForRoute(ctx, oc, exauth.KeycloakResourceName, ns) + o.Expect(err).NotTo(o.HaveOccurred(), "should not encounter an error getting keycloak route URL") + + keycloakCli, err = exauth.KeycloakClientFor(kcUrl) + o.Expect(err).NotTo(o.HaveOccurred(), "should not encounter an error creating a keycloak client") + + // First authenticate as the admin keycloak user so we can add new groups and users + err = keycloakCli.Authenticate("admin-cli", exauth.KeycloakAdminUsername, exauth.KeycloakAdminPassword) + o.Expect(err).NotTo(o.HaveOccurred(), "should not encounter an error authenticating as keycloak admin") + + o.Expect(keycloakCli.ConfigureClient("admin-cli")).NotTo(o.HaveOccurred(), "should not encounter an error configuring the admin-cli client") + + testID := rand.String(8) + + username = fmt.Sprintf("user-%s", testID) + password = fmt.Sprintf("password-%s", testID) + group = fmt.Sprintf("ocp-test-%s-group", testID) + + o.Expect(keycloakCli.CreateGroup(group)).To(o.Succeed(), "should be able to create a new keycloak group") + o.Expect(keycloakCli.CreateUser(username, password, group)).To(o.Succeed(), "should be able to create a new keycloak user") + }) + + g.AfterAll(func() { + current, err := oc.AdminOperatorClient().OperatorV1().Authentications().Get(ctx, "cluster", metav1.GetOptions{}) + o.Expect(err).NotTo(o.HaveOccurred()) + current.Spec.Proxy = original.Spec.Proxy + _, err = oc.AdminOperatorClient().OperatorV1().Authentications().Update(ctx, current, metav1.UpdateOptions{}) + o.Expect(err).NotTo(o.HaveOccurred()) + + err = exauth.RemoveResources(ctx, cleanups...) + o.Expect(err).NotTo(o.HaveOccurred()) + }) + + g.It("should apply proxy configuration to the authentication operator [apigroup:operator.openshift.io] and perform full oidc login flow", func() { + modified := authConfig.DeepCopy() + + // actual proxy values will be set at a later stage + modified.Spec.Proxy = operatorv1.AuthenticationProxyConfig{ + HTTPProxy: "httpProxyURL", + HTTPSProxy: "httpsProxyURL", + NoProxy: []string{"dontGoHere"}, + } + + _, err := oc.AdminOperatorClient().OperatorV1().Authentications().Update(ctx, modified, metav1.UpdateOptions{}) + o.Expect(err).NotTo(o.HaveOccurred(), "should be able to update the authentication operator proxy config") + + o.Eventually(func(gomega o.Gomega) { + authn, err := oc.AdminOperatorClient().OperatorV1().Authentications().Get(ctx, "cluster", metav1.GetOptions{}) + gomega.Expect(err).NotTo(o.HaveOccurred()) + + progressing := false + for _, cond := range authn.Status.Conditions { + if cond.Type == "Progressing" && cond.Status == operatorv1.ConditionFalse { + progressing = true + break + } + } + gomega.Expect(progressing).To(o.BeTrue(), "authentication operator should finish progressing") + + available := false + for _, cond := range authn.Status.Conditions { + if cond.Type == "Available" && cond.Status == operatorv1.ConditionTrue { + available = true + break + } + } + gomega.Expect(available).To(o.BeTrue(), "authentication operator should be available") + }).WithTimeout(5*time.Minute).WithPolling(10*time.Second).Should(o.Succeed(), "authentication operator should reconcile proxy config") + + err = exoperator.WaitForOperatorsToSettle(ctx, oc.AdminConfigClient(), 10) + o.Expect(err).NotTo(o.HaveOccurred(), "cluster operators should settle after proxy config change") + + route, err := oc.AdminRouteClient().RouteV1().Routes("openshift-authentication").Get(ctx, "oauth-openshift", metav1.GetOptions{}) + o.Expect(err).NotTo(o.HaveOccurred(), "should be able to get the OAuth server route") + oauthServerURL := fmt.Sprintf("https://%s", route.Spec.Host) + + o.Eventually(func(gomega o.Gomega) { + tokenOpts := tokenrequest.NewRequestTokenOptions(oc.AdminConfig(), false) + tokenOpts, err := tokenOpts.WithChallengeHandlers( + challengehandlers.NewBasicChallengeHandler(oauthServerURL, "", nil, io.Discard, nil, username, password), + ) + gomega.Expect(err).NotTo(o.HaveOccurred()) + + err = tokenOpts.SetDefaultOsinConfig("openshift-challenging-client", nil) + gomega.Expect(err).NotTo(o.HaveOccurred(), "should discover OAuth metadata") + + token, err := tokenOpts.RequestToken() + gomega.Expect(err).NotTo(o.HaveOccurred(), "should get an OpenShift token via OAuth flow through the component proxy") + gomega.Expect(token).NotTo(o.BeEmpty()) + + copiedOC := *oc + tokenOC := copiedOC.WithToken(token) + ssr, err := tokenOC.KubeClient().AuthenticationV1().SelfSubjectReviews().Create(ctx, &authnv1.SelfSubjectReview{}, metav1.CreateOptions{}) + gomega.Expect(err).NotTo(o.HaveOccurred(), "should be able to create a SelfSubjectReview") + + gomega.Expect(ssr.Status.UserInfo.Username).NotTo(o.BeEmpty()) + gomega.Expect(ssr.Status.UserInfo.Groups).To(o.ContainElement(group)) + }).WithTimeout(5 * time.Minute).WithPolling(10 * time.Second).Should(o.Succeed()) + }) +}) From 102559c640c64e837a638749df9e89878fa3048b Mon Sep 17 00:00:00 2001 From: Evan Hearne Date: Fri, 17 Jul 2026 15:22:22 +0100 Subject: [PATCH 4/5] test should fall back to direct IdP connectivity for oidc login --- test/extended/oauth/oidc_proxy.go | 169 +++++++++++++++++++++++++----- 1 file changed, 145 insertions(+), 24 deletions(-) diff --git a/test/extended/oauth/oidc_proxy.go b/test/extended/oauth/oidc_proxy.go index 6045c21f9fac..9477453ec38c 100644 --- a/test/extended/oauth/oidc_proxy.go +++ b/test/extended/oauth/oidc_proxy.go @@ -17,6 +17,8 @@ import ( exutil "github.com/openshift/origin/test/extended/util" exoperator "github.com/openshift/origin/test/extended/util/operator" authnv1 "k8s.io/api/authentication/v1" + networkingv1 "k8s.io/api/networking/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/rand" @@ -32,8 +34,21 @@ var _ = g.Describe("[sig-auth][Feature:AuthenticationComponentProxy] OIDC login var password string var group string - ns := "oidc-oauth-login-flow" - oc := exutil.NewCLIWithoutNamespace(ns) + squidServiceName := "squid-proxy" + + networkPolicyCopyList := map[string]networkingv1.NetworkPolicy{} + + keycloakNS := "keycloakNamespace" + // This value will need to be saved somewhere to be accessed. + proxyNS := "e2e-proxy-abc123" + + networkPolicyMap := []NetworkPolicyMap{ + {"proxy-e2e-deny-direct-openshift-authentication", "openshift-authentication"}, + {"proxy-e2e-deny-direct-openshift-authentication-operator", "openshift-authentication-operator"}, + {"proxy-e2e-allow-only-from-proxy", keycloakNS}, + } + + oc := exutil.NewCLIWithoutNamespace(keycloakNS) ctx := context.TODO() g.BeforeAll(func() { @@ -49,8 +64,15 @@ var _ = g.Describe("[sig-auth][Feature:AuthenticationComponentProxy] OIDC login original = authConfig.DeepCopy() + for _, np := range networkPolicyMap { + networkPolicy, err := oc.AdminKubeClient().NetworkingV1().NetworkPolicies(np.namespace).Get(ctx, np.name, metav1.GetOptions{}) + o.Expect(err).NotTo(o.HaveOccurred(), "should be able to get NetworkPolicy") + + networkPolicyCopyList[np.name] = *networkPolicy.DeepCopy() + } + // We assume keycloak has been deployed and tests done previously that it works fine. - kcUrl, err := exauth.AdmittedURLForRoute(ctx, oc, exauth.KeycloakResourceName, ns) + kcUrl, err := exauth.AdmittedURLForRoute(ctx, oc, exauth.KeycloakResourceName, keycloakNS) o.Expect(err).NotTo(o.HaveOccurred(), "should not encounter an error getting keycloak route URL") keycloakCli, err = exauth.KeycloakClientFor(kcUrl) @@ -72,30 +94,13 @@ var _ = g.Describe("[sig-auth][Feature:AuthenticationComponentProxy] OIDC login o.Expect(keycloakCli.CreateUser(username, password, group)).To(o.Succeed(), "should be able to create a new keycloak user") }) - g.AfterAll(func() { + g.AfterEach(func() { current, err := oc.AdminOperatorClient().OperatorV1().Authentications().Get(ctx, "cluster", metav1.GetOptions{}) o.Expect(err).NotTo(o.HaveOccurred()) current.Spec.Proxy = original.Spec.Proxy _, err = oc.AdminOperatorClient().OperatorV1().Authentications().Update(ctx, current, metav1.UpdateOptions{}) o.Expect(err).NotTo(o.HaveOccurred()) - err = exauth.RemoveResources(ctx, cleanups...) - o.Expect(err).NotTo(o.HaveOccurred()) - }) - - g.It("should apply proxy configuration to the authentication operator [apigroup:operator.openshift.io] and perform full oidc login flow", func() { - modified := authConfig.DeepCopy() - - // actual proxy values will be set at a later stage - modified.Spec.Proxy = operatorv1.AuthenticationProxyConfig{ - HTTPProxy: "httpProxyURL", - HTTPSProxy: "httpsProxyURL", - NoProxy: []string{"dontGoHere"}, - } - - _, err := oc.AdminOperatorClient().OperatorV1().Authentications().Update(ctx, modified, metav1.UpdateOptions{}) - o.Expect(err).NotTo(o.HaveOccurred(), "should be able to update the authentication operator proxy config") - o.Eventually(func(gomega o.Gomega) { authn, err := oc.AdminOperatorClient().OperatorV1().Authentications().Get(ctx, "cluster", metav1.GetOptions{}) gomega.Expect(err).NotTo(o.HaveOccurred()) @@ -117,10 +122,33 @@ var _ = g.Describe("[sig-auth][Feature:AuthenticationComponentProxy] OIDC login } } gomega.Expect(available).To(o.BeTrue(), "authentication operator should be available") - }).WithTimeout(5*time.Minute).WithPolling(10*time.Second).Should(o.Succeed(), "authentication operator should reconcile proxy config") + }).WithTimeout(5*time.Minute).WithPolling(10*time.Second).Should(o.Succeed(), "authentication operator should reconcile without proxy config") err = exoperator.WaitForOperatorsToSettle(ctx, oc.AdminConfigClient(), 10) - o.Expect(err).NotTo(o.HaveOccurred(), "cluster operators should settle after proxy config change") + o.Expect(err).NotTo(o.HaveOccurred(), "cluster operators should settle after removing proxy config") + + for name, saved := range networkPolicyCopyList { + restored := saved.DeepCopy() + existing, err := oc.AdminKubeClient().NetworkingV1().NetworkPolicies(saved.Namespace).Get(ctx, name, metav1.GetOptions{}) + if apierrors.IsNotFound(err) { + restored.ResourceVersion = "" + _, err = oc.AdminKubeClient().NetworkingV1().NetworkPolicies(saved.Namespace).Create(ctx, restored, metav1.CreateOptions{}) + o.Expect(err).NotTo(o.HaveOccurred(), "network policy should be created") + continue + } + o.Expect(err).NotTo(o.HaveOccurred(), "should be able to get network policy") + + restored.ResourceVersion = existing.ResourceVersion + _, err = oc.AdminKubeClient().NetworkingV1().NetworkPolicies(saved.Namespace).Update(ctx, restored, metav1.UpdateOptions{}) + o.Expect(err).NotTo(o.HaveOccurred(), "network policy should be updated") + } + + err = exauth.RemoveResources(ctx, cleanups...) + o.Expect(err).NotTo(o.HaveOccurred()) + }) + + assertOIDCLogin := func(msg string) { + g.GinkgoHelper() route, err := oc.AdminRouteClient().RouteV1().Routes("openshift-authentication").Get(ctx, "oauth-openshift", metav1.GetOptions{}) o.Expect(err).NotTo(o.HaveOccurred(), "should be able to get the OAuth server route") @@ -137,7 +165,7 @@ var _ = g.Describe("[sig-auth][Feature:AuthenticationComponentProxy] OIDC login gomega.Expect(err).NotTo(o.HaveOccurred(), "should discover OAuth metadata") token, err := tokenOpts.RequestToken() - gomega.Expect(err).NotTo(o.HaveOccurred(), "should get an OpenShift token via OAuth flow through the component proxy") + gomega.Expect(err).NotTo(o.HaveOccurred(), msg) gomega.Expect(token).NotTo(o.BeEmpty()) copiedOC := *oc @@ -148,5 +176,98 @@ var _ = g.Describe("[sig-auth][Feature:AuthenticationComponentProxy] OIDC login gomega.Expect(ssr.Status.UserInfo.Username).NotTo(o.BeEmpty()) gomega.Expect(ssr.Status.UserInfo.Groups).To(o.ContainElement(group)) }).WithTimeout(5 * time.Minute).WithPolling(10 * time.Second).Should(o.Succeed()) + } + + g.It("should apply proxy configuration to the authentication operator [apigroup:operator.openshift.io] and perform full oidc login flow", func() { + modified := authConfig.DeepCopy() + + // actual proxy values will be set at a later stage + modified.Spec.Proxy = operatorv1.AuthenticationProxyConfig{ + HTTPProxy: "httpProxyURL", + HTTPSProxy: "httpsProxyURL", + NoProxy: []string{"dontGoHere"}, + } + + _, err := oc.AdminOperatorClient().OperatorV1().Authentications().Update(ctx, modified, metav1.UpdateOptions{}) + o.Expect(err).NotTo(o.HaveOccurred(), "should be able to update the authentication operator proxy config") + + o.Eventually(func(gomega o.Gomega) { + authn, err := oc.AdminOperatorClient().OperatorV1().Authentications().Get(ctx, "cluster", metav1.GetOptions{}) + gomega.Expect(err).NotTo(o.HaveOccurred()) + + progressing := false + for _, cond := range authn.Status.Conditions { + if cond.Type == "Progressing" && cond.Status == operatorv1.ConditionFalse { + progressing = true + break + } + } + gomega.Expect(progressing).To(o.BeTrue(), "authentication operator should finish progressing") + + available := false + for _, cond := range authn.Status.Conditions { + if cond.Type == "Available" && cond.Status == operatorv1.ConditionTrue { + available = true + break + } + } + gomega.Expect(available).To(o.BeTrue(), "authentication operator should be available") + }).WithTimeout(5*time.Minute).WithPolling(10*time.Second).Should(o.Succeed(), "authentication operator should reconcile proxy config") + + err = exoperator.WaitForOperatorsToSettle(ctx, oc.AdminConfigClient(), 10) + o.Expect(err).NotTo(o.HaveOccurred(), "cluster operators should settle after proxy config change") + + assertOIDCLogin("should get an OpenShift token via OAuth flow through the component proxy") + }) + + g.It("should fall back to direct IdP connectivity for oidc login", func() { + // spec.proxy has been removed in g.AfterEach(), need to remove NetworkPolicies + // to test direct IdP connectivity + + for name, np := range networkPolicyCopyList { + err := oc.AdminKubeClient().NetworkingV1().NetworkPolicies(np.Namespace).Delete(ctx, name, metav1.DeleteOptions{}) + o.Expect(err).NotTo(o.HaveOccurred(), "should be able to delete NetworkPolicy") + _, err = oc.AdminKubeClient().NetworkingV1().NetworkPolicies(np.Namespace).Get(ctx, name, metav1.GetOptions{}) + o.Expect(apierrors.IsNotFound(err)).To(o.BeTrue()) + } + + // add a network policy to deny all egress from squid + denyAllSquid := &networkingv1.NetworkPolicy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "block-squid-to-keycloak", + Namespace: proxyNS, + }, + Spec: networkingv1.NetworkPolicySpec{ + PodSelector: metav1.LabelSelector{ + MatchLabels: map[string]string{"app": squidServiceName}, + }, + PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeEgress}, + Egress: []networkingv1.NetworkPolicyEgressRule{}, + }, + } + + // applying this policy ensures proxy cannot be used during oauth flow - meaning + // only direct IdP would have taken place. + _, err := oc.AdminKubeClient().NetworkingV1().NetworkPolicies(proxyNS).Create(ctx, denyAllSquid, metav1.CreateOptions{}) + o.Expect(err).NotTo(o.HaveOccurred(), "network policy should create successfully") + + g.DeferCleanup(func() { + err := oc.AdminKubeClient().NetworkingV1().NetworkPolicies(proxyNS).Delete(ctx, denyAllSquid.Name, metav1.DeleteOptions{}) + if err != nil && !apierrors.IsNotFound(err) { + g.GinkgoWriter.Printf("failed to clean up NetworkPolicy %s: %v\n", denyAllSquid.Name, err) + } + }) + + assertOIDCLogin("should get an OpenShift token via direct IdP connectivity") }) }) + +type NetworkPolicyMap struct { + name string + namespace string +} + +type NetworkPolicyCopy struct { + name string + networkPolicy *networkingv1.NetworkPolicy +} From 614051c7e74fedd9db014cdc78ea581f87fdf87c Mon Sep 17 00:00:00 2001 From: Evan Hearne Date: Sat, 18 Jul 2026 11:07:04 +0100 Subject: [PATCH 5/5] test trustedCA hot-reload --- test/extended/oauth/oidc_proxy.go | 173 ++++++++++++++++++++++++------ 1 file changed, 139 insertions(+), 34 deletions(-) diff --git a/test/extended/oauth/oidc_proxy.go b/test/extended/oauth/oidc_proxy.go index 9477453ec38c..8ac5d4b9eb6c 100644 --- a/test/extended/oauth/oidc_proxy.go +++ b/test/extended/oauth/oidc_proxy.go @@ -4,6 +4,8 @@ import ( "context" "fmt" "io" + "os" + "path" "time" g "github.com/onsi/ginkgo/v2" @@ -11,17 +13,20 @@ import ( configv1 "github.com/openshift/api/config/v1" operatorv1 "github.com/openshift/api/operator/v1" + "github.com/openshift/library-go/pkg/crypto" "github.com/openshift/library-go/pkg/oauth/tokenrequest" "github.com/openshift/library-go/pkg/oauth/tokenrequest/challengehandlers" exauth "github.com/openshift/origin/test/extended/authentication" exutil "github.com/openshift/origin/test/extended/util" exoperator "github.com/openshift/origin/test/extended/util/operator" authnv1 "k8s.io/api/authentication/v1" + corev1 "k8s.io/api/core/v1" networkingv1 "k8s.io/api/networking/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/rand" + "k8s.io/apimachinery/pkg/util/sets" ) var _ = g.Describe("[sig-auth][Feature:AuthenticationComponentProxy] OIDC login component proxy", g.Ordered, func() { @@ -41,6 +46,7 @@ var _ = g.Describe("[sig-auth][Feature:AuthenticationComponentProxy] OIDC login keycloakNS := "keycloakNamespace" // This value will need to be saved somewhere to be accessed. proxyNS := "e2e-proxy-abc123" + configMapName := "e2e-proxy-cm" networkPolicyMap := []NetworkPolicyMap{ {"proxy-e2e-deny-direct-openshift-authentication", "openshift-authentication"}, @@ -179,43 +185,11 @@ var _ = g.Describe("[sig-auth][Feature:AuthenticationComponentProxy] OIDC login } g.It("should apply proxy configuration to the authentication operator [apigroup:operator.openshift.io] and perform full oidc login flow", func() { - modified := authConfig.DeepCopy() - - // actual proxy values will be set at a later stage - modified.Spec.Proxy = operatorv1.AuthenticationProxyConfig{ + updateAuthenticationProxyConfig(ctx, oc, authConfig, operatorv1.AuthenticationProxyConfig{ HTTPProxy: "httpProxyURL", HTTPSProxy: "httpsProxyURL", NoProxy: []string{"dontGoHere"}, - } - - _, err := oc.AdminOperatorClient().OperatorV1().Authentications().Update(ctx, modified, metav1.UpdateOptions{}) - o.Expect(err).NotTo(o.HaveOccurred(), "should be able to update the authentication operator proxy config") - - o.Eventually(func(gomega o.Gomega) { - authn, err := oc.AdminOperatorClient().OperatorV1().Authentications().Get(ctx, "cluster", metav1.GetOptions{}) - gomega.Expect(err).NotTo(o.HaveOccurred()) - - progressing := false - for _, cond := range authn.Status.Conditions { - if cond.Type == "Progressing" && cond.Status == operatorv1.ConditionFalse { - progressing = true - break - } - } - gomega.Expect(progressing).To(o.BeTrue(), "authentication operator should finish progressing") - - available := false - for _, cond := range authn.Status.Conditions { - if cond.Type == "Available" && cond.Status == operatorv1.ConditionTrue { - available = true - break - } - } - gomega.Expect(available).To(o.BeTrue(), "authentication operator should be available") - }).WithTimeout(5*time.Minute).WithPolling(10*time.Second).Should(o.Succeed(), "authentication operator should reconcile proxy config") - - err = exoperator.WaitForOperatorsToSettle(ctx, oc.AdminConfigClient(), 10) - o.Expect(err).NotTo(o.HaveOccurred(), "cluster operators should settle after proxy config change") + }) assertOIDCLogin("should get an OpenShift token via OAuth flow through the component proxy") }) @@ -260,6 +234,101 @@ var _ = g.Describe("[sig-auth][Feature:AuthenticationComponentProxy] OIDC login assertOIDCLogin("should get an OpenShift token via direct IdP connectivity") }) + + g.It("should hot-reload the mounted CA file on change when spec.proxy.trustedCA is set", func() { + tempDir, err := os.MkdirTemp("", "testca") + o.Expect(err).NotTo(o.HaveOccurred()) + defer os.RemoveAll(tempDir) + + ca, err := crypto.MakeSelfSignedCA( + path.Join(tempDir, "ca.crt"), + path.Join(tempDir, "ca.key"), + path.Join(tempDir, "serial"), + "proxy-e2e-ca", + 100*24*time.Hour, + ) + o.Expect(err).NotTo(o.HaveOccurred()) + + caPEM, _, err := ca.Config.GetPEMBytes() + o.Expect(err).NotTo(o.HaveOccurred()) + + caConfigMap := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: configMapName, + Namespace: "openshift-config", + }, + Data: map[string]string{ + "ca-bundle.crt": string(caPEM), + }, + } + _, err = oc.AdminKubeClient().CoreV1().ConfigMaps("openshift-config").Create(ctx, caConfigMap, metav1.CreateOptions{}) + o.Expect(err).NotTo(o.HaveOccurred(), "should be able to create trustedCA ConfigMap") + g.DeferCleanup(func() { + err := oc.AdminKubeClient().CoreV1().ConfigMaps("openshift-config").Delete(ctx, configMapName, metav1.DeleteOptions{}) + if err != nil && !apierrors.IsNotFound(err) { + g.GinkgoWriter.Printf("failed to clean up ConfigMap %s: %v\n", configMapName, err) + } + }) + + updateAuthenticationProxyConfig(ctx, oc, authConfig, operatorv1.AuthenticationProxyConfig{ + HTTPProxy: "httpProxyURL", + HTTPSProxy: "httpsProxyURL", + NoProxy: []string{"dontGoHere"}, + TrustedCA: operatorv1.AuthenticationConfigMapReference{ + Name: configMapName, + }, + }) + + assertOIDCLogin("should be able to log in after setting spec.proxy with trustedCA") + + // Explicitly verify trustedCA ConfigMap is synced to openshift-authentication namespace. + cm, err := oc.AdminKubeClient().CoreV1().ConfigMaps("openshift-authentication").Get(ctx, configMapName, metav1.GetOptions{}) + o.Expect(err).NotTo(o.HaveOccurred(), "trustedCA ConfigMap %s should exist in openshift-authentication", configMapName) + o.Expect(cm).NotTo(o.BeEmpty(), "trustedCA ConfigMap %s should have data", configMapName) + + // Grab oauth-server pod list to confirm no re-deployment later + oauthServerPodList, err := oc.AdminKubeClient().CoreV1().Pods("openshift-authentication").List(ctx, metav1.ListOptions{LabelSelector: "app=oauth-openshift"}) + o.Expect(err).NotTo(o.HaveOccurred(), "should be able to query for oauth-server pods") + o.Expect(oauthServerPodList.Items).NotTo(o.BeEmpty(), "pod items list should contain at least one") + + // Update CA file contents + newCA, err := crypto.MakeSelfSignedCA( + path.Join(tempDir, "ca-new.crt"), + path.Join(tempDir, "ca-new.key"), + path.Join(tempDir, "serial-new"), + "proxy-e2e-ca-rotated", + 100*24*time.Hour, + ) + o.Expect(err).NotTo(o.HaveOccurred()) + + newCAPEM, _, err := newCA.Config.GetPEMBytes() + o.Expect(err).NotTo(o.HaveOccurred()) + + cm, err = oc.AdminKubeClient().CoreV1().ConfigMaps("openshift-config").Get(ctx, configMapName, metav1.GetOptions{}) + o.Expect(err).NotTo(o.HaveOccurred()) + cm.Data["ca-bundle.crt"] = string(newCAPEM) + _, err = oc.AdminKubeClient().CoreV1().ConfigMaps("openshift-config").Update(ctx, cm, metav1.UpdateOptions{}) + o.Expect(err).NotTo(o.HaveOccurred()) + + assertOIDCLogin("should be able to log in after setting spec.proxy with trustedCA") + + // Grab oauth-server pod-list again to confirm no-redeployment + oauthServerPodList1, err := oc.AdminKubeClient().CoreV1().Pods("openshift-authentication").List(ctx, metav1.ListOptions{LabelSelector: "app=oauth-openshift"}) + o.Expect(err).NotTo(o.HaveOccurred(), "should be able to query for oauth-server pods") + o.Expect(oauthServerPodList1.Items).NotTo(o.BeEmpty(), "pod items list should contain at least one") + + podNamesBefore := sets.New[string]() + for _, pod := range oauthServerPodList.Items { + podNamesBefore.Insert(pod.Name) + } + + podNamesAfter := sets.New[string]() + for _, pod := range oauthServerPodList1.Items { + podNamesAfter.Insert(pod.Name) + } + + o.Expect(podNamesAfter.Equal(podNamesBefore)).To(o.BeTrue(), "oauth-server pods should not have been redeployed after CA file change") + }) }) type NetworkPolicyMap struct { @@ -271,3 +340,39 @@ type NetworkPolicyCopy struct { name string networkPolicy *networkingv1.NetworkPolicy } + +func updateAuthenticationProxyConfig(ctx context.Context, oc *exutil.CLI, authConfig *operatorv1.Authentication, proxy operatorv1.AuthenticationProxyConfig) { + g.GinkgoHelper() + + modified := authConfig.DeepCopy() + modified.Spec.Proxy = proxy + + _, err := oc.AdminOperatorClient().OperatorV1().Authentications().Update(ctx, modified, metav1.UpdateOptions{}) + o.Expect(err).NotTo(o.HaveOccurred(), "should be able to update the authentication operator proxy config") + + o.Eventually(func(gomega o.Gomega) { + authn, err := oc.AdminOperatorClient().OperatorV1().Authentications().Get(ctx, "cluster", metav1.GetOptions{}) + gomega.Expect(err).NotTo(o.HaveOccurred()) + + progressing := false + for _, cond := range authn.Status.Conditions { + if cond.Type == "Progressing" && cond.Status == operatorv1.ConditionFalse { + progressing = true + break + } + } + gomega.Expect(progressing).To(o.BeTrue(), "authentication operator should finish progressing") + + available := false + for _, cond := range authn.Status.Conditions { + if cond.Type == "Available" && cond.Status == operatorv1.ConditionTrue { + available = true + break + } + } + gomega.Expect(available).To(o.BeTrue(), "authentication operator should be available") + }).WithTimeout(5*time.Minute).WithPolling(10*time.Second).Should(o.Succeed(), "authentication operator should reconcile proxy config") + + err = exoperator.WaitForOperatorsToSettle(ctx, oc.AdminConfigClient(), 10) + o.Expect(err).NotTo(o.HaveOccurred(), "cluster operators should settle after proxy config change") +}