diff --git a/cmd/power_user_tasks.go b/cmd/power_user_tasks.go index 10070e548..a33036cac 100644 --- a/cmd/power_user_tasks.go +++ b/cmd/power_user_tasks.go @@ -1,6 +1,9 @@ package cmd import ( + "crypto" + "fmt" + "github.com/anchore/syft/internal/presenter/poweruser" "github.com/anchore/syft/syft" "github.com/anchore/syft/syft/file" @@ -80,7 +83,26 @@ func catalogFileDigestTask() (powerUserTask, error) { return nil, nil } - digestsCataloger, err := file.NewDigestsCataloger(appConfig.FileMetadata.Digests) + supportedHashAlgorithms := make(map[string]crypto.Hash) + for _, h := range []crypto.Hash{ + crypto.MD5, + crypto.SHA1, + crypto.SHA256, + } { + supportedHashAlgorithms[file.DigestAlgorithmName(h)] = h + } + + var hashes []crypto.Hash + for _, hashStr := range appConfig.FileMetadata.Digests { + name := file.CleanDigestAlgorithmName(hashStr) + hashObj, ok := supportedHashAlgorithms[name] + if !ok { + return nil, fmt.Errorf("unsupported hash algorithm: %s", hashStr) + } + hashes = append(hashes, hashObj) + } + + digestsCataloger, err := file.NewDigestsCataloger(hashes) if err != nil { return nil, err } diff --git a/internal/presenter/poweruser/json_presenter_test.go b/internal/presenter/poweruser/json_presenter_test.go index eacd59cc0..97724da69 100644 --- a/internal/presenter/poweruser/json_presenter_test.go +++ b/internal/presenter/poweruser/json_presenter_test.go @@ -47,6 +47,7 @@ func TestJSONPresenter(t *testing.T) { Metadata: pkg.PythonPackageMetadata{ Name: "package-1", Version: "1.0.1", + Files: []pkg.PythonFileRecord{}, }, PURL: "a-purl-1", CPEs: []pkg.CPE{ @@ -68,6 +69,7 @@ func TestJSONPresenter(t *testing.T) { Metadata: pkg.DpkgMetadata{ Package: "package-2", Version: "2.0.1", + Files: []pkg.DpkgFileRecord{}, }, PURL: "a-purl-2", CPEs: []pkg.CPE{ @@ -76,8 +78,12 @@ func TestJSONPresenter(t *testing.T) { }) cfg := JSONDocumentConfig{ - ApplicationConfig: config.Application{}, - PackageCatalog: catalog, + ApplicationConfig: config.Application{ + FileMetadata: config.FileMetadata{ + Digests: []string{"sha256"}, + }, + }, + PackageCatalog: catalog, FileMetadata: map[source.Location]source.FileMetadata{ source.NewLocation("/a/place"): { Mode: 0775, @@ -149,6 +155,7 @@ func TestJSONPresenter(t *testing.T) { }, RawManifest: []byte("eyJzY2hlbWFWZXJzaW9uIjoyLCJtZWRpYVR5cGUiOiJh..."), RawConfig: []byte("eyJhcmNoaXRlY3R1cmUiOiJhbWQ2NCIsImNvbmZp..."), + RepoDigests: []string{}, }, }, } @@ -162,7 +169,7 @@ func TestJSONPresenter(t *testing.T) { testutils.UpdateGoldenFileContents(t, actual) } - var expected = testutils.GetGoldenFileContents(t) + expected := testutils.GetGoldenFileContents(t) if !bytes.Equal(expected, actual) { dmp := diffmatchpatch.New() diff --git a/internal/presenter/poweruser/test-fixtures/snapshot/TestJSONPresenter.golden b/internal/presenter/poweruser/test-fixtures/snapshot/TestJSONPresenter.golden index 9b428db23..77b2894f9 100644 --- a/internal/presenter/poweruser/test-fixtures/snapshot/TestJSONPresenter.golden +++ b/internal/presenter/poweruser/test-fixtures/snapshot/TestJSONPresenter.golden @@ -115,7 +115,7 @@ "architecture": "", "maintainer": "", "installedSize": 0, - "files": null + "files": [] } } ], @@ -145,6 +145,7 @@ ], "manifest": "ZXlKelkyaGxiV0ZXWlhKemFXOXVJam95TENKdFpXUnBZVlI1Y0dVaU9pSmguLi4=", "config": "ZXlKaGNtTm9hWFJsWTNSMWNtVWlPaUpoYldRMk5DSXNJbU52Ym1acC4uLg==", + "repoDigests": [], "scope": "" } }, @@ -187,7 +188,9 @@ "enabled": false, "scope": "" }, - "digests": null + "digests": [ + "sha256" + ] } } }, diff --git a/syft/file/digest_cataloger.go b/syft/file/digest_cataloger.go index a528d2a81..c18478166 100644 --- a/syft/file/digest_cataloger.go +++ b/syft/file/digest_cataloger.go @@ -10,33 +10,11 @@ import ( "github.com/anchore/syft/syft/source" ) -var supportedHashAlgorithms = make(map[string]crypto.Hash) - type DigestsCataloger struct { hashes []crypto.Hash } -func init() { - for _, h := range []crypto.Hash{ - crypto.MD5, - crypto.SHA1, - crypto.SHA256, - } { - supportedHashAlgorithms[cleanAlgorithmName(h.String())] = h - } -} - -func NewDigestsCataloger(hashAlgorithms []string) (*DigestsCataloger, error) { - var hashes []crypto.Hash - for _, hashStr := range hashAlgorithms { - name := cleanAlgorithmName(hashStr) - hashObj, ok := supportedHashAlgorithms[name] - if !ok { - return nil, fmt.Errorf("unsupported hash algorithm: %s", hashStr) - } - hashes = append(hashes, hashObj) - } - +func NewDigestsCataloger(hashes []crypto.Hash) (*DigestsCataloger, error) { return &DigestsCataloger{ hashes: hashes, }, nil @@ -84,7 +62,7 @@ func (i *DigestsCataloger) catalogLocation(resolver source.FileResolver, locatio // file type but a body is still allowed. for idx, hasher := range hashers { result[idx] = Digest{ - Algorithm: cleanAlgorithmName(i.hashes[idx].String()), + Algorithm: DigestAlgorithmName(i.hashes[idx]), Value: fmt.Sprintf("%+x", hasher.Sum(nil)), } } @@ -92,7 +70,11 @@ func (i *DigestsCataloger) catalogLocation(resolver source.FileResolver, locatio return result, nil } -func cleanAlgorithmName(name string) string { +func DigestAlgorithmName(hash crypto.Hash) string { + return CleanDigestAlgorithmName(hash.String()) +} + +func CleanDigestAlgorithmName(name string) string { lower := strings.ToLower(name) return strings.Replace(lower, "-", "", -1) } diff --git a/syft/file/digest_cataloger_test.go b/syft/file/digest_cataloger_test.go index 7f4516d43..526b79359 100644 --- a/syft/file/digest_cataloger_test.go +++ b/syft/file/digest_cataloger_test.go @@ -33,7 +33,7 @@ func testDigests(t testing.TB, files []string, hashes ...crypto.Hash) map[source h := hash.New() h.Write(b) digests[source.NewLocation(f)] = append(digests[source.NewLocation(f)], Digest{ - Algorithm: cleanAlgorithmName(hash.String()), + Algorithm: CleanDigestAlgorithmName(hash.String()), Value: fmt.Sprintf("%x", h.Sum(nil)), }) } @@ -46,40 +46,27 @@ func TestDigestsCataloger_SimpleContents(t *testing.T) { regularFiles := []string{"test-fixtures/last/path.txt", "test-fixtures/another-path.txt", "test-fixtures/a-path.txt"} tests := []struct { - name string - algorithms []string - files []string - expected map[source.Location][]Digest - constructorErr bool - catalogErr bool + name string + digests []crypto.Hash + files []string + expected map[source.Location][]Digest + catalogErr bool }{ { - name: "bad algorithm", - algorithms: []string{"sha-nothing"}, - files: regularFiles, - constructorErr: true, + name: "md5", + digests: []crypto.Hash{crypto.MD5}, + files: regularFiles, + expected: testDigests(t, regularFiles, crypto.MD5), }, { - name: "unsupported algorithm", - algorithms: []string{"sha512"}, - files: regularFiles, - constructorErr: true, - }, - { - name: "md5", - algorithms: []string{"md5"}, - files: regularFiles, - expected: testDigests(t, regularFiles, crypto.MD5), - }, - { - name: "md5-sha1-sha256", - algorithms: []string{"md5", "sha1", "sha256"}, - files: regularFiles, - expected: testDigests(t, regularFiles, crypto.MD5, crypto.SHA1, crypto.SHA256), + name: "md5-sha1-sha256", + digests: []crypto.Hash{crypto.MD5, crypto.SHA1, crypto.SHA256}, + files: regularFiles, + expected: testDigests(t, regularFiles, crypto.MD5, crypto.SHA1, crypto.SHA256), }, { name: "directory returns error", - algorithms: []string{"md5"}, + digests: []crypto.Hash{crypto.MD5}, files: []string{"test-fixtures/last"}, catalogErr: true, }, @@ -87,13 +74,9 @@ func TestDigestsCataloger_SimpleContents(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - c, err := NewDigestsCataloger(test.algorithms) - if err != nil && !test.constructorErr { - t.Fatalf("could not create cataloger (but should have been able to): %+v", err) - } else if err == nil && test.constructorErr { - t.Fatalf("expected constructor error but did not get one") - } else if test.constructorErr && err != nil { - return + c, err := NewDigestsCataloger(test.digests) + if err != nil { + t.Fatalf("could not create cataloger: %+v", err) } resolver := source.NewMockResolverForPaths(test.files...) @@ -161,7 +144,7 @@ func TestDigestsCataloger_MixFileTypes(t *testing.T) { for _, test := range tests { t.Run(test.path, func(t *testing.T) { - c, err := NewDigestsCataloger([]string{"md5"}) + c, err := NewDigestsCataloger([]crypto.Hash{crypto.MD5}) if err != nil { t.Fatalf("unable to get cataloger: %+v", err) }