Skip to content

Commit e24ce86

Browse files
authored
Merge pull request #1001 from fluxcd/artifact-digest
RFC-0005: introduction of Digest and change of Revision format
2 parents d18988e + 9283894 commit e24ce86

39 files changed

+2458
-1219
lines changed

api/v1beta2/artifact_types.go

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package v1beta2
1818

1919
import (
2020
"path"
21+
"regexp"
2122
"strings"
2223

2324
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -43,8 +44,14 @@ type Artifact struct {
4344
Revision string `json:"revision"`
4445

4546
// Checksum is the SHA256 checksum of the Artifact file.
47+
// Deprecated: use Artifact.Digest instead.
4648
// +optional
47-
Checksum string `json:"checksum"`
49+
Checksum string `json:"checksum,omitempty"`
50+
51+
// Digest is the digest of the file in the form of '<algorithm>:<checksum>'.
52+
// +optional
53+
// +kubebuilder:validation:Pattern="^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$"
54+
Digest string `json:"digest"`
4855

4956
// LastUpdateTime is the timestamp corresponding to the last update of the
5057
// Artifact.
@@ -66,7 +73,7 @@ func (in *Artifact) HasRevision(revision string) bool {
6673
if in == nil {
6774
return false
6875
}
69-
return in.Revision == revision
76+
return TransformLegacyRevision(in.Revision) == TransformLegacyRevision(revision)
7077
}
7178

7279
// HasChecksum returns if the given checksum matches the current Checksum of
@@ -90,3 +97,60 @@ func ArtifactDir(kind, namespace, name string) string {
9097
func ArtifactPath(kind, namespace, name, filename string) string {
9198
return path.Join(ArtifactDir(kind, namespace, name), filename)
9299
}
100+
101+
// TransformLegacyRevision transforms a "legacy" revision string into a "new"
102+
// revision string. It accepts the following formats:
103+
//
104+
// - main/5394cb7f48332b2de7c17dd8b8384bbc84b7e738
105+
// - feature/branch/5394cb7f48332b2de7c17dd8b8384bbc84b7e738
106+
// - HEAD/5394cb7f48332b2de7c17dd8b8384bbc84b7e738
107+
// - tag/55609ff9d959589ed917ce32e6bc0f0a36809565f308602c15c3668965979edc
108+
// - d52bde83c5b2bd0fa7910264e0afc3ac9cfe9b6636ca29c05c09742f01d5a4bd
109+
//
110+
// Which are transformed into the following formats respectively:
111+
//
112+
// - main@sha1:5394cb7f48332b2de7c17dd8b8384bbc84b7e738
113+
// - feature/branch@sha1:5394cb7f48332b2de7c17dd8b8384bbc84b7e738
114+
// - sha1:5394cb7f48332b2de7c17dd8b8384bbc84b7e738
115+
// - tag@sha256:55609ff9d959589ed917ce32e6bc0f0a36809565f308602c15c3668965979edc
116+
// - sha256:d52bde83c5b2bd0fa7910264e0afc3ac9cfe9b6636ca29c05c09742f01d5a4bd
117+
//
118+
// Deprecated, this function exists for backwards compatibility with existing
119+
// resources, and to provide a transition period. Will be removed in a future
120+
// release.
121+
func TransformLegacyRevision(rev string) string {
122+
if rev != "" && strings.LastIndex(rev, ":") == -1 {
123+
if i := strings.LastIndex(rev, "/"); i >= 0 {
124+
sha := rev[i+1:]
125+
if algo := determineSHAType(sha); algo != "" {
126+
if name := rev[:i]; name != "HEAD" {
127+
return name + "@" + algo + ":" + sha
128+
}
129+
return algo + ":" + sha
130+
}
131+
}
132+
if algo := determineSHAType(rev); algo != "" {
133+
return algo + ":" + rev
134+
}
135+
}
136+
return rev
137+
}
138+
139+
// isAlphaNumHex returns true if the given string only contains 0-9 and a-f
140+
// characters.
141+
var isAlphaNumHex = regexp.MustCompile(`^[0-9a-f]+$`).MatchString
142+
143+
// determineSHAType returns the SHA algorithm used to compute the provided hex.
144+
// The determination is heuristic and based on the length of the hex string. If
145+
// the size is not recognized, an empty string is returned.
146+
func determineSHAType(hex string) string {
147+
if isAlphaNumHex(hex) {
148+
switch len(hex) {
149+
case 40:
150+
return "sha1"
151+
case 64:
152+
return "sha256"
153+
}
154+
}
155+
return ""
156+
}

api/v1beta2/artifact_types_test.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
Copyright 2023 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 "testing"
20+
21+
func TestTransformLegacyRevision(t *testing.T) {
22+
tests := []struct {
23+
rev string
24+
want string
25+
}{
26+
{
27+
rev: "HEAD/5394cb7f48332b2de7c17dd8b8384bbc84b7e738",
28+
want: "sha1:5394cb7f48332b2de7c17dd8b8384bbc84b7e738",
29+
},
30+
{
31+
rev: "main/5394cb7f48332b2de7c17dd8b8384bbc84b7e738",
32+
want: "main@sha1:5394cb7f48332b2de7c17dd8b8384bbc84b7e738",
33+
},
34+
{
35+
rev: "main@sha1:5394cb7f48332b2de7c17dd8b8384bbc84b7e738",
36+
want: "main@sha1:5394cb7f48332b2de7c17dd8b8384bbc84b7e738",
37+
},
38+
{
39+
rev: "feature/branch/5394cb7f48332b2de7c17dd8b8384bbc84b7e738",
40+
want: "feature/branch@sha1:5394cb7f48332b2de7c17dd8b8384bbc84b7e738",
41+
},
42+
{
43+
rev: "feature/branch@sha1:5394cb7f48332b2de7c17dd8b8384bbc84b7e738",
44+
want: "feature/branch@sha1:5394cb7f48332b2de7c17dd8b8384bbc84b7e738",
45+
},
46+
{
47+
rev: "5ac85ca617f3774baff4ae0a420b810b2546dbc9af9f346b1d55c5ed9873c55c",
48+
want: "sha256:5ac85ca617f3774baff4ae0a420b810b2546dbc9af9f346b1d55c5ed9873c55c",
49+
},
50+
{
51+
rev: "v1.0.0",
52+
want: "v1.0.0",
53+
},
54+
{
55+
rev: "v1.0.0-rc1",
56+
want: "v1.0.0-rc1",
57+
},
58+
{
59+
rev: "v1.0.0-rc1+metadata",
60+
want: "v1.0.0-rc1+metadata",
61+
},
62+
{
63+
rev: "arbitrary/revision",
64+
want: "arbitrary/revision",
65+
},
66+
{
67+
rev: "5394cb7f48332b2de7c17dd8b8384bbc84b7xxxx",
68+
want: "5394cb7f48332b2de7c17dd8b8384bbc84b7xxxx",
69+
},
70+
}
71+
for _, tt := range tests {
72+
t.Run(tt.rev, func(t *testing.T) {
73+
if got := TransformLegacyRevision(tt.rev); got != tt.want {
74+
t.Errorf("TransformLegacyRevision() = %v, want %v", got, tt.want)
75+
}
76+
})
77+
}
78+
}

config/crd/bases/source.toolkit.fluxcd.io_buckets.yaml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,12 @@ spec:
377377
description: Artifact represents the last successful Bucket reconciliation.
378378
properties:
379379
checksum:
380-
description: Checksum is the SHA256 checksum of the Artifact file.
380+
description: 'Checksum is the SHA256 checksum of the Artifact
381+
file. Deprecated: use Artifact.Digest instead.'
382+
type: string
383+
digest:
384+
description: Digest is the digest of the file in the form of '<algorithm>:<checksum>'.
385+
pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$
381386
type: string
382387
lastUpdateTime:
383388
description: LastUpdateTime is the timestamp corresponding to

config/crd/bases/source.toolkit.fluxcd.io_gitrepositories.yaml

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -554,7 +554,12 @@ spec:
554554
reconciliation.
555555
properties:
556556
checksum:
557-
description: Checksum is the SHA256 checksum of the Artifact file.
557+
description: 'Checksum is the SHA256 checksum of the Artifact
558+
file. Deprecated: use Artifact.Digest instead.'
559+
type: string
560+
digest:
561+
description: Digest is the digest of the file in the form of '<algorithm>:<checksum>'.
562+
pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$
558563
type: string
559564
lastUpdateTime:
560565
description: LastUpdateTime is the timestamp corresponding to
@@ -676,8 +681,13 @@ spec:
676681
description: Artifact represents the output of a Source reconciliation.
677682
properties:
678683
checksum:
679-
description: Checksum is the SHA256 checksum of the Artifact
680-
file.
684+
description: 'Checksum is the SHA256 checksum of the Artifact
685+
file. Deprecated: use Artifact.Digest instead.'
686+
type: string
687+
digest:
688+
description: Digest is the digest of the file in the form of
689+
'<algorithm>:<checksum>'.
690+
pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$
681691
type: string
682692
lastUpdateTime:
683693
description: LastUpdateTime is the timestamp corresponding to

config/crd/bases/source.toolkit.fluxcd.io_helmcharts.yaml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -452,7 +452,12 @@ spec:
452452
reconciliation.
453453
properties:
454454
checksum:
455-
description: Checksum is the SHA256 checksum of the Artifact file.
455+
description: 'Checksum is the SHA256 checksum of the Artifact
456+
file. Deprecated: use Artifact.Digest instead.'
457+
type: string
458+
digest:
459+
description: Digest is the digest of the file in the form of '<algorithm>:<checksum>'.
460+
pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$
456461
type: string
457462
lastUpdateTime:
458463
description: LastUpdateTime is the timestamp corresponding to

config/crd/bases/source.toolkit.fluxcd.io_helmrepositories.yaml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,12 @@ spec:
369369
reconciliation.
370370
properties:
371371
checksum:
372-
description: Checksum is the SHA256 checksum of the Artifact file.
372+
description: 'Checksum is the SHA256 checksum of the Artifact
373+
file. Deprecated: use Artifact.Digest instead.'
374+
type: string
375+
digest:
376+
description: Digest is the digest of the file in the form of '<algorithm>:<checksum>'.
377+
pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$
373378
type: string
374379
lastUpdateTime:
375380
description: LastUpdateTime is the timestamp corresponding to

config/crd/bases/source.toolkit.fluxcd.io_ocirepositories.yaml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,12 @@ spec:
195195
OCI Repository sync.
196196
properties:
197197
checksum:
198-
description: Checksum is the SHA256 checksum of the Artifact file.
198+
description: 'Checksum is the SHA256 checksum of the Artifact
199+
file. Deprecated: use Artifact.Digest instead.'
200+
type: string
201+
digest:
202+
description: Digest is the digest of the file in the form of '<algorithm>:<checksum>'.
203+
pattern: ^[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[a-zA-Z0-9=_-]+$
199204
type: string
200205
lastUpdateTime:
201206
description: LastUpdateTime is the timestamp corresponding to

controllers/artifact.go

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -37,25 +37,3 @@ outer:
3737
}
3838
return false
3939
}
40-
41-
// hasArtifactUpdated returns true if any of the revisions in the current artifacts
42-
// does not match any of the artifacts in the updated artifacts
43-
// NOTE: artifactSet is a replacement for this. Remove this once it's not used
44-
// anywhere.
45-
func hasArtifactUpdated(current []*sourcev1.Artifact, updated []*sourcev1.Artifact) bool {
46-
if len(current) != len(updated) {
47-
return true
48-
}
49-
50-
OUTER:
51-
for _, c := range current {
52-
for _, u := range updated {
53-
if u.HasRevision(c.Revision) {
54-
continue OUTER
55-
}
56-
}
57-
return true
58-
}
59-
60-
return false
61-
}

0 commit comments

Comments
 (0)