Skip to content

Commit bf76ef3

Browse files
committed
review updates
Signed-off-by: grokspawn <jordan@nimblewidget.com>
1 parent 2abab13 commit bf76ef3

26 files changed

Lines changed: 541 additions & 411 deletions

‎api/v1/clusterextension_types.go‎

Lines changed: 64 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -149,11 +149,20 @@ const (
149149
// SourceConfig is a discriminated union which selects the installation source.
150150
//
151151
// +union
152-
// +kubebuilder:validation:XValidation:rule="has(self.sourceType) && self.sourceType == 'Catalog' ? has(self.catalog) : !has(self.catalog)",message="catalog is required when sourceType is Catalog, and forbidden otherwise"
153-
// +kubebuilder:validation:XValidation:rule="has(self.sourceType) && self.sourceType == 'OCIImage' ? has(self.ociImage) : !has(self.ociImage)",message="ociImage is required when sourceType is OCIImage, and forbidden otherwise"
152+
// +kubebuilder:validation:XValidation:rule="has(self.sourceType) && self.sourceType == 'Catalog' ? has(self.catalog) && self.catalog.packageName.size() != 0 : !has(self.catalog) || self.catalog.packageName.size() == 0",message="catalog is required when sourceType is Catalog, and forbidden otherwise"
153+
// <opcon:experimental:validation:XValidation:rule="has(self.sourceType) && self.sourceType == 'OCIImage' ? self.ociImage.ref.size() != 0 : self.ociImage.ref.size() == 0",message="ociImage is required when sourceType is OCIImage, and forbidden otherwise">
154154
type SourceConfig struct {
155155
// sourceType is required and specifies the type of install source.
156156
//
157+
// <opcon:standard:description>
158+
// The allowed value is "Catalog".
159+
//
160+
// When set to "Catalog", information for determining the appropriate bundle of content to install
161+
// is fetched from ClusterCatalog resources on the cluster.
162+
// When using the Catalog sourceType, the catalog field must also be set.
163+
// </opcon:standard:description>
164+
//
165+
// <opcon:experimental:description>
157166
// The allowed values are "Catalog" and "OCIImage".
158167
//
159168
// When set to "OCIImage", the bundle image is used directly. Direct sources do not perform
@@ -162,39 +171,79 @@ type SourceConfig struct {
162171
// When set to "Catalog", information for determining the appropriate bundle of content to install
163172
// is fetched from ClusterCatalog resources on the cluster.
164173
// When using the Catalog sourceType, the catalog field must also be set.
174+
// </opcon:experimental:description>
165175
//
166176
// +unionDiscriminator
167-
// +kubebuilder:validation:Enum:="Catalog";"OCIImage"
177+
// +kubebuilder:validation:Enum:="Catalog"
178+
// <opcon:experimental:validation:Enum=Catalog;OCIImage>
168179
// +required
169180
SourceType string `json:"sourceType"`
170181

171182
// catalog configures how information is sourced from a catalog.
172183
// It is required when sourceType is "Catalog", and forbidden otherwise.
173184
//
174185
// +optional
175-
Catalog *CatalogFilter `json:"catalog,omitempty"`
186+
Catalog CatalogFilter `json:"catalog,omitzero"`
176187

177188
// ociImage configures a bundle image to install directly.
189+
// <opcon:experimental:description>
178190
// They do not provide catalog dependency resolution or upgrade safety.
179-
//
191+
// </opcon:experimental:description>
192+
// <opcon:experimental>
180193
// +optional
181-
OCIImage *OCIImageSource `json:"ociImage,omitempty"`
194+
OCIImage OCIImageSource `json:"ociImage,omitzero"`
182195
}
183196

184197
// OCIImageSource identifies a bundle image to install directly from an OCI registry.
198+
// +kubebuilder:validation:MinProperties:=1
185199
type OCIImageSource struct {
186-
// ref is a Docker-style image reference with a tag or digest.
200+
// ref is a required field that defines the reference to a container image for a registry+v1 bundle.
201+
// It cannot be more than 1000 characters.
202+
//
203+
// A reference has 3 parts: the domain, name, and identifier.
204+
//
205+
// The domain is typically the registry where an image is located.
206+
// It must be alphanumeric characters (lowercase and uppercase) separated by the "." character.
207+
// Hyphenation is allowed, but the domain must start and end with alphanumeric characters.
208+
// Specifying a port to use is also allowed by adding the ":" character followed by numeric values.
209+
// The port must be the last value in the domain.
210+
// Some examples of valid domain values are "registry.mydomain.io", "quay.io", "my-registry.io:8080".
211+
//
212+
// The name is typically the repository in the registry where an image is located.
213+
// It must contain lowercase alphanumeric characters separated only by the ".", "_", "__", "-" characters.
214+
// Multiple names can be concatenated with the "/" character.
215+
// The domain and name are combined using the "/" character.
216+
// Some examples of valid name values are "operatorhubio/catalog", "catalog", "my-catalog.prod".
217+
// An example of the domain and name parts of a reference being combined is "quay.io/operatorhubio/catalog".
218+
//
219+
// The identifier is typically the tag or digest for an image reference and is present at the end of the reference.
220+
// It starts with a separator character used to distinguish the end of the name and beginning of the identifier.
221+
// For a digest-based reference, the "@" character is the separator.
222+
// For a tag-based reference, the ":" character is the separator.
223+
// An identifier is required in the reference.
224+
//
225+
// Digest-based references must contain an algorithm reference immediately after the "@" separator.
226+
// The algorithm reference must be followed by the ":" character and an encoded string.
227+
// The algorithm must start with an uppercase or lowercase alpha character followed by alphanumeric characters and may contain the "-", "_", "+", and "." characters.
228+
// Some examples of valid algorithm values are "sha256", "sha256+b64u", "multihash+base58".
229+
// The encoded string following the algorithm must be hex digits (a-f, A-F, 0-9) and must be a minimum of 32 characters.
230+
//
231+
// Tag-based references must begin with a word character (alphanumeric + "_") followed by word characters or ".", and "-" characters.
232+
// The tag must not be longer than 127 characters.
233+
//
234+
// An example of a valid digest-based image reference is "quay.io/operatorhubio/catalog@sha256:200d4ddb2a73594b91358fe6397424e975205bfbe44614f5846033cad64b3f05"
235+
// An example of a valid tag-based image reference is "quay.io/operatorhubio/catalog:latest"
187236
//
188237
// +required
189238
// +kubebuilder:validation:MaxLength:=1000
190-
// +kubebuilder:validation:XValidation:rule="self.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]))+)?(:[0-9]+)?\\\\b\")",message="must start with a valid domain"
191-
// +kubebuilder:validation:XValidation:rule="self.find(\"(\\\\/[a-z0-9]+((([._]|__|[-]*)[a-z0-9]+)+)?((\\\\/[a-z0-9]+((([._]|__|[-]*)[a-z0-9]+)+)?)+)?)\") != \"\"",message="a valid image name is required"
192-
// +kubebuilder:validation:XValidation:rule="self.find(\"(@.*:)\") != \"\" || self.find(\":.*$\") != \"\"",message="must end with a digest or a tag"
193-
// +kubebuilder:validation:XValidation:rule="self.find(\"(@.*:)\") == \"\" ? (self.find(\":.*$\") != \"\" ? self.find(\":.*$\").substring(1).size() <= 127 : true) : true",message="tag is invalid"
194-
// +kubebuilder:validation:XValidation:rule="self.find(\"(@.*:)\") == \"\" ? (self.find(\":.*$\") != \"\" ? self.find(\":.*$\").matches(\":[\\\\w][\\\\w.-]*$\") : true) : true",message="tag is invalid"
195-
// +kubebuilder:validation:XValidation:rule="self.find(\"(@.*:)\") != \"\" ? self.find(\"(@.*:)\").matches(\"(@[A-Za-z][A-Za-z0-9]*([-_+.][A-Za-z][A-Za-z0-9]*)*[:])\") : true",message="digest algorithm is not valid"
196-
// +kubebuilder:validation:XValidation:rule="self.find(\"(@.*:)\") != \"\" ? self.find(\":.*$\").substring(1).size() >= 32 : true",message="digest is not valid"
197-
// +kubebuilder:validation:XValidation:rule="self.find(\"(@.*:)\") != \"\" ? self.find(\":.*$\").matches(\":[0-9A-Fa-f]*$\") : true",message="digest is not valid"
239+
// +kubebuilder:validation:XValidation:rule="self.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]))+)?(:[0-9]+)?\\\\b')",message="must start with a valid domain. valid domains must be alphanumeric characters (lowercase and uppercase) separated by the \".\" character."
240+
// +kubebuilder:validation:XValidation:rule="self.find('(\\\\/[a-z0-9]+((([._]|__|[-]*)[a-z0-9]+)+)?((\\\\/[a-z0-9]+((([._]|__|[-]*)[a-z0-9]+)+)?)+)?)') != \"\"",message="a valid name is required. valid names must contain lowercase alphanumeric characters separated only by the \".\", \"_\", \"__\", \"-\" characters."
241+
// +kubebuilder:validation:XValidation:rule="self.find('(@.*:)') != \"\" || self.find(':.*$') != \"\"",message="must end with a digest or a tag"
242+
// +kubebuilder:validation:XValidation:rule="self.find('(@.*:)') == \"\" ? (self.find(':.*$') != \"\" ? self.find(':.*$').substring(1).size() <= 127 : true) : true",message="tag is invalid. the tag must not be more than 127 characters"
243+
// +kubebuilder:validation:XValidation:rule="self.find('(@.*:)') == \"\" ? (self.find(':.*$') != \"\" ? self.find(':.*$').matches(':[\\\\w][\\\\w.-]*$') : true) : true",message="tag is invalid. valid tags must begin with a word character (alphanumeric + \"_\") followed by word characters or \".\", and \"-\" characters"
244+
// +kubebuilder:validation:XValidation:rule="self.find('(@.*:)') != \"\" ? self.find('(@.*:)').matches('(@[A-Za-z][A-Za-z0-9]*([-_+.][A-Za-z][A-Za-z0-9]*)*[:])') : true",message="digest algorithm is not valid. valid algorithms must start with an uppercase or lowercase alpha character followed by alphanumeric characters and may contain the \"-\", \"_\", \"+\", and \".\" characters."
245+
// +kubebuilder:validation:XValidation:rule="self.find('(@.*:)') != \"\" ? self.find(':.*$').substring(1).size() >= 32 : true",message="digest is not valid. the encoded string must be at least 32 characters"
246+
// +kubebuilder:validation:XValidation:rule="self.find('(@.*:)') != \"\" ? self.find(':.*$').matches(':[0-9A-Fa-f]*$') : true",message="digest is not valid. the encoded string must only contain hex characters (A-F, a-f, 0-9)"
198247
Ref string `json:"ref"`
199248
}
200249

‎api/v1/validation_test.go‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ func TestValidate(t *testing.T) {
2727
s.Namespace = "ns"
2828
s.Source = SourceConfig{
2929
SourceType: SourceTypeCatalog,
30-
Catalog: &CatalogFilter{
30+
Catalog: CatalogFilter{
3131
PackageName: "test",
3232
},
3333
}

‎api/v1/zz_generated.deepcopy.go‎

Lines changed: 2 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎applyconfigurations/api/v1/ociimagesource.go‎

Lines changed: 36 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎applyconfigurations/api/v1/sourceconfig.go‎

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎cmd/operator-controller/main.go‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -665,7 +665,7 @@ func (c *boxcutterReconcilerConfigurator) Configure(ceReconciler *controllers.Cl
665665
controllers.HandleFinalizers(c.finalizers),
666666
controllers.ValidateClusterExtension(
667667
controllers.ServiceAccountDeprecationWarning(),
668-
controllers.DirectBundleRequiresBoxcutter(),
668+
controllers.ValidateDirectBundle(),
669669
),
670670
controllers.MigrateStorage(storageMigrator),
671671
controllers.RetrieveRevisionStates(revisionStatesGetter),
@@ -755,7 +755,7 @@ func (c *helmReconcilerConfigurator) Configure(ceReconciler *controllers.Cluster
755755
controllers.HandleFinalizers(c.finalizers),
756756
controllers.ValidateClusterExtension(
757757
controllers.ServiceAccountDeprecationWarning(),
758-
controllers.DirectBundleRequiresBoxcutter(),
758+
controllers.ValidateDirectBundle(),
759759
),
760760
controllers.RetrieveRevisionStates(revisionStatesGetter),
761761
controllers.ResolveBundle(c.resolver, c.mgr.GetClient()),

0 commit comments

Comments
 (0)