Skip to content

Conversation

mdbooth
Copy link
Contributor

@mdbooth mdbooth commented Sep 16, 2025

No description provided.

Copy link
Contributor

openshift-ci bot commented Sep 16, 2025

Hello @mdbooth! Some important instructions when contributing to openshift/api:
API design plays an important part in the user experience of OpenShift and as such API PRs are subject to a high level of scrutiny to ensure they follow our best practices. If you haven't already done so, please review the OpenShift API Conventions and ensure that your proposed changes are compliant. Following these conventions will help expedite the api review process for your PR.

@openshift-ci openshift-ci bot added the size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. label Sep 16, 2025
Copy link
Contributor

openshift-ci bot commented Sep 16, 2025

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please assign everettraven for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

Copy link
Contributor

openshift-ci bot commented Sep 16, 2025

@mdbooth: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/verify 25be0e6 link true /test verify

Full PR test history. Your PR dashboard.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

// ensure that only a target CRD compatible with compatibilityCRD may be admitted.
// This field is required.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=1000000
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The maximum request size supported is 1.5MiB, in the worst case, each rune will be exactly 1 byte, so the maximum length here should be

Suggested change
// +kubebuilder:validation:MaxLength=1000000
// +kubebuilder:validation:MaxLength=1572864

// metadata is the standard object's metadata.
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
// +optional
metav1.ObjectMeta `json:"metadata"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
metav1.ObjectMeta `json:"metadata"`
metav1.ObjectMeta `json:"metadata,omitzero"`

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The linter didn't warn me about that one!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure why, a bug to look into I guess 🤔

// +kubebuilder:validation:MaxLength:=253
// +kubebuilder:validation:XValidation:rule="!format.dns1123Subdomain().validate(self).hasValue()",message="a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character."
// +required
CRDRef string `json:"crdRef,omitempty"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't use Ref in openshift APIs. I would generally expect this to be more like a local object reference, so to be consistent with other APIs, WDYT of

crd:
  name:

Potentially, instead of crd, what about target?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Certainly ok on dropping ref if that's the convention.

Are you channeling https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#object-references by any chance here?

It is okay to have the "{field}" component indicate the resource type. For example, "secretRef" when referencing a secret. However, this comes with the risk of the field being a misnomer in the case that the field is expanded to reference more than one type.

Could this ever reference a different type? It feels unlikely. That would likely require a different tool. With that in mind, I think crd is more explicit and therefore more obvious. This object is about adding requirements to a CRD, and the CRD is specified in the crd field.

Is there any circumstance when we might add additional information to a CRD reference? The only things I can think of are:

  • UID - this precise CRD and not its successors
  • APIVersion - CRD version v2beta1

So that's realistic, at least.

I'll change it to

  crd:
    name: 

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had leant on target for a few reasons, yes, it's more generic, but also I wondered if it might have been more intuitive and idiomatic, I have seen many targetRef before across K8s APIs. We do talk about the field being a target in the godoc, so it felt like it made sense.

Comment on lines +46 to +47
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength:=253
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent use of := vs = at the end here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a difference between the 2?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't find := in the docs at all now I look for it. I'm assuming I've just cargo-culted this from somewhere and should stop.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kubebuilder supports both := and = on all of its markers. Upstream markers (e.g. +default) do not support :=, so we would prefer all markers use = and we shouldn't use :=.

Has lead to issues in the past where upstream markers have been ignored because of the := typo

