From 4e719939170aabe2ba398f447fc739c1c2cb5c00 Mon Sep 17 00:00:00 2001 From: Joel Speed Date: Tue, 19 Aug 2025 14:19:24 +0100 Subject: [PATCH] Enable SSATags linter to enforce +listType on lists in APIs --- api/openapi-spec/swagger.json | 6 ++---- ...apis__certificates.k8s.io__v1_openapi.json | 6 ++---- hack/golangci-hints.yaml | 6 +++--- hack/golangci.yaml | 6 +++--- hack/kube-api-linter/kube-api-linter.yaml | 6 +++--- pkg/generated/openapi/zz_generated.openapi.go | 20 ------------------- .../k8s.io/api/admission/v1/generated.proto | 1 + staging/src/k8s.io/api/admission/v1/types.go | 1 + .../api/admission/v1beta1/generated.proto | 1 + .../src/k8s.io/api/admission/v1beta1/types.go | 1 + .../api/certificates/v1/generated.proto | 2 -- .../src/k8s.io/api/certificates/v1/types.go | 2 -- .../api/certificates/v1beta1/generated.proto | 2 -- .../k8s.io/api/certificates/v1beta1/types.go | 2 -- 14 files changed, 17 insertions(+), 45 deletions(-) diff --git a/api/openapi-spec/swagger.json b/api/openapi-spec/swagger.json index 7c8928b90e7..8c5f82e53f4 100644 --- a/api/openapi-spec/swagger.json +++ b/api/openapi-spec/swagger.json @@ -4986,8 +4986,7 @@ "request": { "description": "request contains an x509 certificate signing request encoded in a \"CERTIFICATE REQUEST\" PEM block. When serialized as JSON or YAML, the data is additionally base64-encoded.", "format": "byte", - "type": "string", - "x-kubernetes-list-type": "atomic" + "type": "string" }, "signerName": { "description": "signerName indicates the requested signer, and is a qualified name.\n\nList/watch requests for CertificateSigningRequests can filter on this field using a \"spec.signerName=NAME\" fieldSelector.\n\nWell-known Kubernetes signers are:\n 1. \"kubernetes.io/kube-apiserver-client\": issues client certificates that can be used to authenticate to kube-apiserver.\n Requests for this signer are never auto-approved by kube-controller-manager, can be issued by the \"csrsigning\" controller in kube-controller-manager.\n 2. \"kubernetes.io/kube-apiserver-client-kubelet\": issues client certificates that kubelets use to authenticate to kube-apiserver.\n Requests for this signer can be auto-approved by the \"csrapproving\" controller in kube-controller-manager, and can be issued by the \"csrsigning\" controller in kube-controller-manager.\n 3. \"kubernetes.io/kubelet-serving\" issues serving certificates that kubelets use to serve TLS endpoints, which kube-apiserver can connect to securely.\n Requests for this signer are never auto-approved by kube-controller-manager, and can be issued by the \"csrsigning\" controller in kube-controller-manager.\n\nMore details are available at https://k8s.io/docs/reference/access-authn-authz/certificate-signing-requests/#kubernetes-signers\n\nCustom signerNames can also be specified. The signer defines:\n 1. Trust distribution: how trust (CA bundles) are distributed.\n 2. Permitted subjects: and behavior when a disallowed subject is requested.\n 3. Required, permitted, or forbidden x509 extensions in the request (including whether subjectAltNames are allowed, which types, restrictions on allowed values) and behavior when a disallowed extension is requested.\n 4. Required, permitted, or forbidden key usages / extended key usages.\n 5. Expiration/certificate lifetime: whether it is fixed by the signer, configurable by the admin.\n 6. Whether or not requests for CA certificates are allowed.", @@ -5022,8 +5021,7 @@ "certificate": { "description": "certificate is populated with an issued certificate by the signer after an Approved condition is present. This field is set via the /status subresource. Once populated, this field is immutable.\n\nIf the certificate signing request is denied, a condition of type \"Denied\" is added and this field remains empty. If the signer cannot issue the certificate, a condition of type \"Failed\" is added and this field remains empty.\n\nValidation requirements:\n 1. certificate must contain one or more PEM blocks.\n 2. All PEM blocks must have the \"CERTIFICATE\" label, contain no headers, and the encoded data\n must be a BER-encoded ASN.1 Certificate structure as described in section 4 of RFC5280.\n 3. Non-PEM content may appear before or after the \"CERTIFICATE\" PEM blocks and is unvalidated,\n to allow for explanatory text as described in section 5.2 of RFC7468.\n\nIf more than one PEM block is present, and the definition of the requested spec.signerName does not indicate otherwise, the first block is the issued certificate, and subsequent blocks should be treated as intermediate certificates and presented in TLS handshakes.\n\nThe certificate is encoded in PEM format.\n\nWhen serialized as JSON or YAML, the data is additionally base64-encoded, so it consists of:\n\n base64(\n -----BEGIN CERTIFICATE-----\n ...\n -----END CERTIFICATE-----\n )", "format": "byte", - "type": "string", - "x-kubernetes-list-type": "atomic" + "type": "string" }, "conditions": { "description": "conditions applied to the request. Known conditions are \"Approved\", \"Denied\", and \"Failed\".", diff --git a/api/openapi-spec/v3/apis__certificates.k8s.io__v1_openapi.json b/api/openapi-spec/v3/apis__certificates.k8s.io__v1_openapi.json index c26d30d43c8..f00d40f6e8a 100644 --- a/api/openapi-spec/v3/apis__certificates.k8s.io__v1_openapi.json +++ b/api/openapi-spec/v3/apis__certificates.k8s.io__v1_openapi.json @@ -170,8 +170,7 @@ "request": { "description": "request contains an x509 certificate signing request encoded in a \"CERTIFICATE REQUEST\" PEM block. When serialized as JSON or YAML, the data is additionally base64-encoded.", "format": "byte", - "type": "string", - "x-kubernetes-list-type": "atomic" + "type": "string" }, "signerName": { "default": "", @@ -208,8 +207,7 @@ "certificate": { "description": "certificate is populated with an issued certificate by the signer after an Approved condition is present. This field is set via the /status subresource. Once populated, this field is immutable.\n\nIf the certificate signing request is denied, a condition of type \"Denied\" is added and this field remains empty. If the signer cannot issue the certificate, a condition of type \"Failed\" is added and this field remains empty.\n\nValidation requirements:\n 1. certificate must contain one or more PEM blocks.\n 2. All PEM blocks must have the \"CERTIFICATE\" label, contain no headers, and the encoded data\n must be a BER-encoded ASN.1 Certificate structure as described in section 4 of RFC5280.\n 3. Non-PEM content may appear before or after the \"CERTIFICATE\" PEM blocks and is unvalidated,\n to allow for explanatory text as described in section 5.2 of RFC7468.\n\nIf more than one PEM block is present, and the definition of the requested spec.signerName does not indicate otherwise, the first block is the issued certificate, and subsequent blocks should be treated as intermediate certificates and presented in TLS handshakes.\n\nThe certificate is encoded in PEM format.\n\nWhen serialized as JSON or YAML, the data is additionally base64-encoded, so it consists of:\n\n base64(\n -----BEGIN CERTIFICATE-----\n ...\n -----END CERTIFICATE-----\n )", "format": "byte", - "type": "string", - "x-kubernetes-list-type": "atomic" + "type": "string" }, "conditions": { "description": "conditions applied to the request. Known conditions are \"Approved\", \"Denied\", and \"Failed\".", diff --git a/hack/golangci-hints.yaml b/hack/golangci-hints.yaml index 694baf1180d..005f869436d 100644 --- a/hack/golangci-hints.yaml +++ b/hack/golangci-hints.yaml @@ -302,7 +302,7 @@ linters: # - "optionalfields" # Ensure fields marked optional have omitempty and pointers. # - "optionalorrequired" # Every field should be marked as `+optional` xor `+required`. # - "requiredfields" # Required fields should only be pointers when required based on the validity of the zero value, they should always have `omitempty`. - # - "ssatags" # Ensure lists have a listType tag. + - "ssatags" # Ensure lists have a listType tag. # - "uniquemarkers" # Ensure markers are not duplicated across field and type definitions. lintersConfig: conditions: @@ -340,8 +340,8 @@ linters: # policy: SuggestFix | Warn | Ignore # The policy for omitempty in required fields. Defaults to `SuggestFix`. # omitzero: # policy: SuggestFix | Warn | Forbid # The policy for omitzero in required fields. Defaults to `SuggestFix`. - # ssatags: - # listTypeSetUsage: Warn | Ignore # The policy for listType=set usage on object arrays. Defaults to `Warn`. + ssatags: + listTypeSetUsage: Ignore # The policy for listType=set usage on object arrays. Defaults to `Warn`. # uniquemarkers: # customMarkers: # - identifier: custom:SomeCustomMarker diff --git a/hack/golangci.yaml b/hack/golangci.yaml index e5cd1724a2b..3efcb8035e6 100644 --- a/hack/golangci.yaml +++ b/hack/golangci.yaml @@ -316,7 +316,7 @@ linters: # - "optionalfields" # Ensure fields marked optional have omitempty and pointers. # - "optionalorrequired" # Every field should be marked as `+optional` xor `+required`. # - "requiredfields" # Required fields should only be pointers when required based on the validity of the zero value, they should always have `omitempty`. - # - "ssatags" # Ensure lists have a listType tag. + - "ssatags" # Ensure lists have a listType tag. # - "uniquemarkers" # Ensure markers are not duplicated across field and type definitions. lintersConfig: conditions: @@ -354,8 +354,8 @@ linters: # policy: SuggestFix | Warn | Ignore # The policy for omitempty in required fields. Defaults to `SuggestFix`. # omitzero: # policy: SuggestFix | Warn | Forbid # The policy for omitzero in required fields. Defaults to `SuggestFix`. - # ssatags: - # listTypeSetUsage: Warn | Ignore # The policy for listType=set usage on object arrays. Defaults to `Warn`. + ssatags: + listTypeSetUsage: Ignore # The policy for listType=set usage on object arrays. Defaults to `Warn`. # uniquemarkers: # customMarkers: # - identifier: custom:SomeCustomMarker diff --git a/hack/kube-api-linter/kube-api-linter.yaml b/hack/kube-api-linter/kube-api-linter.yaml index ae3c89a3794..dd4f68be6be 100644 --- a/hack/kube-api-linter/kube-api-linter.yaml +++ b/hack/kube-api-linter/kube-api-linter.yaml @@ -17,7 +17,7 @@ linters: # - "optionalfields" # Ensure fields marked optional have omitempty and pointers. # - "optionalorrequired" # Every field should be marked as `+optional` xor `+required`. # - "requiredfields" # Required fields should only be pointers when required based on the validity of the zero value, they should always have `omitempty`. - # - "ssatags" # Ensure lists have a listType tag. + - "ssatags" # Ensure lists have a listType tag. # - "uniquemarkers" # Ensure markers are not duplicated across field and type definitions. lintersConfig: conditions: @@ -55,8 +55,8 @@ lintersConfig: # policy: SuggestFix | Warn | Ignore # The policy for omitempty in required fields. Defaults to `SuggestFix`. # omitzero: # policy: SuggestFix | Warn | Forbid # The policy for omitzero in required fields. Defaults to `SuggestFix`. - # ssatags: - # listTypeSetUsage: Warn | Ignore # The policy for listType=set usage on object arrays. Defaults to `Warn`. + ssatags: + listTypeSetUsage: Ignore # The policy for listType=set usage on object arrays. Defaults to `Warn`. # uniquemarkers: # customMarkers: # - identifier: custom:SomeCustomMarker diff --git a/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index c8cc9d5171f..ccc4bc0a153 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -19253,11 +19253,6 @@ func schema_k8sio_api_certificates_v1_CertificateSigningRequestSpec(ref common.R Type: []string{"object"}, Properties: map[string]spec.Schema{ "request": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", - }, - }, SchemaProps: spec.SchemaProps{ Description: "request contains an x509 certificate signing request encoded in a \"CERTIFICATE REQUEST\" PEM block. When serialized as JSON or YAML, the data is additionally base64-encoded.", Type: []string{"string"}, @@ -19394,11 +19389,6 @@ func schema_k8sio_api_certificates_v1_CertificateSigningRequestStatus(ref common }, }, "certificate": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", - }, - }, SchemaProps: spec.SchemaProps{ Description: "certificate is populated with an issued certificate by the signer after an Approved condition is present. This field is set via the /status subresource. Once populated, this field is immutable.\n\nIf the certificate signing request is denied, a condition of type \"Denied\" is added and this field remains empty. If the signer cannot issue the certificate, a condition of type \"Failed\" is added and this field remains empty.\n\nValidation requirements:\n 1. certificate must contain one or more PEM blocks.\n 2. All PEM blocks must have the \"CERTIFICATE\" label, contain no headers, and the encoded data\n must be a BER-encoded ASN.1 Certificate structure as described in section 4 of RFC5280.\n 3. Non-PEM content may appear before or after the \"CERTIFICATE\" PEM blocks and is unvalidated,\n to allow for explanatory text as described in section 5.2 of RFC7468.\n\nIf more than one PEM block is present, and the definition of the requested spec.signerName does not indicate otherwise, the first block is the issued certificate, and subsequent blocks should be treated as intermediate certificates and presented in TLS handshakes.\n\nThe certificate is encoded in PEM format.\n\nWhen serialized as JSON or YAML, the data is additionally base64-encoded, so it consists of:\n\n base64(\n -----BEGIN CERTIFICATE-----\n ...\n -----END CERTIFICATE-----\n )", Type: []string{"string"}, @@ -19958,11 +19948,6 @@ func schema_k8sio_api_certificates_v1beta1_CertificateSigningRequestSpec(ref com Type: []string{"object"}, Properties: map[string]spec.Schema{ "request": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", - }, - }, SchemaProps: spec.SchemaProps{ Description: "Base64-encoded PKCS#10 CSR data", Type: []string{"string"}, @@ -20096,11 +20081,6 @@ func schema_k8sio_api_certificates_v1beta1_CertificateSigningRequestStatus(ref c }, }, "certificate": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", - }, - }, SchemaProps: spec.SchemaProps{ Description: "If request was approved, the controller will place the issued certificate here.", Type: []string{"string"}, diff --git a/staging/src/k8s.io/api/admission/v1/generated.proto b/staging/src/k8s.io/api/admission/v1/generated.proto index 9648aa58fbc..b99004e4edb 100644 --- a/staging/src/k8s.io/api/admission/v1/generated.proto +++ b/staging/src/k8s.io/api/admission/v1/generated.proto @@ -151,6 +151,7 @@ message AdmissionResponse { // Limit warnings to 120 characters if possible. // Warnings over 256 characters and large numbers of warnings may be truncated. // +optional + // +listType=atomic repeated string warnings = 7; } diff --git a/staging/src/k8s.io/api/admission/v1/types.go b/staging/src/k8s.io/api/admission/v1/types.go index 2def92da5b3..80400070bf8 100644 --- a/staging/src/k8s.io/api/admission/v1/types.go +++ b/staging/src/k8s.io/api/admission/v1/types.go @@ -147,6 +147,7 @@ type AdmissionResponse struct { // Limit warnings to 120 characters if possible. // Warnings over 256 characters and large numbers of warnings may be truncated. // +optional + // +listType=atomic Warnings []string `json:"warnings,omitempty" protobuf:"bytes,7,rep,name=warnings"` } diff --git a/staging/src/k8s.io/api/admission/v1beta1/generated.proto b/staging/src/k8s.io/api/admission/v1beta1/generated.proto index d27c05b727e..cb6b0c4fda1 100644 --- a/staging/src/k8s.io/api/admission/v1beta1/generated.proto +++ b/staging/src/k8s.io/api/admission/v1beta1/generated.proto @@ -151,6 +151,7 @@ message AdmissionResponse { // Limit warnings to 120 characters if possible. // Warnings over 256 characters and large numbers of warnings may be truncated. // +optional + // +listType=atomic repeated string warnings = 7; } diff --git a/staging/src/k8s.io/api/admission/v1beta1/types.go b/staging/src/k8s.io/api/admission/v1beta1/types.go index 00c619d9986..b4a0aa2fa2b 100644 --- a/staging/src/k8s.io/api/admission/v1beta1/types.go +++ b/staging/src/k8s.io/api/admission/v1beta1/types.go @@ -151,6 +151,7 @@ type AdmissionResponse struct { // Limit warnings to 120 characters if possible. // Warnings over 256 characters and large numbers of warnings may be truncated. // +optional + // +listType=atomic Warnings []string `json:"warnings,omitempty" protobuf:"bytes,7,rep,name=warnings"` } diff --git a/staging/src/k8s.io/api/certificates/v1/generated.proto b/staging/src/k8s.io/api/certificates/v1/generated.proto index 24528fc8bc2..dfe74da4aa0 100644 --- a/staging/src/k8s.io/api/certificates/v1/generated.proto +++ b/staging/src/k8s.io/api/certificates/v1/generated.proto @@ -111,7 +111,6 @@ message CertificateSigningRequestList { message CertificateSigningRequestSpec { // request contains an x509 certificate signing request encoded in a "CERTIFICATE REQUEST" PEM block. // When serialized as JSON or YAML, the data is additionally base64-encoded. - // +listType=atomic optional bytes request = 1; // signerName indicates the requested signer, and is a qualified name. @@ -239,7 +238,6 @@ message CertificateSigningRequestStatus { // -----END CERTIFICATE----- // ) // - // +listType=atomic // +optional optional bytes certificate = 2; } diff --git a/staging/src/k8s.io/api/certificates/v1/types.go b/staging/src/k8s.io/api/certificates/v1/types.go index 71203e80d55..aa87fad89b8 100644 --- a/staging/src/k8s.io/api/certificates/v1/types.go +++ b/staging/src/k8s.io/api/certificates/v1/types.go @@ -61,7 +61,6 @@ type CertificateSigningRequest struct { type CertificateSigningRequestSpec struct { // request contains an x509 certificate signing request encoded in a "CERTIFICATE REQUEST" PEM block. // When serialized as JSON or YAML, the data is additionally base64-encoded. - // +listType=atomic Request []byte `json:"request" protobuf:"bytes,1,opt,name=request"` // signerName indicates the requested signer, and is a qualified name. @@ -214,7 +213,6 @@ type CertificateSigningRequestStatus struct { // -----END CERTIFICATE----- // ) // - // +listType=atomic // +optional Certificate []byte `json:"certificate,omitempty" protobuf:"bytes,2,opt,name=certificate"` } diff --git a/staging/src/k8s.io/api/certificates/v1beta1/generated.proto b/staging/src/k8s.io/api/certificates/v1beta1/generated.proto index 4c9385c1960..223dc485de9 100644 --- a/staging/src/k8s.io/api/certificates/v1beta1/generated.proto +++ b/staging/src/k8s.io/api/certificates/v1beta1/generated.proto @@ -86,7 +86,6 @@ message CertificateSigningRequestList { // CertificateSigningRequestSpec contains the certificate request. message CertificateSigningRequestSpec { // Base64-encoded PKCS#10 CSR data - // +listType=atomic optional bytes request = 1; // Requested signer for the request. It is a qualified name in the form: @@ -192,7 +191,6 @@ message CertificateSigningRequestStatus { repeated CertificateSigningRequestCondition conditions = 1; // If request was approved, the controller will place the issued certificate here. - // +listType=atomic // +optional optional bytes certificate = 2; } diff --git a/staging/src/k8s.io/api/certificates/v1beta1/types.go b/staging/src/k8s.io/api/certificates/v1beta1/types.go index fadb7e082ef..2a9648ef169 100644 --- a/staging/src/k8s.io/api/certificates/v1beta1/types.go +++ b/staging/src/k8s.io/api/certificates/v1beta1/types.go @@ -51,7 +51,6 @@ type CertificateSigningRequest struct { // CertificateSigningRequestSpec contains the certificate request. type CertificateSigningRequestSpec struct { // Base64-encoded PKCS#10 CSR data - // +listType=atomic Request []byte `json:"request" protobuf:"bytes,1,opt,name=request"` // Requested signer for the request. It is a qualified name in the form: @@ -185,7 +184,6 @@ type CertificateSigningRequestStatus struct { Conditions []CertificateSigningRequestCondition `json:"conditions,omitempty" protobuf:"bytes,1,rep,name=conditions"` // If request was approved, the controller will place the issued certificate here. - // +listType=atomic // +optional Certificate []byte `json:"certificate,omitempty" protobuf:"bytes,2,opt,name=certificate"` }