storage: add VerifyArtifact method

Signed-off-by: Hidde Beydals <hidde@hhh.computer>
This commit is contained in:
Hidde Beydals 2023-05-10 11:39:59 +02:00
parent 62fd433e79
commit 67e9c94abf
No known key found for this signature in database
GPG Key ID: 979F380FC2341744
2 changed files with 89 additions and 0 deletions

View File

@ -21,6 +21,7 @@ import (
"compress/gzip"
"context"
"fmt"
"github.com/opencontainers/go-digest"
"io"
"io/fs"
"net/url"
@ -325,6 +326,35 @@ func (s *Storage) ArtifactExist(artifact v1.Artifact) bool {
return fi.Mode().IsRegular()
}
// VerifyArtifact verifies if the Digest of the v1.Artifact matches the digest
// of the file in Storage. It returns an error if the digests don't match, or
// if it can't be verified.
func (s *Storage) VerifyArtifact(artifact v1.Artifact) error {
if artifact.Digest == "" {
return fmt.Errorf("artifact has no digest")
}
d, err := digest.Parse(artifact.Digest)
if err != nil {
return fmt.Errorf("failed to parse artifact digest '%s': %w", artifact.Digest, err)
}
f, err := os.Open(s.LocalPath(artifact))
if err != nil {
return err
}
defer f.Close()
verifier := d.Verifier()
if _, err = io.Copy(verifier, f); err != nil {
return err
}
if !verifier.Verified() {
return fmt.Errorf("computed digest doesn't match '%s'", d.String())
}
return nil
}
// ArchiveFileFilter must return true if a file should not be included in the archive after inspecting the given path
// and/or os.FileInfo.
type ArchiveFileFilter func(p string, fi os.FileInfo) bool

View File

@ -20,6 +20,7 @@ import (
"archive/tar"
"compress/gzip"
"context"
"errors"
"fmt"
"io"
"os"
@ -718,3 +719,61 @@ func TestStorage_GarbageCollect(t *testing.T) {
})
}
}
func TestStorage_VerifyArtifact(t *testing.T) {
g := NewWithT(t)
dir := t.TempDir()
s, err := NewStorage(dir, "", 0, 0)
g.Expect(err).ToNot(HaveOccurred(), "failed to create new storage")
g.Expect(os.WriteFile(filepath.Join(dir, "artifact"), []byte("test"), 0o600)).To(Succeed())
t.Run("artifact without digest", func(t *testing.T) {
g := NewWithT(t)
err := s.VerifyArtifact(sourcev1.Artifact{})
g.Expect(err).To(HaveOccurred())
g.Expect(err).To(MatchError("artifact has no digest"))
})
t.Run("artifact with invalid digest", func(t *testing.T) {
g := NewWithT(t)
err := s.VerifyArtifact(sourcev1.Artifact{Digest: "invalid"})
g.Expect(err).To(HaveOccurred())
g.Expect(err).To(MatchError("failed to parse artifact digest 'invalid': invalid checksum digest format"))
})
t.Run("artifact with invalid path", func(t *testing.T) {
g := NewWithT(t)
err := s.VerifyArtifact(sourcev1.Artifact{
Digest: "sha256:9ba7a35ce8acd3557fe30680ef193ca7a36bb5dc62788f30de7122a0a5beab69",
Path: "invalid",
})
g.Expect(err).To(HaveOccurred())
g.Expect(errors.Is(err, os.ErrNotExist)).To(BeTrue())
})
t.Run("artifact with digest mismatch", func(t *testing.T) {
g := NewWithT(t)
err := s.VerifyArtifact(sourcev1.Artifact{
Digest: "sha256:9ba7a35ce8acd3557fe30680ef193ca7a36bb5dc62788f30de7122a0a5beab69",
Path: "artifact",
})
g.Expect(err).To(HaveOccurred())
g.Expect(err).To(MatchError("computed digest doesn't match 'sha256:9ba7a35ce8acd3557fe30680ef193ca7a36bb5dc62788f30de7122a0a5beab69'"))
})
t.Run("artifact with digest match", func(t *testing.T) {
g := NewWithT(t)
err := s.VerifyArtifact(sourcev1.Artifact{
Digest: "sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
Path: "artifact",
})
g.Expect(err).ToNot(HaveOccurred())
})
}