1 /* 2 Copyright 2022 The Flux authors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package v1beta2 18 19 import ( 20 "path" 21 "regexp" 22 "strings" 23 24 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 25 ) 26 27 // Artifact represents the output of a Source reconciliation. 28 // 29 // Deprecated: use Artifact from api/v1 instead. This type will be removed in 30 // a future release. 31 type Artifact struct { 32 // Path is the relative file path of the Artifact. It can be used to locate 33 // the file in the root of the Artifact storage on the local file system of 34 // the controller managing the Source. 35 // +required 36 Path string `json:"path"` 37 38 // URL is the HTTP address of the Artifact as exposed by the controller 39 // managing the Source. It can be used to retrieve the Artifact for 40 // consumption, e.g. by another controller applying the Artifact contents. 41 // +required 42 URL string `json:"url"` 43 44 // Revision is a human-readable identifier traceable in the origin source 45 // system. It can be a Git commit SHA, Git tag, a Helm chart version, etc. 46 // +optional 47 Revision string `json:"revision"` 48 49 // Checksum is the SHA256 checksum of the Artifact file. 50 // Deprecated: use Artifact.Digest instead. 51 // +optional 52 Checksum string `json:"checksum,omitempty"` 53 54 // Digest is the digest of the file in the form of '<algorithm>:<checksum>'. 55 // +optional 56 // +kubebuilder:validation:Pattern="^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$" 57 Digest string `json:"digest,omitempty"` 58 59 // LastUpdateTime is the timestamp corresponding to the last update of the 60 // Artifact. 61 // +required 62 LastUpdateTime metav1.Time `json:"lastUpdateTime,omitempty"` 63 64 // Size is the number of bytes in the file. 65 // +optional 66 Size *int64 `json:"size,omitempty"` 67 68 // Metadata holds upstream information such as OCI annotations. 69 // +optional 70 Metadata map[string]string `json:"metadata,omitempty"` 71 } 72 73 // HasRevision returns if the given revision matches the current Revision of 74 // the Artifact. 75 func (in *Artifact) HasRevision(revision string) bool { 76 if in == nil { 77 return false 78 } 79 return TransformLegacyRevision(in.Revision) == TransformLegacyRevision(revision) 80 } 81 82 // HasChecksum returns if the given checksum matches the current Checksum of 83 // the Artifact. 84 func (in *Artifact) HasChecksum(checksum string) bool { 85 if in == nil { 86 return false 87 } 88 return in.Checksum == checksum 89 } 90 91 // ArtifactDir returns the artifact dir path in the form of 92 // '<kind>/<namespace>/<name>'. 93 func ArtifactDir(kind, namespace, name string) string { 94 kind = strings.ToLower(kind) 95 return path.Join(kind, namespace, name) 96 } 97 98 // ArtifactPath returns the artifact path in the form of 99 // '<kind>/<namespace>/name>/<filename>'. 100 func ArtifactPath(kind, namespace, name, filename string) string { 101 return path.Join(ArtifactDir(kind, namespace, name), filename) 102 } 103 104 // TransformLegacyRevision transforms a "legacy" revision string into a "new" 105 // revision string. It accepts the following formats: 106 // 107 // - main/5394cb7f48332b2de7c17dd8b8384bbc84b7e738 108 // - feature/branch/5394cb7f48332b2de7c17dd8b8384bbc84b7e738 109 // - HEAD/5394cb7f48332b2de7c17dd8b8384bbc84b7e738 110 // - tag/55609ff9d959589ed917ce32e6bc0f0a36809565f308602c15c3668965979edc 111 // - d52bde83c5b2bd0fa7910264e0afc3ac9cfe9b6636ca29c05c09742f01d5a4bd 112 // 113 // Which are transformed into the following formats respectively: 114 // 115 // - main@sha1:5394cb7f48332b2de7c17dd8b8384bbc84b7e738 116 // - feature/branch@sha1:5394cb7f48332b2de7c17dd8b8384bbc84b7e738 117 // - sha1:5394cb7f48332b2de7c17dd8b8384bbc84b7e738 118 // - tag@sha256:55609ff9d959589ed917ce32e6bc0f0a36809565f308602c15c3668965979edc 119 // - sha256:d52bde83c5b2bd0fa7910264e0afc3ac9cfe9b6636ca29c05c09742f01d5a4bd 120 // 121 // Deprecated, this function exists for backwards compatibility with existing 122 // resources, and to provide a transition period. Will be removed in a future 123 // release. 124 func TransformLegacyRevision(rev string) string { 125 if rev != "" && strings.LastIndex(rev, ":") == -1 { 126 if i := strings.LastIndex(rev, "/"); i >= 0 { 127 sha := rev[i+1:] 128 if algo := determineSHAType(sha); algo != "" { 129 if name := rev[:i]; name != "HEAD" { 130 return name + "@" + algo + ":" + sha 131 } 132 return algo + ":" + sha 133 } 134 } 135 if algo := determineSHAType(rev); algo != "" { 136 return algo + ":" + rev 137 } 138 } 139 return rev 140 } 141 142 // isAlphaNumHex returns true if the given string only contains 0-9 and a-f 143 // characters. 144 var isAlphaNumHex = regexp.MustCompile(`^[0-9a-f]+$`).MatchString 145 146 // determineSHAType returns the SHA algorithm used to compute the provided hex. 147 // The determination is heuristic and based on the length of the hex string. If 148 // the size is not recognized, an empty string is returned. 149 func determineSHAType(hex string) string { 150 if isAlphaNumHex(hex) { 151 switch len(hex) { 152 case 40: 153 return "sha1" 154 case 64: 155 return "sha256" 156 } 157 } 158 return "" 159 } 160