diff --git a/api/core/v1alpha1/clustercatalog_types.go b/api/core/v1alpha1/clustercatalog_types.go index 595c4280..df38ec6a 100644 --- a/api/core/v1alpha1/clustercatalog_types.go +++ b/api/core/v1alpha1/clustercatalog_types.go @@ -311,8 +311,11 @@ type ResolvedImageSource struct { // Check for the existence of either a digest or tag reference at the end of the image reference // +kubebuilder:validation:XValidation:rule="self.ref.find('(@.*:)') != \"\" || self.ref.find(':.*$') != \"\"",message="ref is invalid, must end with a digest or a tag" // -// If we don't find a digest in the reference, attempt to find the tag. Check if the tag is valid -// +kubebuilder:validation:XValidation:rule="self.ref.find('(@.*:)') == \"\" ? (self.ref.find(':.*$') != \"\" ? self.ref.find(':.*$').matches(':[\\\\w][\\\\w.-]{0,127}$') : true) : true",message="ref is invalid, tag is invalid" +// If we don't find a digest in the reference, attempt to find the tag. Check that the tag is less than 127 characters +// +kubebuilder:validation:XValidation:rule="self.ref.find('(@.*:)') == \"\" ? (self.ref.find(':.*$') != \"\" ? self.ref.find(':.*$').substring(1).size() <= 127 : true) : true",message="ref is invalid, tag is invalid. the tag must not be more than 127 characters" +// +// If we don't find a digest in the reference, attempt to find the tag. Check that the tag is valid (word characters) +// +kubebuilder:validation:XValidation:rule="self.ref.find('(@.*:)') == \"\" ? (self.ref.find(':.*$') != \"\" ? self.ref.find(':.*$').matches(':[\\\\w][\\\\w.-]*$') : true) : true",message="ref is invalid, tag is invalid. tag-based references must begin with a word character (alphanumeric + \"_\") followed by word characters or \".\", and \"-\" characters" // // If we find a digest in the reference, check that the digest algorithm is valid // +kubebuilder:validation:XValidation:rule="self.ref.find('(@.*:)') != \"\" ? self.ref.find('(@.*:)').matches('(@[A-Za-z][A-Za-z0-9]*([-_+.][A-Za-z][A-Za-z0-9]*)*[:])') : true",message="ref is invalid, digest algorithm is not valid. the algorithm must start with an uppercase or lowercase alpha character followed by alphanumeric characters and may contain the \"-\", \"_\", \"+\", and \".\" characters." diff --git a/api/core/v1alpha1/clustercatalog_types_test.go b/api/core/v1alpha1/clustercatalog_types_test.go index c24927f4..903e2aa5 100644 --- a/api/core/v1alpha1/clustercatalog_types_test.go +++ b/api/core/v1alpha1/clustercatalog_types_test.go @@ -98,7 +98,7 @@ func TestImageSourceCELValidationRules(t *testing.T) { Ref: fmt.Sprintf("docker.io/foo/bar:%s", strings.Repeat("x", 200)), }, wantErrs: []string{ - "openAPIV3Schema.properties.spec.properties.source.properties.image: Invalid value: \"object\": ref is invalid, tag is invalid", + "openAPIV3Schema.properties.spec.properties.source.properties.image: Invalid value: \"object\": ref is invalid, tag is invalid. the tag must not be more than 127 characters", }, }, "invalid tag based image ref, tag contains invalid characters": { @@ -106,7 +106,7 @@ func TestImageSourceCELValidationRules(t *testing.T) { Ref: "docker.io/foo/bar:-foo_bar-", }, wantErrs: []string{ - "openAPIV3Schema.properties.spec.properties.source.properties.image: Invalid value: \"object\": ref is invalid, tag is invalid", + "openAPIV3Schema.properties.spec.properties.source.properties.image: Invalid value: \"object\": ref is invalid, tag is invalid. tag-based references must begin with a word character (alphanumeric + \"_\") followed by word characters or \".\", and \"-\" characters", }, }, "valid tag based image ref": { @@ -130,6 +130,18 @@ func TestImageSourceCELValidationRules(t *testing.T) { "openAPIV3Schema.properties.spec.properties.source.properties.image: Invalid value: \"object\": ref is invalid, a valid name is required", }, }, + "valid image ref, domain with port": { + spec: ImageSource{ + Ref: "my-subdomain.docker.io:8080/foo/bar:latest", + }, + wantErrs: []string{}, + }, + "valid image ref, tag ends with hyphen": { + spec: ImageSource{ + Ref: "my-subdomain.docker.io:8080/foo/bar:latest-", + }, + wantErrs: []string{}, + }, } { t.Run(name, func(t *testing.T) { obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&tc.spec) //nolint:gosec diff --git a/config/base/crd/bases/olm.operatorframework.io_clustercatalogs.yaml b/config/base/crd/bases/olm.operatorframework.io_clustercatalogs.yaml index aa71fc7d..f37c1c5e 100644 --- a/config/base/crd/bases/olm.operatorframework.io_clustercatalogs.yaml +++ b/config/base/crd/bases/olm.operatorframework.io_clustercatalogs.yaml @@ -187,9 +187,16 @@ spec: - message: ref is invalid, must end with a digest or a tag rule: self.ref.find('(@.*:)') != "" || self.ref.find(':.*$') != "" - - message: ref is invalid, tag is invalid + - message: ref is invalid, tag is invalid. the tag must not be + more than 127 characters rule: 'self.ref.find(''(@.*:)'') == "" ? (self.ref.find('':.*$'') - != "" ? self.ref.find('':.*$'').matches('':[\\w][\\w.-]{0,127}$'') + != "" ? self.ref.find('':.*$'').substring(1).size() <= 127 + : true) : true' + - message: ref is invalid, tag is invalid. tag-based references + must begin with a word character (alphanumeric + "_") followed + by word characters or ".", and "-" characters + rule: 'self.ref.find(''(@.*:)'') == "" ? (self.ref.find('':.*$'') + != "" ? self.ref.find('':.*$'').matches('':[\\w][\\w.-]*$'') : true) : true' - message: ref is invalid, digest algorithm is not valid. the algorithm must start with an uppercase or lowercase alpha