-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Strengthen our resource name validation. #3019
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,28 +19,22 @@ package v1alpha1 | |
| import ( | ||
| "fmt" | ||
| "strconv" | ||
| "strings" | ||
|
|
||
| "github.com/knative/pkg/apis" | ||
| "github.com/knative/serving/pkg/apis/autoscaling" | ||
| metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
| "k8s.io/apimachinery/pkg/util/validation" | ||
| ) | ||
|
|
||
| // ValidateObjectMetadata validates that `metadata` stanza of the | ||
| // resources is correct. | ||
| func ValidateObjectMetadata(meta metav1.Object) *apis.FieldError { | ||
| name := meta.GetName() | ||
|
|
||
| if strings.Contains(name, ".") { | ||
| msgs := validation.IsDNS1035Label(name) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the experience mutating an existing object that satisfied the old regex, but breaks the new one? Does it only error if the change touches the metadata, or will it error if anything on the object changes?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you cannot change name |
||
| if len(msgs) > 0 { | ||
| return &apis.FieldError{ | ||
| Message: "Invalid resource name: special character . must not be present", | ||
| Paths: []string{"name"}, | ||
| } | ||
| } | ||
|
|
||
| if len(name) > 63 { | ||
| return &apis.FieldError{ | ||
| Message: "Invalid resource name: length must be no more than 63 characters", | ||
| Message: fmt.Sprintf("not a DNS 1035 label: %v", msgs), | ||
| Paths: []string{"name"}, | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -628,6 +628,9 @@ func TestRevisionValidation(t *testing.T) { | |
| }{{ | ||
| name: "valid", | ||
| r: &Revision{ | ||
| ObjectMeta: metav1.ObjectMeta{ | ||
| Name: "valid", | ||
| }, | ||
| Spec: RevisionSpec{ | ||
| Container: corev1.Container{ | ||
| Image: "helloworld", | ||
|
|
@@ -638,11 +641,18 @@ func TestRevisionValidation(t *testing.T) { | |
| want: nil, | ||
| }, { | ||
| name: "empty spec", | ||
| r: &Revision{}, | ||
| r: &Revision{ | ||
| ObjectMeta: metav1.ObjectMeta{ | ||
| Name: "valid", | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this now required for this test to work, or is this just filling in some forgotten boilerplate on the test table?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, the K8s function rejects empty names, so the validation before was overly weak. |
||
| }, | ||
| }, | ||
| want: apis.ErrMissingField("spec"), | ||
| }, { | ||
| name: "nested spec error", | ||
| r: &Revision{ | ||
| ObjectMeta: metav1.ObjectMeta{ | ||
| Name: "valid", | ||
| }, | ||
| Spec: RevisionSpec{ | ||
| Container: corev1.Container{ | ||
| Name: "kevin", | ||
|
|
@@ -653,10 +663,10 @@ func TestRevisionValidation(t *testing.T) { | |
| }, | ||
| want: apis.ErrDisallowedFields("spec.container.name"), | ||
| }, { | ||
| name: "invalid name - dots", | ||
| name: "invalid name - dots and too long", | ||
| r: &Revision{ | ||
| ObjectMeta: metav1.ObjectMeta{ | ||
| Name: "do.not.use.dots", | ||
| Name: "a" + strings.Repeat(".", 62) + "a", | ||
| }, | ||
| Spec: RevisionSpec{ | ||
| Container: corev1.Container{ | ||
|
|
@@ -665,7 +675,10 @@ func TestRevisionValidation(t *testing.T) { | |
| ConcurrencyModel: "Multi", | ||
| }, | ||
| }, | ||
| want: &apis.FieldError{Message: "Invalid resource name: special character . must not be present", Paths: []string{"metadata.name"}}, | ||
| want: &apis.FieldError{ | ||
| Message: "not a DNS 1035 label: [must be no more than 63 characters a DNS-1035 label must consist of lower case alphanumeric characters or '-', start with an alphabetic character, and end with an alphanumeric character (e.g. 'my-name', or 'abc-123', regex used for validation is '[a-z]([-a-z0-9]*[a-z0-9])?')]", | ||
| Paths: []string{"metadata.name"}, | ||
| }, | ||
| }, { | ||
| name: "invalid metadata.annotations - scale bounds", | ||
| r: &Revision{ | ||
|
|
@@ -687,20 +700,6 @@ func TestRevisionValidation(t *testing.T) { | |
| Message: fmt.Sprintf("%s=%v is less than %s=%v", autoscaling.MaxScaleAnnotationKey, 2, autoscaling.MinScaleAnnotationKey, 5), | ||
| Paths: []string{autoscaling.MaxScaleAnnotationKey, autoscaling.MinScaleAnnotationKey}, | ||
| }).ViaField("annotations").ViaField("metadata"), | ||
| }, { | ||
| name: "invalid name - too long", | ||
| r: &Revision{ | ||
| ObjectMeta: metav1.ObjectMeta{ | ||
| Name: strings.Repeat("a", 65), | ||
| }, | ||
| Spec: RevisionSpec{ | ||
| Container: corev1.Container{ | ||
| Image: "helloworld", | ||
| }, | ||
| ConcurrencyModel: "Multi", | ||
| }, | ||
| }, | ||
| want: &apis.FieldError{Message: "Invalid resource name: length must be no more than 63 characters", Paths: []string{"metadata.name"}}, | ||
| }} | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do you want a test with both error conditions?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not really :) I don't think we need 100% path coverage of a (hopefully) well exercised library. I can add it if you feel strongly (assuming you don't want ~5 versions of that same test).
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FWIW, you can collapse 2 tests into 1 :-)
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done for Revision. |
||
|
|
||
| for _, test := range tests { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something like test/util.go:Error1035 = ...?
When k8s changes this string, it'll be a single place to change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same for the length.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That actually creates an import cycle, and I'm not sure of a good place to put it that could also be shared by autoscaling (we could share it across
pkg/apis/serving/v1alpha1via a private variable).