diff --git a/internal/digest/digest.go b/internal/digest/digest.go index 1be1e9388..f1e5154b6 100644 --- a/internal/digest/digest.go +++ b/internal/digest/digest.go @@ -20,6 +20,7 @@ import ( "crypto" _ "crypto/sha256" _ "crypto/sha512" + "fmt" "github.com/opencontainers/go-digest" _ "github.com/opencontainers/go-digest/blake3" @@ -39,3 +40,13 @@ func init() { // Register SHA-1 algorithm for support of legacy values checksums. digest.RegisterAlgorithm(SHA1, crypto.SHA1) } + +// AlgorithmForName returns the digest algorithm for the given name, or an +// error of type digest.ErrDigestUnsupported if the algorithm is unavailable. +func AlgorithmForName(name string) (digest.Algorithm, error) { + a := digest.Algorithm(name) + if !a.Available() { + return "", fmt.Errorf("%w: %s", digest.ErrDigestUnsupported, name) + } + return a, nil +} diff --git a/internal/digest/digest_test.go b/internal/digest/digest_test.go new file mode 100644 index 000000000..fb56e65d9 --- /dev/null +++ b/internal/digest/digest_test.go @@ -0,0 +1,71 @@ +/* +Copyright 2023 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 digest + +import ( + "errors" + "testing" + + . "github.com/onsi/gomega" + "github.com/opencontainers/go-digest" +) + +func TestAlgorithmForName(t *testing.T) { + tests := []struct { + name string + want digest.Algorithm + wantErr error + }{ + { + name: "sha256", + want: digest.SHA256, + }, + { + name: "sha384", + want: digest.SHA384, + }, + { + name: "sha512", + want: digest.SHA512, + }, + { + name: "blake3", + want: digest.BLAKE3, + }, + { + name: "sha1", + want: SHA1, + }, + { + name: "not-available", + wantErr: digest.ErrDigestUnsupported, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + g := NewWithT(t) + got, err := AlgorithmForName(tt.name) + if tt.wantErr != nil { + g.Expect(err).To(HaveOccurred()) + g.Expect(errors.Is(err, tt.wantErr)).To(BeTrue()) + return + } + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(got).To(Equal(tt.want)) + }) + } +} diff --git a/main.go b/main.go index 23ee93cf9..2f8349744 100644 --- a/main.go +++ b/main.go @@ -49,6 +49,8 @@ import ( sourcev1 "github.com/fluxcd/source-controller/api/v1beta2" v2 "github.com/fluxcd/helm-controller/api/v2beta2" + intdigest "github.com/fluxcd/helm-controller/internal/digest" + // +kubebuilder:scaffold:imports intacl "github.com/fluxcd/helm-controller/internal/acl" @@ -95,6 +97,7 @@ func main() { oomWatchMemoryThreshold uint8 oomWatchMaxMemoryPath string oomWatchCurrentMemoryPath string + snapshotDigestAlgo string ) flag.StringVar(&metricsAddr, "metrics-addr", ":8080", @@ -121,6 +124,8 @@ func main() { "The path to the cgroup memory limit file. Requires feature gate 'OOMWatch' to be enabled. If not set, the path will be automatically detected.") flag.StringVar(&oomWatchCurrentMemoryPath, "oom-watch-current-memory-path", "", "The path to the cgroup current memory usage file. Requires feature gate 'OOMWatch' to be enabled. If not set, the path will be automatically detected.") + flag.StringVar(&snapshotDigestAlgo, "snapshot-digest-algo", intdigest.Canonical.String(), + "The algorithm to use to calculate the digest of Helm release storage snapshots.") clientOptions.BindFlags(flag.CommandLine) logOptions.BindFlags(flag.CommandLine) @@ -180,6 +185,16 @@ func main() { // Configure the ACL policy. intacl.AllowCrossNamespaceRef = !aclOptions.NoCrossNamespaceRefs + // Configure the digest algorithm. + if snapshotDigestAlgo != intdigest.Canonical.String() { + algo, err := intdigest.AlgorithmForName(snapshotDigestAlgo) + if err != nil { + setupLog.Error(err, "unable to configure canonical digest algorithm") + os.Exit(1) + } + intdigest.Canonical = algo + } + restConfig := client.GetConfigOrDie(clientOptions) mgrConfig := ctrl.Options{