diff --git a/Makefile b/Makefile index a0b08df48..b68a895bf 100644 --- a/Makefile +++ b/Makefile @@ -115,7 +115,6 @@ manifests: controller-gen ## Generate manifests, e.g. CRD, RBAC, etc. cd api; $(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=manager-role paths="./..." output:crd:artifacts:config="../config/crd/bases" api-docs: gen-crd-api-reference-docs ## Generate API reference documentation - $(GEN_CRD_API_REFERENCE_DOCS) -api-dir=./api/v1beta2 -config=./hack/api-docs/config.json -template-dir=./hack/api-docs/template -out-file=./docs/api/v1beta2/source.md $(GEN_CRD_API_REFERENCE_DOCS) -api-dir=./api/v1 -config=./hack/api-docs/config.json -template-dir=./hack/api-docs/template -out-file=./docs/api/v1/source.md tidy: ## Run go mod tidy diff --git a/PROJECT b/PROJECT index 0c243993c..8f7b42aef 100644 --- a/PROJECT +++ b/PROJECT @@ -40,4 +40,7 @@ resources: - group: source kind: Bucket version: v1 +- group: source + kind: OCIRepository + version: v1 version: "2" diff --git a/README.md b/README.md index 1838328d2..6f07b2e00 100644 --- a/README.md +++ b/README.md @@ -16,13 +16,13 @@ and is a core component of the [GitOps toolkit](https://fluxcd.io/flux/component ## APIs -| Kind | API Version | -|-------------------------------------------------------|------------------------------------| -| [GitRepository](docs/spec/v1/gitrepositories.md) | `source.toolkit.fluxcd.io/v1` | -| [OCIRepository](docs/spec/v1beta2/ocirepositories.md) | `source.toolkit.fluxcd.io/v1beta2` | -| [HelmRepository](docs/spec/v1/helmrepositories.md) | `source.toolkit.fluxcd.io/v1` | -| [HelmChart](docs/spec/v1/helmcharts.md) | `source.toolkit.fluxcd.io/v1` | -| [Bucket](docs/spec/v1/buckets.md) | `source.toolkit.fluxcd.io/v1` | +| Kind | API Version | +|----------------------------------------------------|-------------------------------| +| [GitRepository](docs/spec/v1/gitrepositories.md) | `source.toolkit.fluxcd.io/v1` | +| [OCIRepository](docs/spec/v1/ocirepositories.md) | `source.toolkit.fluxcd.io/v1` | +| [HelmRepository](docs/spec/v1/helmrepositories.md) | `source.toolkit.fluxcd.io/v1` | +| [HelmChart](docs/spec/v1/helmcharts.md) | `source.toolkit.fluxcd.io/v1` | +| [Bucket](docs/spec/v1/buckets.md) | `source.toolkit.fluxcd.io/v1` | ## Features diff --git a/api/go.mod b/api/go.mod index 8429d555c..0ba0df120 100644 --- a/api/go.mod +++ b/api/go.mod @@ -22,8 +22,8 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/spf13/pflag v1.0.6 // indirect github.com/x448/float16 v0.8.4 // indirect - golang.org/x/net v0.39.0 // indirect - golang.org/x/text v0.24.0 // indirect + golang.org/x/net v0.40.0 // indirect + golang.org/x/text v0.25.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/inf.v0 v0.9.1 // indirect k8s.io/api v0.33.0 // indirect diff --git a/api/go.sum b/api/go.sum index 76f507298..120636b80 100644 --- a/api/go.sum +++ b/api/go.sum @@ -64,20 +64,20 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= -golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= +golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= -golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= -golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= +golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= diff --git a/api/v1/ocirepository_types.go b/api/v1/ocirepository_types.go new file mode 100644 index 000000000..b12773a66 --- /dev/null +++ b/api/v1/ocirepository_types.go @@ -0,0 +1,296 @@ +/* +Copyright 2025 The Flux authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/fluxcd/pkg/apis/meta" +) + +const ( + // OCIRepositoryKind is the string representation of an OCIRepository. + OCIRepositoryKind = "OCIRepository" + + // OCIRepositoryPrefix is the prefix used for OCIRepository URLs. + OCIRepositoryPrefix = "oci://" + + // GenericOCIProvider provides support for authentication using static credentials + // for any OCI compatible API such as Docker Registry, GitHub Container Registry, + // Docker Hub, Quay, etc. + GenericOCIProvider string = "generic" + + // AmazonOCIProvider provides support for OCI authentication using AWS IRSA. + AmazonOCIProvider string = "aws" + + // GoogleOCIProvider provides support for OCI authentication using GCP workload identity. + GoogleOCIProvider string = "gcp" + + // AzureOCIProvider provides support for OCI authentication using a Azure Service Principal, + // Managed Identity or Shared Key. + AzureOCIProvider string = "azure" + + // OCILayerExtract defines the operation type for extracting the content from an OCI artifact layer. + OCILayerExtract = "extract" + + // OCILayerCopy defines the operation type for copying the content from an OCI artifact layer. + OCILayerCopy = "copy" +) + +// OCIRepositorySpec defines the desired state of OCIRepository +type OCIRepositorySpec struct { + // URL is a reference to an OCI artifact repository hosted + // on a remote container registry. + // +kubebuilder:validation:Pattern="^oci://.*$" + // +required + URL string `json:"url"` + + // The OCI reference to pull and monitor for changes, + // defaults to the latest tag. + // +optional + Reference *OCIRepositoryRef `json:"ref,omitempty"` + + // LayerSelector specifies which layer should be extracted from the OCI artifact. + // When not specified, the first layer found in the artifact is selected. + // +optional + LayerSelector *OCILayerSelector `json:"layerSelector,omitempty"` + + // The provider used for authentication, can be 'aws', 'azure', 'gcp' or 'generic'. + // When not specified, defaults to 'generic'. + // +kubebuilder:validation:Enum=generic;aws;azure;gcp + // +kubebuilder:default:=generic + // +optional + Provider string `json:"provider,omitempty"` + + // SecretRef contains the secret name containing the registry login + // credentials to resolve image metadata. + // The secret must be of type kubernetes.io/dockerconfigjson. + // +optional + SecretRef *meta.LocalObjectReference `json:"secretRef,omitempty"` + + // Verify contains the secret name containing the trusted public keys + // used to verify the signature and specifies which provider to use to check + // whether OCI image is authentic. + // +optional + Verify *OCIRepositoryVerification `json:"verify,omitempty"` + + // ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate + // the image pull if the service account has attached pull secrets. For more information: + // https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account + // +optional + ServiceAccountName string `json:"serviceAccountName,omitempty"` + + // CertSecretRef can be given the name of a Secret containing + // either or both of + // + // - a PEM-encoded client certificate (`tls.crt`) and private + // key (`tls.key`); + // - a PEM-encoded CA certificate (`ca.crt`) + // + // and whichever are supplied, will be used for connecting to the + // registry. The client cert and key are useful if you are + // authenticating with a certificate; the CA cert is useful if + // you are using a self-signed server certificate. The Secret must + // be of type `Opaque` or `kubernetes.io/tls`. + // +optional + CertSecretRef *meta.LocalObjectReference `json:"certSecretRef,omitempty"` + + // ProxySecretRef specifies the Secret containing the proxy configuration + // to use while communicating with the container registry. + // +optional + ProxySecretRef *meta.LocalObjectReference `json:"proxySecretRef,omitempty"` + + // Interval at which the OCIRepository URL is checked for updates. + // This interval is approximate and may be subject to jitter to ensure + // efficient use of resources. + // +kubebuilder:validation:Type=string + // +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m|h))+$" + // +required + Interval metav1.Duration `json:"interval"` + + // The timeout for remote OCI Repository operations like pulling, defaults to 60s. + // +kubebuilder:default="60s" + // +kubebuilder:validation:Type=string + // +kubebuilder:validation:Pattern="^([0-9]+(\\.[0-9]+)?(ms|s|m))+$" + // +optional + Timeout *metav1.Duration `json:"timeout,omitempty"` + + // Ignore overrides the set of excluded patterns in the .sourceignore format + // (which is the same as .gitignore). If not provided, a default will be used, + // consult the documentation for your version to find out what those are. + // +optional + Ignore *string `json:"ignore,omitempty"` + + // Insecure allows connecting to a non-TLS HTTP container registry. + // +optional + Insecure bool `json:"insecure,omitempty"` + + // This flag tells the controller to suspend the reconciliation of this source. + // +optional + Suspend bool `json:"suspend,omitempty"` +} + +// OCIRepositoryRef defines the image reference for the OCIRepository's URL +type OCIRepositoryRef struct { + // Digest is the image digest to pull, takes precedence over SemVer. + // The value should be in the format 'sha256:'. + // +optional + Digest string `json:"digest,omitempty"` + + // SemVer is the range of tags to pull selecting the latest within + // the range, takes precedence over Tag. + // +optional + SemVer string `json:"semver,omitempty"` + + // SemverFilter is a regex pattern to filter the tags within the SemVer range. + // +optional + SemverFilter string `json:"semverFilter,omitempty"` + + // Tag is the image tag to pull, defaults to latest. + // +optional + Tag string `json:"tag,omitempty"` +} + +// OCILayerSelector specifies which layer should be extracted from an OCI Artifact +type OCILayerSelector struct { + // MediaType specifies the OCI media type of the layer + // which should be extracted from the OCI Artifact. The + // first layer matching this type is selected. + // +optional + MediaType string `json:"mediaType,omitempty"` + + // Operation specifies how the selected layer should be processed. + // By default, the layer compressed content is extracted to storage. + // When the operation is set to 'copy', the layer compressed content + // is persisted to storage as it is. + // +kubebuilder:validation:Enum=extract;copy + // +optional + Operation string `json:"operation,omitempty"` +} + +// OCIRepositoryStatus defines the observed state of OCIRepository +type OCIRepositoryStatus struct { + // ObservedGeneration is the last observed generation. + // +optional + ObservedGeneration int64 `json:"observedGeneration,omitempty"` + + // Conditions holds the conditions for the OCIRepository. + // +optional + Conditions []metav1.Condition `json:"conditions,omitempty"` + + // URL is the download link for the artifact output of the last OCI Repository sync. + // +optional + URL string `json:"url,omitempty"` + + // Artifact represents the output of the last successful OCI Repository sync. + // +optional + Artifact *Artifact `json:"artifact,omitempty"` + + // ObservedIgnore is the observed exclusion patterns used for constructing + // the source artifact. + // +optional + ObservedIgnore *string `json:"observedIgnore,omitempty"` + + // ObservedLayerSelector is the observed layer selector used for constructing + // the source artifact. + // +optional + ObservedLayerSelector *OCILayerSelector `json:"observedLayerSelector,omitempty"` + + meta.ReconcileRequestStatus `json:",inline"` +} + +const ( + // OCIPullFailedReason signals that a pull operation failed. + OCIPullFailedReason string = "OCIArtifactPullFailed" + + // OCILayerOperationFailedReason signals that an OCI layer operation failed. + OCILayerOperationFailedReason string = "OCIArtifactLayerOperationFailed" +) + +// GetConditions returns the status conditions of the object. +func (in OCIRepository) GetConditions() []metav1.Condition { + return in.Status.Conditions +} + +// SetConditions sets the status conditions on the object. +func (in *OCIRepository) SetConditions(conditions []metav1.Condition) { + in.Status.Conditions = conditions +} + +// GetRequeueAfter returns the duration after which the OCIRepository must be +// reconciled again. +func (in OCIRepository) GetRequeueAfter() time.Duration { + return in.Spec.Interval.Duration +} + +// GetArtifact returns the latest Artifact from the OCIRepository if present in +// the status sub-resource. +func (in *OCIRepository) GetArtifact() *Artifact { + return in.Status.Artifact +} + +// GetLayerMediaType returns the media type layer selector if found in spec. +func (in *OCIRepository) GetLayerMediaType() string { + if in.Spec.LayerSelector == nil { + return "" + } + + return in.Spec.LayerSelector.MediaType +} + +// GetLayerOperation returns the layer selector operation (defaults to extract). +func (in *OCIRepository) GetLayerOperation() string { + if in.Spec.LayerSelector == nil || in.Spec.LayerSelector.Operation == "" { + return OCILayerExtract + } + + return in.Spec.LayerSelector.Operation +} + +// +genclient +// +kubebuilder:storageversion +// +kubebuilder:object:root=true +// +kubebuilder:resource:shortName=ocirepo +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="URL",type=string,JSONPath=`.spec.url` +// +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",description="" +// +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].message",description="" +// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp",description="" + +// OCIRepository is the Schema for the ocirepositories API +type OCIRepository struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec OCIRepositorySpec `json:"spec,omitempty"` + // +kubebuilder:default={"observedGeneration":-1} + Status OCIRepositoryStatus `json:"status,omitempty"` +} + +// OCIRepositoryList contains a list of OCIRepository +// +kubebuilder:object:root=true +type OCIRepositoryList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []OCIRepository `json:"items"` +} + +func init() { + SchemeBuilder.Register(&OCIRepository{}, &OCIRepositoryList{}) +} diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index 9ac5d593d..0a8fb3583 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -696,6 +696,189 @@ func (in *LocalHelmChartSourceReference) DeepCopy() *LocalHelmChartSourceReferen return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OCILayerSelector) DeepCopyInto(out *OCILayerSelector) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OCILayerSelector. +func (in *OCILayerSelector) DeepCopy() *OCILayerSelector { + if in == nil { + return nil + } + out := new(OCILayerSelector) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OCIRepository) DeepCopyInto(out *OCIRepository) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OCIRepository. +func (in *OCIRepository) DeepCopy() *OCIRepository { + if in == nil { + return nil + } + out := new(OCIRepository) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *OCIRepository) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OCIRepositoryList) DeepCopyInto(out *OCIRepositoryList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]OCIRepository, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OCIRepositoryList. +func (in *OCIRepositoryList) DeepCopy() *OCIRepositoryList { + if in == nil { + return nil + } + out := new(OCIRepositoryList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *OCIRepositoryList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OCIRepositoryRef) DeepCopyInto(out *OCIRepositoryRef) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OCIRepositoryRef. +func (in *OCIRepositoryRef) DeepCopy() *OCIRepositoryRef { + if in == nil { + return nil + } + out := new(OCIRepositoryRef) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OCIRepositorySpec) DeepCopyInto(out *OCIRepositorySpec) { + *out = *in + if in.Reference != nil { + in, out := &in.Reference, &out.Reference + *out = new(OCIRepositoryRef) + **out = **in + } + if in.LayerSelector != nil { + in, out := &in.LayerSelector, &out.LayerSelector + *out = new(OCILayerSelector) + **out = **in + } + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef + *out = new(meta.LocalObjectReference) + **out = **in + } + if in.Verify != nil { + in, out := &in.Verify, &out.Verify + *out = new(OCIRepositoryVerification) + (*in).DeepCopyInto(*out) + } + if in.CertSecretRef != nil { + in, out := &in.CertSecretRef, &out.CertSecretRef + *out = new(meta.LocalObjectReference) + **out = **in + } + if in.ProxySecretRef != nil { + in, out := &in.ProxySecretRef, &out.ProxySecretRef + *out = new(meta.LocalObjectReference) + **out = **in + } + out.Interval = in.Interval + if in.Timeout != nil { + in, out := &in.Timeout, &out.Timeout + *out = new(metav1.Duration) + **out = **in + } + if in.Ignore != nil { + in, out := &in.Ignore, &out.Ignore + *out = new(string) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OCIRepositorySpec. +func (in *OCIRepositorySpec) DeepCopy() *OCIRepositorySpec { + if in == nil { + return nil + } + out := new(OCIRepositorySpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OCIRepositoryStatus) DeepCopyInto(out *OCIRepositoryStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]metav1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Artifact != nil { + in, out := &in.Artifact, &out.Artifact + *out = new(Artifact) + (*in).DeepCopyInto(*out) + } + if in.ObservedIgnore != nil { + in, out := &in.ObservedIgnore, &out.ObservedIgnore + *out = new(string) + **out = **in + } + if in.ObservedLayerSelector != nil { + in, out := &in.ObservedLayerSelector, &out.ObservedLayerSelector + *out = new(OCILayerSelector) + **out = **in + } + out.ReconcileRequestStatus = in.ReconcileRequestStatus +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OCIRepositoryStatus. +func (in *OCIRepositoryStatus) DeepCopy() *OCIRepositoryStatus { + if in == nil { + return nil + } + out := new(OCIRepositoryStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OCIRepositoryVerification) DeepCopyInto(out *OCIRepositoryVerification) { *out = *in diff --git a/api/v1beta2/ocirepository_types.go b/api/v1beta2/ocirepository_types.go index 9030fab74..55a513410 100644 --- a/api/v1beta2/ocirepository_types.go +++ b/api/v1beta2/ocirepository_types.go @@ -283,10 +283,10 @@ func (in *OCIRepository) GetLayerOperation() string { } // +genclient -// +kubebuilder:storageversion // +kubebuilder:object:root=true // +kubebuilder:resource:shortName=ocirepo // +kubebuilder:subresource:status +// +kubebuilder:deprecatedversion:warning="v1beta2 OCIRepository is deprecated, upgrade to v1" // +kubebuilder:printcolumn:name="URL",type=string,JSONPath=`.spec.url` // +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].status",description="" // +kubebuilder:printcolumn:name="Status",type="string",JSONPath=".status.conditions[?(@.type==\"Ready\")].message",description="" diff --git a/config/crd/bases/source.toolkit.fluxcd.io_ocirepositories.yaml b/config/crd/bases/source.toolkit.fluxcd.io_ocirepositories.yaml index a60b7b416..589a275d0 100644 --- a/config/crd/bases/source.toolkit.fluxcd.io_ocirepositories.yaml +++ b/config/crd/bases/source.toolkit.fluxcd.io_ocirepositories.yaml @@ -29,6 +29,400 @@ spec: - jsonPath: .metadata.creationTimestamp name: Age type: date + name: v1 + schema: + openAPIV3Schema: + description: OCIRepository is the Schema for the ocirepositories API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: OCIRepositorySpec defines the desired state of OCIRepository + properties: + certSecretRef: + description: |- + CertSecretRef can be given the name of a Secret containing + either or both of + + - a PEM-encoded client certificate (`tls.crt`) and private + key (`tls.key`); + - a PEM-encoded CA certificate (`ca.crt`) + + and whichever are supplied, will be used for connecting to the + registry. The client cert and key are useful if you are + authenticating with a certificate; the CA cert is useful if + you are using a self-signed server certificate. The Secret must + be of type `Opaque` or `kubernetes.io/tls`. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + ignore: + description: |- + Ignore overrides the set of excluded patterns in the .sourceignore format + (which is the same as .gitignore). If not provided, a default will be used, + consult the documentation for your version to find out what those are. + type: string + insecure: + description: Insecure allows connecting to a non-TLS HTTP container + registry. + type: boolean + interval: + description: |- + Interval at which the OCIRepository URL is checked for updates. + This interval is approximate and may be subject to jitter to ensure + efficient use of resources. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m|h))+$ + type: string + layerSelector: + description: |- + LayerSelector specifies which layer should be extracted from the OCI artifact. + When not specified, the first layer found in the artifact is selected. + properties: + mediaType: + description: |- + MediaType specifies the OCI media type of the layer + which should be extracted from the OCI Artifact. The + first layer matching this type is selected. + type: string + operation: + description: |- + Operation specifies how the selected layer should be processed. + By default, the layer compressed content is extracted to storage. + When the operation is set to 'copy', the layer compressed content + is persisted to storage as it is. + enum: + - extract + - copy + type: string + type: object + provider: + default: generic + description: |- + The provider used for authentication, can be 'aws', 'azure', 'gcp' or 'generic'. + When not specified, defaults to 'generic'. + enum: + - generic + - aws + - azure + - gcp + type: string + proxySecretRef: + description: |- + ProxySecretRef specifies the Secret containing the proxy configuration + to use while communicating with the container registry. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + ref: + description: |- + The OCI reference to pull and monitor for changes, + defaults to the latest tag. + properties: + digest: + description: |- + Digest is the image digest to pull, takes precedence over SemVer. + The value should be in the format 'sha256:'. + type: string + semver: + description: |- + SemVer is the range of tags to pull selecting the latest within + the range, takes precedence over Tag. + type: string + semverFilter: + description: SemverFilter is a regex pattern to filter the tags + within the SemVer range. + type: string + tag: + description: Tag is the image tag to pull, defaults to latest. + type: string + type: object + secretRef: + description: |- + SecretRef contains the secret name containing the registry login + credentials to resolve image metadata. + The secret must be of type kubernetes.io/dockerconfigjson. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + serviceAccountName: + description: |- + ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate + the image pull if the service account has attached pull secrets. For more information: + https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account + type: string + suspend: + description: This flag tells the controller to suspend the reconciliation + of this source. + type: boolean + timeout: + default: 60s + description: The timeout for remote OCI Repository operations like + pulling, defaults to 60s. + pattern: ^([0-9]+(\.[0-9]+)?(ms|s|m))+$ + type: string + url: + description: |- + URL is a reference to an OCI artifact repository hosted + on a remote container registry. + pattern: ^oci://.*$ + type: string + verify: + description: |- + Verify contains the secret name containing the trusted public keys + used to verify the signature and specifies which provider to use to check + whether OCI image is authentic. + properties: + matchOIDCIdentity: + description: |- + MatchOIDCIdentity specifies the identity matching criteria to use + while verifying an OCI artifact which was signed using Cosign keyless + signing. The artifact's identity is deemed to be verified if any of the + specified matchers match against the identity. + items: + description: |- + OIDCIdentityMatch specifies options for verifying the certificate identity, + i.e. the issuer and the subject of the certificate. + properties: + issuer: + description: |- + Issuer specifies the regex pattern to match against to verify + the OIDC issuer in the Fulcio certificate. The pattern must be a + valid Go regular expression. + type: string + subject: + description: |- + Subject specifies the regex pattern to match against to verify + the identity subject in the Fulcio certificate. The pattern must + be a valid Go regular expression. + type: string + required: + - issuer + - subject + type: object + type: array + provider: + default: cosign + description: Provider specifies the technology used to sign the + OCI Artifact. + enum: + - cosign + - notation + type: string + secretRef: + description: |- + SecretRef specifies the Kubernetes Secret containing the + trusted public keys. + properties: + name: + description: Name of the referent. + type: string + required: + - name + type: object + required: + - provider + type: object + required: + - interval + - url + type: object + status: + default: + observedGeneration: -1 + description: OCIRepositoryStatus defines the observed state of OCIRepository + properties: + artifact: + description: Artifact represents the output of the last successful + OCI Repository sync. + properties: + digest: + description: Digest is the digest of the file in the form of ':'. + pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$ + type: string + lastUpdateTime: + description: |- + LastUpdateTime is the timestamp corresponding to the last update of the + Artifact. + format: date-time + type: string + metadata: + additionalProperties: + type: string + description: Metadata holds upstream information such as OCI annotations. + type: object + path: + description: |- + Path is the relative file path of the Artifact. It can be used to locate + the file in the root of the Artifact storage on the local file system of + the controller managing the Source. + type: string + revision: + description: |- + Revision is a human-readable identifier traceable in the origin source + system. It can be a Git commit SHA, Git tag, a Helm chart version, etc. + type: string + size: + description: Size is the number of bytes in the file. + format: int64 + type: integer + url: + description: |- + URL is the HTTP address of the Artifact as exposed by the controller + managing the Source. It can be used to retrieve the Artifact for + consumption, e.g. by another controller applying the Artifact contents. + type: string + required: + - lastUpdateTime + - path + - revision + - url + type: object + conditions: + description: Conditions holds the conditions for the OCIRepository. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + lastHandledReconcileAt: + description: |- + LastHandledReconcileAt holds the value of the most recent + reconcile request value, so a change of the annotation value + can be detected. + type: string + observedGeneration: + description: ObservedGeneration is the last observed generation. + format: int64 + type: integer + observedIgnore: + description: |- + ObservedIgnore is the observed exclusion patterns used for constructing + the source artifact. + type: string + observedLayerSelector: + description: |- + ObservedLayerSelector is the observed layer selector used for constructing + the source artifact. + properties: + mediaType: + description: |- + MediaType specifies the OCI media type of the layer + which should be extracted from the OCI Artifact. The + first layer matching this type is selected. + type: string + operation: + description: |- + Operation specifies how the selected layer should be processed. + By default, the layer compressed content is extracted to storage. + When the operation is set to 'copy', the layer compressed content + is persisted to storage as it is. + enum: + - extract + - copy + type: string + type: object + url: + description: URL is the download link for the artifact output of the + last OCI Repository sync. + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .spec.url + name: URL + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=="Ready")].message + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + deprecated: true + deprecationWarning: v1beta2 OCIRepository is deprecated, upgrade to v1 name: v1beta2 schema: openAPIV3Schema: @@ -422,6 +816,6 @@ spec: type: object type: object served: true - storage: true + storage: false subresources: status: {} diff --git a/config/samples/source_v1beta2_ocirepository.yaml b/config/samples/source_v1_ocirepository.yaml similarity index 77% rename from config/samples/source_v1beta2_ocirepository.yaml rename to config/samples/source_v1_ocirepository.yaml index e06241b97..69fb19e2a 100644 --- a/config/samples/source_v1beta2_ocirepository.yaml +++ b/config/samples/source_v1_ocirepository.yaml @@ -1,4 +1,4 @@ -apiVersion: source.toolkit.fluxcd.io/v1beta2 +apiVersion: source.toolkit.fluxcd.io/v1 kind: OCIRepository metadata: name: ocirepository-sample diff --git a/config/testdata/helmchart-from-oci/source.yaml b/config/testdata/helmchart-from-oci/source.yaml index 354325efa..b2786531e 100644 --- a/config/testdata/helmchart-from-oci/source.yaml +++ b/config/testdata/helmchart-from-oci/source.yaml @@ -1,5 +1,5 @@ --- -apiVersion: source.toolkit.fluxcd.io/v1beta2 +apiVersion: source.toolkit.fluxcd.io/v1 kind: HelmRepository metadata: name: podinfo @@ -8,7 +8,7 @@ spec: type: "oci" interval: 1m --- -apiVersion: source.toolkit.fluxcd.io/v1beta2 +apiVersion: source.toolkit.fluxcd.io/v1 kind: HelmChart metadata: name: podinfo @@ -20,7 +20,7 @@ spec: version: '6.1.*' interval: 1m --- -apiVersion: source.toolkit.fluxcd.io/v1beta2 +apiVersion: source.toolkit.fluxcd.io/v1 kind: HelmChart metadata: name: podinfo-keyless diff --git a/config/testdata/ocirepository/signed-with-key.yaml b/config/testdata/ocirepository/signed-with-key.yaml index 7a2bd3c2c..0a3a652ee 100644 --- a/config/testdata/ocirepository/signed-with-key.yaml +++ b/config/testdata/ocirepository/signed-with-key.yaml @@ -1,5 +1,5 @@ --- -apiVersion: source.toolkit.fluxcd.io/v1beta2 +apiVersion: source.toolkit.fluxcd.io/v1 kind: OCIRepository metadata: name: podinfo-deploy-signed-with-key diff --git a/config/testdata/ocirepository/signed-with-keyless.yaml b/config/testdata/ocirepository/signed-with-keyless.yaml index efb02fc28..ff46ed30d 100644 --- a/config/testdata/ocirepository/signed-with-keyless.yaml +++ b/config/testdata/ocirepository/signed-with-keyless.yaml @@ -1,5 +1,5 @@ --- -apiVersion: source.toolkit.fluxcd.io/v1beta2 +apiVersion: source.toolkit.fluxcd.io/v1 kind: OCIRepository metadata: name: podinfo-deploy-signed-with-keyless diff --git a/config/testdata/ocirepository/signed-with-notation.yaml b/config/testdata/ocirepository/signed-with-notation.yaml index 39f3fe81f..55820f6d4 100644 --- a/config/testdata/ocirepository/signed-with-notation.yaml +++ b/config/testdata/ocirepository/signed-with-notation.yaml @@ -1,5 +1,5 @@ --- -apiVersion: source.toolkit.fluxcd.io/v1beta2 +apiVersion: source.toolkit.fluxcd.io/v1 kind: OCIRepository metadata: name: podinfo-deploy-signed-with-notation diff --git a/docs/api/v1/source.md b/docs/api/v1/source.md index df1b800ce..0e9c7cc8f 100644 --- a/docs/api/v1/source.md +++ b/docs/api/v1/source.md @@ -16,6 +16,8 @@ Resource Types: HelmChart
  • HelmRepository +
  • +OCIRepository
  • Bucket

    @@ -1013,6 +1015,290 @@ HelmRepositoryStatus +

    OCIRepository +

    +

    OCIRepository is the Schema for the ocirepositories API

    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    FieldDescription
    +apiVersion
    +string
    +source.toolkit.fluxcd.io/v1 +
    +kind
    +string +
    +OCIRepository +
    +metadata
    + + +Kubernetes meta/v1.ObjectMeta + + +
    +Refer to the Kubernetes API documentation for the fields of the +metadata field. +
    +spec
    + + +OCIRepositorySpec + + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +url
    + +string + +
    +

    URL is a reference to an OCI artifact repository hosted +on a remote container registry.

    +
    +ref
    + + +OCIRepositoryRef + + +
    +(Optional) +

    The OCI reference to pull and monitor for changes, +defaults to the latest tag.

    +
    +layerSelector
    + + +OCILayerSelector + + +
    +(Optional) +

    LayerSelector specifies which layer should be extracted from the OCI artifact. +When not specified, the first layer found in the artifact is selected.

    +
    +provider
    + +string + +
    +(Optional) +

    The provider used for authentication, can be ‘aws’, ‘azure’, ‘gcp’ or ‘generic’. +When not specified, defaults to ‘generic’.

    +
    +secretRef
    + + +github.com/fluxcd/pkg/apis/meta.LocalObjectReference + + +
    +(Optional) +

    SecretRef contains the secret name containing the registry login +credentials to resolve image metadata. +The secret must be of type kubernetes.io/dockerconfigjson.

    +
    +verify
    + + +OCIRepositoryVerification + + +
    +(Optional) +

    Verify contains the secret name containing the trusted public keys +used to verify the signature and specifies which provider to use to check +whether OCI image is authentic.

    +
    +serviceAccountName
    + +string + +
    +(Optional) +

    ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate +the image pull if the service account has attached pull secrets. For more information: +https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account

    +
    +certSecretRef
    + + +github.com/fluxcd/pkg/apis/meta.LocalObjectReference + + +
    +(Optional) +

    CertSecretRef can be given the name of a Secret containing +either or both of

    +
      +
    • a PEM-encoded client certificate (tls.crt) and private +key (tls.key);
    • +
    • a PEM-encoded CA certificate (ca.crt)
    • +
    +

    and whichever are supplied, will be used for connecting to the +registry. The client cert and key are useful if you are +authenticating with a certificate; the CA cert is useful if +you are using a self-signed server certificate. The Secret must +be of type Opaque or kubernetes.io/tls.

    +
    +proxySecretRef
    + + +github.com/fluxcd/pkg/apis/meta.LocalObjectReference + + +
    +(Optional) +

    ProxySecretRef specifies the Secret containing the proxy configuration +to use while communicating with the container registry.

    +
    +interval
    + + +Kubernetes meta/v1.Duration + + +
    +

    Interval at which the OCIRepository URL is checked for updates. +This interval is approximate and may be subject to jitter to ensure +efficient use of resources.

    +
    +timeout
    + + +Kubernetes meta/v1.Duration + + +
    +(Optional) +

    The timeout for remote OCI Repository operations like pulling, defaults to 60s.

    +
    +ignore
    + +string + +
    +(Optional) +

    Ignore overrides the set of excluded patterns in the .sourceignore format +(which is the same as .gitignore). If not provided, a default will be used, +consult the documentation for your version to find out what those are.

    +
    +insecure
    + +bool + +
    +(Optional) +

    Insecure allows connecting to a non-TLS HTTP container registry.

    +
    +suspend
    + +bool + +
    +(Optional) +

    This flag tells the controller to suspend the reconciliation of this source.

    +
    +
    +status
    + + +OCIRepositoryStatus + + +
    +
    +
    +

    Artifact

    @@ -1020,7 +1306,8 @@ HelmRepositoryStatus BucketStatus, GitRepositoryStatus, HelmChartStatus, -HelmRepositoryStatus) +HelmRepositoryStatus, +OCIRepositoryStatus)

    Artifact represents the output of a Source reconciliation.

    @@ -2744,11 +3031,479 @@ string
    -

    OCIRepositoryVerification +

    OCILayerSelector

    (Appears on: -HelmChartSpec) +OCIRepositorySpec, +OCIRepositoryStatus) +

    +

    OCILayerSelector specifies which layer should be extracted from an OCI Artifact

    +
    +
    + + + + + + + + + + + + + + + + + +
    FieldDescription
    +mediaType
    + +string + +
    +(Optional) +

    MediaType specifies the OCI media type of the layer +which should be extracted from the OCI Artifact. The +first layer matching this type is selected.

    +
    +operation
    + +string + +
    +(Optional) +

    Operation specifies how the selected layer should be processed. +By default, the layer compressed content is extracted to storage. +When the operation is set to ‘copy’, the layer compressed content +is persisted to storage as it is.

    +
    +
    +
    +

    OCIRepositoryRef +

    +

    +(Appears on: +OCIRepositorySpec) +

    +

    OCIRepositoryRef defines the image reference for the OCIRepository’s URL

    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + +
    FieldDescription
    +digest
    + +string + +
    +(Optional) +

    Digest is the image digest to pull, takes precedence over SemVer. +The value should be in the format ‘sha256:’.

    +
    +semver
    + +string + +
    +(Optional) +

    SemVer is the range of tags to pull selecting the latest within +the range, takes precedence over Tag.

    +
    +semverFilter
    + +string + +
    +(Optional) +

    SemverFilter is a regex pattern to filter the tags within the SemVer range.

    +
    +tag
    + +string + +
    +(Optional) +

    Tag is the image tag to pull, defaults to latest.

    +
    +
    +
    +

    OCIRepositorySpec +

    +

    +(Appears on: +OCIRepository) +

    +

    OCIRepositorySpec defines the desired state of OCIRepository

    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    FieldDescription
    +url
    + +string + +
    +

    URL is a reference to an OCI artifact repository hosted +on a remote container registry.

    +
    +ref
    + + +OCIRepositoryRef + + +
    +(Optional) +

    The OCI reference to pull and monitor for changes, +defaults to the latest tag.

    +
    +layerSelector
    + + +OCILayerSelector + + +
    +(Optional) +

    LayerSelector specifies which layer should be extracted from the OCI artifact. +When not specified, the first layer found in the artifact is selected.

    +
    +provider
    + +string + +
    +(Optional) +

    The provider used for authentication, can be ‘aws’, ‘azure’, ‘gcp’ or ‘generic’. +When not specified, defaults to ‘generic’.

    +
    +secretRef
    + + +github.com/fluxcd/pkg/apis/meta.LocalObjectReference + + +
    +(Optional) +

    SecretRef contains the secret name containing the registry login +credentials to resolve image metadata. +The secret must be of type kubernetes.io/dockerconfigjson.

    +
    +verify
    + + +OCIRepositoryVerification + + +
    +(Optional) +

    Verify contains the secret name containing the trusted public keys +used to verify the signature and specifies which provider to use to check +whether OCI image is authentic.

    +
    +serviceAccountName
    + +string + +
    +(Optional) +

    ServiceAccountName is the name of the Kubernetes ServiceAccount used to authenticate +the image pull if the service account has attached pull secrets. For more information: +https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account

    +
    +certSecretRef
    + + +github.com/fluxcd/pkg/apis/meta.LocalObjectReference + + +
    +(Optional) +

    CertSecretRef can be given the name of a Secret containing +either or both of

    +
      +
    • a PEM-encoded client certificate (tls.crt) and private +key (tls.key);
    • +
    • a PEM-encoded CA certificate (ca.crt)
    • +
    +

    and whichever are supplied, will be used for connecting to the +registry. The client cert and key are useful if you are +authenticating with a certificate; the CA cert is useful if +you are using a self-signed server certificate. The Secret must +be of type Opaque or kubernetes.io/tls.

    +
    +proxySecretRef
    + + +github.com/fluxcd/pkg/apis/meta.LocalObjectReference + + +
    +(Optional) +

    ProxySecretRef specifies the Secret containing the proxy configuration +to use while communicating with the container registry.

    +
    +interval
    + + +Kubernetes meta/v1.Duration + + +
    +

    Interval at which the OCIRepository URL is checked for updates. +This interval is approximate and may be subject to jitter to ensure +efficient use of resources.

    +
    +timeout
    + + +Kubernetes meta/v1.Duration + + +
    +(Optional) +

    The timeout for remote OCI Repository operations like pulling, defaults to 60s.

    +
    +ignore
    + +string + +
    +(Optional) +

    Ignore overrides the set of excluded patterns in the .sourceignore format +(which is the same as .gitignore). If not provided, a default will be used, +consult the documentation for your version to find out what those are.

    +
    +insecure
    + +bool + +
    +(Optional) +

    Insecure allows connecting to a non-TLS HTTP container registry.

    +
    +suspend
    + +bool + +
    +(Optional) +

    This flag tells the controller to suspend the reconciliation of this source.

    +
    +
    +
    +

    OCIRepositoryStatus +

    +

    +(Appears on: +OCIRepository) +

    +

    OCIRepositoryStatus defines the observed state of OCIRepository

    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    FieldDescription
    +observedGeneration
    + +int64 + +
    +(Optional) +

    ObservedGeneration is the last observed generation.

    +
    +conditions
    + + +[]Kubernetes meta/v1.Condition + + +
    +(Optional) +

    Conditions holds the conditions for the OCIRepository.

    +
    +url
    + +string + +
    +(Optional) +

    URL is the download link for the artifact output of the last OCI Repository sync.

    +
    +artifact
    + + +Artifact + + +
    +(Optional) +

    Artifact represents the output of the last successful OCI Repository sync.

    +
    +observedIgnore
    + +string + +
    +(Optional) +

    ObservedIgnore is the observed exclusion patterns used for constructing +the source artifact.

    +
    +observedLayerSelector
    + + +OCILayerSelector + + +
    +(Optional) +

    ObservedLayerSelector is the observed layer selector used for constructing +the source artifact.

    +
    +ReconcileRequestStatus
    + + +github.com/fluxcd/pkg/apis/meta.ReconcileRequestStatus + + +
    +

    +(Members of ReconcileRequestStatus are embedded into this type.) +

    +
    +
    +
    +

    OCIRepositoryVerification +

    +

    +(Appears on: +HelmChartSpec, +OCIRepositorySpec)

    OCIRepositoryVerification verifies the authenticity of an OCI Artifact

    diff --git a/docs/spec/v1/README.md b/docs/spec/v1/README.md index 3a382959f..07b7abf61 100644 --- a/docs/spec/v1/README.md +++ b/docs/spec/v1/README.md @@ -6,6 +6,7 @@ This is the v1 API specification for defining the desired state sources of Kuber * Source kinds: + [GitRepository](gitrepositories.md) + + [OCIRepository](ocirepositories.md) + [HelmRepository](helmrepositories.md) + [HelmChart](helmcharts.md) + [Bucket](buckets.md) diff --git a/docs/spec/v1/ocirepositories.md b/docs/spec/v1/ocirepositories.md new file mode 100644 index 000000000..b3fc82031 --- /dev/null +++ b/docs/spec/v1/ocirepositories.md @@ -0,0 +1,1134 @@ +# OCI Repositories + + + +The `OCIRepository` API defines a Source to produce an Artifact for an OCI +repository. + +## Example + +The following is an example of an OCIRepository. It creates a tarball +(`.tar.gz`) Artifact with the fetched data from an OCI repository for the +resolved digest. + +```yaml +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: OCIRepository +metadata: + name: podinfo + namespace: default +spec: + interval: 5m0s + url: oci://ghcr.io/stefanprodan/manifests/podinfo + ref: + tag: latest +``` + +In the above example: + +- An OCIRepository named `podinfo` is created, indicated by the + `.metadata.name` field. +- The source-controller checks the OCI repository every five minutes, indicated + by the `.spec.interval` field. +- It pulls the `latest` tag of the `ghcr.io/stefanprodan/manifests/podinfo` + repository, indicated by the `.spec.ref.tag` and `.spec.url` fields. +- The resolved tag and SHA256 digest is used as the Artifact + revision, reported in-cluster in the `.status.artifact.revision` field. +- When the current OCIRepository digest differs from the latest fetched + digest, a new Artifact is archived. +- The new Artifact is reported in the `.status.artifact` field. + +You can run this example by saving the manifest into `ocirepository.yaml`. + +1. Apply the resource on the cluster: + + ```sh + kubectl apply -f ocirepository.yaml + ``` + +2. Run `kubectl get ocirepository` to see the OCIRepository: + + ```console + NAME URL AGE READY STATUS + podinfo oci://ghcr.io/stefanprodan/manifests/podinfo 5s True stored artifact with revision 'latest@sha256:3b6cdcc7adcc9a84d3214ee1c029543789d90b5ae69debe9efa3f66e982875de' + ``` + +3. Run `kubectl describe ocirepository podinfo` to see the [Artifact](#artifact) + and [Conditions](#conditions) in the OCIRepository's Status: + + ```console + ... + Status: + Artifact: + Digest: sha256:d7e924b4882e55b97627355c7b3d2e711e9b54303afa2f50c25377f4df66a83b + Last Update Time: 2025-06-14T11:23:36Z + Path: ocirepository/default/podinfo/3b6cdcc7adcc9a84d3214ee1c029543789d90b5ae69debe9efa3f66e982875de.tar.gz + Revision: latest@sha256:3b6cdcc7adcc9a84d3214ee1c029543789d90b5ae69debe9efa3f66e982875de + Size: 1105 + URL: http://source-controller.flux-system.svc.cluster.local./ocirepository/oci/podinfo/3b6cdcc7adcc9a84d3214ee1c029543789d90b5ae69debe9efa3f66e982875de.tar.gz + Conditions: + Last Transition Time: 2025-06-14T11:23:36Z + Message: stored artifact for revision 'latest@sha256:3b6cdcc7adcc9a84d3214ee1c029543789d90b5ae69debe9efa3f66e982875de' + Observed Generation: 1 + Reason: Succeeded + Status: True + Type: Ready + Last Transition Time: 2025-06-14T11:23:36Z + Message: stored artifact for revision 'latest@sha256:3b6cdcc7adcc9a84d3214ee1c029543789d90b5ae69debe9efa3f66e982875de' + Observed Generation: 1 + Reason: Succeeded + Status: True + Type: ArtifactInStorage + Observed Generation: 1 + URL: http://source-controller.source-system.svc.cluster.local./gitrepository/default/podinfo/latest.tar.gz + Events: + Type Reason Age From Message + ---- ------ ---- ---- ------- + Normal NewArtifact 62s source-controller stored artifact with revision 'latest/3b6cdcc7adcc9a84d3214ee1c029543789d90b5ae69debe9efa3f66e982875de' from 'oci://ghcr.io/stefanprodan/manifests/podinfo' + ``` + +## Writing an OCIRepository spec + +As with all other Kubernetes config, an OCIRepository needs `apiVersion`, +`kind`, and `metadata` fields. The name of an OCIRepository object must be a +valid [DNS subdomain name](https://kubernetes.io/docs/concepts/overview/working-with-objects/names#dns-subdomain-names). + +An OCIRepository also needs a +[`.spec` section](https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#spec-and-status). + +### URL + +`.spec.url` is a required field that specifies the address of the +container image repository in the format `oci://://`. + +**Note:** that specifying a tag or digest is not acceptable for this field. + +### Provider + +`.spec.provider` is an optional field that allows specifying an OIDC provider used for +authentication purposes. + +Supported options are: + +- `generic` +- `aws` +- `azure` +- `gcp` + +The `generic` provider can be used for public repositories or when +static credentials are used for authentication, either with +`spec.secretRef` or `spec.serviceAccountName`. +If you do not specify `.spec.provider`, it defaults to `generic`. + +#### AWS + +The `aws` provider can be used to authenticate automatically using the EKS +worker node IAM role or IAM Role for Service Accounts (IRSA), and by extension +gain access to ECR. + +When the worker node IAM role has access to ECR, source-controller running on it +will also have access to ECR. + +When using IRSA to enable access to ECR, add the following patch to your +bootstrap repository, in the `flux-system/kustomization.yaml` file: + +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - gotk-components.yaml + - gotk-sync.yaml +patches: + - patch: | + apiVersion: v1 + kind: ServiceAccount + metadata: + name: source-controller + annotations: + eks.amazonaws.com/role-arn: + target: + kind: ServiceAccount + name: source-controller +``` + +Note that you can attach the AWS managed policy `arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly` +to the IAM role when using IRSA. + +#### Azure + +The `azure` provider can be used to authenticate automatically using Workload Identity and Kubelet Managed +Identity to gain access to ACR. + +##### Kubelet Managed Identity + +When the kubelet managed identity has access to ACR, source-controller running +on it will also have access to ACR. + +**Note:** If you have more than one identity configured on the cluster, you have to specify which one to use +by setting the `AZURE_CLIENT_ID` environment variable in the source-controller deployment. + +If you are running into further issues, please look at the +[troubleshooting guide](https://github.com/Azure/azure-sdk-for-go/blob/main/sdk/azidentity/TROUBLESHOOTING.md#azure-virtual-machine-managed-identity). + +##### Workload Identity + +When using Workload Identity to enable access to ACR, add the following patch to +your bootstrap repository, in the `flux-system/kustomization.yaml` file: + +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - gotk-components.yaml + - gotk-sync.yaml +patches: + - patch: |- + apiVersion: v1 + kind: ServiceAccount + metadata: + name: source-controller + namespace: flux-system + annotations: + azure.workload.identity/client-id: + labels: + azure.workload.identity/use: "true" + - patch: |- + apiVersion: apps/v1 + kind: Deployment + metadata: + name: source-controller + namespace: flux-system + labels: + azure.workload.identity/use: "true" + spec: + template: + metadata: + labels: + azure.workload.identity/use: "true" +``` + +Ensure Workload Identity is properly set up on your cluster and the mutating webhook is installed. +Create an identity that has access to ACR. Next, establish +a federated identity between the source-controller ServiceAccount and the +identity. Patch the source-controller Deployment and ServiceAccount as shown in the patch +above. Please take a look at this [guide](https://azure.github.io/azure-workload-identity/docs/quick-start.html#6-establish-federated-identity-credential-between-the-identity-and-the-service-account-issuer--subject). + +#### GCP + +The `gcp` provider can be used to authenticate automatically using OAuth scopes +or Workload Identity, and by extension gain access to GCR or Artifact Registry. + +When the GKE nodes have the appropriate OAuth scope for accessing GCR and +Artifact Registry, source-controller running on it will also have access to them. + +When using Workload Identity to enable access to GCR or Artifact Registry, add +the following patch to your bootstrap repository, in the +`flux-system/kustomization.yaml` file: + +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - gotk-components.yaml + - gotk-sync.yaml +patches: + - patch: | + apiVersion: v1 + kind: ServiceAccount + metadata: + name: source-controller + annotations: + iam.gke.io/gcp-service-account: + target: + kind: ServiceAccount + name: source-controller +``` + +The Artifact Registry service uses the permission `artifactregistry.repositories.downloadArtifacts` +that is located under the Artifact Registry Reader role. If you are using +Google Container Registry service, the needed permission is instead `storage.objects.list` +which can be bound as part of the Container Registry Service Agent role. +Take a look at [this guide](https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity) +for more information about setting up GKE Workload Identity. + +### Secret reference + +`.spec.secretRef.name` is an optional field to specify a name reference to a +Secret in the same namespace as the OCIRepository, containing authentication +credentials for the OCI repository. + +This secret is expected to be in the same format as [`imagePullSecrets`][image-pull-secrets]. +The usual way to create such a secret is with: + +```sh +kubectl create secret docker-registry ... +``` + +### Service Account reference + +`.spec.serviceAccountName` is an optional field to specify a name reference to a +Service Account in the same namespace as the OCIRepository. The controller will +fetch the image pull secrets attached to the service account and use them for authentication. + +**Note:** that for a publicly accessible image repository, you don't need to provide a `secretRef` +nor `serviceAccountName`. + +### Cert secret reference + +`.spec.certSecretRef.name` is an optional field to specify a secret containing +TLS certificate data. The secret can contain the following keys: + +* `tls.crt` and `tls.key`, to specify the client certificate and private key used +for TLS client authentication. These must be used in conjunction, i.e. +specifying one without the other will lead to an error. +* `ca.crt`, to specify the CA certificate used to verify the server, which is +required if the server is using a self-signed certificate. + +If the server is using a self-signed certificate and has TLS client +authentication enabled, all three values are required. + +The Secret should be of type `Opaque` or `kubernetes.io/tls`. All the files in +the Secret are expected to be [PEM-encoded][pem-encoding]. Assuming you have +three files; `client.key`, `client.crt` and `ca.crt` for the client private key, +client certificate and the CA certificate respectively, you can generate the +required Secret using the `flux create secret tls` command: + +```sh +flux create secret tls --tls-key-file=client.key --tls-crt-file=client.crt --ca-crt-file=ca.crt +``` + +Example usage: + +```yaml +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: OCIRepository +metadata: + name: example + namespace: default +spec: + interval: 5m0s + url: oci://example.com + certSecretRef: + name: example-tls +--- +apiVersion: v1 +kind: Secret +metadata: + name: example-tls + namespace: default +type: kubernetes.io/tls # or Opaque +data: + tls.crt: + tls.key: + # NOTE: Can be supplied without the above values + ca.crt: +``` + +### Proxy secret reference + +`.spec.proxySecretRef.name` is an optional field used to specify the name of a +Secret that contains the proxy settings for the object. These settings are used +for all the remote operations related to the OCIRepository. +The Secret can contain three keys: + +- `address`, to specify the address of the proxy server. This is a required key. +- `username`, to specify the username to use if the proxy server is protected by + basic authentication. This is an optional key. +- `password`, to specify the password to use if the proxy server is protected by + basic authentication. This is an optional key. + +Example: + +```yaml +--- +apiVersion: v1 +kind: Secret +metadata: + name: http-proxy +type: Opaque +stringData: + address: http://proxy.com + username: mandalorian + password: grogu +``` + +Proxying can also be configured in the source-controller Deployment directly by +using the standard environment variables such as `HTTPS_PROXY`, `ALL_PROXY`, etc. + +`.spec.proxySecretRef.name` takes precedence over all environment variables. + +**Warning:** [Cosign](https://github.com/sigstore/cosign) *keyless* +[verification](#verification) is not supported for this API. If you +require cosign keyless verification to use a proxy you must use the +standard environment variables mentioned above. If you specify a +`proxySecretRef` the controller will simply send out the requests +needed for keyless verification without the associated object-level +proxy settings. + +### Insecure + +`.spec.insecure` is an optional field to allow connecting to an insecure (HTTP) +container registry server, if set to `true`. The default value is `false`, +denying insecure (HTTP) connections. + +### Interval + +`.spec.interval` is a required field that specifies the interval at which the +OCI repository must be fetched. + +After successfully reconciling the object, the source-controller requeues it +for inspection after the specified interval. The value must be in a +[Go recognized duration string format](https://pkg.go.dev/time#ParseDuration), +e.g. `10m0s` to reconcile the object every 10 minutes. + +If the `.metadata.generation` of a resource changes (due to e.g. a change to +the spec), this is handled instantly outside the interval window. + +**Note:** The controller can be configured to apply a jitter to the interval in +order to distribute the load more evenly when multiple OCIRepository objects are +set up with the same interval. For more information, please refer to the +[source-controller configuration options](https://fluxcd.io/flux/components/source/options/). + +### Timeout + +`.spec.timeout` is an optional field to specify a timeout for OCI operations +like pulling. The value must be in a +[Go recognized duration string format](https://pkg.go.dev/time#ParseDuration), +e.g. `1m30s` for a timeout of one minute and thirty seconds. The default value +is `60s`. + +### Reference + +`.spec.ref` is an optional field to specify the OCI reference to resolve and +watch for changes. References are specified in one or more subfields +(`.tag`, `.semver`, `.digest`), with latter listed fields taking +precedence over earlier ones. If not specified, it defaults to the `latest` +tag. + +#### Tag example + +To pull a specific tag, use `.spec.ref.tag`: + +```yaml +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: OCIRepository +metadata: + name: +spec: + ref: + tag: "" +``` + +#### SemVer example + +To pull a tag based on a +[SemVer range](https://github.com/Masterminds/semver#checking-version-constraints), +use `.spec.ref.semver`: + +```yaml +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: OCIRepository +metadata: + name: +spec: + ref: + # SemVer range reference: https://github.com/Masterminds/semver#checking-version-constraints + semver: "" +``` + +This field takes precedence over [`.tag`](#tag-example). + +#### SemverFilter example + +`.spec.ref.semverFilter` is an optional field to specify a SemVer filter to apply +when fetching tags from the OCI repository. The filter is a regular expression +that is applied to the tags fetched from the repository. Only tags that match +the filter are considered for the semver range resolution. + +**Note:** The filter is only taken into account when the `.spec.ref.semver` field +is set. + +```yaml +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: OCIRepository +metadata: + name: podinfo + namespace: default +spec: + interval: 5m0s + url: oci://ghcr.io/stefanprodan/manifests/podinfo + ref: + # SemVer comparisons using constraints without a prerelease comparator will skip prerelease versions. + # Adding a `-0` suffix to the semver range will include prerelease versions. + semver: ">= 6.1.x-0" + semverFilter: ".*-rc.*" +``` + +In the above example, the controller fetches tags from the `ghcr.io/stefanprodan/manifests/podinfo` +repository and filters them using the regular expression `.*-rc.*`. Only tags that +contain the `-rc` suffix are considered for the semver range resolution. + +#### Digest example + +To pull a specific digest, use `.spec.ref.digest`: + +```yaml +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: OCIRepository +metadata: + name: +spec: + ref: + digest: "sha256:" +``` + +This field takes precedence over all other fields. + +### Layer selector + +`spec.layerSelector` is an optional field to specify which layer should be extracted from the OCI Artifact. +If not specified, the controller will extract the first layer found in the artifact. + +To extract a layer matching a specific +[OCI media type](https://github.com/opencontainers/image-spec/blob/v1.0.2/media-types.md): + +```yaml +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: OCIRepository +metadata: + name: +spec: + layerSelector: + mediaType: "application/vnd.cncf.helm.chart.content.v1.tar+gzip" + operation: extract # can be 'extract' or 'copy', defaults to 'extract' +``` + +If the layer selector matches more than one layer, the first layer matching the specified media type will be used. +Note that the selected OCI layer must be +[compressed](https://github.com/opencontainers/image-spec/blob/v1.0.2/layer.md#gzip-media-types) +in the `tar+gzip` format. + +When `.spec.layerSelector.operation` is set to `copy`, instead of extracting the +compressed layer, the controller copies the tarball as-is to storage, thus +keeping the original content unaltered. + +### Ignore + +`.spec.ignore` is an optional field to specify rules in [the `.gitignore` +pattern format](https://git-scm.com/docs/gitignore#_pattern_format). Paths +matching the defined rules are excluded while archiving. + +When specified, `.spec.ignore` overrides the [default exclusion +list](#default-exclusions), and may overrule the [`.sourceignore` file +exclusions](#sourceignore-file). See [excluding files](#excluding-files) +for more information. + +### Verification + +`.spec.verify` is an optional field to enable the verification of [Cosign](https://github.com/sigstore/cosign) +or [Notation](https://github.com/notaryproject/notation) +signatures. The field offers three subfields: + +- `.provider`, to specify the verification provider. The supported options are `cosign` and `notation` at present. +- `.secretRef.name`, to specify a reference to a Secret in the same namespace as + the OCIRepository, containing the Cosign public keys of trusted authors. For Notation this Secret should also + include the [trust policy](https://github.com/notaryproject/specifications/blob/v1.0.0/specs/trust-store-trust-policy.md#trust-policy) in + addition to the CA certificate. +- `.matchOIDCIdentity`, to specify a list of OIDC identity matchers (only supported when using `cosign` as the + verification provider). Please see + [Keyless verification](#keyless-verification) for more details. + +#### Cosign + +The `cosign` provider can be used to verify the signature of an OCI artifact using either a known public key +or via the [Cosign Keyless](https://github.com/sigstore/cosign/blob/main/KEYLESS.md) procedure. + +```yaml +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: OCIRepository +metadata: + name: +spec: + verify: + provider: cosign + secretRef: + name: cosign-public-keys +``` + +When the verification succeeds, the controller adds a Condition with the +following attributes to the OCIRepository's `.status.conditions`: + +- `type: SourceVerified` +- `status: "True"` +- `reason: Succeeded` + +##### Public keys verification + +To verify the authenticity of an OCI artifact, create a Kubernetes secret +with the Cosign public keys: + +```yaml +--- +apiVersion: v1 +kind: Secret +metadata: + name: cosign-public-keys +type: Opaque +data: + key1.pub: + key2.pub: +``` + +Note that the keys must have the `.pub` extension for Flux to make use of them. + +Flux will loop over the public keys and use them to verify an artifact's signature. +This allows for older artifacts to be valid as long as the right key is in the secret. + +##### Keyless verification + +For publicly available OCI artifacts, which are signed using the +[Cosign Keyless](https://github.com/sigstore/cosign/blob/main/KEYLESS.md) procedure, +you can enable the verification by omitting the `.verify.secretRef` field. + +To verify the identity's subject and the OIDC issuer present in the Fulcio +certificate, you can specify a list of OIDC identity matchers using +`.spec.verify.matchOIDCIdentity`. The matcher provides two required fields: + +- `.issuer`, to specify a regexp that matches against the OIDC issuer. +- `.subject`, to specify a regexp that matches against the subject identity in + the certificate. +Both values should follow the [Go regular expression syntax](https://golang.org/s/re2syntax). + +The matchers are evaluated in an OR fashion, i.e. the identity is deemed to be +verified if any one matcher successfully matches against the identity. + +Example of verifying artifacts signed by the +[Cosign GitHub Action](https://github.com/sigstore/cosign-installer) with GitHub OIDC Token: + +```yaml +apiVersion: source.toolkit.fluxcd.io/v1 +kind: OCIRepository +metadata: + name: podinfo +spec: + interval: 5m + url: oci://ghcr.io/stefanprodan/manifests/podinfo + verify: + provider: cosign + matchOIDCIdentity: + - issuer: "^https://token.actions.githubusercontent.com$" + subject: "^https://github.com/stefanprodan/podinfo.*$" +``` + +The controller verifies the signatures using the Fulcio root CA and the Rekor +instance hosted at [rekor.sigstore.dev](https://rekor.sigstore.dev/). + +Note that keyless verification is an **experimental feature**, using +custom root CAs or self-hosted Rekor instances are not currently supported. + +#### Notation + +The `notation` provider can be used to verify the signature of an OCI artifact using known +trust policy and CA certificate. + +```yaml +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: OCIRepository +metadata: + name: +spec: + verify: + provider: notation + secretRef: + name: notation-config +``` + +When the verification succeeds, the controller adds a Condition with the +following attributes to the OCIRepository's `.status.conditions`: + +- `type: SourceVerified` +- `status: "True"` +- `reason: Succeeded` + +To verify the authenticity of an OCI artifact, create a Kubernetes secret +containing Certificate Authority (CA) root certificates and the a `trust policy` + +```yaml +--- +apiVersion: v1 +kind: Secret +metadata: + name: notation-config +type: Opaque +data: + certificate1.pem: + certificate2.crt: + trustpolicy.json: +``` + +Note that the CA certificates must have either `.pem` or `.crt` extension and your trust policy must +be named `trustpolicy.json` for Flux to make use of them. + +For more information on the signing and verification process see [Signing and Verification Workflow](https://github.com/notaryproject/specifications/blob/v1.0.0/specs/signing-and-verification-workflow.md). + +Flux will loop over the certificates and use them to verify an artifact's signature. +This allows for older artifacts to be valid as long as the right certificate is in the secret. + +### Suspend + +`.spec.suspend` is an optional field to suspend the reconciliation of a +OCIRepository. When set to `true`, the controller will stop reconciling the +OCIRepository, and changes to the resource or in the OCI repository will not +result in a new Artifact. When the field is set to `false` or removed, it will +resume. + +## Working with OCIRepositories + +### Excluding files + +By default, files which match the [default exclusion rules](#default-exclusions) +are excluded while archiving the OCI repository contents as an Artifact. +It is possible to overwrite and/or overrule the default exclusions using +the [`.spec.ignore` field](#ignore). + +```yaml +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: OCIRepository +metadata: + name: +spec: + ignore: | + # exclude all + /* + # include deploy dir + !/deploy + # exclude file extensions from deploy dir + /deploy/**/*.md + /deploy/**/*.txt +``` + +#### `.sourceignore` file + +Excluding files is possible by adding a `.sourceignore` file in the artifact. +The `.sourceignore` file follows [the `.gitignore` pattern +format](https://git-scm.com/docs/gitignore#_pattern_format), and pattern +entries may overrule [default exclusions](#default-exclusions). + +The controller recursively loads ignore files so a `.sourceignore` can be +placed in the artifact root or in subdirectories. + +### Triggering a reconcile + +To manually tell the source-controller to reconcile a OCIRepository outside the +[specified interval window](#interval), an OCIRepository can be annotated with +`reconcile.fluxcd.io/requestedAt: `. Annotating the resource +queues the OCIRepository for reconciliation if the `` differs +from the last value the controller acted on, as reported in +[`.status.lastHandledReconcileAt`](#last-handled-reconcile-at). + +Using `kubectl`: + +```sh +kubectl annotate --field-manager=flux-client-side-apply --overwrite ocirepository/ reconcile.fluxcd.io/requestedAt="$(date +%s)" +``` + +Using `flux`: + +```sh +flux reconcile source oci +``` + +### Waiting for `Ready` + +When a change is applied, it is possible to wait for the OCIRepository to reach +a [ready state](#ready-ocirepository) using `kubectl`: + +```sh +kubectl wait gitrepository/ --for=condition=ready --timeout=1m +``` + +### Suspending and resuming + +When you find yourself in a situation where you temporarily want to pause the +reconciliation of an OCIRepository, you can suspend it using the +[`.spec.suspend` field](#suspend). + +#### Suspend an OCIRepository + +In your YAML declaration: + +```yaml +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: OCIRepository +metadata: + name: +spec: + suspend: true +``` + +Using `kubectl`: + +```sh +kubectl patch ocirepository --field-manager=flux-client-side-apply -p '{\"spec\": {\"suspend\" : true }}' +``` + +Using `flux`: + +```sh +flux suspend source oci +``` + +**Note:** When an OCIRepository has an Artifact and it is suspended, and this +Artifact later disappears from the storage due to e.g. the source-controller +Pod being evicted from a Node, this will not be reflected in the +OCIRepository's Status until it is resumed. + +#### Resume an OCIRepository + +In your YAML declaration, comment out (or remove) the field: + +```yaml +--- +apiVersion: source.toolkit.fluxcd.io/v1 +kind: OCIRepository +metadata: + name: +spec: + # suspend: true +``` + +**Note:** Setting the field value to `false` has the same effect as removing +it, but does not allow for "hot patching" using e.g. `kubectl` while practicing +GitOps; as the manually applied patch would be overwritten by the declared +state in Git. + +Using `kubectl`: + +```sh +kubectl patch ocirepository --field-manager=flux-client-side-apply -p '{\"spec\" : {\"suspend\" : false }}' +``` + +Using `flux`: + +```sh +flux resume source oci +``` + +### Debugging an OCIRepository + +There are several ways to gather information about a OCIRepository for +debugging purposes. + +#### Describe the OCIRepository + +Describing an OCIRepository using +`kubectl describe ocirepository ` +displays the latest recorded information for the resource in the `Status` and +`Events` sections: + +```console +... +Status: +... + Conditions: + Last Transition Time: 2025-02-14T09:40:27Z + Message: processing object: new generation 1 -> 2 + Observed Generation: 2 + Reason: ProgressingWithRetry + Status: True + Type: Reconciling + Last Transition Time: 2025-02-14T09:40:27Z + Message: failed to pull artifact from 'oci://ghcr.io/stefanprodan/manifests/podinfo': couldn't find tag "0.0.1" + Observed Generation: 2 + Reason: OCIOperationFailed + Status: False + Type: Ready + Last Transition Time: 2025-02-14T09:40:27Z + Message: failed to pull artifact from 'oci://ghcr.io/stefanprodan/manifests/podinfo': couldn't find tag "0.0.1" + Observed Generation: 2 + Reason: OCIOperationFailed + Status: True + Type: FetchFailed + Observed Generation: 1 + URL: http://source-controller.source-system.svc.cluster.local./ocirepository/default/podinfo/latest.tar.gz +Events: + Type Reason Age From Message + ---- ------ ---- ---- ------- + Warning OCIOperationFailed 2s (x9 over 4s) source-controller failed to pull artifact from 'oci://ghcr.io/stefanprodan/manifests/podinfo': couldn't find tag "0.0.1" +``` + +#### Trace emitted Events + +To view events for specific OCIRepository(s), `kubectl events` can be used +in combination with `--for` to list the Events for specific objects. For +example, running + +```sh +kubectl events --for OCIRepository/ +``` + +lists + +```console +LAST SEEN TYPE REASON OBJECT MESSAGE +2m14s Normal NewArtifact ocirepository/ stored artifact for revision 'latest@sha256:3b6cdcc7adcc9a84d3214ee1c029543789d90b5ae69debe9efa3f66e982875de' +36s Normal ArtifactUpToDate ocirepository/ artifact up-to-date with remote revision: 'latest@sha256:3b6cdcc7adcc9a84d3214ee1c029543789d90b5ae69debe9efa3f66e982875de' +94s Warning OCIOperationFailed ocirepository/ failed to pull artifact from 'oci://ghcr.io/stefanprodan/manifests/podinfo': couldn't find tag "0.0.1" +``` + +Besides being reported in Events, the reconciliation errors are also logged by +the controller. The Flux CLI offer commands for filtering the logs for a +specific OCIRepository, e.g. +`flux logs --level=error --kind=OCIRepository --name=`. + +## OCIRepository Status + +### Artifact + +The OCIRepository reports the latest synchronized state from the OCI repository +as an Artifact object in the `.status.artifact` of the resource. + +The `.status.artifact.revision` holds the tag and SHA256 digest of the upstream OCI artifact. + +The `.status.artifact.metadata` holds the upstream OCI artifact metadata such as the +[OpenContainers standard annotations](https://github.com/opencontainers/image-spec/blob/main/annotations.md). +If the OCI artifact was created with `flux push artifact`, then the `metadata` will contain the following +annotations: +- `org.opencontainers.image.created` the date and time on which the artifact was built +- `org.opencontainers.image.source` the URL of the Git repository containing the source files +- `org.opencontainers.image.revision` the Git branch and commit SHA1 of the source files + +The Artifact file is a gzip compressed TAR archive (`.tar.gz`), and +can be retrieved in-cluster from the `.status.artifact.url` HTTP address. + +#### Artifact example + +```yaml +apiVersion: source.toolkit.fluxcd.io/v1 +kind: OCIRepository +metadata: + name: +status: + artifact: + digest: sha256:9f3bc0f341d4ecf2bab460cc59320a2a9ea292f01d7b96e32740a9abfd341088 + lastUpdateTime: "2025-08-08T09:35:45Z" + metadata: + org.opencontainers.image.created: "2025-08-08T12:31:41+03:00" + org.opencontainers.image.revision: 6.1.8/b3b00fe35424a45d373bf4c7214178bc36fd7872 + org.opencontainers.image.source: https://github.com/stefanprodan/podinfo.git + path: ocirepository///.tar.gz + revision: @ + size: 1105 + url: http://source-controller..svc.cluster.local./ocirepository///.tar.gz +``` + +#### Default exclusions + +The following files and extensions are excluded from the Artifact by +default: + +- Git files (`.git/, .gitignore, .gitmodules, .gitattributes`) +- File extensions (`.jpg, .jpeg, .gif, .png, .wmv, .flv, .tar.gz, .zip`) +- CI configs (`.github/, .circleci/, .travis.yml, .gitlab-ci.yml, appveyor.yml, .drone.yml, cloudbuild.yaml, codeship-services.yml, codeship-steps.yml`) +- CLI configs (`.goreleaser.yml, .sops.yaml`) +- Flux v1 config (`.flux.yaml`) + +To define your own exclusion rules, see [excluding files](#excluding-files). + +### Conditions + +OCIRepository has various states during its lifecycle, reflected as +[Kubernetes Conditions][typical-status-properties]. +It can be [reconciling](#reconciling-ocirepository) while fetching the remote +state, it can be [ready](#ready-ocirepository), or it can [fail during +reconciliation](#failed-ocirepository). + +The OCIRepository API is compatible with the [kstatus specification][kstatus-spec], +and reports `Reconciling` and `Stalled` conditions where applicable to +provide better (timeout) support to solutions polling the OCIRepository to +become `Ready`. + +#### Reconciling OCIRepository + +The source-controller marks an OCIRepository as _reconciling_ when one of the +following is true: + +- There is no current Artifact for the OCIRepository, or the reported Artifact + is determined to have disappeared from the storage. +- The generation of the OCIRepository is newer than the [Observed + Generation](#observed-generation). +- The newly resolved Artifact digest differs from the current Artifact. + +When the OCIRepository is "reconciling", the `Ready` Condition status becomes +`Unknown` when the controller detects drift, and the controller adds a Condition +with the following attributes to the OCIRepository's `.status.conditions`: + +- `type: Reconciling` +- `status: "True"` +- `reason: Progressing` | `reason: ProgressingWithRetry` + +If the reconciling state is due to a new revision, an additional Condition is +added with the following attributes: + +- `type: ArtifactOutdated` +- `status: "True"` +- `reason: NewRevision` + +Both Conditions have a ["negative polarity"][typical-status-properties], +and are only present on the OCIRepository while their status value is `"True"`. + +#### Ready OCIRepository + +The source-controller marks an OCIRepository as _ready_ when it has the +following characteristics: + +- The OCIRepository reports an [Artifact](#artifact). +- The reported Artifact exists in the controller's Artifact storage. +- The controller was able to communicate with the remote OCI repository using + the current spec. +- The digest of the reported Artifact is up-to-date with the latest + resolved digest of the remote OCI repository. + +When the OCIRepository is "ready", the controller sets a Condition with the +following attributes in the OCIRepository's `.status.conditions`: + +- `type: Ready` +- `status: "True"` +- `reason: Succeeded` + +This `Ready` Condition will retain a status value of `"True"` until the +OCIRepository is marked as [reconciling](#reconciling-ocirepository), or e.g. a +[transient error](#failed-ocirepository) occurs due to a temporary network issue. + +When the OCIRepository Artifact is archived in the controller's Artifact +storage, the controller sets a Condition with the following attributes in the +OCIRepository's `.status.conditions`: + +- `type: ArtifactInStorage` +- `status: "True"` +- `reason: Succeeded` + +This `ArtifactInStorage` Condition will retain a status value of `"True"` until +the Artifact in the storage no longer exists. + +#### Failed OCIRepository + +The source-controller may get stuck trying to produce an Artifact for a +OCIRepository without completing. This can occur due to some of the following +factors: + +- The remote OCI repository [URL](#url) is temporarily unavailable. +- The OCI repository does not exist. +- The [Secret reference](#secret-reference) contains a reference to a + non-existing Secret. +- The credentials in the referenced Secret are invalid. +- The OCIRepository spec contains a generic misconfiguration. +- A storage related failure when storing the artifact. + +When this happens, the controller sets the `Ready` Condition status to `False`, +and adds a Condition with the following attributes to the OCIRepository's +`.status.conditions`: + +- `type: FetchFailed` | `type: IncludeUnavailable` | `type: StorageOperationFailed` +- `status: "True"` +- `reason: AuthenticationFailed` | `reason: OCIArtifactPullFailed` | `reason: OCIArtifactLayerOperationFailed` + +This condition has a ["negative polarity"][typical-status-properties], +and is only present on the OCIRepository while the status value is `"True"`. +There may be more arbitrary values for the `reason` field to provide accurate +reason for a condition. + +In addition to the above Condition types, when the signature +[verification](#verification) fails. A condition with +the following attributes is added to the GitRepository's `.status.conditions`: + +- `type: SourceVerified` +- `status: "False"` +- `reason: VerificationError` + +While the OCIRepository has one or more of these Conditions, the controller +will continue to attempt to produce an Artifact for the resource with an +exponential backoff, until it succeeds and the OCIRepository is marked as +[ready](#ready-ocirepository). + +Note that a OCIRepository can be [reconciling](#reconciling-ocirepository) +while failing at the same time, for example due to a newly introduced +configuration issue in the OCIRepository spec. When a reconciliation fails, the +`Reconciling` Condition reason would be `ProgressingWithRetry`. When the +reconciliation is performed again after the failure, the reason is updated to +`Progressing`. + +### Observed Ignore + +The source-controller reports an observed ignore in the OCIRepository's +`.status.observedIgnore`. The observed ignore is the latest `.spec.ignore` value +which resulted in a [ready state](#ready-ocirepository), or stalled due to error +it can not recover from without human intervention. The value is the same as the +[ignore in spec](#ignore). It indicates the ignore rules used in building the +current artifact in storage. It is also used by the controller to determine if +an artifact needs to be rebuilt. + +Example: +```yaml +status: + ... + observedIgnore: | + hpa.yaml + build + ... +``` + +### Observed Layer Selector + +The source-controller reports an observed layer selector in the OCIRepository's +`.status.observedLayerSelector`. The observed layer selector is the latest +`.spec.layerSelector` value which resulted in a [ready state](#ready-ocirepository), +or stalled due to error it can not recover from without human intervention. +The value is the same as the [layer selector in spec](#layer-selector). +It indicates the layer selection configuration used in building the current +artifact in storage. It is also used by the controller to determine if an +artifact needs to be rebuilt. + +Example: +```yaml +status: + ... + observedLayerSelector: + mediaType: application/vnd.cncf.helm.chart.content.v1.tar+gzip + operation: copy + ... +``` + +### Observed Generation + +The source-controller reports an [observed generation][typical-status-properties] +in the OCIRepository's `.status.observedGeneration`. The observed generation is +the latest `.metadata.generation` which resulted in either a [ready state](#ready-ocirepository), +or stalled due to error it can not recover from without human +intervention. + +### Last Handled Reconcile At + +The source-controller reports the last `reconcile.fluxcd.io/requestedAt` +annotation value it acted on in the `.status.lastHandledReconcileAt` field. + +For practical information about this field, see [triggering a +reconcile](#triggering-a-reconcile). + +[typical-status-properties]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties +[kstatus-spec]: https://github.com/kubernetes-sigs/cli-utils/tree/master/pkg/kstatus +[image-pull-secrets]: https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod +[image-auto-provider-secrets]: https://fluxcd.io/flux/guides/image-update/#imagerepository-cloud-providers-authentication +[pem-encoding]: https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail +[sops-guide]: https://fluxcd.io/flux/guides/mozilla-sops/ diff --git a/go.mod b/go.mod index 6134ad004..a376ffd13 100644 --- a/go.mod +++ b/go.mod @@ -62,9 +62,9 @@ require ( github.com/sigstore/sigstore v1.8.15 github.com/sirupsen/logrus v1.9.3 github.com/spf13/pflag v1.0.6 - golang.org/x/crypto v0.37.0 - golang.org/x/oauth2 v0.29.0 - golang.org/x/sync v0.13.0 + golang.org/x/crypto v0.38.0 + golang.org/x/oauth2 v0.30.0 + golang.org/x/sync v0.14.0 google.golang.org/api v0.211.0 gotest.tools v2.2.0+incompatible helm.sh/helm/v3 v3.17.3 @@ -158,8 +158,8 @@ require ( github.com/cloudflare/circl v1.6.1 // indirect github.com/cncf/xds/go v0.0.0-20240905190251-b4127c9b8d78 // indirect github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect - github.com/containerd/containerd v1.7.24 // indirect - github.com/containerd/continuity v0.4.3 // indirect + github.com/containerd/containerd v1.7.27 // indirect + github.com/containerd/continuity v0.4.4 // indirect github.com/containerd/errdefs v0.3.0 // indirect github.com/containerd/log v0.1.0 // indirect github.com/containerd/platforms v0.2.1 // indirect @@ -199,7 +199,7 @@ require ( github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-gorp/gorp/v3 v3.1.0 // indirect github.com/go-ini/ini v1.67.0 // indirect - github.com/go-jose/go-jose/v3 v3.0.3 // indirect + github.com/go-jose/go-jose/v3 v3.0.4 // indirect github.com/go-jose/go-jose/v4 v4.0.5 // indirect github.com/go-ldap/ldap/v3 v3.4.10 // indirect github.com/go-logr/stdr v1.2.2 // indirect @@ -386,10 +386,10 @@ require ( go.uber.org/zap v1.27.0 // indirect golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect golang.org/x/mod v0.24.0 // indirect - golang.org/x/net v0.39.0 // indirect - golang.org/x/sys v0.32.0 // indirect - golang.org/x/term v0.31.0 // indirect - golang.org/x/text v0.24.0 // indirect + golang.org/x/net v0.40.0 // indirect + golang.org/x/sys v0.33.0 // indirect + golang.org/x/term v0.32.0 // indirect + golang.org/x/text v0.25.0 // indirect golang.org/x/time v0.11.0 // indirect golang.org/x/tools v0.32.0 // indirect gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 4a832fbdd..0babad57b 100644 --- a/go.sum +++ b/go.sum @@ -274,10 +274,10 @@ github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be h1:J5BL github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be/go.mod h1:mk5IQ+Y0ZeO87b858TlA645sVcEcbiX6YqP98kt+7+w= github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= -github.com/containerd/containerd v1.7.24 h1:zxszGrGjrra1yYJW/6rhm9cJ1ZQ8rkKBR48brqsa7nA= -github.com/containerd/containerd v1.7.24/go.mod h1:7QUzfURqZWCZV7RLNEn1XjUCQLEf0bkaK4GjUaZehxw= -github.com/containerd/continuity v0.4.3 h1:6HVkalIp+2u1ZLH1J/pYX2oBVXlJZvh1X1A7bEZ9Su8= -github.com/containerd/continuity v0.4.3/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= +github.com/containerd/containerd v1.7.27 h1:yFyEyojddO3MIGVER2xJLWoCIn+Up4GaHFquP7hsFII= +github.com/containerd/containerd v1.7.27/go.mod h1:xZmPnl75Vc+BLGt4MIfu6bp+fy03gdHAn9bz+FreFR0= +github.com/containerd/continuity v0.4.4 h1:/fNVfTJ7wIl/YPMHjf+5H32uFhl63JucB34PlCpMKII= +github.com/containerd/continuity v0.4.4/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE= github.com/containerd/errdefs v0.3.0 h1:FSZgGOeK4yuT/+DnF07/Olde/q4KBoMsaamhXxIMDp4= github.com/containerd/errdefs v0.3.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= @@ -435,8 +435,8 @@ github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw= github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= -github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= -github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= +github.com/go-jose/go-jose/v3 v3.0.4 h1:Wp5HA7bLQcKnf6YYao/4kpRpVMp/yf6+pJKV8WFSaNY= +github.com/go-jose/go-jose/v3 v3.0.4/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE= github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= @@ -1125,8 +1125,8 @@ golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72 golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= -golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= +golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8= +golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= @@ -1175,11 +1175,11 @@ golang.org/x/net v0.18.0/go.mod h1:/czyP5RqHAH4odGYxBJ1qz0+CE5WZ+2j1YgoEo8F2jQ= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= -golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= -golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= +golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY= +golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.29.0 h1:WdYw2tdTK1S8olAzWHdgeqfy+Mtm9XNhv/xJsY65d98= -golang.org/x/oauth2 v0.29.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1195,8 +1195,8 @@ golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= -golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= +golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1235,8 +1235,8 @@ golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= -golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -1249,8 +1249,8 @@ golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= -golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o= -golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw= +golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= +golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -1263,8 +1263,8 @@ golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= -golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= +golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= +golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/internal/controller/bucket_controller.go b/internal/controller/bucket_controller.go index 086d5b0d4..d67c10f9b 100644 --- a/internal/controller/bucket_controller.go +++ b/internal/controller/bucket_controller.go @@ -77,7 +77,7 @@ import ( const maxConcurrentBucketFetches = 100 // bucketReadyCondition contains the information required to summarize a -// v1beta2.Bucket Ready Condition. +// v1.Bucket Ready Condition. var bucketReadyCondition = summarize.Conditions{ Target: meta.ReadyCondition, Owned: []string{ @@ -117,7 +117,7 @@ var bucketFailConditions = []string{ // +kubebuilder:rbac:groups=source.toolkit.fluxcd.io,resources=buckets/finalizers,verbs=get;create;update;patch;delete // +kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch -// BucketReconciler reconciles a v1beta2.Bucket object. +// BucketReconciler reconciles a v1.Bucket object. type BucketReconciler struct { client.Client kuberecorder.EventRecorder @@ -155,7 +155,7 @@ type BucketProvider interface { Close(context.Context) } -// bucketReconcileFunc is the function type for all the v1beta2.Bucket +// bucketReconcileFunc is the function type for all the v1.Bucket // (sub)reconcile functions. The type implementations are grouped and // executed serially to perform the complete reconcile of the object. type bucketReconcileFunc func(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.Bucket, index *index.Digester, dir string) (sreconcile.Result, error) @@ -418,7 +418,7 @@ func (r *BucketReconciler) reconcileStorage(ctx context.Context, sp *patch.Seria // reconcileSource fetches the upstream bucket contents with the client for the // given object's Provider, and returns the result. // When a SecretRef is defined, it attempts to fetch the Secret before calling -// the provider. If this fails, it records v1beta2.FetchFailedCondition=True on +// the provider. If this fails, it records v1.FetchFailedCondition=True on // the object and returns early. func (r *BucketReconciler) reconcileSource(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.Bucket, index *index.Digester, dir string) (sreconcile.Result, error) { secret, err := r.getSecret(ctx, obj.Spec.SecretRef, obj.GetNamespace()) @@ -588,7 +588,7 @@ func (r *BucketReconciler) reconcileSource(ctx context.Context, sp *patch.Serial // (Status) data on the object does not match the given. // // The inspection of the given data to the object is differed, ensuring any -// stale observations like v1beta2.ArtifactOutdatedCondition are removed. +// stale observations like v1.ArtifactOutdatedCondition are removed. // If the given Artifact does not differ from the object's current, it returns // early. // On a successful archive, the Artifact in the Status of the object is set, diff --git a/internal/controller/gitrepository_controller.go b/internal/controller/gitrepository_controller.go index 045bb2443..809f99171 100644 --- a/internal/controller/gitrepository_controller.go +++ b/internal/controller/gitrepository_controller.go @@ -69,7 +69,7 @@ import ( ) // gitRepositoryReadyCondition contains the information required to summarize a -// v1beta2.GitRepository Ready Condition. +// v1.GitRepository Ready Condition. var gitRepositoryReadyCondition = summarize.Conditions{ Target: meta.ReadyCondition, Owned: []string{ @@ -124,7 +124,7 @@ func getPatchOptions(ownedConditions []string, controllerName string) []patch.Op // +kubebuilder:rbac:groups=source.toolkit.fluxcd.io,resources=gitrepositories/finalizers,verbs=get;create;update;patch;delete // +kubebuilder:rbac:groups="",resources=events,verbs=create;patch -// GitRepositoryReconciler reconciles a v1beta2.GitRepository object. +// GitRepositoryReconciler reconciles a v1.GitRepository object. type GitRepositoryReconciler struct { client.Client kuberecorder.EventRecorder @@ -146,7 +146,7 @@ type GitRepositoryReconcilerOptions struct { } // gitRepositoryReconcileFunc is the function type for all the -// v1beta2.GitRepository (sub)reconcile functions. +// v1.GitRepository (sub)reconcile functions. type gitRepositoryReconcileFunc func(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.GitRepository, commit *git.Commit, includes *artifactSet, dir string) (sreconcile.Result, error) func (r *GitRepositoryReconciler) SetupWithManager(mgr ctrl.Manager) error { @@ -446,23 +446,23 @@ func (r *GitRepositoryReconciler) reconcileStorage(ctx context.Context, sp *patc // // The included repositories are fetched and their metadata are stored. In case // one of the included repositories isn't ready, it records -// v1beta2.IncludeUnavailableCondition=True and returns early. When all the +// v1.IncludeUnavailableCondition=True and returns early. When all the // included repositories are ready, it removes -// v1beta2.IncludeUnavailableCondition from the object. +// v1.IncludeUnavailableCondition from the object. // When the included artifactSet differs from the current set in the Status of -// the object, it marks the object with v1beta2.ArtifactOutdatedCondition=True. +// the object, it marks the object with v1.ArtifactOutdatedCondition=True. // The repository is cloned to the given dir, using the specified configuration // to check out the reference. In case of an error during this process -// (including transient errors), it records v1beta2.FetchFailedCondition=True +// (including transient errors), it records v1.FetchFailedCondition=True // and returns early. -// On a successful checkout, it removes v1beta2.FetchFailedCondition and +// On a successful checkout, it removes v1.FetchFailedCondition and // compares the current revision of HEAD to the revision of the Artifact in the -// Status of the object. It records v1beta2.ArtifactOutdatedCondition=True when +// Status of the object. It records v1.ArtifactOutdatedCondition=True when // they differ. // If specified, the signature of the Git commit is verified. If the signature // can not be verified or the verification fails, it records -// v1beta2.SourceVerifiedCondition=False and returns early. When successful, -// it records v1beta2.SourceVerifiedCondition=True. +// v1.SourceVerifiedCondition=False and returns early. When successful, +// it records v1.SourceVerifiedCondition=True. // When all the above is successful, the given Commit pointer is set to the // commit of the checked out Git repository. // @@ -756,7 +756,7 @@ func (r *GitRepositoryReconciler) getSecretData(ctx context.Context, name, names // (Status) data on the object does not match the given. // // The inspection of the given data to the object is differed, ensuring any -// stale observations like v1beta2.ArtifactOutdatedCondition are removed. +// stale observations like v1.ArtifactOutdatedCondition are removed. // If the given Artifact and/or artifactSet (includes) and observed artifact // content config do not differ from the object's current, it returns early. // Source ignore patterns are loaded, and the given directory is archived while @@ -872,15 +872,15 @@ func (r *GitRepositoryReconciler) reconcileArtifact(ctx context.Context, sp *pat } // reconcileInclude reconciles the on the object specified -// v1beta2.GitRepositoryInclude list by copying their Artifact (sub)contents to +// v1.GitRepositoryInclude list by copying their Artifact (sub)contents to // the specified paths in the given directory. // // When one of the includes is unavailable, it marks the object with -// v1beta2.IncludeUnavailableCondition=True and returns early. +// v1.IncludeUnavailableCondition=True and returns early. // When the copy operations are successful, it removes the -// v1beta2.IncludeUnavailableCondition from the object. +// v1.IncludeUnavailableCondition from the object. // When the composed artifactSet differs from the current set in the Status of -// the object, it marks the object with v1beta2.ArtifactOutdatedCondition=True. +// the object, it marks the object with v1.ArtifactOutdatedCondition=True. func (r *GitRepositoryReconciler) reconcileInclude(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.GitRepository, _ *git.Commit, includes *artifactSet, dir string) (sreconcile.Result, error) { @@ -1029,10 +1029,10 @@ func (r *GitRepositoryReconciler) fetchIncludes(ctx context.Context, obj *source // verifySignature verifies the signature of the given Git commit and/or its referencing tag // depending on the verification mode specified on the object. // If the signature can not be verified or the verification fails, it records -// v1beta2.SourceVerifiedCondition=False and returns. -// When successful, it records v1beta2.SourceVerifiedCondition=True. +// v1.SourceVerifiedCondition=False and returns. +// When successful, it records v1.SourceVerifiedCondition=True. // If no verification mode is specified on the object, the -// v1beta2.SourceVerifiedCondition Condition is removed. +// v1.SourceVerifiedCondition Condition is removed. func (r *GitRepositoryReconciler) verifySignature(ctx context.Context, obj *sourcev1.GitRepository, commit git.Commit) (sreconcile.Result, error) { // Check if there is a commit verification is configured and remove any old // observations if there is none diff --git a/internal/controller/helmchart_controller_test.go b/internal/controller/helmchart_controller_test.go index 2d796123d..e93a9516f 100644 --- a/internal/controller/helmchart_controller_test.go +++ b/internal/controller/helmchart_controller_test.go @@ -67,7 +67,6 @@ import ( "github.com/fluxcd/pkg/testserver" sourcev1 "github.com/fluxcd/source-controller/api/v1" - sourcev1beta2 "github.com/fluxcd/source-controller/api/v1beta2" serror "github.com/fluxcd/source-controller/internal/error" "github.com/fluxcd/source-controller/internal/helm/chart" "github.com/fluxcd/source-controller/internal/helm/chart/secureloader" @@ -1366,7 +1365,7 @@ func TestHelmChartReconciler_buildFromOCIHelmRepository(t *testing.T) { Spec: sourcev1.HelmRepositorySpec{ URL: fmt.Sprintf("oci://%s/testrepo", testRegistryServer.registryHost), Timeout: &metav1.Duration{Duration: timeout}, - Provider: sourcev1beta2.GenericOCIProvider, + Provider: sourcev1.GenericOCIProvider, Type: sourcev1.HelmRepositoryTypeOCI, Insecure: true, }, @@ -2595,7 +2594,7 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_authStrategy(t *testing.T) { Interval: metav1.Duration{Duration: interval}, Timeout: &metav1.Duration{Duration: timeout}, Type: sourcev1.HelmRepositoryTypeOCI, - Provider: sourcev1beta2.GenericOCIProvider, + Provider: sourcev1.GenericOCIProvider, URL: fmt.Sprintf("oci://%s/testrepo", server.registryHost), Insecure: tt.insecure, }, @@ -2798,7 +2797,7 @@ func TestHelmChartRepository_reconcileSource_verifyOCISourceSignature_keyless(t Spec: sourcev1.HelmRepositorySpec{ URL: "oci://ghcr.io/stefanprodan/charts", Timeout: &metav1.Duration{Duration: timeout}, - Provider: sourcev1beta2.GenericOCIProvider, + Provider: sourcev1.GenericOCIProvider, Type: sourcev1.HelmRepositoryTypeOCI, }, } @@ -3059,7 +3058,7 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignatureNotation(t *t Spec: sourcev1.HelmRepositorySpec{ URL: fmt.Sprintf("oci://%s/testrepo", server.registryHost), Timeout: &metav1.Duration{Duration: timeout}, - Provider: sourcev1beta2.GenericOCIProvider, + Provider: sourcev1.GenericOCIProvider, Type: sourcev1.HelmRepositoryTypeOCI, Insecure: true, }, @@ -3332,7 +3331,7 @@ func TestHelmChartReconciler_reconcileSourceFromOCI_verifySignatureCosign(t *tes Spec: sourcev1.HelmRepositorySpec{ URL: fmt.Sprintf("oci://%s/testrepo", server.registryHost), Timeout: &metav1.Duration{Duration: timeout}, - Provider: sourcev1beta2.GenericOCIProvider, + Provider: sourcev1.GenericOCIProvider, Type: sourcev1.HelmRepositoryTypeOCI, Insecure: true, }, diff --git a/internal/controller/ocirepository_controller.go b/internal/controller/ocirepository_controller.go index 577cf8639..938a8a9d5 100644 --- a/internal/controller/ocirepository_controller.go +++ b/internal/controller/ocirepository_controller.go @@ -71,7 +71,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/predicate" sourcev1 "github.com/fluxcd/source-controller/api/v1" - ociv1 "github.com/fluxcd/source-controller/api/v1beta2" serror "github.com/fluxcd/source-controller/internal/error" soci "github.com/fluxcd/source-controller/internal/oci" scosign "github.com/fluxcd/source-controller/internal/oci/cosign" @@ -83,7 +82,7 @@ import ( ) // ociRepositoryReadyCondition contains the information required to summarize a -// v1beta2.OCIRepository Ready Condition. +// v1.OCIRepository Ready Condition. var ociRepositoryReadyCondition = summarize.Conditions{ Target: meta.ReadyCondition, Owned: []string{ @@ -130,12 +129,12 @@ func (e invalidOCIURLError) Error() string { return e.err.Error() } -// ociRepositoryReconcileFunc is the function type for all the v1beta2.OCIRepository +// ociRepositoryReconcileFunc is the function type for all the v1.OCIRepository // (sub)reconcile functions. The type implementations are grouped and // executed serially to perform the complete reconcile of the object. -type ociRepositoryReconcileFunc func(ctx context.Context, sp *patch.SerialPatcher, obj *ociv1.OCIRepository, metadata *sourcev1.Artifact, dir string) (sreconcile.Result, error) +type ociRepositoryReconcileFunc func(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.OCIRepository, metadata *sourcev1.Artifact, dir string) (sreconcile.Result, error) -// OCIRepositoryReconciler reconciles a v1beta2.OCIRepository object +// OCIRepositoryReconciler reconciles a v1.OCIRepository object type OCIRepositoryReconciler struct { client.Client helper.Metrics @@ -165,7 +164,7 @@ func (r *OCIRepositoryReconciler) SetupWithManagerAndOptions(mgr ctrl.Manager, o r.requeueDependency = opts.DependencyRequeueInterval return ctrl.NewControllerManagedBy(mgr). - For(&ociv1.OCIRepository{}, builder.WithPredicates( + For(&sourcev1.OCIRepository{}, builder.WithPredicates( predicate.Or(predicate.GenerationChangedPredicate{}, predicates.ReconcileRequestedPredicate{}), )). WithOptions(controller.Options{ @@ -185,7 +184,7 @@ func (r *OCIRepositoryReconciler) Reconcile(ctx context.Context, req ctrl.Reques log := ctrl.LoggerFrom(ctx) // Fetch the OCIRepository - obj := &ociv1.OCIRepository{} + obj := &sourcev1.OCIRepository{} if err := r.Get(ctx, req.NamespacedName, obj); err != nil { return ctrl.Result{}, client.IgnoreNotFound(err) } @@ -257,7 +256,7 @@ func (r *OCIRepositoryReconciler) Reconcile(ctx context.Context, req ctrl.Reques // reconcile iterates through the ociRepositoryReconcileFunc tasks for the // object. It returns early on the first call that returns // reconcile.ResultRequeue, or produces an error. -func (r *OCIRepositoryReconciler) reconcile(ctx context.Context, sp *patch.SerialPatcher, obj *ociv1.OCIRepository, reconcilers []ociRepositoryReconcileFunc) (sreconcile.Result, error) { +func (r *OCIRepositoryReconciler) reconcile(ctx context.Context, sp *patch.SerialPatcher, obj *sourcev1.OCIRepository, reconcilers []ociRepositoryReconcileFunc) (sreconcile.Result, error) { oldObj := obj.DeepCopy() rreconcile.ProgressiveStatus(false, obj, meta.ProgressingReason, "reconciliation in progress") @@ -329,9 +328,9 @@ func (r *OCIRepositoryReconciler) reconcile(ctx context.Context, sp *patch.Seria } // reconcileSource fetches the upstream OCI artifact metadata and content. -// If this fails, it records v1beta2.FetchFailedCondition=True on the object and returns early. +// If this fails, it records v1.FetchFailedCondition=True on the object and returns early. func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch.SerialPatcher, - obj *ociv1.OCIRepository, metadata *sourcev1.Artifact, dir string) (sreconcile.Result, error) { + obj *sourcev1.OCIRepository, metadata *sourcev1.Artifact, dir string) (sreconcile.Result, error) { var authenticator authn.Authenticator ctxTimeout, cancel := context.WithTimeout(ctx, obj.Spec.Timeout.Duration) @@ -366,7 +365,7 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch return sreconcile.ResultEmpty, e } - if _, ok := keychain.(soci.Anonymous); obj.Spec.Provider != ociv1.GenericOCIProvider && ok { + if _, ok := keychain.(soci.Anonymous); obj.Spec.Provider != sourcev1.GenericOCIProvider && ok { var opts []auth.Option if obj.Spec.ServiceAccountName != "" { serviceAccount := client.ObjectKey{ @@ -377,7 +376,7 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch } if r.TokenCache != nil { involvedObject := cache.InvolvedObject{ - Kind: ociv1.OCIRepositoryKind, + Kind: sourcev1.OCIRepositoryKind, Name: obj.GetName(), Namespace: obj.GetNamespace(), Operation: cache.OperationReconcile, @@ -436,7 +435,7 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch if err != nil { e := serror.NewGeneric( fmt.Errorf("failed to determine artifact digest: %w", err), - ociv1.OCIPullFailedReason, + sourcev1.OCIPullFailedReason, ) conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, "%s", e) return sreconcile.ResultEmpty, e @@ -501,7 +500,7 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch if err != nil { e := serror.NewGeneric( fmt.Errorf("failed to pull artifact from '%s': %w", obj.Spec.URL, err), - ociv1.OCIPullFailedReason, + sourcev1.OCIPullFailedReason, ) conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, "%s", e) return sreconcile.ResultEmpty, e @@ -512,7 +511,7 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch if err != nil { e := serror.NewGeneric( fmt.Errorf("failed to parse artifact manifest: %w", err), - ociv1.OCILayerOperationFailedReason, + sourcev1.OCILayerOperationFailedReason, ) conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, "%s", e) return sreconcile.ResultEmpty, e @@ -522,29 +521,29 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch // Extract the compressed content from the selected layer blob, err := r.selectLayer(obj, img) if err != nil { - e := serror.NewGeneric(err, ociv1.OCILayerOperationFailedReason) + e := serror.NewGeneric(err, sourcev1.OCILayerOperationFailedReason) conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, "%s", e) return sreconcile.ResultEmpty, e } // Persist layer content to storage using the specified operation switch obj.GetLayerOperation() { - case ociv1.OCILayerExtract: + case sourcev1.OCILayerExtract: if err = tar.Untar(blob, dir, tar.WithMaxUntarSize(-1), tar.WithSkipSymlinks()); err != nil { e := serror.NewGeneric( fmt.Errorf("failed to extract layer contents from artifact: %w", err), - ociv1.OCILayerOperationFailedReason, + sourcev1.OCILayerOperationFailedReason, ) conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, "%s", e) return sreconcile.ResultEmpty, e } - case ociv1.OCILayerCopy: + case sourcev1.OCILayerCopy: metadata.Path = fmt.Sprintf("%s.tgz", r.digestFromRevision(metadata.Revision)) file, err := os.Create(filepath.Join(dir, metadata.Path)) if err != nil { e := serror.NewGeneric( fmt.Errorf("failed to create file to copy layer to: %w", err), - ociv1.OCILayerOperationFailedReason, + sourcev1.OCILayerOperationFailedReason, ) conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, "%s", e) return sreconcile.ResultEmpty, e @@ -555,7 +554,7 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch if err != nil { e := serror.NewGeneric( fmt.Errorf("failed to copy layer from artifact: %w", err), - ociv1.OCILayerOperationFailedReason, + sourcev1.OCILayerOperationFailedReason, ) conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, "%s", e) return sreconcile.ResultEmpty, e @@ -563,7 +562,7 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch default: e := serror.NewGeneric( fmt.Errorf("unsupported layer operation: %s", obj.GetLayerOperation()), - ociv1.OCILayerOperationFailedReason, + sourcev1.OCILayerOperationFailedReason, ) conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, e.Reason, "%s", e) return sreconcile.ResultEmpty, e @@ -575,7 +574,7 @@ func (r *OCIRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch // selectLayer finds the matching layer and returns its compressed contents. // If no layer selector was provided, we pick the first layer from the OCI artifact. -func (r *OCIRepositoryReconciler) selectLayer(obj *ociv1.OCIRepository, image gcrv1.Image) (io.ReadCloser, error) { +func (r *OCIRepositoryReconciler) selectLayer(obj *sourcev1.OCIRepository, image gcrv1.Image) (io.ReadCloser, error) { layers, err := image.Layers() if err != nil { return nil, fmt.Errorf("failed to parse artifact layers: %w", err) @@ -656,7 +655,7 @@ func (r *OCIRepositoryReconciler) digestFromRevision(revision string) string { // If not, when using cosign it falls back to a keyless approach for verification. // When notation is used, a trust policy is required to verify the image. // The verification result is returned as a VerificationResult and any error encountered. -func (r *OCIRepositoryReconciler) verifySignature(ctx context.Context, obj *ociv1.OCIRepository, +func (r *OCIRepositoryReconciler) verifySignature(ctx context.Context, obj *sourcev1.OCIRepository, ref name.Reference, keychain authn.Keychain, auth authn.Authenticator, transport *http.Transport, opt ...remote.Option) (soci.VerificationResult, error) { @@ -824,12 +823,12 @@ func (r *OCIRepositoryReconciler) retrieveSecret(ctx context.Context, verifySecr } // parseRepository validates and extracts the repository URL. -func (r *OCIRepositoryReconciler) parseRepository(obj *ociv1.OCIRepository) (name.Repository, error) { - if !strings.HasPrefix(obj.Spec.URL, ociv1.OCIRepositoryPrefix) { +func (r *OCIRepositoryReconciler) parseRepository(obj *sourcev1.OCIRepository) (name.Repository, error) { + if !strings.HasPrefix(obj.Spec.URL, sourcev1.OCIRepositoryPrefix) { return name.Repository{}, fmt.Errorf("URL must be in format 'oci:////'") } - url := strings.TrimPrefix(obj.Spec.URL, ociv1.OCIRepositoryPrefix) + url := strings.TrimPrefix(obj.Spec.URL, sourcev1.OCIRepositoryPrefix) options := []name.Option{} if obj.Spec.Insecure { @@ -849,7 +848,7 @@ func (r *OCIRepositoryReconciler) parseRepository(obj *ociv1.OCIRepository) (nam } // getArtifactRef determines which tag or revision should be used and returns the OCI artifact FQN. -func (r *OCIRepositoryReconciler) getArtifactRef(obj *ociv1.OCIRepository, options []remote.Option) (name.Reference, error) { +func (r *OCIRepositoryReconciler) getArtifactRef(obj *sourcev1.OCIRepository, options []remote.Option) (name.Reference, error) { repo, err := r.parseRepository(obj) if err != nil { return nil, invalidOCIURLError{err} @@ -913,7 +912,7 @@ func (r *OCIRepositoryReconciler) getTagBySemver(repo name.Repository, exp strin // keychain generates the credential keychain based on the resource // configuration. If no auth is specified a default keychain with // anonymous access is returned -func (r *OCIRepositoryReconciler) keychain(ctx context.Context, obj *ociv1.OCIRepository) (authn.Keychain, error) { +func (r *OCIRepositoryReconciler) keychain(ctx context.Context, obj *sourcev1.OCIRepository) (authn.Keychain, error) { pullSecretNames := sets.NewString() // lookup auth secret @@ -959,7 +958,7 @@ func (r *OCIRepositoryReconciler) keychain(ctx context.Context, obj *ociv1.OCIRe // the returned transport will include the TLS client and/or CA certificates. // If the insecure flag is set, the transport will skip the verification of the server's certificate. // Additionally, if a proxy is specified, transport will use it. -func (r *OCIRepositoryReconciler) transport(ctx context.Context, obj *ociv1.OCIRepository, proxyURL *url.URL) (*http.Transport, error) { +func (r *OCIRepositoryReconciler) transport(ctx context.Context, obj *sourcev1.OCIRepository, proxyURL *url.URL) (*http.Transport, error) { transport := remote.DefaultTransport.(*http.Transport).Clone() tlsConfig, err := r.getTLSConfig(ctx, obj) @@ -979,7 +978,7 @@ func (r *OCIRepositoryReconciler) transport(ctx context.Context, obj *ociv1.OCIR // getTLSConfig gets the TLS configuration for the transport based on the // specified secret reference in the OCIRepository object, or the insecure flag. -func (r *OCIRepositoryReconciler) getTLSConfig(ctx context.Context, obj *ociv1.OCIRepository) (*cryptotls.Config, error) { +func (r *OCIRepositoryReconciler) getTLSConfig(ctx context.Context, obj *sourcev1.OCIRepository) (*cryptotls.Config, error) { if obj.Spec.CertSecretRef == nil || obj.Spec.CertSecretRef.Name == "" { if obj.Spec.Insecure { return &cryptotls.Config{ @@ -1018,7 +1017,7 @@ func (r *OCIRepositoryReconciler) getTLSConfig(ctx context.Context, obj *ociv1.O // getProxyURL gets the proxy configuration for the transport based on the // specified proxy secret reference in the OCIRepository object. -func (r *OCIRepositoryReconciler) getProxyURL(ctx context.Context, obj *ociv1.OCIRepository) (*url.URL, error) { +func (r *OCIRepositoryReconciler) getProxyURL(ctx context.Context, obj *sourcev1.OCIRepository) (*url.URL, error) { if obj.Spec.ProxySecretRef == nil || obj.Spec.ProxySecretRef.Name == "" { return nil, nil } @@ -1063,7 +1062,7 @@ func (r *OCIRepositoryReconciler) getProxyURL(ctx context.Context, obj *ociv1.OC // The hostname of any URL in the Status of the object are updated, to ensure // they match the Storage server hostname of current runtime. func (r *OCIRepositoryReconciler) reconcileStorage(ctx context.Context, sp *patch.SerialPatcher, - obj *ociv1.OCIRepository, _ *sourcev1.Artifact, _ string) (sreconcile.Result, error) { + obj *sourcev1.OCIRepository, _ *sourcev1.Artifact, _ string) (sreconcile.Result, error) { // Garbage collect previous advertised artifact(s) from storage _ = r.garbageCollect(ctx, obj) @@ -1120,13 +1119,13 @@ func (r *OCIRepositoryReconciler) reconcileStorage(ctx context.Context, sp *patc // (Status) data on the object does not match the given. // // The inspection of the given data to the object is differed, ensuring any -// stale observations like v1beta2.ArtifactOutdatedCondition are removed. +// stale observations like v1.ArtifactOutdatedCondition are removed. // If the given Artifact does not differ from the object's current, it returns // early. // On a successful archive, the Artifact in the Status of the object is set, // and the symlink in the Storage is updated to its path. func (r *OCIRepositoryReconciler) reconcileArtifact(ctx context.Context, sp *patch.SerialPatcher, - obj *ociv1.OCIRepository, metadata *sourcev1.Artifact, dir string) (sreconcile.Result, error) { + obj *sourcev1.OCIRepository, metadata *sourcev1.Artifact, dir string) (sreconcile.Result, error) { // Create artifact artifact := r.Storage.NewArtifactFor(obj.Kind, obj, metadata.Revision, fmt.Sprintf("%s.tar.gz", r.digestFromRevision(metadata.Revision))) @@ -1183,7 +1182,7 @@ func (r *OCIRepositoryReconciler) reconcileArtifact(ctx context.Context, sp *pat defer unlock() switch obj.GetLayerOperation() { - case ociv1.OCILayerCopy: + case sourcev1.OCILayerCopy: if err = r.Storage.CopyFromPath(&artifact, filepath.Join(dir, metadata.Path)); err != nil { e := serror.NewGeneric( fmt.Errorf("unable to copy artifact to storage: %w", err), @@ -1219,7 +1218,6 @@ func (r *OCIRepositoryReconciler) reconcileArtifact(ctx context.Context, sp *pat // Record the observations on the object. obj.Status.Artifact = artifact.DeepCopy() obj.Status.Artifact.Metadata = metadata.Metadata - obj.Status.ContentConfigChecksum = "" // To be removed in the next API version. obj.Status.ObservedIgnore = obj.Spec.Ignore obj.Status.ObservedLayerSelector = obj.Spec.LayerSelector @@ -1239,7 +1237,7 @@ func (r *OCIRepositoryReconciler) reconcileArtifact(ctx context.Context, sp *pat // reconcileDelete handles the deletion of the object. // It first garbage collects all Artifacts for the object from the Storage. // Removing the finalizer from the object if successful. -func (r *OCIRepositoryReconciler) reconcileDelete(ctx context.Context, obj *ociv1.OCIRepository) (sreconcile.Result, error) { +func (r *OCIRepositoryReconciler) reconcileDelete(ctx context.Context, obj *sourcev1.OCIRepository) (sreconcile.Result, error) { // Garbage collect the resource's artifacts if err := r.garbageCollect(ctx, obj); err != nil { // Return the error so we retry the failed garbage collection @@ -1250,7 +1248,7 @@ func (r *OCIRepositoryReconciler) reconcileDelete(ctx context.Context, obj *ociv controllerutil.RemoveFinalizer(obj, sourcev1.SourceFinalizer) // Cleanup caches. - r.TokenCache.DeleteEventsForObject(ociv1.OCIRepositoryKind, + r.TokenCache.DeleteEventsForObject(sourcev1.OCIRepositoryKind, obj.GetName(), obj.GetNamespace(), cache.OperationReconcile) // Stop reconciliation as the object is being deleted @@ -1262,7 +1260,7 @@ func (r *OCIRepositoryReconciler) reconcileDelete(ctx context.Context, obj *ociv // It removes all but the current Artifact from the Storage, unless the // deletion timestamp on the object is set. Which will result in the // removal of all Artifacts for the objects. -func (r *OCIRepositoryReconciler) garbageCollect(ctx context.Context, obj *ociv1.OCIRepository) error { +func (r *OCIRepositoryReconciler) garbageCollect(ctx context.Context, obj *sourcev1.OCIRepository) error { if !obj.DeletionTimestamp.IsZero() { if deleted, err := r.Storage.RemoveAll(r.Storage.NewArtifactFor(obj.Kind, obj.GetObjectMeta(), "", "*")); err != nil { return serror.NewGeneric( @@ -1310,7 +1308,7 @@ func (r *OCIRepositoryReconciler) eventLogf(ctx context.Context, obj runtime.Obj } // notify emits notification related to the reconciliation. -func (r *OCIRepositoryReconciler) notify(ctx context.Context, oldObj, newObj *ociv1.OCIRepository, res sreconcile.Result, resErr error) { +func (r *OCIRepositoryReconciler) notify(ctx context.Context, oldObj, newObj *sourcev1.OCIRepository, res sreconcile.Result, resErr error) { // Notify successful reconciliation for new artifact and recovery from any // failure. if resErr == nil && res == sreconcile.ResultSuccess && newObj.Status.Artifact != nil { @@ -1376,7 +1374,7 @@ type remoteOptions []remote.Option // ociContentConfigChanged evaluates the current spec with the observations // of the artifact in the status to determine if artifact content configuration // has changed and requires rebuilding the artifact. -func ociContentConfigChanged(obj *ociv1.OCIRepository) bool { +func ociContentConfigChanged(obj *sourcev1.OCIRepository) bool { if !ptr.Equal(obj.Spec.Ignore, obj.Status.ObservedIgnore) { return true } @@ -1391,7 +1389,7 @@ func ociContentConfigChanged(obj *ociv1.OCIRepository) bool { // Returns true if both arguments are nil or both arguments // dereference to the same value. // Based on k8s.io/utils/pointer/pointer.go pointer value equality. -func layerSelectorEqual(a, b *ociv1.OCILayerSelector) bool { +func layerSelectorEqual(a, b *sourcev1.OCILayerSelector) bool { if (a == nil) != (b == nil) { return false } diff --git a/internal/controller/ocirepository_controller_test.go b/internal/controller/ocirepository_controller_test.go index 93e34384d..3b5decb09 100644 --- a/internal/controller/ocirepository_controller_test.go +++ b/internal/controller/ocirepository_controller_test.go @@ -68,7 +68,6 @@ import ( "github.com/fluxcd/pkg/tar" sourcev1 "github.com/fluxcd/source-controller/api/v1" - ociv1 "github.com/fluxcd/source-controller/api/v1beta2" intdigest "github.com/fluxcd/source-controller/internal/digest" serror "github.com/fluxcd/source-controller/internal/error" snotation "github.com/fluxcd/source-controller/internal/oci/notation" @@ -88,10 +87,10 @@ func TestOCIRepositoryReconciler_deleteBeforeFinalizer(t *testing.T) { g.Expect(k8sClient.Delete(ctx, namespace)).NotTo(HaveOccurred()) }) - ocirepo := &ociv1.OCIRepository{} + ocirepo := &sourcev1.OCIRepository{} ocirepo.Name = "test-ocirepo" ocirepo.Namespace = namespaceName - ocirepo.Spec = ociv1.OCIRepositorySpec{ + ocirepo.Spec = sourcev1.OCIRepositorySpec{ Interval: metav1.Duration{Duration: interval}, URL: "oci://example.com", } @@ -143,7 +142,7 @@ func TestOCIRepository_Reconcile(t *testing.T) { tag: podinfoVersions["6.1.6"].tag, revision: fmt.Sprintf("%s@%s", podinfoVersions["6.1.6"].tag, podinfoVersions["6.1.6"].digest.String()), mediaType: "application/vnd.docker.image.rootfs.diff.tar.gzip", - operation: ociv1.OCILayerCopy, + operation: sourcev1.OCILayerCopy, assertArtifact: []artifactFixture{ { expectedPath: "kustomize/deployment.yaml", @@ -181,15 +180,15 @@ func TestOCIRepository_Reconcile(t *testing.T) { g.Expect(err).ToNot(HaveOccurred()) defer func() { g.Expect(testEnv.Delete(ctx, ns)).To(Succeed()) }() - origObj := &ociv1.OCIRepository{ + origObj := &sourcev1.OCIRepository{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "ocirepository-reconcile", Namespace: ns.Name, }, - Spec: ociv1.OCIRepositorySpec{ + Spec: sourcev1.OCIRepositorySpec{ URL: tt.url, Interval: metav1.Duration{Duration: 60 * time.Minute}, - Reference: &ociv1.OCIRepositoryRef{}, + Reference: &sourcev1.OCIRepositoryRef{}, Insecure: true, }, } @@ -202,7 +201,7 @@ func TestOCIRepository_Reconcile(t *testing.T) { obj.Spec.Reference.SemVer = tt.semver } if tt.mediaType != "" { - obj.Spec.LayerSelector = &ociv1.OCILayerSelector{MediaType: tt.mediaType} + obj.Spec.LayerSelector = &sourcev1.OCILayerSelector{MediaType: tt.mediaType} if tt.operation != "" { obj.Spec.LayerSelector.Operation = tt.operation @@ -349,18 +348,18 @@ func TestOCIRepository_Reconcile_MediaType(t *testing.T) { g.Expect(err).ToNot(HaveOccurred()) defer func() { g.Expect(testEnv.Delete(ctx, ns)).To(Succeed()) }() - obj := &ociv1.OCIRepository{ + obj := &sourcev1.OCIRepository{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "ocirepository-reconcile", Namespace: ns.Name, }, - Spec: ociv1.OCIRepositorySpec{ + Spec: sourcev1.OCIRepositorySpec{ URL: tt.url, Interval: metav1.Duration{Duration: 60 * time.Minute}, - Reference: &ociv1.OCIRepositoryRef{ + Reference: &sourcev1.OCIRepositoryRef{ Tag: tt.tag, }, - LayerSelector: &ociv1.OCILayerSelector{ + LayerSelector: &sourcev1.OCILayerSelector{ MediaType: tt.mediaType, }, Insecure: true, @@ -504,7 +503,7 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) { crane.Insecure, }, assertConditions: []metav1.Condition{ - *conditions.TrueCondition(sourcev1.FetchFailedCondition, ociv1.OCIPullFailedReason, "failed to determine artifact digest"), + *conditions.TrueCondition(sourcev1.FetchFailedCondition, sourcev1.OCIPullFailedReason, "%s", "failed to determine artifact digest"), }, }, { @@ -528,7 +527,7 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) { includeSecret: true, }, assertConditions: []metav1.Condition{ - *conditions.TrueCondition(sourcev1.FetchFailedCondition, ociv1.OCIPullFailedReason, "UNAUTHORIZED"), + *conditions.TrueCondition(sourcev1.FetchFailedCondition, sourcev1.OCIPullFailedReason, "%s", "UNAUTHORIZED"), }, }, { @@ -552,7 +551,7 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) { includeSA: true, }, assertConditions: []metav1.Condition{ - *conditions.TrueCondition(sourcev1.FetchFailedCondition, ociv1.OCIPullFailedReason, "UNAUTHORIZED"), + *conditions.TrueCondition(sourcev1.FetchFailedCondition, sourcev1.OCIPullFailedReason, "%s", "UNAUTHORIZED"), }, }, { @@ -576,8 +575,8 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) { }, }, assertConditions: []metav1.Condition{ - *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "building artifact: new revision '' for ''"), - *conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "building artifact: new revision '' for ''"), + *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "%s", "building artifact: new revision '' for ''"), + *conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "%s", "building artifact: new revision '' for ''"), }, }, { @@ -601,8 +600,8 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) { }, }, assertConditions: []metav1.Condition{ - *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "building artifact: new revision '' for ''"), - *conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "building artifact: new revision '' for ''"), + *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "%s", "building artifact: new revision '' for ''"), + *conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "%s", "building artifact: new revision '' for ''"), }, }, { @@ -619,7 +618,7 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) { }), }, assertConditions: []metav1.Condition{ - *conditions.TrueCondition(sourcev1.FetchFailedCondition, ociv1.OCIPullFailedReason, "failed to determine artifact digest"), + *conditions.TrueCondition(sourcev1.FetchFailedCondition, sourcev1.OCIPullFailedReason, "%s", "failed to determine artifact digest"), }, }, { @@ -644,7 +643,7 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) { }, }, assertConditions: []metav1.Condition{ - *conditions.TrueCondition(sourcev1.FetchFailedCondition, ociv1.AuthenticationFailedReason, "cannot append certificate into certificate pool: invalid CA certificate"), + *conditions.TrueCondition(sourcev1.FetchFailedCondition, sourcev1.AuthenticationFailedReason, "%s", "cannot append certificate into certificate pool: invalid CA certificate"), }, }, { @@ -669,8 +668,8 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) { }, }, assertConditions: []metav1.Condition{ - *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "building artifact: new revision '' for ''"), - *conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "building artifact: new revision '' for ''"), + *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "%s", "building artifact: new revision '' for ''"), + *conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "%s", "building artifact: new revision '' for ''"), }, }, { @@ -682,7 +681,7 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) { crane.Insecure, }, assertConditions: []metav1.Condition{ - *conditions.TrueCondition(sourcev1.FetchFailedCondition, sourcev1.AuthenticationFailedReason, "failed to get credential from"), + *conditions.TrueCondition(sourcev1.FetchFailedCondition, sourcev1.AuthenticationFailedReason, "%s", "failed to get credential from"), }, }, { @@ -706,8 +705,8 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) { insecure: true, provider: "azure", assertConditions: []metav1.Condition{ - *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "building artifact: new revision '' for ''"), - *conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "building artifact: new revision '' for ''"), + *conditions.TrueCondition(meta.ReconcilingCondition, meta.ProgressingReason, "%s", "building artifact: new revision '' for ''"), + *conditions.UnknownCondition(meta.ReadyCondition, meta.ProgressingReason, "%s", "building artifact: new revision '' for ''"), }, }, } @@ -718,14 +717,14 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) { clientBuilder := fakeclient.NewClientBuilder(). WithScheme(testEnv.GetScheme()). - WithStatusSubresource(&ociv1.OCIRepository{}) + WithStatusSubresource(&sourcev1.OCIRepository{}) - obj := &ociv1.OCIRepository{ + obj := &sourcev1.OCIRepository{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "auth-strategy-", Generation: 1, }, - Spec: ociv1.OCIRepositorySpec{ + Spec: sourcev1.OCIRepositorySpec{ Interval: metav1.Duration{Duration: interval}, Timeout: &metav1.Duration{Duration: timeout}, }, @@ -741,7 +740,7 @@ func TestOCIRepository_reconcileSource_authStrategy(t *testing.T) { img, err := createPodinfoImageFromTar("podinfo-6.1.6.tar", "6.1.6", server.registryHost, tt.craneOpts...) g.Expect(err).ToNot(HaveOccurred()) obj.Spec.URL = img.url - obj.Spec.Reference = &ociv1.OCIRepositoryRef{ + obj.Spec.Reference = &sourcev1.OCIRepositoryRef{ Tag: img.tag, } @@ -925,16 +924,16 @@ func TestOCIRepository_CertSecret(t *testing.T) { g.Expect(err).ToNot(HaveOccurred()) defer func() { g.Expect(testEnv.Delete(ctx, ns)).To(Succeed()) }() - obj := &ociv1.OCIRepository{ + obj := &sourcev1.OCIRepository{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "ocirepository-test-resource", Namespace: ns.Name, Generation: 1, }, - Spec: ociv1.OCIRepositorySpec{ + Spec: sourcev1.OCIRepositorySpec{ URL: tt.url, Interval: metav1.Duration{Duration: 60 * time.Minute}, - Reference: &ociv1.OCIRepositoryRef{Digest: tt.digest.String()}, + Reference: &sourcev1.OCIRepositoryRef{Digest: tt.digest.String()}, }, } @@ -954,7 +953,7 @@ func TestOCIRepository_CertSecret(t *testing.T) { key := client.ObjectKey{Name: obj.Name, Namespace: obj.Namespace} - resultobj := ociv1.OCIRepository{} + resultobj := sourcev1.OCIRepository{} // Wait for the finalizer to be set g.Eventually(func() bool { @@ -1051,16 +1050,16 @@ func TestOCIRepository_ProxySecret(t *testing.T) { g.Expect(err).ToNot(HaveOccurred()) defer func() { g.Expect(testEnv.Delete(ctx, ns)).To(Succeed()) }() - obj := &ociv1.OCIRepository{ + obj := &sourcev1.OCIRepository{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "ocirepository-test-resource", Namespace: ns.Name, Generation: 1, }, - Spec: ociv1.OCIRepositorySpec{ + Spec: sourcev1.OCIRepositorySpec{ URL: tt.url, Interval: metav1.Duration{Duration: 60 * time.Minute}, - Reference: &ociv1.OCIRepositoryRef{Digest: tt.digest.String()}, + Reference: &sourcev1.OCIRepositoryRef{Digest: tt.digest.String()}, }, } @@ -1080,7 +1079,7 @@ func TestOCIRepository_ProxySecret(t *testing.T) { key := client.ObjectKey{Name: obj.Name, Namespace: obj.Namespace} - resultobj := ociv1.OCIRepository{} + resultobj := sourcev1.OCIRepository{} // Wait for the finalizer to be set g.Eventually(func() bool { @@ -1138,7 +1137,7 @@ func TestOCIRepository_reconcileSource_remoteReference(t *testing.T) { tests := []struct { name string - reference *ociv1.OCIRepositoryRef + reference *sourcev1.OCIRepositoryRef want sreconcile.Result wantErr bool wantRevision string @@ -1155,7 +1154,7 @@ func TestOCIRepository_reconcileSource_remoteReference(t *testing.T) { }, { name: "tag reference", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ Tag: "6.1.6", }, want: sreconcile.ResultSuccess, @@ -1167,7 +1166,7 @@ func TestOCIRepository_reconcileSource_remoteReference(t *testing.T) { }, { name: "semver reference", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ SemVer: ">= 6.1.5", }, want: sreconcile.ResultSuccess, @@ -1179,7 +1178,7 @@ func TestOCIRepository_reconcileSource_remoteReference(t *testing.T) { }, { name: "digest reference", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ Digest: img6.digest.String(), }, wantRevision: img6.digest.String(), @@ -1191,18 +1190,18 @@ func TestOCIRepository_reconcileSource_remoteReference(t *testing.T) { }, { name: "invalid tag reference", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ Tag: "6.1.0", }, want: sreconcile.ResultEmpty, wantErr: true, assertConditions: []metav1.Condition{ - *conditions.TrueCondition(sourcev1.FetchFailedCondition, ociv1.OCIPullFailedReason, " MANIFEST_UNKNOWN"), + *conditions.TrueCondition(sourcev1.FetchFailedCondition, sourcev1.OCIPullFailedReason, " MANIFEST_UNKNOWN"), }, }, { name: "invalid semver reference", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ SemVer: "<= 6.1.0", }, want: sreconcile.ResultEmpty, @@ -1213,18 +1212,18 @@ func TestOCIRepository_reconcileSource_remoteReference(t *testing.T) { }, { name: "invalid digest reference", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ Digest: "invalid", }, want: sreconcile.ResultEmpty, wantErr: true, assertConditions: []metav1.Condition{ - *conditions.TrueCondition(sourcev1.FetchFailedCondition, ociv1.OCIPullFailedReason, "failed to determine artifact digest"), + *conditions.TrueCondition(sourcev1.FetchFailedCondition, sourcev1.OCIPullFailedReason, "failed to determine artifact digest"), }, }, { name: "semver should take precedence over tag", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ SemVer: ">= 6.1.5", Tag: "6.1.5", }, @@ -1237,7 +1236,7 @@ func TestOCIRepository_reconcileSource_remoteReference(t *testing.T) { }, { name: "digest should take precedence over semver", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ Tag: "6.1.6", SemVer: ">= 6.1.6", Digest: img5.digest.String(), @@ -1253,7 +1252,7 @@ func TestOCIRepository_reconcileSource_remoteReference(t *testing.T) { clientBuilder := fakeclient.NewClientBuilder(). WithScheme(testEnv.GetScheme()). - WithStatusSubresource(&ociv1.OCIRepository{}) + WithStatusSubresource(&sourcev1.OCIRepository{}) r := &OCIRepositoryReconciler{ Client: clientBuilder.Build(), @@ -1264,12 +1263,12 @@ func TestOCIRepository_reconcileSource_remoteReference(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - obj := &ociv1.OCIRepository{ + obj := &sourcev1.OCIRepository{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "checkout-strategy-", Generation: 1, }, - Spec: ociv1.OCIRepositorySpec{ + Spec: sourcev1.OCIRepositorySpec{ URL: fmt.Sprintf("oci://%s/podinfo", server.registryHost), Interval: metav1.Duration{Duration: interval}, Timeout: &metav1.Duration{Duration: timeout}, @@ -1309,7 +1308,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureNotation(t *testi tests := []struct { name string - reference *ociv1.OCIRepositoryRef + reference *sourcev1.OCIRepositoryRef insecure bool want sreconcile.Result wantErr bool @@ -1318,12 +1317,12 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureNotation(t *testi useDigest bool addMultipleCerts bool provideNoCert bool - beforeFunc func(obj *ociv1.OCIRepository, tag, revision string) + beforeFunc func(obj *sourcev1.OCIRepository, tag, revision string) assertConditions []metav1.Condition }{ { name: "signed image should pass verification", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ Tag: "6.1.4", }, shouldSign: true, @@ -1336,7 +1335,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureNotation(t *testi }, { name: "unsigned image should not pass verification", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ Tag: "6.1.5", }, wantErr: true, @@ -1351,8 +1350,8 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureNotation(t *testi }, { name: "verify failed before, removed from spec, remove condition", - reference: &ociv1.OCIRepositoryRef{Tag: "6.1.4"}, - beforeFunc: func(obj *ociv1.OCIRepository, tag, revision string) { + reference: &sourcev1.OCIRepositoryRef{Tag: "6.1.4"}, + beforeFunc: func(obj *sourcev1.OCIRepository, tag, revision string) { conditions.MarkFalse(obj, sourcev1.SourceVerifiedCondition, "VerifyFailed", "fail msg") obj.Spec.Verify = nil obj.Status.Artifact = &sourcev1.Artifact{Revision: fmt.Sprintf("%s@%s", tag, revision)} @@ -1361,9 +1360,9 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureNotation(t *testi }, { name: "same artifact, verified before, change in obj gen verify again", - reference: &ociv1.OCIRepositoryRef{Tag: "6.1.4"}, + reference: &sourcev1.OCIRepositoryRef{Tag: "6.1.4"}, shouldSign: true, - beforeFunc: func(obj *ociv1.OCIRepository, tag, revision string) { + beforeFunc: func(obj *sourcev1.OCIRepository, tag, revision string) { obj.Status.Artifact = &sourcev1.Artifact{Revision: fmt.Sprintf("%s@%s", tag, revision)} // Set Verified with old observed generation and different reason/message. conditions.MarkTrue(obj, sourcev1.SourceVerifiedCondition, "Verified", "verified") @@ -1377,9 +1376,9 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureNotation(t *testi }, { name: "no verify for already verified, verified condition remains the same", - reference: &ociv1.OCIRepositoryRef{Tag: "6.1.4"}, + reference: &sourcev1.OCIRepositoryRef{Tag: "6.1.4"}, shouldSign: true, - beforeFunc: func(obj *ociv1.OCIRepository, tag, revision string) { + beforeFunc: func(obj *sourcev1.OCIRepository, tag, revision string) { // Artifact present and custom verified condition reason/message. obj.Status.Artifact = &sourcev1.Artifact{Revision: fmt.Sprintf("%s@%s", tag, revision)} conditions.MarkTrue(obj, sourcev1.SourceVerifiedCondition, "Verified", "verified") @@ -1391,7 +1390,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureNotation(t *testi }, { name: "signed image on an insecure registry passes verification", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ Tag: "6.1.6", }, shouldSign: true, @@ -1405,7 +1404,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureNotation(t *testi }, { name: "signed image on an insecure registry using digest as reference passes verification", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ Tag: "6.1.6", }, shouldSign: true, @@ -1420,7 +1419,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureNotation(t *testi }, { name: "verification level audit and correct trust identity should pass verification", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ Tag: "6.1.6", }, shouldSign: true, @@ -1436,7 +1435,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureNotation(t *testi }, { name: "no cert provided should not pass verification", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ Tag: "6.1.5", }, wantErr: true, @@ -1455,7 +1454,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureNotation(t *testi clientBuilder := fakeclient.NewClientBuilder(). WithScheme(testEnv.GetScheme()). - WithStatusSubresource(&ociv1.OCIRepository{}) + WithStatusSubresource(&sourcev1.OCIRepository{}) r := &OCIRepositoryReconciler{ Client: clientBuilder.Build(), @@ -1513,12 +1512,12 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureNotation(t *testi server.Close() }) - obj := &ociv1.OCIRepository{ + obj := &sourcev1.OCIRepository{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "verify-oci-source-signature-", Generation: 1, }, - Spec: ociv1.OCIRepositorySpec{ + Spec: sourcev1.OCIRepositorySpec{ URL: fmt.Sprintf("oci://%s/podinfo", server.registryHost), Verify: &sourcev1.OCIRepositoryVerification{ Provider: "notation", @@ -1649,7 +1648,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceTrustPolicyNotation(t *tes tests := []struct { name string - reference *ociv1.OCIRepositoryRef + reference *sourcev1.OCIRepositoryRef signatureVerification trustpolicy.SignatureVerification trustedIdentities []string trustStores []string @@ -1660,12 +1659,12 @@ func TestOCIRepository_reconcileSource_verifyOCISourceTrustPolicyNotation(t *tes usePolicyJson bool provideNoPolicy bool policyJson string - beforeFunc func(obj *ociv1.OCIRepository, tag, revision string) + beforeFunc func(obj *sourcev1.OCIRepository, tag, revision string) assertConditions []metav1.Condition }{ { name: "verification level audit and incorrect trust identity should fail verification but not error", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ Tag: "6.1.4", }, signatureVerification: trustpolicy.SignatureVerification{VerificationLevel: trustpolicy.LevelAudit.Name}, @@ -1679,7 +1678,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceTrustPolicyNotation(t *tes }, { name: "verification level permissive and incorrect trust identity should fail verification and error", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ Tag: "6.1.4", }, signatureVerification: trustpolicy.SignatureVerification{VerificationLevel: trustpolicy.LevelPermissive.Name}, @@ -1697,7 +1696,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceTrustPolicyNotation(t *tes }, { name: "verification level permissive and correct trust identity should pass verification", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ Tag: "6.1.4", }, signatureVerification: trustpolicy.SignatureVerification{VerificationLevel: trustpolicy.LevelPermissive.Name}, @@ -1712,7 +1711,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceTrustPolicyNotation(t *tes }, { name: "verification level audit and correct trust identity should pass verification", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ Tag: "6.1.4", }, signatureVerification: trustpolicy.SignatureVerification{VerificationLevel: trustpolicy.LevelAudit.Name}, @@ -1727,7 +1726,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceTrustPolicyNotation(t *tes }, { name: "verification level skip and should not be marked as verified", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ Tag: "6.1.4", }, signatureVerification: trustpolicy.SignatureVerification{VerificationLevel: trustpolicy.LevelSkip.Name}, @@ -1740,7 +1739,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceTrustPolicyNotation(t *tes }, { name: "valid json but empty policy json should fail verification", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ Tag: "6.1.4", }, usePolicyJson: true, @@ -1756,7 +1755,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceTrustPolicyNotation(t *tes }, { name: "empty string should fail verification", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ Tag: "6.1.4", }, usePolicyJson: true, @@ -1772,7 +1771,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceTrustPolicyNotation(t *tes }, { name: "invalid character in string should fail verification", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ Tag: "6.1.4", }, usePolicyJson: true, @@ -1788,7 +1787,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceTrustPolicyNotation(t *tes }, { name: "empty string should fail verification", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ Tag: "6.1.4", }, provideNoPolicy: true, @@ -1805,7 +1804,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceTrustPolicyNotation(t *tes clientBuilder := fakeclient.NewClientBuilder(). WithScheme(testEnv.GetScheme()). - WithStatusSubresource(&ociv1.OCIRepository{}) + WithStatusSubresource(&sourcev1.OCIRepository{}) r := &OCIRepositoryReconciler{ Client: clientBuilder.Build(), @@ -1833,12 +1832,12 @@ func TestOCIRepository_reconcileSource_verifyOCISourceTrustPolicyNotation(t *tes server.Close() }) - obj := &ociv1.OCIRepository{ + obj := &sourcev1.OCIRepository{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "verify-oci-source-signature-", Generation: 1, }, - Spec: ociv1.OCIRepositorySpec{ + Spec: sourcev1.OCIRepositorySpec{ URL: fmt.Sprintf("oci://%s/podinfo", server.registryHost), Verify: &sourcev1.OCIRepositoryVerification{ Provider: "notation", @@ -1992,19 +1991,19 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureCosign(t *testing tests := []struct { name string - reference *ociv1.OCIRepositoryRef + reference *sourcev1.OCIRepositoryRef insecure bool want sreconcile.Result wantErr bool wantErrMsg string shouldSign bool keyless bool - beforeFunc func(obj *ociv1.OCIRepository, tag, revision string) + beforeFunc func(obj *sourcev1.OCIRepository, tag, revision string) assertConditions []metav1.Condition }{ { name: "signed image should pass verification", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ Tag: "6.1.4", }, shouldSign: true, @@ -2017,7 +2016,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureCosign(t *testing }, { name: "unsigned image should not pass verification", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ Tag: "6.1.5", }, wantErr: true, @@ -2031,7 +2030,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureCosign(t *testing }, { name: "unsigned image should not pass keyless verification", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ Tag: "6.1.5", }, wantErr: true, @@ -2045,8 +2044,8 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureCosign(t *testing }, { name: "verify failed before, removed from spec, remove condition", - reference: &ociv1.OCIRepositoryRef{Tag: "6.1.4"}, - beforeFunc: func(obj *ociv1.OCIRepository, tag, revision string) { + reference: &sourcev1.OCIRepositoryRef{Tag: "6.1.4"}, + beforeFunc: func(obj *sourcev1.OCIRepository, tag, revision string) { conditions.MarkFalse(obj, sourcev1.SourceVerifiedCondition, "VerifyFailed", "fail msg") obj.Spec.Verify = nil obj.Status.Artifact = &sourcev1.Artifact{Revision: fmt.Sprintf("%s@%s", tag, revision)} @@ -2055,9 +2054,9 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureCosign(t *testing }, { name: "same artifact, verified before, change in obj gen verify again", - reference: &ociv1.OCIRepositoryRef{Tag: "6.1.4"}, + reference: &sourcev1.OCIRepositoryRef{Tag: "6.1.4"}, shouldSign: true, - beforeFunc: func(obj *ociv1.OCIRepository, tag, revision string) { + beforeFunc: func(obj *sourcev1.OCIRepository, tag, revision string) { obj.Status.Artifact = &sourcev1.Artifact{Revision: fmt.Sprintf("%s@%s", tag, revision)} // Set Verified with old observed generation and different reason/message. conditions.MarkTrue(obj, sourcev1.SourceVerifiedCondition, "Verified", "verified") @@ -2071,9 +2070,9 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureCosign(t *testing }, { name: "no verify for already verified, verified condition remains the same", - reference: &ociv1.OCIRepositoryRef{Tag: "6.1.4"}, + reference: &sourcev1.OCIRepositoryRef{Tag: "6.1.4"}, shouldSign: true, - beforeFunc: func(obj *ociv1.OCIRepository, tag, revision string) { + beforeFunc: func(obj *sourcev1.OCIRepository, tag, revision string) { // Artifact present and custom verified condition reason/message. obj.Status.Artifact = &sourcev1.Artifact{Revision: fmt.Sprintf("%s@%s", tag, revision)} conditions.MarkTrue(obj, sourcev1.SourceVerifiedCondition, "Verified", "verified") @@ -2085,7 +2084,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureCosign(t *testing }, { name: "signed image on an insecure registry passes verification", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ Tag: "6.1.6", }, shouldSign: true, @@ -2101,7 +2100,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureCosign(t *testing clientBuilder := fakeclient.NewClientBuilder(). WithScheme(testEnv.GetScheme()). - WithStatusSubresource(&ociv1.OCIRepository{}) + WithStatusSubresource(&sourcev1.OCIRepository{}) r := &OCIRepositoryReconciler{ Client: clientBuilder.Build(), @@ -2157,12 +2156,12 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureCosign(t *testing server.Close() }) - obj := &ociv1.OCIRepository{ + obj := &sourcev1.OCIRepository{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "verify-oci-source-signature-", Generation: 1, }, - Spec: ociv1.OCIRepositorySpec{ + Spec: sourcev1.OCIRepositorySpec{ URL: fmt.Sprintf("oci://%s/podinfo", server.registryHost), Verify: &sourcev1.OCIRepositoryVerification{ Provider: "cosign", @@ -2258,17 +2257,17 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignatureCosign(t *testing func TestOCIRepository_reconcileSource_verifyOCISourceSignature_keyless(t *testing.T) { tests := []struct { name string - reference *ociv1.OCIRepositoryRef + reference *sourcev1.OCIRepositoryRef want sreconcile.Result wantErr bool wantErrMsg string - beforeFunc func(obj *ociv1.OCIRepository) + beforeFunc func(obj *sourcev1.OCIRepository) assertConditions []metav1.Condition revision string }{ { name: "signed image with no identity matching specified should pass verification", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ Tag: "6.5.1", }, want: sreconcile.ResultSuccess, @@ -2281,11 +2280,11 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature_keyless(t *testi }, { name: "signed image with correct subject and issuer should pass verification", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ Tag: "6.5.1", }, want: sreconcile.ResultSuccess, - beforeFunc: func(obj *ociv1.OCIRepository) { + beforeFunc: func(obj *sourcev1.OCIRepository) { obj.Spec.Verify.MatchOIDCIdentity = []sourcev1.OIDCIdentityMatch{ { @@ -2303,11 +2302,11 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature_keyless(t *testi }, { name: "signed image with both incorrect and correct identity matchers should pass verification", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ Tag: "6.5.1", }, want: sreconcile.ResultSuccess, - beforeFunc: func(obj *ociv1.OCIRepository) { + beforeFunc: func(obj *sourcev1.OCIRepository) { obj.Spec.Verify.MatchOIDCIdentity = []sourcev1.OIDCIdentityMatch{ { Subject: "intruder", @@ -2329,12 +2328,12 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature_keyless(t *testi }, { name: "signed image with incorrect subject and issuer should not pass verification", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ Tag: "6.5.1", }, wantErr: true, want: sreconcile.ResultEmpty, - beforeFunc: func(obj *ociv1.OCIRepository) { + beforeFunc: func(obj *sourcev1.OCIRepository) { obj.Spec.Verify.MatchOIDCIdentity = []sourcev1.OIDCIdentityMatch{ { Subject: "intruder", @@ -2351,7 +2350,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature_keyless(t *testi }, { name: "unsigned image should not pass verification", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ Tag: "6.1.0", }, wantErr: true, @@ -2367,7 +2366,7 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature_keyless(t *testi clientBuilder := fakeclient.NewClientBuilder(). WithScheme(testEnv.GetScheme()). - WithStatusSubresource(&ociv1.OCIRepository{}) + WithStatusSubresource(&sourcev1.OCIRepository{}) r := &OCIRepositoryReconciler{ Client: clientBuilder.Build(), @@ -2380,12 +2379,12 @@ func TestOCIRepository_reconcileSource_verifyOCISourceSignature_keyless(t *testi t.Run(tt.name, func(t *testing.T) { g := NewWithT(t) - obj := &ociv1.OCIRepository{ + obj := &sourcev1.OCIRepository{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "verify-oci-source-signature-", Generation: 1, }, - Spec: ociv1.OCIRepositorySpec{ + Spec: sourcev1.OCIRepositorySpec{ URL: "oci://ghcr.io/stefanprodan/manifests/podinfo", Verify: &sourcev1.OCIRepositoryVerification{ Provider: "cosign", @@ -2450,7 +2449,7 @@ func TestOCIRepository_reconcileSource_noop(t *testing.T) { tests := []struct { name string - beforeFunc func(obj *ociv1.OCIRepository) + beforeFunc func(obj *sourcev1.OCIRepository) afterFunc func(g *WithT, artifact *sourcev1.Artifact) }{ { @@ -2461,7 +2460,7 @@ func TestOCIRepository_reconcileSource_noop(t *testing.T) { }, { name: "noop - artifact revisions match", - beforeFunc: func(obj *ociv1.OCIRepository) { + beforeFunc: func(obj *sourcev1.OCIRepository) { obj.Status.Artifact = &sourcev1.Artifact{ Revision: testRevision, } @@ -2472,7 +2471,7 @@ func TestOCIRepository_reconcileSource_noop(t *testing.T) { }, { name: "full reconcile - same rev, unobserved ignore", - beforeFunc: func(obj *ociv1.OCIRepository) { + beforeFunc: func(obj *sourcev1.OCIRepository) { obj.Status.ObservedIgnore = ptr.To("aaa") obj.Status.Artifact = &sourcev1.Artifact{ Revision: testRevision, @@ -2484,7 +2483,7 @@ func TestOCIRepository_reconcileSource_noop(t *testing.T) { }, { name: "noop - same rev, observed ignore", - beforeFunc: func(obj *ociv1.OCIRepository) { + beforeFunc: func(obj *sourcev1.OCIRepository) { obj.Spec.Ignore = ptr.To("aaa") obj.Status.ObservedIgnore = ptr.To("aaa") obj.Status.Artifact = &sourcev1.Artifact{ @@ -2497,10 +2496,10 @@ func TestOCIRepository_reconcileSource_noop(t *testing.T) { }, { name: "full reconcile - same rev, unobserved layer selector", - beforeFunc: func(obj *ociv1.OCIRepository) { - obj.Spec.LayerSelector = &ociv1.OCILayerSelector{ + beforeFunc: func(obj *sourcev1.OCIRepository) { + obj.Spec.LayerSelector = &sourcev1.OCILayerSelector{ MediaType: "application/vnd.docker.image.rootfs.diff.tar.gzip", - Operation: ociv1.OCILayerCopy, + Operation: sourcev1.OCILayerCopy, } obj.Status.Artifact = &sourcev1.Artifact{ Revision: testRevision, @@ -2512,14 +2511,14 @@ func TestOCIRepository_reconcileSource_noop(t *testing.T) { }, { name: "noop - same rev, observed layer selector", - beforeFunc: func(obj *ociv1.OCIRepository) { - obj.Spec.LayerSelector = &ociv1.OCILayerSelector{ + beforeFunc: func(obj *sourcev1.OCIRepository) { + obj.Spec.LayerSelector = &sourcev1.OCILayerSelector{ MediaType: "application/vnd.docker.image.rootfs.diff.tar.gzip", - Operation: ociv1.OCILayerCopy, + Operation: sourcev1.OCILayerCopy, } - obj.Status.ObservedLayerSelector = &ociv1.OCILayerSelector{ + obj.Status.ObservedLayerSelector = &sourcev1.OCILayerSelector{ MediaType: "application/vnd.docker.image.rootfs.diff.tar.gzip", - Operation: ociv1.OCILayerCopy, + Operation: sourcev1.OCILayerCopy, } obj.Status.Artifact = &sourcev1.Artifact{ Revision: testRevision, @@ -2531,14 +2530,14 @@ func TestOCIRepository_reconcileSource_noop(t *testing.T) { }, { name: "full reconcile - same rev, observed layer selector changed", - beforeFunc: func(obj *ociv1.OCIRepository) { - obj.Spec.LayerSelector = &ociv1.OCILayerSelector{ + beforeFunc: func(obj *sourcev1.OCIRepository) { + obj.Spec.LayerSelector = &sourcev1.OCILayerSelector{ MediaType: "application/vnd.docker.image.rootfs.diff.tar.gzip", - Operation: ociv1.OCILayerExtract, + Operation: sourcev1.OCILayerExtract, } - obj.Status.ObservedLayerSelector = &ociv1.OCILayerSelector{ + obj.Status.ObservedLayerSelector = &sourcev1.OCILayerSelector{ MediaType: "application/vnd.docker.image.rootfs.diff.tar.gzip", - Operation: ociv1.OCILayerCopy, + Operation: sourcev1.OCILayerCopy, } obj.Status.Artifact = &sourcev1.Artifact{ Revision: testRevision, @@ -2552,7 +2551,7 @@ func TestOCIRepository_reconcileSource_noop(t *testing.T) { clientBuilder := fakeclient.NewClientBuilder(). WithScheme(testEnv.GetScheme()). - WithStatusSubresource(&ociv1.OCIRepository{}) + WithStatusSubresource(&sourcev1.OCIRepository{}) r := &OCIRepositoryReconciler{ Client: clientBuilder.Build(), @@ -2565,14 +2564,14 @@ func TestOCIRepository_reconcileSource_noop(t *testing.T) { t.Run(tt.name, func(t *testing.T) { g := NewWithT(t) - obj := &ociv1.OCIRepository{ + obj := &sourcev1.OCIRepository{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "noop-", Generation: 1, }, - Spec: ociv1.OCIRepositorySpec{ + Spec: sourcev1.OCIRepositorySpec{ URL: fmt.Sprintf("oci://%s/podinfo", server.registryHost), - Reference: &ociv1.OCIRepositoryRef{Tag: "6.1.5"}, + Reference: &sourcev1.OCIRepositoryRef{Tag: "6.1.5"}, Interval: metav1.Duration{Duration: interval}, Timeout: &metav1.Duration{Duration: timeout}, Insecure: true, @@ -2608,13 +2607,13 @@ func TestOCIRepository_reconcileArtifact(t *testing.T) { name string targetPath string artifact *sourcev1.Artifact - beforeFunc func(obj *ociv1.OCIRepository) + beforeFunc func(obj *sourcev1.OCIRepository) want sreconcile.Result wantErr bool assertArtifact *sourcev1.Artifact assertPaths []string assertConditions []metav1.Condition - afterFunc func(g *WithT, obj *ociv1.OCIRepository) + afterFunc func(g *WithT, obj *sourcev1.OCIRepository) }{ { name: "Archiving Artifact creates correct files and condition", @@ -2622,14 +2621,14 @@ func TestOCIRepository_reconcileArtifact(t *testing.T) { artifact: &sourcev1.Artifact{ Revision: "revision", }, - beforeFunc: func(obj *ociv1.OCIRepository) { + beforeFunc: func(obj *sourcev1.OCIRepository) { conditions.MarkTrue(obj, sourcev1.ArtifactOutdatedCondition, "NewRevision", "new revision") }, want: sreconcile.ResultSuccess, assertPaths: []string{ "latest.tar.gz", }, - afterFunc: func(g *WithT, obj *ociv1.OCIRepository) { + afterFunc: func(g *WithT, obj *sourcev1.OCIRepository) { g.Expect(obj.Status.Artifact.Digest).To(Equal("sha256:6a5bd135a816ec0ad246c41cfdd87629e40ef6520001aeb2d0118a703abe9e7a")) }, assertConditions: []metav1.Condition{ @@ -2640,14 +2639,14 @@ func TestOCIRepository_reconcileArtifact(t *testing.T) { name: "Artifact with source ignore", targetPath: "testdata/oci/repository", artifact: &sourcev1.Artifact{Revision: "revision"}, - beforeFunc: func(obj *ociv1.OCIRepository) { + beforeFunc: func(obj *sourcev1.OCIRepository) { obj.Spec.Ignore = ptr.To("foo.txt") }, want: sreconcile.ResultSuccess, assertPaths: []string{ "latest.tar.gz", }, - afterFunc: func(g *WithT, obj *ociv1.OCIRepository) { + afterFunc: func(g *WithT, obj *sourcev1.OCIRepository) { g.Expect(obj.Status.Artifact.Digest).To(Equal("sha256:9102e9c8626e48821a91a4963436f1673cd85f8fb3deb843c992f85b995c38ea")) }, assertConditions: []metav1.Condition{ @@ -2661,7 +2660,7 @@ func TestOCIRepository_reconcileArtifact(t *testing.T) { }, targetPath: "testdata/oci/repository", want: sreconcile.ResultSuccess, - beforeFunc: func(obj *ociv1.OCIRepository) { + beforeFunc: func(obj *sourcev1.OCIRepository) { obj.Status.Artifact = &sourcev1.Artifact{ Revision: "revision", } @@ -2679,7 +2678,7 @@ func TestOCIRepository_reconcileArtifact(t *testing.T) { artifact: &sourcev1.Artifact{ Revision: "revision", }, - beforeFunc: func(obj *ociv1.OCIRepository) { + beforeFunc: func(obj *sourcev1.OCIRepository) { obj.Status.Artifact = &sourcev1.Artifact{Revision: "revision"} obj.Spec.Ignore = ptr.To("aaa") }, @@ -2687,7 +2686,7 @@ func TestOCIRepository_reconcileArtifact(t *testing.T) { assertPaths: []string{ "latest.tar.gz", }, - afterFunc: func(g *WithT, obj *ociv1.OCIRepository) { + afterFunc: func(g *WithT, obj *sourcev1.OCIRepository) { g.Expect(*obj.Status.ObservedIgnore).To(Equal("aaa")) }, assertConditions: []metav1.Condition{ @@ -2700,15 +2699,15 @@ func TestOCIRepository_reconcileArtifact(t *testing.T) { artifact: &sourcev1.Artifact{ Revision: "revision", }, - beforeFunc: func(obj *ociv1.OCIRepository) { - obj.Spec.LayerSelector = &ociv1.OCILayerSelector{MediaType: "foo"} + beforeFunc: func(obj *sourcev1.OCIRepository) { + obj.Spec.LayerSelector = &sourcev1.OCILayerSelector{MediaType: "foo"} obj.Status.Artifact = &sourcev1.Artifact{Revision: "revision"} }, want: sreconcile.ResultSuccess, assertPaths: []string{ "latest.tar.gz", }, - afterFunc: func(g *WithT, obj *ociv1.OCIRepository) { + afterFunc: func(g *WithT, obj *sourcev1.OCIRepository) { g.Expect(obj.Status.ObservedLayerSelector.MediaType).To(Equal("foo")) }, assertConditions: []metav1.Condition{ @@ -2722,10 +2721,10 @@ func TestOCIRepository_reconcileArtifact(t *testing.T) { Revision: "revision", Path: "foo.txt", }, - beforeFunc: func(obj *ociv1.OCIRepository) { - obj.Spec.LayerSelector = &ociv1.OCILayerSelector{ + beforeFunc: func(obj *sourcev1.OCIRepository) { + obj.Spec.LayerSelector = &sourcev1.OCILayerSelector{ MediaType: "foo", - Operation: ociv1.OCILayerCopy, + Operation: sourcev1.OCILayerCopy, } obj.Status.Artifact = &sourcev1.Artifact{Revision: "revision"} }, @@ -2733,9 +2732,9 @@ func TestOCIRepository_reconcileArtifact(t *testing.T) { assertPaths: []string{ "latest.tar.gz", }, - afterFunc: func(g *WithT, obj *ociv1.OCIRepository) { + afterFunc: func(g *WithT, obj *sourcev1.OCIRepository) { g.Expect(obj.Status.ObservedLayerSelector.MediaType).To(Equal("foo")) - g.Expect(obj.Status.ObservedLayerSelector.Operation).To(Equal(ociv1.OCILayerCopy)) + g.Expect(obj.Status.ObservedLayerSelector.Operation).To(Equal(sourcev1.OCILayerCopy)) }, assertConditions: []metav1.Condition{ *conditions.TrueCondition(sourcev1.ArtifactInStorageCondition, meta.SucceededReason, "stored artifact for digest"), @@ -2747,12 +2746,12 @@ func TestOCIRepository_reconcileArtifact(t *testing.T) { artifact: &sourcev1.Artifact{ Revision: "revision", }, - beforeFunc: func(obj *ociv1.OCIRepository) { + beforeFunc: func(obj *sourcev1.OCIRepository) { obj.Spec.Ignore = ptr.To("aaa") - obj.Spec.LayerSelector = &ociv1.OCILayerSelector{MediaType: "foo"} + obj.Spec.LayerSelector = &sourcev1.OCILayerSelector{MediaType: "foo"} obj.Status.Artifact = &sourcev1.Artifact{Revision: "revision"} obj.Status.ObservedIgnore = ptr.To("aaa") - obj.Status.ObservedLayerSelector = &ociv1.OCILayerSelector{MediaType: "foo"} + obj.Status.ObservedLayerSelector = &sourcev1.OCILayerSelector{MediaType: "foo"} }, want: sreconcile.ResultSuccess, assertArtifact: &sourcev1.Artifact{ @@ -2784,7 +2783,7 @@ func TestOCIRepository_reconcileArtifact(t *testing.T) { clientBuilder := fakeclient.NewClientBuilder(). WithScheme(testEnv.GetScheme()). - WithStatusSubresource(&ociv1.OCIRepository{}) + WithStatusSubresource(&sourcev1.OCIRepository{}) r := &OCIRepositoryReconciler{ Client: clientBuilder.Build(), @@ -2799,7 +2798,7 @@ func TestOCIRepository_reconcileArtifact(t *testing.T) { _ = resetChmod(tt.targetPath, 0o755, 0o644) - obj := &ociv1.OCIRepository{ + obj := &sourcev1.OCIRepository{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "reconcile-artifact-", Generation: 1, @@ -2872,7 +2871,7 @@ func TestOCIRepository_getArtifactRef(t *testing.T) { tests := []struct { name string url string - reference *ociv1.OCIRepositoryRef + reference *sourcev1.OCIRepositoryRef wantErr bool want string }{ @@ -2884,7 +2883,7 @@ func TestOCIRepository_getArtifactRef(t *testing.T) { { name: "valid url with tag reference", url: "oci://ghcr.io/stefanprodan/charts", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ Tag: "6.1.6", }, want: "ghcr.io/stefanprodan/charts:6.1.6", @@ -2892,7 +2891,7 @@ func TestOCIRepository_getArtifactRef(t *testing.T) { { name: "valid url with digest reference", url: "oci://ghcr.io/stefanprodan/charts", - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ Digest: imgs["6.1.6"].digest.String(), }, want: "ghcr.io/stefanprodan/charts@" + imgs["6.1.6"].digest.String(), @@ -2900,7 +2899,7 @@ func TestOCIRepository_getArtifactRef(t *testing.T) { { name: "valid url with semver reference", url: fmt.Sprintf("oci://%s/podinfo", server.registryHost), - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ SemVer: ">= 6.1.6", }, want: server.registryHost + "/podinfo:6.1.6", @@ -2913,7 +2912,7 @@ func TestOCIRepository_getArtifactRef(t *testing.T) { { name: "valid url with semver filter", url: fmt.Sprintf("oci://%s/podinfo", server.registryHost), - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ SemVer: ">= 6.1.x-0", SemverFilter: ".*-rc.*", }, @@ -2922,7 +2921,7 @@ func TestOCIRepository_getArtifactRef(t *testing.T) { { name: "valid url with semver filter and unexisting version", url: fmt.Sprintf("oci://%s/podinfo", server.registryHost), - reference: &ociv1.OCIRepositoryRef{ + reference: &sourcev1.OCIRepositoryRef{ SemVer: ">= 6.1.x-0", SemverFilter: ".*-alpha.*", }, @@ -2932,7 +2931,7 @@ func TestOCIRepository_getArtifactRef(t *testing.T) { clientBuilder := fakeclient.NewClientBuilder(). WithScheme(testEnv.GetScheme()). - WithStatusSubresource(&ociv1.OCIRepository{}) + WithStatusSubresource(&sourcev1.OCIRepository{}) r := &OCIRepositoryReconciler{ Client: clientBuilder.Build(), @@ -2943,11 +2942,11 @@ func TestOCIRepository_getArtifactRef(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - obj := &ociv1.OCIRepository{ + obj := &sourcev1.OCIRepository{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "artifact-url-", }, - Spec: ociv1.OCIRepositorySpec{ + Spec: sourcev1.OCIRepositorySpec{ URL: tt.url, Interval: metav1.Duration{Duration: interval}, Timeout: &metav1.Duration{Duration: timeout}, @@ -2978,12 +2977,12 @@ func TestOCIRepository_stalled(t *testing.T) { g.Expect(err).ToNot(HaveOccurred()) defer func() { g.Expect(testEnv.Delete(ctx, ns)).To(Succeed()) }() - obj := &ociv1.OCIRepository{ + obj := &sourcev1.OCIRepository{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "ocirepository-reconcile", Namespace: ns.Name, }, - Spec: ociv1.OCIRepositorySpec{ + Spec: sourcev1.OCIRepositorySpec{ URL: "oci://ghcr.io/test/test:v1", Interval: metav1.Duration{Duration: 60 * time.Minute}, }, @@ -2992,7 +2991,7 @@ func TestOCIRepository_stalled(t *testing.T) { g.Expect(testEnv.Create(ctx, obj)).To(Succeed()) key := client.ObjectKey{Name: obj.Name, Namespace: obj.Namespace} - resultobj := ociv1.OCIRepository{} + resultobj := sourcev1.OCIRepository{} // Wait for the object to fail g.Eventually(func() bool { @@ -3016,7 +3015,7 @@ func TestOCIRepository_stalled(t *testing.T) { func TestOCIRepository_reconcileStorage(t *testing.T) { tests := []struct { name string - beforeFunc func(obj *ociv1.OCIRepository, storage *Storage) error + beforeFunc func(obj *sourcev1.OCIRepository, storage *Storage) error want sreconcile.Result wantErr bool assertConditions []metav1.Condition @@ -3025,7 +3024,7 @@ func TestOCIRepository_reconcileStorage(t *testing.T) { }{ { name: "garbage collects", - beforeFunc: func(obj *ociv1.OCIRepository, storage *Storage) error { + beforeFunc: func(obj *sourcev1.OCIRepository, storage *Storage) error { revisions := []string{"a", "b", "c", "d"} for n := range revisions { @@ -3079,7 +3078,7 @@ func TestOCIRepository_reconcileStorage(t *testing.T) { }, { name: "notices missing artifact in storage", - beforeFunc: func(obj *ociv1.OCIRepository, storage *Storage) error { + beforeFunc: func(obj *sourcev1.OCIRepository, storage *Storage) error { obj.Status.Artifact = &sourcev1.Artifact{ Path: "/oci-reconcile-storage/invalid.txt", Revision: "e", @@ -3098,7 +3097,7 @@ func TestOCIRepository_reconcileStorage(t *testing.T) { }, { name: "notices empty artifact digest", - beforeFunc: func(obj *ociv1.OCIRepository, storage *Storage) error { + beforeFunc: func(obj *sourcev1.OCIRepository, storage *Storage) error { f := "empty-digest.txt" obj.Status.Artifact = &sourcev1.Artifact{ @@ -3129,7 +3128,7 @@ func TestOCIRepository_reconcileStorage(t *testing.T) { }, { name: "notices artifact digest mismatch", - beforeFunc: func(obj *ociv1.OCIRepository, storage *Storage) error { + beforeFunc: func(obj *sourcev1.OCIRepository, storage *Storage) error { f := "digest-mismatch.txt" obj.Status.Artifact = &sourcev1.Artifact{ @@ -3160,7 +3159,7 @@ func TestOCIRepository_reconcileStorage(t *testing.T) { }, { name: "updates hostname on diff from current", - beforeFunc: func(obj *ociv1.OCIRepository, storage *Storage) error { + beforeFunc: func(obj *sourcev1.OCIRepository, storage *Storage) error { obj.Status.Artifact = &sourcev1.Artifact{ Path: "/oci-reconcile-storage/hostname.txt", Revision: "f", @@ -3195,7 +3194,7 @@ func TestOCIRepository_reconcileStorage(t *testing.T) { clientBuilder := fakeclient.NewClientBuilder(). WithScheme(testEnv.GetScheme()). - WithStatusSubresource(&ociv1.OCIRepository{}) + WithStatusSubresource(&sourcev1.OCIRepository{}) r := &OCIRepositoryReconciler{ Client: clientBuilder.Build(), @@ -3208,7 +3207,7 @@ func TestOCIRepository_reconcileStorage(t *testing.T) { t.Run(tt.name, func(t *testing.T) { g := NewWithT(t) - obj := &ociv1.OCIRepository{ + obj := &sourcev1.OCIRepository{ ObjectMeta: metav1.ObjectMeta{ GenerateName: "test-", Generation: 1, @@ -3267,7 +3266,7 @@ func TestOCIRepository_ReconcileDelete(t *testing.T) { patchOptions: getPatchOptions(ociRepositoryReadyCondition.Owned, "sc"), } - obj := &ociv1.OCIRepository{ + obj := &sourcev1.OCIRepository{ ObjectMeta: metav1.ObjectMeta{ Name: "reconcile-delete-", DeletionTimestamp: &metav1.Time{Time: time.Now()}, @@ -3275,10 +3274,10 @@ func TestOCIRepository_ReconcileDelete(t *testing.T) { sourcev1.SourceFinalizer, }, }, - Status: ociv1.OCIRepositoryStatus{}, + Status: sourcev1.OCIRepositoryStatus{}, } - artifact := testStorage.NewArtifactFor(ociv1.OCIRepositoryKind, obj.GetObjectMeta(), "revision", "foo.txt") + artifact := testStorage.NewArtifactFor(sourcev1.OCIRepositoryKind, obj.GetObjectMeta(), "revision", "foo.txt") obj.Status.Artifact = &artifact got, err := r.reconcileDelete(ctx, obj) @@ -3297,8 +3296,8 @@ func TestOCIRepositoryReconciler_notify(t *testing.T) { name string res sreconcile.Result resErr error - oldObjBeforeFunc func(obj *ociv1.OCIRepository) - newObjBeforeFunc func(obj *ociv1.OCIRepository) + oldObjBeforeFunc func(obj *sourcev1.OCIRepository) + newObjBeforeFunc func(obj *sourcev1.OCIRepository) commit git.Commit wantEvent string }{ @@ -3311,7 +3310,7 @@ func TestOCIRepositoryReconciler_notify(t *testing.T) { name: "new artifact", res: sreconcile.ResultSuccess, resErr: nil, - newObjBeforeFunc: func(obj *ociv1.OCIRepository) { + newObjBeforeFunc: func(obj *sourcev1.OCIRepository) { obj.Spec.URL = "oci://newurl.io" obj.Status.Artifact = &sourcev1.Artifact{ Revision: "xxx", @@ -3328,12 +3327,12 @@ func TestOCIRepositoryReconciler_notify(t *testing.T) { name: "recovery from failure", res: sreconcile.ResultSuccess, resErr: nil, - oldObjBeforeFunc: func(obj *ociv1.OCIRepository) { + oldObjBeforeFunc: func(obj *sourcev1.OCIRepository) { obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.ReadOperationFailedReason, "fail") conditions.MarkFalse(obj, meta.ReadyCondition, meta.FailedReason, "foo") }, - newObjBeforeFunc: func(obj *ociv1.OCIRepository) { + newObjBeforeFunc: func(obj *sourcev1.OCIRepository) { obj.Spec.URL = "oci://newurl.io" obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") @@ -3344,12 +3343,12 @@ func TestOCIRepositoryReconciler_notify(t *testing.T) { name: "recovery and new artifact", res: sreconcile.ResultSuccess, resErr: nil, - oldObjBeforeFunc: func(obj *ociv1.OCIRepository) { + oldObjBeforeFunc: func(obj *sourcev1.OCIRepository) { obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.ReadOperationFailedReason, "fail") conditions.MarkFalse(obj, meta.ReadyCondition, meta.FailedReason, "foo") }, - newObjBeforeFunc: func(obj *ociv1.OCIRepository) { + newObjBeforeFunc: func(obj *sourcev1.OCIRepository) { obj.Spec.URL = "oci://newurl.io" obj.Status.Artifact = &sourcev1.Artifact{Revision: "aaa", Digest: "bbb"} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") @@ -3360,11 +3359,11 @@ func TestOCIRepositoryReconciler_notify(t *testing.T) { name: "no updates", res: sreconcile.ResultSuccess, resErr: nil, - oldObjBeforeFunc: func(obj *ociv1.OCIRepository) { + oldObjBeforeFunc: func(obj *sourcev1.OCIRepository) { obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") }, - newObjBeforeFunc: func(obj *ociv1.OCIRepository) { + newObjBeforeFunc: func(obj *sourcev1.OCIRepository) { obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, meta.ReadyCondition, meta.SucceededReason, "ready") }, @@ -3373,7 +3372,7 @@ func TestOCIRepositoryReconciler_notify(t *testing.T) { name: "no updates on requeue", res: sreconcile.ResultRequeue, resErr: nil, - oldObjBeforeFunc: func(obj *ociv1.OCIRepository) { + oldObjBeforeFunc: func(obj *sourcev1.OCIRepository) { obj.Status.Artifact = &sourcev1.Artifact{Revision: "xxx", Digest: "yyy"} conditions.MarkTrue(obj, sourcev1.FetchFailedCondition, sourcev1.URLInvalidReason, "ready") }, @@ -3385,7 +3384,7 @@ func TestOCIRepositoryReconciler_notify(t *testing.T) { g := NewWithT(t) recorder := record.NewFakeRecorder(32) - oldObj := &ociv1.OCIRepository{} + oldObj := &sourcev1.OCIRepository{} newObj := oldObj.DeepCopy() if tt.oldObjBeforeFunc != nil { @@ -3513,112 +3512,112 @@ func setPodinfoImageAnnotations(img gcrv1.Image, tag string) gcrv1.Image { func TestOCIContentConfigChanged(t *testing.T) { tests := []struct { name string - spec ociv1.OCIRepositorySpec - status ociv1.OCIRepositoryStatus + spec sourcev1.OCIRepositorySpec + status sourcev1.OCIRepositoryStatus want bool }{ { name: "same ignore, no layer selector", - spec: ociv1.OCIRepositorySpec{ + spec: sourcev1.OCIRepositorySpec{ Ignore: ptr.To("nnn"), }, - status: ociv1.OCIRepositoryStatus{ + status: sourcev1.OCIRepositoryStatus{ ObservedIgnore: ptr.To("nnn"), }, want: false, }, { name: "different ignore, no layer selector", - spec: ociv1.OCIRepositorySpec{ + spec: sourcev1.OCIRepositorySpec{ Ignore: ptr.To("nnn"), }, - status: ociv1.OCIRepositoryStatus{ + status: sourcev1.OCIRepositoryStatus{ ObservedIgnore: ptr.To("mmm"), }, want: true, }, { name: "same ignore, same layer selector", - spec: ociv1.OCIRepositorySpec{ + spec: sourcev1.OCIRepositorySpec{ Ignore: ptr.To("nnn"), - LayerSelector: &ociv1.OCILayerSelector{ + LayerSelector: &sourcev1.OCILayerSelector{ MediaType: "foo", - Operation: ociv1.OCILayerExtract, + Operation: sourcev1.OCILayerExtract, }, }, - status: ociv1.OCIRepositoryStatus{ + status: sourcev1.OCIRepositoryStatus{ ObservedIgnore: ptr.To("nnn"), - ObservedLayerSelector: &ociv1.OCILayerSelector{ + ObservedLayerSelector: &sourcev1.OCILayerSelector{ MediaType: "foo", - Operation: ociv1.OCILayerExtract, + Operation: sourcev1.OCILayerExtract, }, }, want: false, }, { name: "same ignore, different layer selector operation", - spec: ociv1.OCIRepositorySpec{ + spec: sourcev1.OCIRepositorySpec{ Ignore: ptr.To("nnn"), - LayerSelector: &ociv1.OCILayerSelector{ + LayerSelector: &sourcev1.OCILayerSelector{ MediaType: "foo", - Operation: ociv1.OCILayerCopy, + Operation: sourcev1.OCILayerCopy, }, }, - status: ociv1.OCIRepositoryStatus{ + status: sourcev1.OCIRepositoryStatus{ ObservedIgnore: ptr.To("nnn"), - ObservedLayerSelector: &ociv1.OCILayerSelector{ + ObservedLayerSelector: &sourcev1.OCILayerSelector{ MediaType: "foo", - Operation: ociv1.OCILayerExtract, + Operation: sourcev1.OCILayerExtract, }, }, want: true, }, { name: "same ignore, different layer selector mediatype", - spec: ociv1.OCIRepositorySpec{ + spec: sourcev1.OCIRepositorySpec{ Ignore: ptr.To("nnn"), - LayerSelector: &ociv1.OCILayerSelector{ + LayerSelector: &sourcev1.OCILayerSelector{ MediaType: "bar", - Operation: ociv1.OCILayerExtract, + Operation: sourcev1.OCILayerExtract, }, }, - status: ociv1.OCIRepositoryStatus{ + status: sourcev1.OCIRepositoryStatus{ ObservedIgnore: ptr.To("nnn"), - ObservedLayerSelector: &ociv1.OCILayerSelector{ + ObservedLayerSelector: &sourcev1.OCILayerSelector{ MediaType: "foo", - Operation: ociv1.OCILayerExtract, + Operation: sourcev1.OCILayerExtract, }, }, want: true, }, { name: "no ignore, same layer selector", - spec: ociv1.OCIRepositorySpec{ - LayerSelector: &ociv1.OCILayerSelector{ + spec: sourcev1.OCIRepositorySpec{ + LayerSelector: &sourcev1.OCILayerSelector{ MediaType: "foo", - Operation: ociv1.OCILayerExtract, + Operation: sourcev1.OCILayerExtract, }, }, - status: ociv1.OCIRepositoryStatus{ - ObservedLayerSelector: &ociv1.OCILayerSelector{ + status: sourcev1.OCIRepositoryStatus{ + ObservedLayerSelector: &sourcev1.OCILayerSelector{ MediaType: "foo", - Operation: ociv1.OCILayerExtract, + Operation: sourcev1.OCILayerExtract, }, }, want: false, }, { name: "no ignore, different layer selector", - spec: ociv1.OCIRepositorySpec{ - LayerSelector: &ociv1.OCILayerSelector{ + spec: sourcev1.OCIRepositorySpec{ + LayerSelector: &sourcev1.OCILayerSelector{ MediaType: "bar", - Operation: ociv1.OCILayerExtract, + Operation: sourcev1.OCILayerExtract, }, }, - status: ociv1.OCIRepositoryStatus{ - ObservedLayerSelector: &ociv1.OCILayerSelector{ + status: sourcev1.OCIRepositoryStatus{ + ObservedLayerSelector: &sourcev1.OCILayerSelector{ MediaType: "foo", - Operation: ociv1.OCILayerExtract, + Operation: sourcev1.OCILayerExtract, }, }, want: true, @@ -3629,7 +3628,7 @@ func TestOCIContentConfigChanged(t *testing.T) { t.Run(tt.name, func(t *testing.T) { g := NewWithT(t) - obj := &ociv1.OCIRepository{ + obj := &sourcev1.OCIRepository{ Spec: tt.spec, Status: tt.status, } @@ -3642,23 +3641,23 @@ func TestOCIContentConfigChanged(t *testing.T) { func TestOCIRepositoryReconciler_getProxyURL(t *testing.T) { tests := []struct { name string - ociRepo *ociv1.OCIRepository + ociRepo *sourcev1.OCIRepository objects []client.Object expectedURL string expectedErr string }{ { name: "empty proxySecretRef", - ociRepo: &ociv1.OCIRepository{ - Spec: ociv1.OCIRepositorySpec{ + ociRepo: &sourcev1.OCIRepository{ + Spec: sourcev1.OCIRepositorySpec{ ProxySecretRef: nil, }, }, }, { name: "non-existing proxySecretRef", - ociRepo: &ociv1.OCIRepository{ - Spec: ociv1.OCIRepositorySpec{ + ociRepo: &sourcev1.OCIRepository{ + Spec: sourcev1.OCIRepositorySpec{ ProxySecretRef: &meta.LocalObjectReference{ Name: "non-existing", }, @@ -3668,8 +3667,8 @@ func TestOCIRepositoryReconciler_getProxyURL(t *testing.T) { }, { name: "missing address in proxySecretRef", - ociRepo: &ociv1.OCIRepository{ - Spec: ociv1.OCIRepositorySpec{ + ociRepo: &sourcev1.OCIRepository{ + Spec: sourcev1.OCIRepositorySpec{ ProxySecretRef: &meta.LocalObjectReference{ Name: "dummy", }, @@ -3687,8 +3686,8 @@ func TestOCIRepositoryReconciler_getProxyURL(t *testing.T) { }, { name: "invalid address in proxySecretRef", - ociRepo: &ociv1.OCIRepository{ - Spec: ociv1.OCIRepositorySpec{ + ociRepo: &sourcev1.OCIRepository{ + Spec: sourcev1.OCIRepositorySpec{ ProxySecretRef: &meta.LocalObjectReference{ Name: "dummy", }, @@ -3708,8 +3707,8 @@ func TestOCIRepositoryReconciler_getProxyURL(t *testing.T) { }, { name: "no user, no password", - ociRepo: &ociv1.OCIRepository{ - Spec: ociv1.OCIRepositorySpec{ + ociRepo: &sourcev1.OCIRepository{ + Spec: sourcev1.OCIRepositorySpec{ ProxySecretRef: &meta.LocalObjectReference{ Name: "dummy", }, @@ -3729,8 +3728,8 @@ func TestOCIRepositoryReconciler_getProxyURL(t *testing.T) { }, { name: "user, no password", - ociRepo: &ociv1.OCIRepository{ - Spec: ociv1.OCIRepositorySpec{ + ociRepo: &sourcev1.OCIRepository{ + Spec: sourcev1.OCIRepositorySpec{ ProxySecretRef: &meta.LocalObjectReference{ Name: "dummy", }, @@ -3751,8 +3750,8 @@ func TestOCIRepositoryReconciler_getProxyURL(t *testing.T) { }, { name: "no user, password", - ociRepo: &ociv1.OCIRepository{ - Spec: ociv1.OCIRepositorySpec{ + ociRepo: &sourcev1.OCIRepository{ + Spec: sourcev1.OCIRepositorySpec{ ProxySecretRef: &meta.LocalObjectReference{ Name: "dummy", }, @@ -3773,8 +3772,8 @@ func TestOCIRepositoryReconciler_getProxyURL(t *testing.T) { }, { name: "user, password", - ociRepo: &ociv1.OCIRepository{ - Spec: ociv1.OCIRepositorySpec{ + ociRepo: &sourcev1.OCIRepository{ + Spec: sourcev1.OCIRepositorySpec{ ProxySecretRef: &meta.LocalObjectReference{ Name: "dummy", }, diff --git a/internal/controller/suite_test.go b/internal/controller/suite_test.go index 89a51bea8..ad7b0f635 100644 --- a/internal/controller/suite_test.go +++ b/internal/controller/suite_test.go @@ -55,7 +55,6 @@ import ( "github.com/fluxcd/pkg/testserver" sourcev1 "github.com/fluxcd/source-controller/api/v1" - sourcev1beta2 "github.com/fluxcd/source-controller/api/v1beta2" "github.com/fluxcd/source-controller/internal/cache" // +kubebuilder:scaffold:imports ) @@ -273,7 +272,6 @@ func TestMain(m *testing.M) { initTestTLS() utilruntime.Must(sourcev1.AddToScheme(scheme.Scheme)) - utilruntime.Must(sourcev1beta2.AddToScheme(scheme.Scheme)) testEnv = testenv.New( testenv.WithCRDPath(filepath.Join("..", "..", "config", "crd", "bases")), diff --git a/internal/helm/getter/client_opts.go b/internal/helm/getter/client_opts.go index c08fb81d4..4cfa8ee4b 100644 --- a/internal/helm/getter/client_opts.go +++ b/internal/helm/getter/client_opts.go @@ -32,7 +32,6 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" sourcev1 "github.com/fluxcd/source-controller/api/v1" - sourcev1beta2 "github.com/fluxcd/source-controller/api/v1beta2" "github.com/fluxcd/source-controller/internal/helm/registry" soci "github.com/fluxcd/source-controller/internal/oci" stls "github.com/fluxcd/source-controller/internal/tls" @@ -135,7 +134,7 @@ func GetClientOpts(ctx context.Context, c client.Client, obj *sourcev1.HelmRepos return nil, "", fmt.Errorf("failed to configure login options: %w", err) } } - } else if obj.Spec.Provider != sourcev1beta2.GenericOCIProvider && obj.Spec.Type == sourcev1.HelmRepositoryTypeOCI && ociRepo { + } else if obj.Spec.Provider != sourcev1.GenericOCIProvider && obj.Spec.Type == sourcev1.HelmRepositoryTypeOCI && ociRepo { authenticator, authErr := soci.OIDCAuth(ctx, obj.Spec.URL, obj.Spec.Provider) if authErr != nil { return nil, "", fmt.Errorf("failed to get credential from '%s': %w", obj.Spec.Provider, authErr) diff --git a/internal/oci/auth.go b/internal/oci/auth.go index c917a0d9e..6bd35c59e 100644 --- a/internal/oci/auth.go +++ b/internal/oci/auth.go @@ -25,7 +25,7 @@ import ( "github.com/fluxcd/pkg/auth" authutils "github.com/fluxcd/pkg/auth/utils" - sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" + sourcev1 "github.com/fluxcd/source-controller/api/v1" ) // Anonymous is an authn.AuthConfig that always returns an anonymous diff --git a/internal/reconcile/reconcile_test.go b/internal/reconcile/reconcile_test.go index 15a60b0d4..e22f370b5 100644 --- a/internal/reconcile/reconcile_test.go +++ b/internal/reconcile/reconcile_test.go @@ -29,7 +29,7 @@ import ( "github.com/fluxcd/pkg/runtime/conditions" "github.com/fluxcd/pkg/runtime/patch" - sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" + sourcev1 "github.com/fluxcd/source-controller/api/v1" serror "github.com/fluxcd/source-controller/internal/error" ) diff --git a/internal/reconcile/summarize/processor_test.go b/internal/reconcile/summarize/processor_test.go index dc6765d83..9db129a99 100644 --- a/internal/reconcile/summarize/processor_test.go +++ b/internal/reconcile/summarize/processor_test.go @@ -26,7 +26,8 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "github.com/fluxcd/pkg/apis/meta" - sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" + + sourcev1 "github.com/fluxcd/source-controller/api/v1" "github.com/fluxcd/source-controller/internal/object" "github.com/fluxcd/source-controller/internal/reconcile" ) diff --git a/main.go b/main.go index a8c0f518b..d9e474620 100644 --- a/main.go +++ b/main.go @@ -52,9 +52,7 @@ import ( "github.com/fluxcd/pkg/runtime/pprof" "github.com/fluxcd/pkg/runtime/probes" - v1 "github.com/fluxcd/source-controller/api/v1" - "github.com/fluxcd/source-controller/api/v1beta2" - + sourcev1 "github.com/fluxcd/source-controller/api/v1" // +kubebuilder:scaffold:imports "github.com/fluxcd/source-controller/internal/cache" @@ -85,8 +83,7 @@ var ( func init() { utilruntime.Must(clientgoscheme.AddToScheme(scheme)) - utilruntime.Must(v1beta2.AddToScheme(scheme)) - utilruntime.Must(v1.AddToScheme(scheme)) + utilruntime.Must(sourcev1.AddToScheme(scheme)) // +kubebuilder:scaffold:scheme } @@ -187,7 +184,7 @@ func main() { probes.SetupChecks(mgr, setupLog) - metrics := helper.NewMetrics(mgr, metrics.MustMakeRecorder(), v1.SourceFinalizer) + metrics := helper.NewMetrics(mgr, metrics.MustMakeRecorder(), sourcev1.SourceFinalizer) cacheRecorder := cache.MustMakeMetrics() eventRecorder := mustSetupEventRecorder(mgr, eventsAddr, controllerName) storage := mustInitStorage(storagePath, storageAdvAddr, artifactRetentionTTL, artifactRetentionRecords, artifactDigestAlgo) @@ -221,7 +218,7 @@ func main() { DependencyRequeueInterval: requeueDependency, RateLimiter: helper.GetRateLimiter(rateLimiterOptions), }); err != nil { - setupLog.Error(err, "unable to create controller", "controller", v1.GitRepositoryKind) + setupLog.Error(err, "unable to create controller", "controller", sourcev1.GitRepositoryKind) os.Exit(1) } @@ -238,7 +235,7 @@ func main() { }).SetupWithManagerAndOptions(mgr, controller.HelmRepositoryReconcilerOptions{ RateLimiter: helper.GetRateLimiter(rateLimiterOptions), }); err != nil { - setupLog.Error(err, "unable to create controller", "controller", v1.HelmRepositoryKind) + setupLog.Error(err, "unable to create controller", "controller", sourcev1.HelmRepositoryKind) os.Exit(1) } @@ -256,7 +253,7 @@ func main() { }).SetupWithManagerAndOptions(ctx, mgr, controller.HelmChartReconcilerOptions{ RateLimiter: helper.GetRateLimiter(rateLimiterOptions), }); err != nil { - setupLog.Error(err, "unable to create controller", "controller", v1.HelmChartKind) + setupLog.Error(err, "unable to create controller", "controller", sourcev1.HelmChartKind) os.Exit(1) } @@ -269,7 +266,7 @@ func main() { }).SetupWithManagerAndOptions(mgr, controller.BucketReconcilerOptions{ RateLimiter: helper.GetRateLimiter(rateLimiterOptions), }); err != nil { - setupLog.Error(err, "unable to create controller", "controller", v1.BucketKind) + setupLog.Error(err, "unable to create controller", "controller", sourcev1.BucketKind) os.Exit(1) } @@ -283,7 +280,7 @@ func main() { }).SetupWithManagerAndOptions(mgr, controller.OCIRepositoryReconcilerOptions{ RateLimiter: helper.GetRateLimiter(rateLimiterOptions), }); err != nil { - setupLog.Error(err, "unable to create controller", "controller", v1beta2.OCIRepositoryKind) + setupLog.Error(err, "unable to create controller", "controller", sourcev1.OCIRepositoryKind) os.Exit(1) } // +kubebuilder:scaffold:builder @@ -371,11 +368,11 @@ func mustSetupManager(metricsAddr, healthAddr string, maxConcurrent int, }, Cache: ctrlcache.Options{ ByObject: map[ctrlclient.Object]ctrlcache.ByObject{ - &v1.GitRepository{}: {Label: watchSelector}, - &v1.HelmRepository{}: {Label: watchSelector}, - &v1.HelmChart{}: {Label: watchSelector}, - &v1.Bucket{}: {Label: watchSelector}, - &v1beta2.OCIRepository{}: {Label: watchSelector}, + &sourcev1.GitRepository{}: {Label: watchSelector}, + &sourcev1.HelmRepository{}: {Label: watchSelector}, + &sourcev1.HelmChart{}: {Label: watchSelector}, + &sourcev1.Bucket{}: {Label: watchSelector}, + &sourcev1.OCIRepository{}: {Label: watchSelector}, }, }, Metrics: metricsserver.Options{ diff --git a/pkg/minio/minio_test.go b/pkg/minio/minio_test.go index 9a31d49b5..596e61810 100644 --- a/pkg/minio/minio_test.go +++ b/pkg/minio/minio_test.go @@ -52,7 +52,7 @@ import ( const ( objectName string = "test.yaml" - objectEtag string = "2020beab5f1711919157756379622d1d" + objectEtag string = "b07bba5a280b58791bc78fb9fc414b09" ) var ( @@ -801,7 +801,7 @@ func removeObjectFromBucket(ctx context.Context) { func getObjectFile() string { return ` - apiVersion: source.toolkit.fluxcd.io/v1beta2 + apiVersion: source.toolkit.fluxcd.io/v1 kind: Bucket metadata: name: podinfo