From 548a8fe91e3b47a20eba48a417233aea35bbc3c8 Mon Sep 17 00:00:00 2001 From: Keith Zantow Date: Thu, 1 Sep 2022 08:44:44 -0400 Subject: [PATCH] Add RPM file scanning support Signed-off-by: Keith Zantow --- .github/workflows/validations.yaml | 10 ++ Makefile | 7 + go.mod | 2 + go.sum | 5 + syft/pkg/cataloger/cataloger.go | 11 +- .../cataloger.go => rpm/db_cataloger.go} | 21 +-- syft/pkg/cataloger/rpm/file_cataloger.go | 141 ++++++++++++++++++ syft/pkg/cataloger/rpm/file_cataloger_test.go | 109 ++++++++++++++ .../cataloger/{rpmdb => rpm}/parse_rpmdb.go | 4 +- .../{rpmdb => rpm}/parse_rpmdb_test.go | 6 +- .../{rpmdb => rpm}/parse_rpmmanifest.go | 4 +- .../{rpmdb => rpm}/parse_rpmmanifest_test.go | 10 +- .../cataloger/rpm/test-fixtures/.gitignore | 2 + syft/pkg/cataloger/rpm/test-fixtures/Makefile | 21 +++ .../{rpmdb => rpm}/test-fixtures/Packages | Bin .../test-fixtures/container-manifest-2 | 0 .../test-fixtures/generate-fixture.sh | 0 17 files changed, 327 insertions(+), 26 deletions(-) rename syft/pkg/cataloger/{rpmdb/cataloger.go => rpm/db_cataloger.go} (79%) create mode 100644 syft/pkg/cataloger/rpm/file_cataloger.go create mode 100644 syft/pkg/cataloger/rpm/file_cataloger_test.go rename syft/pkg/cataloger/{rpmdb => rpm}/parse_rpmdb.go (98%) rename syft/pkg/cataloger/{rpmdb => rpm}/parse_rpmdb_test.go (98%) rename syft/pkg/cataloger/{rpmdb => rpm}/parse_rpmmanifest.go (98%) rename syft/pkg/cataloger/{rpmdb => rpm}/parse_rpmmanifest_test.go (94%) create mode 100644 syft/pkg/cataloger/rpm/test-fixtures/.gitignore create mode 100644 syft/pkg/cataloger/rpm/test-fixtures/Makefile rename syft/pkg/cataloger/{rpmdb => rpm}/test-fixtures/Packages (100%) rename syft/pkg/cataloger/{rpmdb => rpm}/test-fixtures/container-manifest-2 (100%) rename syft/pkg/cataloger/{rpmdb => rpm}/test-fixtures/generate-fixture.sh (100%) diff --git a/.github/workflows/validations.yaml b/.github/workflows/validations.yaml index fd5baa7e492a..b01a2d8299cf 100644 --- a/.github/workflows/validations.yaml +++ b/.github/workflows/validations.yaml @@ -95,6 +95,16 @@ jobs: path: syft/pkg/cataloger/java/test-fixtures/java-builds/packages key: ${{ runner.os }}-unit-java-cache-${{ hashFiles( 'syft/pkg/cataloger/java/test-fixtures/java-builds/packages.fingerprint' ) }} + - name: Build cache key for rpm test-fixture blobs (for unit tests) + run: make rpm-binaries-fingerprint + + - name: Restore RPM test-fixture cache + id: unit-rpm-cache + uses: actions/cache@v2.1.3 + with: + path: syft/pkg/cataloger/rpm/test-fixtures/rpms + key: ${{ runner.os }}-unit-rpm-cache-${{ hashFiles( 'syft/pkg/cataloger/rpm/test-fixtures/rpms.fingerprint' ) }} + - name: Build cache key for go binary test-fixture blobs (for unit tests) run: make go-binaries-fingerprint diff --git a/Makefile b/Makefile index 9706a5d46dd7..f7091a648313 100644 --- a/Makefile +++ b/Makefile @@ -226,10 +226,17 @@ go-binaries-fingerprint: cd syft/pkg/cataloger/golang/test-fixtures/archs && \ make binaries.fingerprint +.PHONY: rpm-binaries-fingerprint +rpm-binaries-fingerprint: + $(call title,RPM binary test fixture fingerprint) + cd syft/pkg/cataloger/rpm/test-fixtures && \ + make rpms.fingerprint + .PHONY: fixtures fixtures: $(call title,Generating test fixtures) cd syft/pkg/cataloger/java/test-fixtures/java-builds && make + cd syft/pkg/cataloger/rpm/test-fixtures && make .PHONY: generate-json-schema generate-json-schema: ## Generate a new json schema diff --git a/go.mod b/go.mod index 293eee28d593..11b64061b497 100644 --- a/go.mod +++ b/go.mod @@ -60,6 +60,7 @@ require ( github.com/google/go-containerregistry v0.11.0 github.com/in-toto/in-toto-golang v0.3.4-0.20220709202702-fa494aaa0add github.com/knqyf263/go-rpmdb v0.0.0-20220629110411-9a3bd2ebb923 + github.com/sassoftware/go-rpmutils v0.2.0 github.com/sigstore/cosign v1.11.1 github.com/sigstore/rekor v0.11.0 github.com/sigstore/sigstore v1.4.0 @@ -79,6 +80,7 @@ require ( github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect github.com/Azure/go-autorest/logger v0.2.1 // indirect github.com/Azure/go-autorest/tracing v0.6.0 // indirect + github.com/DataDog/zstd v1.4.5 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver/v3 v3.1.1 // indirect github.com/Microsoft/go-winio v0.5.2 // indirect diff --git a/go.sum b/go.sum index 22c760db9235..acc61d985e33 100644 --- a/go.sum +++ b/go.sum @@ -147,6 +147,8 @@ github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbi github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/CycloneDX/cyclonedx-go v0.5.2 h1:CkdGw2R/tZWmEbSypJVZG+3+2SAsDjJirfIrG/RbIVg= github.com/CycloneDX/cyclonedx-go v0.5.2/go.mod h1:nQCiF4Tvrg5Ieu8qPhYMvzPGMu5I7fANZkrSsJjl5mg= +github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= +github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs= github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20191009163259-e802c2cb94ae/go.mod h1:mjwGPas4yKduTyubHvD1Atl9r1rUq8DfVy+gkVvZ+oo= github.com/GoogleCloudPlatform/docker-credential-gcr v2.0.5+incompatible/go.mod h1:BB1eHdMLYEFuFdBlRMb0N7YGVdM5s6Pt0njxgvfbGGs= @@ -1190,6 +1192,7 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.11.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg= github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= @@ -1611,6 +1614,8 @@ github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0 github.com/sanposhiho/wastedassign/v2 v2.0.6/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI= github.com/sassoftware/go-rpmutils v0.0.0-20190420191620-a8f1baeba37b/go.mod h1:am+Fp8Bt506lA3Rk3QCmSqmYmLMnPDhdDUcosQCAx+I= github.com/sassoftware/go-rpmutils v0.1.1/go.mod h1:euhXULoBpvAxqrBHEyJS4Tsu3hHxUmQWNymxoJbzgUY= +github.com/sassoftware/go-rpmutils v0.2.0 h1:pKW0HDYMFWQ5b4JQPiI3WI12hGsVoW0V8+GMoZiI/JE= +github.com/sassoftware/go-rpmutils v0.2.0/go.mod h1:TJJQYtLe/BeEmEjelI3b7xNZjzAukEkeWKmoakvaOoI= github.com/sassoftware/relic v0.0.0-20210427151427-dfb082b79b74 h1:sUNzanSKA9z/h8xXl+ZJoxIYZL0Qx306MmxqRrvUgr0= github.com/sassoftware/relic v0.0.0-20210427151427-dfb082b79b74/go.mod h1:YlB8wFIZmFLZ1JllNBfSURzz52fBxbliNgYALk1UDmk= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= diff --git a/syft/pkg/cataloger/cataloger.go b/syft/pkg/cataloger/cataloger.go index 3170c70ea15e..57ad5390f692 100644 --- a/syft/pkg/cataloger/cataloger.go +++ b/syft/pkg/cataloger/cataloger.go @@ -24,7 +24,7 @@ import ( "github.com/anchore/syft/syft/pkg/cataloger/php" "github.com/anchore/syft/syft/pkg/cataloger/portage" "github.com/anchore/syft/syft/pkg/cataloger/python" - "github.com/anchore/syft/syft/pkg/cataloger/rpmdb" + "github.com/anchore/syft/syft/pkg/cataloger/rpm" "github.com/anchore/syft/syft/pkg/cataloger/ruby" "github.com/anchore/syft/syft/pkg/cataloger/rust" "github.com/anchore/syft/syft/pkg/cataloger/swift" @@ -54,7 +54,8 @@ func ImageCatalogers(cfg Config) []Cataloger { php.NewPHPComposerInstalledCataloger(), javascript.NewJavascriptPackageCataloger(), deb.NewDpkgdbCataloger(), - rpmdb.NewRpmdbCataloger(), + rpm.NewRpmdbCataloger(), + rpm.NewFileCataloger(), java.NewJavaCataloger(cfg.Java()), apkdb.NewApkdbCataloger(), golang.NewGoModuleBinaryCataloger(), @@ -73,7 +74,8 @@ func DirectoryCatalogers(cfg Config) []Cataloger { php.NewPHPComposerLockCataloger(), javascript.NewJavascriptLockCataloger(), deb.NewDpkgdbCataloger(), - rpmdb.NewRpmdbCataloger(), + rpm.NewRpmdbCataloger(), + rpm.NewFileCataloger(), java.NewJavaCataloger(cfg.Java()), java.NewJavaPomCataloger(), apkdb.NewApkdbCataloger(), @@ -100,7 +102,8 @@ func AllCatalogers(cfg Config) []Cataloger { javascript.NewJavascriptLockCataloger(), javascript.NewJavascriptPackageCataloger(), deb.NewDpkgdbCataloger(), - rpmdb.NewRpmdbCataloger(), + rpm.NewRpmdbCataloger(), + rpm.NewFileCataloger(), java.NewJavaCataloger(cfg.Java()), java.NewJavaPomCataloger(), apkdb.NewApkdbCataloger(), diff --git a/syft/pkg/cataloger/rpmdb/cataloger.go b/syft/pkg/cataloger/rpm/db_cataloger.go similarity index 79% rename from syft/pkg/cataloger/rpmdb/cataloger.go rename to syft/pkg/cataloger/rpm/db_cataloger.go index 67425802bbb2..6d39b1da5fb9 100644 --- a/syft/pkg/cataloger/rpmdb/cataloger.go +++ b/syft/pkg/cataloger/rpm/db_cataloger.go @@ -1,7 +1,8 @@ /* -Package rpmdb provides a concrete Cataloger implementation for RPM "Package" DB files. +Package rpm provides a concrete DBCataloger implementation for RPM "Package" DB files +and a FileCataloger for RPM files. */ -package rpmdb +package rpm import ( "fmt" @@ -13,27 +14,27 @@ import ( "github.com/anchore/syft/syft/source" ) -const catalogerName = "rpmdb-cataloger" +const dbCatalogerName = "rpmdb-cataloger" -type Cataloger struct{} +type DBCataloger struct{} // NewRpmdbCataloger returns a new RPM DB cataloger object. -func NewRpmdbCataloger() *Cataloger { - return &Cataloger{} +func NewRpmdbCataloger() *DBCataloger { + return &DBCataloger{} } // Name returns a string that uniquely describes a cataloger -func (c *Cataloger) Name() string { - return catalogerName +func (c *DBCataloger) Name() string { + return dbCatalogerName } // UsesExternalSources indicates that the rpmdb cataloger does not use external sources -func (c *Cataloger) UsesExternalSources() bool { +func (c *DBCataloger) UsesExternalSources() bool { return false } // Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing rpm db installation. -func (c *Cataloger) Catalog(resolver source.FileResolver) ([]pkg.Package, []artifact.Relationship, error) { +func (c *DBCataloger) Catalog(resolver source.FileResolver) ([]pkg.Package, []artifact.Relationship, error) { fileMatches, err := resolver.FilesByGlob(pkg.RpmDBGlob) if err != nil { return nil, nil, fmt.Errorf("failed to find rpmdb's by glob: %w", err) diff --git a/syft/pkg/cataloger/rpm/file_cataloger.go b/syft/pkg/cataloger/rpm/file_cataloger.go new file mode 100644 index 000000000000..a3b5221ac6f2 --- /dev/null +++ b/syft/pkg/cataloger/rpm/file_cataloger.go @@ -0,0 +1,141 @@ +package rpm + +import ( + "fmt" + "strconv" + "strings" + + "github.com/anchore/syft/internal" + "github.com/anchore/syft/syft/file" + rpmdb "github.com/knqyf263/go-rpmdb/pkg" + "github.com/sassoftware/go-rpmutils" + + "github.com/anchore/syft/syft/artifact" + "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/source" +) + +type FileCataloger struct{} + +// NewFileCataloger returns a new RPM file cataloger object. +func NewFileCataloger() *FileCataloger { + return &FileCataloger{} +} + +// Name returns a string that uniquely describes a cataloger +func (c *FileCataloger) Name() string { + return "rpm-file-cataloger" +} + +// UsesExternalSources indicates that the rpmdb cataloger does not use external sources +func (c *FileCataloger) UsesExternalSources() bool { + return false +} + +// Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing rpm files +func (c *FileCataloger) Catalog(resolver source.FileResolver) ([]pkg.Package, []artifact.Relationship, error) { + fileMatches, err := resolver.FilesByGlob("**/*.rpm") + if err != nil { + return nil, nil, fmt.Errorf("failed to find rpm files's by glob: %w", err) + } + + var pkgs []pkg.Package + for _, location := range fileMatches { + dbContentReader, err := resolver.FileContentsByLocation(location) + if err != nil { + return nil, nil, err + } + + rpm, err := rpmutils.ReadRpm(dbContentReader) + if err != nil { + return nil, nil, err + } + + nevra, err := rpm.Header.GetNEVRA() + if err != nil { + return nil, nil, err + } + + licenses, _ := rpm.Header.GetStrings(rpmutils.LICENSE) + sourceRpm, _ := rpm.Header.GetString(rpmutils.SOURCERPM) + vendor, _ := rpm.Header.GetString(rpmutils.VENDOR) + digestAlgorithm := getDigestAlgorithm(rpm.Header) + size, _ := rpm.Header.InstalledSize() + files, _ := rpm.Header.GetFiles() + + p := pkg.Package{ + Name: nevra.Name, + Version: nevra.Version, + FoundBy: c.Name(), + Licenses: licenses, + Locations: source.NewLocationSet(location), + Type: pkg.RpmPkg, + MetadataType: pkg.RpmdbMetadataType, + Metadata: pkg.RpmdbMetadata{ + Name: nevra.Name, + Version: nevra.Version, + Epoch: parseEpoch(nevra.Epoch), + Arch: nevra.Arch, + Release: nevra.Release, + SourceRpm: sourceRpm, + Vendor: vendor, + License: strings.Join(licenses, " AND "), + Size: int(size), + Files: mapFiles(files, digestAlgorithm), + }, + } + p.SetID() + pkgs = append(pkgs, p) + + internal.CloseAndLogError(dbContentReader, location.VirtualPath) + if err != nil { + return nil, nil, fmt.Errorf("unable to catalog rpm file=%+v: %w", location.RealPath, err) + } + } + + return pkgs, nil, nil +} + +func getDigestAlgorithm(header *rpmutils.RpmHeader) string { + digestAlgorithm, _ := header.GetString(rpmutils.FILEDIGESTALGO) + if digestAlgorithm != "" { + return digestAlgorithm + } + digestAlgorithms, _ := header.GetUint32s(rpmutils.FILEDIGESTALGO) + if len(digestAlgorithms) > 0 { + digestAlgo := int(digestAlgorithms[0]) + return rpmutils.GetFileAlgoName(digestAlgo) + } + return "" +} + +func mapFiles(files []rpmutils.FileInfo, digestAlgorithm string) []pkg.RpmdbFileRecord { + var out []pkg.RpmdbFileRecord + for _, f := range files { + digest := file.Digest{} + if f.Digest() != "" { + digest = file.Digest{ + Algorithm: digestAlgorithm, + Value: f.Digest(), + } + } + out = append(out, pkg.RpmdbFileRecord{ + Path: f.Name(), + Mode: pkg.RpmdbFileMode(f.Mode()), + Size: int(f.Size()), + Digest: digest, + UserName: f.UserName(), + GroupName: f.GroupName(), + Flags: rpmdb.FileFlags(f.Flags()).String(), + }) + } + return out +} + +func parseEpoch(epoch string) *int { + i, err := strconv.Atoi(epoch) + if err != nil { + return nil + } + return &i +} diff --git a/syft/pkg/cataloger/rpm/file_cataloger_test.go b/syft/pkg/cataloger/rpm/file_cataloger_test.go new file mode 100644 index 000000000000..40cb2b3a3d16 --- /dev/null +++ b/syft/pkg/cataloger/rpm/file_cataloger_test.go @@ -0,0 +1,109 @@ +package rpm + +import ( + "github.com/anchore/syft/syft/file" + "testing" + + "github.com/go-test/deep" + "github.com/stretchr/testify/require" + + "github.com/anchore/syft/syft/pkg" + "github.com/anchore/syft/syft/source" +) + +func TestParseRpmFiles(t *testing.T) { + tests := []struct { + fixture string + expected map[string]pkg.Package + ignorePaths bool + }{ + { + fixture: "test-fixtures/rpms", + // we only surface package paths for files that exist (here we DO NOT expect a path) + ignorePaths: true, + expected: map[string]pkg.Package{ + "abc": { + Name: "abc", + Version: "1.01", + Locations: source.NewLocationSet(), + FoundBy: "rpm-file-cataloger", + Type: pkg.RpmPkg, + MetadataType: pkg.RpmdbMetadataType, + Licenses: []string{"MIT"}, + Metadata: pkg.RpmdbMetadata{ + Name: "abc", + Epoch: intRef(0), + Arch: "x86_64", + Release: "9.hg20160905.el7", + Version: "1.01", + SourceRpm: "abc-1.01-9.hg20160905.el7.src.rpm", + Size: 17396, + License: "MIT", + Vendor: "Fedora Project", + Files: []pkg.RpmdbFileRecord{ + {"/usr/bin/abc", 33261, 7120, file.Digest{"sha256", "8f8495a65c66762b60afa0c3949d81b275ca6fa0601696caba5af762f455d0b9"}, "root", "root", ""}, + {"/usr/share/doc/abc-1.01", 16877, 4096, file.Digest{}, "root", "root", ""}, + {"/usr/share/doc/abc-1.01/readme.md", 33188, 4984, file.Digest{"sha256", "808af8a28391e96ca0d91086789488dda3724fe7c8b2859efd464fb04b94b2d4"}, "root", "root", "d"}, + {"/usr/share/doc/abc-1.01/readmeaig", 33188, 3324, file.Digest{"sha256", "530ec6175cf7fbeb7b595cbe7a50994429c4e62cae6666fb3a1d5745f3127b19"}, "root", "root", "d"}, + {"/usr/share/man/man1/abc.1.gz", 33188, 1968, file.Digest{"sha256", "cf2cfe25b29087e60ffd5f31f974a0762172fc2f009704951f12ff750ea77ed6"}, "root", "root", "d"}, + }, + }, + }, + "zork": { + Name: "zork", + Version: "1.0.3", + Locations: source.NewLocationSet(), + FoundBy: "rpm-file-cataloger", + Type: pkg.RpmPkg, + MetadataType: pkg.RpmdbMetadataType, + Licenses: []string{"Public Domain"}, + Metadata: pkg.RpmdbMetadata{ + Name: "zork", + Epoch: intRef(0), + Arch: "x86_64", + Release: "1.el7", + Version: "1.0.3", + SourceRpm: "zork-1.0.3-1.el7.src.rpm", + Size: 262367, + License: "Public Domain", + Vendor: "Fedora Project", + Files: []pkg.RpmdbFileRecord{ + {"/usr/bin/zork", 33261, 115440, file.Digest{"sha256", "31b2ffc20b676a8fff795a45308f584273b9c47e8f7e196b4f36220b2734b472"}, "root", "root", ""}, + {"/usr/share/doc/zork-1.0.3", 16877, 38, file.Digest{}, "root", "root", ""}, + {"/usr/share/doc/zork-1.0.3/README.md", 33188, 5123, file.Digest{"sha256", "0013d67610a80c9f62d151a952f18d520b15b4c505b3ec2af34b96ab824654a4"}, "root", "root", "d"}, + {"/usr/share/doc/zork-1.0.3/history", 33188, 4816, file.Digest{"sha256", "6949044a65adefca6ac0132c18cfccc4ba8fdaec948424b6ccb60afd8a6ac82f"}, "root", "root", "d"}, + {"/usr/share/licenses/zork-1.0.3", 16877, 24, file.Digest{}, "root", "root", ""}, + {"/usr/share/licenses/zork-1.0.3/readme.txt", 33188, 146, file.Digest{"sha256", "9d6f7500555a2ecc3cb289dcca1e37fb96894dab1e4ba692b4d36fd6c3bdf939"}, "root", "root", "l"}, + {"/usr/share/man/man6/dungeon.6.gz", 33188, 3800, file.Digest{"sha256", "9b065d6a6f65b4d2d038fcca0af47a38e8723c32008d08659739ac34abe018da"}, "root", "root", "d"}, + {"/usr/share/man/man6/zork.6.gz", 33188, 34, file.Digest{"sha256", "18fbcb598bc40a25befe26256e29366984d2288dd154f877b8ac5fc138dd0884"}, "root", "root", "d"}, + {"/usr/share/zork/dtextc.dat", 33188, 133008, file.Digest{"sha256", "25ca42857c2b32054916d9258152293ead644023d5e03bec039ea92014e2ef91"}, "root", "root", ""}, + }, + }, + }, + }, + }, + } + + for _, test := range tests { + t.Run(test.fixture, func(t *testing.T) { + s, err := source.NewFromDirectory(test.fixture) + require.NoError(t, err) + + r, err := s.FileResolver(source.SquashedScope) + require.NoError(t, err) + + packages, _, err := NewFileCataloger().Catalog(r) + require.NoError(t, err) + + for _, a := range packages { + e := test.expected[a.Name] + diffs := deep.Equal(e, a) + if len(diffs) > 0 { + for _, d := range diffs { + t.Errorf("diff: %+v", d) + } + } + } + }) + } +} diff --git a/syft/pkg/cataloger/rpmdb/parse_rpmdb.go b/syft/pkg/cataloger/rpm/parse_rpmdb.go similarity index 98% rename from syft/pkg/cataloger/rpmdb/parse_rpmdb.go rename to syft/pkg/cataloger/rpm/parse_rpmdb.go index d3ec6e2059fc..80404be19709 100644 --- a/syft/pkg/cataloger/rpmdb/parse_rpmdb.go +++ b/syft/pkg/cataloger/rpm/parse_rpmdb.go @@ -1,4 +1,4 @@ -package rpmdb +package rpm import ( "fmt" @@ -86,7 +86,7 @@ func newPkg(resolver source.FilePathResolver, dbLocation source.Location, entry Name: entry.Name, Version: toELVersion(metadata), Locations: source.NewLocationSet(dbLocation), - FoundBy: catalogerName, + FoundBy: dbCatalogerName, Type: pkg.RpmPkg, MetadataType: pkg.RpmdbMetadataType, Metadata: metadata, diff --git a/syft/pkg/cataloger/rpmdb/parse_rpmdb_test.go b/syft/pkg/cataloger/rpm/parse_rpmdb_test.go similarity index 98% rename from syft/pkg/cataloger/rpmdb/parse_rpmdb_test.go rename to syft/pkg/cataloger/rpm/parse_rpmdb_test.go index 659c6d89819a..7c9d787fc0fd 100644 --- a/syft/pkg/cataloger/rpmdb/parse_rpmdb_test.go +++ b/syft/pkg/cataloger/rpm/parse_rpmdb_test.go @@ -1,4 +1,4 @@ -package rpmdb +package rpm import ( "fmt" @@ -72,7 +72,7 @@ func TestParseRpmDB(t *testing.T) { Name: "dive", Version: "0.9.2-1", Locations: source.NewLocationSet(dbLocation), - FoundBy: catalogerName, + FoundBy: dbCatalogerName, Type: pkg.RpmPkg, MetadataType: pkg.RpmdbMetadataType, Licenses: []string{"MIT"}, @@ -100,7 +100,7 @@ func TestParseRpmDB(t *testing.T) { Name: "dive", Version: "0.9.2-1", Locations: source.NewLocationSet(dbLocation), - FoundBy: catalogerName, + FoundBy: dbCatalogerName, Type: pkg.RpmPkg, MetadataType: pkg.RpmdbMetadataType, Licenses: []string{"MIT"}, diff --git a/syft/pkg/cataloger/rpmdb/parse_rpmmanifest.go b/syft/pkg/cataloger/rpm/parse_rpmmanifest.go similarity index 98% rename from syft/pkg/cataloger/rpmdb/parse_rpmmanifest.go rename to syft/pkg/cataloger/rpm/parse_rpmmanifest.go index 5897ba8bef33..f758c679cda8 100644 --- a/syft/pkg/cataloger/rpmdb/parse_rpmmanifest.go +++ b/syft/pkg/cataloger/rpm/parse_rpmmanifest.go @@ -1,4 +1,4 @@ -package rpmdb +package rpm import ( "bufio" @@ -58,7 +58,7 @@ func parseRpmManifestEntry(entry string, location source.Location) (*pkg.Package Name: parts[0], Version: toELVersion(metadata), Locations: source.NewLocationSet(location), - FoundBy: catalogerName, + FoundBy: dbCatalogerName, Type: pkg.RpmPkg, MetadataType: pkg.RpmdbMetadataType, Metadata: metadata, diff --git a/syft/pkg/cataloger/rpmdb/parse_rpmmanifest_test.go b/syft/pkg/cataloger/rpm/parse_rpmmanifest_test.go similarity index 94% rename from syft/pkg/cataloger/rpmdb/parse_rpmmanifest_test.go rename to syft/pkg/cataloger/rpm/parse_rpmmanifest_test.go index 13ca05abd16a..8483c0f6ef80 100644 --- a/syft/pkg/cataloger/rpmdb/parse_rpmmanifest_test.go +++ b/syft/pkg/cataloger/rpm/parse_rpmmanifest_test.go @@ -1,4 +1,4 @@ -package rpmdb +package rpm import ( "os" @@ -18,7 +18,7 @@ func TestParseRpmManifest(t *testing.T) { Name: "mariner-release", Version: "2.0-12.cm2", Locations: source.NewLocationSet(location), - FoundBy: catalogerName, + FoundBy: dbCatalogerName, Type: pkg.RpmPkg, MetadataType: pkg.RpmdbMetadataType, Metadata: pkg.RpmdbMetadata{ @@ -36,7 +36,7 @@ func TestParseRpmManifest(t *testing.T) { Name: "filesystem", Version: "1.1-9.cm2", Locations: source.NewLocationSet(location), - FoundBy: catalogerName, + FoundBy: dbCatalogerName, Type: pkg.RpmPkg, MetadataType: pkg.RpmdbMetadataType, Metadata: pkg.RpmdbMetadata{ @@ -54,7 +54,7 @@ func TestParseRpmManifest(t *testing.T) { Name: "glibc", Version: "2.35-2.cm2", Locations: source.NewLocationSet(location), - FoundBy: catalogerName, + FoundBy: dbCatalogerName, Type: pkg.RpmPkg, MetadataType: pkg.RpmdbMetadataType, Metadata: pkg.RpmdbMetadata{ @@ -72,7 +72,7 @@ func TestParseRpmManifest(t *testing.T) { Name: "openssl-libs", Version: "1.1.1k-15.cm2", Locations: source.NewLocationSet(location), - FoundBy: catalogerName, + FoundBy: dbCatalogerName, Type: pkg.RpmPkg, MetadataType: pkg.RpmdbMetadataType, Metadata: pkg.RpmdbMetadata{ diff --git a/syft/pkg/cataloger/rpm/test-fixtures/.gitignore b/syft/pkg/cataloger/rpm/test-fixtures/.gitignore new file mode 100644 index 000000000000..5eae26881b9a --- /dev/null +++ b/syft/pkg/cataloger/rpm/test-fixtures/.gitignore @@ -0,0 +1,2 @@ +/rpms/* +*.fingerprint diff --git a/syft/pkg/cataloger/rpm/test-fixtures/Makefile b/syft/pkg/cataloger/rpm/test-fixtures/Makefile new file mode 100644 index 000000000000..e280d5e60e7b --- /dev/null +++ b/syft/pkg/cataloger/rpm/test-fixtures/Makefile @@ -0,0 +1,21 @@ +RPMSDIR=rpms + +ifndef RPMSDIR + $(error RPMSDIR is not set) +endif + +all: rpms + +clean: + rm -rf $(RPMSDIR) + +rpms: + mkdir -p $(RPMSDIR) + cd $(RPMSDIR) && curl https://dl.fedoraproject.org/pub/epel/7/x86_64/Packages/a/abc-1.01-9.hg20160905.el7.x86_64.rpm -O + cd $(RPMSDIR) && curl https://dl.fedoraproject.org/pub/epel/7/x86_64/Packages/z/zork-1.0.3-1.el7.x86_64.rpm -O + +# we need a way to determine if CI should bust the test cache based on the source material +.PHONY: $(RPMSDIR).fingerprint +$(RPMSDIR).fingerprint: + find Makefile -type f -exec sha256sum {} \; | sort | tee /dev/stderr | tee $(RPMSDIR).fingerprint + sha256sum $(RPMSDIR).fingerprint diff --git a/syft/pkg/cataloger/rpmdb/test-fixtures/Packages b/syft/pkg/cataloger/rpm/test-fixtures/Packages similarity index 100% rename from syft/pkg/cataloger/rpmdb/test-fixtures/Packages rename to syft/pkg/cataloger/rpm/test-fixtures/Packages diff --git a/syft/pkg/cataloger/rpmdb/test-fixtures/container-manifest-2 b/syft/pkg/cataloger/rpm/test-fixtures/container-manifest-2 similarity index 100% rename from syft/pkg/cataloger/rpmdb/test-fixtures/container-manifest-2 rename to syft/pkg/cataloger/rpm/test-fixtures/container-manifest-2 diff --git a/syft/pkg/cataloger/rpmdb/test-fixtures/generate-fixture.sh b/syft/pkg/cataloger/rpm/test-fixtures/generate-fixture.sh similarity index 100% rename from syft/pkg/cataloger/rpmdb/test-fixtures/generate-fixture.sh rename to syft/pkg/cataloger/rpm/test-fixtures/generate-fixture.sh