Comment on lines +52 to +59
// creatorDescription is a string describing the owner of this CRDCompatibilityRequirement. It will be printed in any error or
// warning emitted by any of the CRDCompatibilityRequirement's webhooks. It should indicate to the recipient who they need to coordinate
// with in order to safely update the target CRD. The message emitted will be: "This requirement was added by <creatorDescription>".
// This field is required.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=253
// +required
CreatorDescription string `json:"creatorDescription,omitempty"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you considered what a valid set of characters might look like for this field? Since this is being used as input to a logging output, I assume it would be bad if I tried to inject some json into this?

creatorDescription: "\" nastySomething:\"doBadThingToLogs\""

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm assuming that any JSON logging library we're using escapes its output. If it doesn't we already have severe problems! We certainly don't want to ask the user to do their own escaping here.

It's a while since I wrote this, and I just re-read it with fresh eyes. I think it's usefully descriptive? I can't think how I would improve it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking along the lines of restricting the valid character set to [a-zA-Z0-9\ ] to prevent folks from putting any data into this string that we need to be worried about or even consider the safety element of

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That just feels like a footgun. For example, it would prevent us from using non-US ASCII characters in a string which is intended to describe people. I don't think we can usefully validate this string, and I think we can trust logging software to escape any possible byte sequence correctly.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kubernetes is built on US ASCII already, all of our APIs, code and even user facing logging is also US ASCII. If we implement this validation, we can always relax it later if we were to get complaints. I'm open to a less restrictive set if you have a suggestion, but I don't think we should leave it unbounded

Comment on lines +46 to +48
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength:=253
// +kubebuilder:validation:XValidation:rule="!format.dns1123Subdomain().validate(self).hasValue()",message="a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character."
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All validations like this must be explained in prose inside the godoc

Suggested change
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength:=253
// +kubebuilder:validation:XValidation:rule="!format.dns1123Subdomain().validate(self).hasValue()",message="a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character."
// crdRef must be at most 253 characters in length and must consist only of lower-case alphanumeric characters, periods (.) and hyphens (-). Each period separated label must start and end with an alphanumeric character and be at most 63 characters in length.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength:=253
// +kubebuilder:validation:XValidation:rule="!format.dns1123Subdomain().validate(self).hasValue()",message="a lowercase RFC 1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character."

Please apply similar feedback to other fields

Copy link
Contributor Author

@mdbooth mdbooth Sep 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Presumably we do this for UX, and in general I get it. However, in this case (and presumably many similar cases), I believe the additional text actually makes the UX worse because it's complex, distracting, and irrelevant. The 'correct' validation here is 'the name of a CRD'. This CRD may or may not exist yet, so we can't even validate it with a VAP. All we're trying to do here with this somewhat complex validation (which I presumably just copied from somewhere) is exclude a certain class of thing which is obviously wrong because it would fail k8s naming validation. If it excludes the valid name of a CRD, that would be a bug. If this ever did happen, the user would open a bug against the product because the field did not accept the name of their CRD, not because they mentally executed the pseudocode in the documentation1. Even if they did read the pseudocode, it might lead them to the incorrect belief that we only intend to support CRDs whose names conform to some arbitrary additional restrictions.

I can see that this kind of validation is useful when we're trying to guide the user to form correct input for something we're going to create, but here we're just referencing something which was validated elsewhere with rules we don't control. Our own validation is nothing more than a loose proxy to exclude a small class of obvious error.

Footnotes

  1. Which in any case hasn't corresponded to the actual validation for the last 18 months since we tweaked it but forgot to make the corresponding change to the pseudocode in the docs, but nobody noticed because we don't run tests against the docs2.

  2. A linter which uses AI to attempt to validate that godoc remains consistent with the code it describes 🤔

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Validation markers are not documented in any user readable documentation by default. We document all validations in the text to explain what the valid values are, so that folks using oc explain or reading our generated API documentation in the product docs have a sense of what value input is.

While I get your point about us documenting a validation that isn't actually ours, we aim to be consistent in validating the field validations across all fields in our APIs, independent of whether its our own restriction, or something imposed upon us

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack. I'll also make it clear that it's a proxy validation, just in case.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The validation of a CRD name is never going to change, I don't think we need to document that this is proxy validation

// CRDCompatibilityRequirementStatus defines the observed status of the CRD Compatibility Requirement.
// +kubebuilder:validation:MinProperties=1
type CRDCompatibilityRequirementStatus struct {
// conditions is a list of conditions and their status.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Document valid condition types?

// +optional
// +listType=map
// +listMapKey=type
// +kubebuilder:validation:MaxItems=16
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a MinItems 1 as well

// uid is the uid of the observed CRD.
// +kubebuilder:validation:MaxLength=36
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:Format=uuid
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC, the API server won't actually validate this at admission time, so we should validate this ourselves with a CEL rule (please test)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm convinced I've written an API validation for this before, but I can't find it now 🤔

Is there a canned one you're aware of that's already battle hardened? It's not actually important, so if this requires anything more than a trivial amount of work I'll just remove the validation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking about it further: this is status. A validation failure here is only ever likely to result in a bug. I'm just going to remove it because it's unnecessary tight coupling.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even though this is status, it should be validated correctly

// +kubebuilder:validation:Format=uuid
// +kubebuilder:validation:XValidation:rule="!format.uuid().validate(self).hasValue()",message="uid must be a valid UUID. It must consist only of lower-case hexadecimal digits, in 5 hyphenated blocks, where the blocks are of length 8-4-4-4-12 respectively."

// metadata is the standard list's metadata.
// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
// +optional
metav1.ListMeta `json:"metadata"`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
metav1.ListMeta `json:"metadata"`
metav1.ListMeta `json:"metadata,omitzero"`

@damdo
Copy link
Member

damdo commented Sep 16, 2025

/assign @damdo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
size/XL Denotes a PR that changes 500-999 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants