mirror of
https://github.com/anchore/syft
synced 2024-11-10 06:14:16 +00:00
Add RPM file scanning support (#1188)
This commit is contained in:
parent
1c7b7c5f8a
commit
70db13d49e
37 changed files with 470 additions and 108 deletions
10
.github/workflows/validations.yaml
vendored
10
.github/workflows/validations.yaml
vendored
|
@ -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
|
||||
|
||||
|
|
7
Makefile
7
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
|
||||
|
|
2
go.mod
2
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
|
||||
|
|
5
go.sum
5
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=
|
||||
|
|
|
@ -80,6 +80,8 @@ func decodeComponent(c *cyclonedx.Component) *pkg.Package {
|
|||
|
||||
common.DecodeInto(p, values, "syft:package", CycloneDXFields)
|
||||
|
||||
p.MetadataType = pkg.CleanMetadataType(p.MetadataType)
|
||||
|
||||
p.Metadata = decodePackageMetadata(values, c, p.MetadataType)
|
||||
|
||||
if p.Type == "" {
|
||||
|
|
|
@ -109,8 +109,8 @@ func Test_encodeComponentProperties(t *testing.T) {
|
|||
Name: "dive",
|
||||
Version: "0.9.2-1",
|
||||
Type: pkg.RpmPkg,
|
||||
MetadataType: pkg.RpmdbMetadataType,
|
||||
Metadata: pkg.RpmdbMetadata{
|
||||
MetadataType: pkg.RpmMetadataType,
|
||||
Metadata: pkg.RpmMetadata{
|
||||
Name: "dive",
|
||||
Epoch: &epoch,
|
||||
Arch: "x86_64",
|
||||
|
@ -124,7 +124,7 @@ func Test_encodeComponentProperties(t *testing.T) {
|
|||
},
|
||||
},
|
||||
expected: &[]cyclonedx.Property{
|
||||
{Name: "syft:package:metadataType", Value: "RpmdbMetadata"},
|
||||
{Name: "syft:package:metadataType", Value: "RpmMetadata"},
|
||||
{Name: "syft:package:type", Value: "rpm"},
|
||||
{Name: "syft:metadata:epoch", Value: "2"},
|
||||
{Name: "syft:metadata:release", Value: "1"},
|
||||
|
@ -193,29 +193,51 @@ func Test_deriveBomRef(t *testing.T) {
|
|||
}
|
||||
|
||||
func Test_decodeComponent(t *testing.T) {
|
||||
javaComponentWithNoSyftProperties := cyclonedx.Component{
|
||||
Name: "ch.qos.logback/logback-classic",
|
||||
Version: "1.2.3",
|
||||
PackageURL: "pkg:maven/ch.qos.logback/logback-classic@1.2.3",
|
||||
Type: "library",
|
||||
BOMRef: "pkg:maven/ch.qos.logback/logback-classic@1.2.3",
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
component cyclonedx.Component
|
||||
want pkg.Language
|
||||
name string
|
||||
component cyclonedx.Component
|
||||
wantLanguage pkg.Language
|
||||
wantMetadataType pkg.MetadataType
|
||||
}{
|
||||
{
|
||||
name: "derive language from pURL if missing",
|
||||
component: javaComponentWithNoSyftProperties,
|
||||
want: pkg.Java,
|
||||
name: "derive language from pURL if missing",
|
||||
component: cyclonedx.Component{
|
||||
Name: "ch.qos.logback/logback-classic",
|
||||
Version: "1.2.3",
|
||||
PackageURL: "pkg:maven/ch.qos.logback/logback-classic@1.2.3",
|
||||
Type: "library",
|
||||
BOMRef: "pkg:maven/ch.qos.logback/logback-classic@1.2.3",
|
||||
},
|
||||
wantLanguage: pkg.Java,
|
||||
},
|
||||
{
|
||||
name: "handle existing RpmdbMetadata type",
|
||||
component: cyclonedx.Component{
|
||||
Name: "acl",
|
||||
Version: "2.2.53-1.el8",
|
||||
PackageURL: "pkg:rpm/centos/acl@2.2.53-1.el8?arch=x86_64&upstream=acl-2.2.53-1.el8.src.rpm&distro=centos-8",
|
||||
Type: "library",
|
||||
BOMRef: "pkg:rpm/centos/acl@2.2.53-1.el8?arch=x86_64&upstream=acl-2.2.53-1.el8.src.rpm&distro=centos-8",
|
||||
Properties: &[]cyclonedx.Property{
|
||||
{
|
||||
Name: "syft:package:metadataType",
|
||||
Value: "RpmdbMetadata",
|
||||
},
|
||||
},
|
||||
},
|
||||
wantMetadataType: pkg.RpmMetadataType,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assert.Equal(t, tt.want, decodeComponent(&tt.component).Language)
|
||||
p := decodeComponent(&tt.component)
|
||||
if tt.wantLanguage != "" {
|
||||
assert.Equal(t, tt.wantLanguage, p.Language)
|
||||
}
|
||||
if tt.wantMetadataType != "" {
|
||||
assert.Equal(t, tt.wantMetadataType, p.MetadataType)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ func encodePublisher(p pkg.Package) string {
|
|||
switch metadata := p.Metadata.(type) {
|
||||
case pkg.ApkMetadata:
|
||||
return metadata.Maintainer
|
||||
case pkg.RpmdbMetadata:
|
||||
case pkg.RpmMetadata:
|
||||
return metadata.Vendor
|
||||
case pkg.DpkgMetadata:
|
||||
return metadata.Maintainer
|
||||
|
@ -22,7 +22,7 @@ func decodePublisher(publisher string, metadata interface{}) {
|
|||
switch meta := metadata.(type) {
|
||||
case *pkg.ApkMetadata:
|
||||
meta.Maintainer = publisher
|
||||
case *pkg.RpmdbMetadata:
|
||||
case *pkg.RpmMetadata:
|
||||
meta.Vendor = publisher
|
||||
case *pkg.DpkgMetadata:
|
||||
meta.Maintainer = publisher
|
||||
|
|
|
@ -31,7 +31,7 @@ func Test_encodePublisher(t *testing.T) {
|
|||
{
|
||||
name: "from rpm",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.RpmdbMetadata{
|
||||
Metadata: pkg.RpmMetadata{
|
||||
Vendor: "auth",
|
||||
},
|
||||
},
|
||||
|
|
|
@ -80,7 +80,7 @@ func Test_Originator(t *testing.T) {
|
|||
{
|
||||
name: "from rpm",
|
||||
input: pkg.Package{
|
||||
Metadata: pkg.RpmdbMetadata{
|
||||
Metadata: pkg.RpmMetadata{
|
||||
Vendor: "auth",
|
||||
},
|
||||
},
|
||||
|
|
|
@ -28,7 +28,7 @@ func Originator(p pkg.Package) string {
|
|||
if len(metadata.Authors) > 0 {
|
||||
author = metadata.Authors[0]
|
||||
}
|
||||
case pkg.RpmdbMetadata:
|
||||
case pkg.RpmMetadata:
|
||||
return "Organization: " + metadata.Vendor
|
||||
case pkg.DpkgMetadata:
|
||||
author = metadata.Maintainer
|
||||
|
|
|
@ -326,7 +326,7 @@ func extractMetadata(p *spdx.Package2_2, info pkgInfo) (pkg.MetadataType, interf
|
|||
if license == "" {
|
||||
license = p.PackageLicenseConcluded
|
||||
}
|
||||
return pkg.RpmdbMetadataType, pkg.RpmdbMetadata{
|
||||
return pkg.RpmMetadataType, pkg.RpmMetadata{
|
||||
Name: p.PackageName,
|
||||
Version: p.PackageVersion,
|
||||
Epoch: epoch,
|
||||
|
|
|
@ -176,8 +176,8 @@ func Test_extractMetadata(t *testing.T) {
|
|||
},
|
||||
},
|
||||
},
|
||||
metaType: pkg.RpmdbMetadataType,
|
||||
meta: pkg.RpmdbMetadata{
|
||||
metaType: pkg.RpmMetadataType,
|
||||
meta: pkg.RpmMetadata{
|
||||
Name: "SomeRpmPkg",
|
||||
Version: "13.2.79",
|
||||
Epoch: &oneTwoThreeFour,
|
||||
|
|
|
@ -74,7 +74,8 @@ func (p *Package) UnmarshalJSON(b []byte) error {
|
|||
|
||||
//nolint:funlen,gocognit,gocyclo
|
||||
func unpackMetadata(p *Package, unpacker packageMetadataUnpacker) error {
|
||||
p.MetadataType = unpacker.MetadataType
|
||||
p.MetadataType = pkg.CleanMetadataType(unpacker.MetadataType)
|
||||
|
||||
switch p.MetadataType {
|
||||
case "":
|
||||
// there is no metadata, skip
|
||||
|
@ -91,8 +92,8 @@ func unpackMetadata(p *Package, unpacker packageMetadataUnpacker) error {
|
|||
return err
|
||||
}
|
||||
p.Metadata = payload
|
||||
case pkg.RpmdbMetadataType:
|
||||
var payload pkg.RpmdbMetadata
|
||||
case pkg.RpmMetadataType:
|
||||
var payload pkg.RpmMetadata
|
||||
if err := json.Unmarshal(unpacker.Metadata, &payload); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -133,6 +133,45 @@ func Test_unpackMetadata(t *testing.T) {
|
|||
"purl": "pkg:golang/gopkg.in/square/go-jose.v2@v2.6.0"
|
||||
}`),
|
||||
},
|
||||
{
|
||||
name: "can handle RpmdbMetadata",
|
||||
metadataType: pkg.RpmMetadataType,
|
||||
packageData: []byte(`{
|
||||
"id": "4ac699c3b8fe1835",
|
||||
"name": "acl",
|
||||
"version": "2.2.53-1.el8",
|
||||
"type": "rpm",
|
||||
"foundBy": "rpm-db-cataloger",
|
||||
"locations": [
|
||||
{
|
||||
"path": "/var/lib/rpm/Packages",
|
||||
"layerID": "sha256:74ddd0ec08fa43d09f32636ba91a0a3053b02cb4627c35051aff89f853606b59"
|
||||
}
|
||||
],
|
||||
"licenses": [
|
||||
"GPLv2+"
|
||||
],
|
||||
"language": "",
|
||||
"cpes": [
|
||||
"cpe:2.3:a:centos:acl:2.2.53-1.el8:*:*:*:*:*:*:*",
|
||||
"cpe:2.3:a:acl:acl:2.2.53-1.el8:*:*:*:*:*:*:*"
|
||||
],
|
||||
"purl": "pkg:rpm/centos/acl@2.2.53-1.el8?arch=x86_64&upstream=acl-2.2.53-1.el8.src.rpm&distro=centos-8",
|
||||
"metadataType": "RpmdbMetadata",
|
||||
"metadata": {
|
||||
"name": "acl",
|
||||
"version": "2.2.53",
|
||||
"epoch": null,
|
||||
"architecture": "x86_64",
|
||||
"release": "1.el8",
|
||||
"sourceRpm": "acl-2.2.53-1.el8.src.rpm",
|
||||
"size": 205740,
|
||||
"license": "GPLv2+",
|
||||
"vendor": "CentOS",
|
||||
"modularityLabel": ""
|
||||
}
|
||||
}`),
|
||||
},
|
||||
{
|
||||
name: "bad metadata type is an error",
|
||||
metadataType: "BOGOSITY",
|
||||
|
|
|
@ -34,7 +34,7 @@ type artifactMetadataContainer struct {
|
|||
Java pkg.JavaMetadata
|
||||
Npm pkg.NpmPackageJSONMetadata
|
||||
Python pkg.PythonPackageMetadata
|
||||
Rpm pkg.RpmdbMetadata
|
||||
Rpm pkg.RpmMetadata
|
||||
Cargo pkg.CargoPackageMetadata
|
||||
Go pkg.GolangBinMetadata
|
||||
Php pkg.PhpComposerJSONMetadata
|
||||
|
|
|
@ -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"
|
||||
|
@ -52,7 +52,7 @@ func ImageCatalogers(cfg Config) []Cataloger {
|
|||
php.NewPHPComposerInstalledCataloger(),
|
||||
javascript.NewJavascriptPackageCataloger(),
|
||||
deb.NewDpkgdbCataloger(),
|
||||
rpmdb.NewRpmdbCataloger(),
|
||||
rpm.NewRpmdbCataloger(),
|
||||
java.NewJavaCataloger(cfg.Java()),
|
||||
apkdb.NewApkdbCataloger(),
|
||||
golang.NewGoModuleBinaryCataloger(),
|
||||
|
@ -71,7 +71,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(),
|
||||
|
@ -98,7 +99,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(),
|
||||
|
|
|
@ -89,7 +89,7 @@ func candidateVendors(p pkg.Package) []string {
|
|||
}
|
||||
|
||||
switch p.MetadataType {
|
||||
case pkg.RpmdbMetadataType:
|
||||
case pkg.RpmMetadataType:
|
||||
vendors.union(candidateVendorsForRPM(p))
|
||||
case pkg.GemMetadataType:
|
||||
vendors.union(candidateVendorsForRuby(p))
|
||||
|
|
|
@ -316,8 +316,8 @@ func TestGeneratePackageCPEs(t *testing.T) {
|
|||
Version: "3.2",
|
||||
FoundBy: "some-analyzer",
|
||||
Type: pkg.RpmPkg,
|
||||
MetadataType: pkg.RpmdbMetadataType,
|
||||
Metadata: pkg.RpmdbMetadata{
|
||||
MetadataType: pkg.RpmMetadataType,
|
||||
Metadata: pkg.RpmMetadata{
|
||||
Vendor: "some-vendor",
|
||||
},
|
||||
},
|
||||
|
@ -334,8 +334,8 @@ func TestGeneratePackageCPEs(t *testing.T) {
|
|||
Version: "1:3.2",
|
||||
FoundBy: "some-analyzer",
|
||||
Type: pkg.RpmPkg,
|
||||
MetadataType: pkg.RpmdbMetadataType,
|
||||
Metadata: pkg.RpmdbMetadata{
|
||||
MetadataType: pkg.RpmMetadataType,
|
||||
Metadata: pkg.RpmMetadata{
|
||||
Vendor: "some-vendor",
|
||||
},
|
||||
},
|
||||
|
|
|
@ -3,7 +3,7 @@ package cpe
|
|||
import "github.com/anchore/syft/syft/pkg"
|
||||
|
||||
func candidateVendorsForRPM(p pkg.Package) fieldCandidateSet {
|
||||
metadata, ok := p.Metadata.(pkg.RpmdbMetadata)
|
||||
metadata, ok := p.Metadata.(pkg.RpmMetadata)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -1,34 +1,34 @@
|
|||
/*
|
||||
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"
|
||||
|
||||
"github.com/anchore/syft/internal"
|
||||
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
const catalogerName = "rpmdb-cataloger"
|
||||
const dbCatalogerName = "rpm-db-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
|
||||
}
|
||||
|
||||
// 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)
|
136
syft/pkg/cataloger/rpm/file_cataloger.go
Normal file
136
syft/pkg/cataloger/rpm/file_cataloger.go
Normal file
|
@ -0,0 +1,136 @@
|
|||
package rpm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
rpmdb "github.com/knqyf263/go-rpmdb/pkg"
|
||||
"github.com/sassoftware/go-rpmutils"
|
||||
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/syft/artifact"
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"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"
|
||||
}
|
||||
|
||||
// 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 {
|
||||
contentReader, err := resolver.FileContentsByLocation(location)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
rpm, err := rpmutils.ReadRpm(contentReader)
|
||||
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.RpmMetadataType,
|
||||
Metadata: pkg.RpmMetadata{
|
||||
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(contentReader, 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
|
||||
}
|
106
syft/pkg/cataloger/rpm/file_cataloger_test.go
Normal file
106
syft/pkg/cataloger/rpm/file_cataloger_test.go
Normal file
|
@ -0,0 +1,106 @@
|
|||
package rpm
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/go-test/deep"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/anchore/syft/syft/file"
|
||||
"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
|
||||
}{
|
||||
{
|
||||
fixture: "test-fixtures/rpms",
|
||||
expected: map[string]pkg.Package{
|
||||
"abc": {
|
||||
Name: "abc",
|
||||
Version: "1.01",
|
||||
Locations: source.NewLocationSet(),
|
||||
FoundBy: "rpm-file-cataloger",
|
||||
Type: pkg.RpmPkg,
|
||||
MetadataType: pkg.RpmMetadataType,
|
||||
Licenses: []string{"MIT"},
|
||||
Metadata: pkg.RpmMetadata{
|
||||
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.RpmMetadataType,
|
||||
Licenses: []string{"Public Domain"},
|
||||
Metadata: pkg.RpmMetadata{
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package rpmdb
|
||||
package rpm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -68,7 +68,7 @@ func newPkg(resolver source.FilePathResolver, dbLocation source.Location, entry
|
|||
return nil, err
|
||||
}
|
||||
|
||||
metadata := pkg.RpmdbMetadata{
|
||||
metadata := pkg.RpmMetadata{
|
||||
Name: entry.Name,
|
||||
Version: entry.Version,
|
||||
Epoch: entry.Epoch,
|
||||
|
@ -86,9 +86,9 @@ 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,
|
||||
MetadataType: pkg.RpmMetadataType,
|
||||
Metadata: metadata,
|
||||
}
|
||||
|
||||
|
@ -106,7 +106,7 @@ func newPkg(resolver source.FilePathResolver, dbLocation source.Location, entry
|
|||
// version string, containing epoch (optional), version, and release information. Epoch is an optional field and can be
|
||||
// assumed to be 0 when not provided for comparison purposes, however, if the underlying RPM DB entry does not have
|
||||
// an epoch specified it would be slightly disingenuous to display a value of 0.
|
||||
func toELVersion(metadata pkg.RpmdbMetadata) string {
|
||||
func toELVersion(metadata pkg.RpmMetadata) string {
|
||||
if metadata.Epoch != nil {
|
||||
return fmt.Sprintf("%d:%s-%s", *metadata.Epoch, metadata.Version, metadata.Release)
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package rpmdb
|
||||
package rpm
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -72,11 +72,11 @@ 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,
|
||||
MetadataType: pkg.RpmMetadataType,
|
||||
Licenses: []string{"MIT"},
|
||||
Metadata: pkg.RpmdbMetadata{
|
||||
Metadata: pkg.RpmMetadata{
|
||||
Name: "dive",
|
||||
Epoch: nil,
|
||||
Arch: "x86_64",
|
||||
|
@ -100,11 +100,11 @@ 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,
|
||||
MetadataType: pkg.RpmMetadataType,
|
||||
Licenses: []string{"MIT"},
|
||||
Metadata: pkg.RpmdbMetadata{
|
||||
Metadata: pkg.RpmMetadata{
|
||||
Name: "dive",
|
||||
Epoch: nil,
|
||||
Arch: "x86_64",
|
||||
|
@ -170,12 +170,12 @@ func TestParseRpmDB(t *testing.T) {
|
|||
func TestToElVersion(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
entry pkg.RpmdbMetadata
|
||||
entry pkg.RpmMetadata
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "no epoch",
|
||||
entry: pkg.RpmdbMetadata{
|
||||
entry: pkg.RpmMetadata{
|
||||
Version: "1.2.3-4",
|
||||
Release: "el7",
|
||||
Arch: "x86-64",
|
||||
|
@ -184,7 +184,7 @@ func TestToElVersion(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "with 0 epoch",
|
||||
entry: pkg.RpmdbMetadata{
|
||||
entry: pkg.RpmMetadata{
|
||||
Version: "1.2.3-4",
|
||||
Release: "el7",
|
||||
Arch: "x86-64",
|
||||
|
@ -194,7 +194,7 @@ func TestToElVersion(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "with non-zero epoch",
|
||||
entry: pkg.RpmdbMetadata{
|
||||
entry: pkg.RpmMetadata{
|
||||
Version: "1.2.3-4",
|
||||
Release: "el7",
|
||||
Arch: "x86-64",
|
|
@ -1,4 +1,4 @@
|
|||
package rpmdb
|
||||
package rpm
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
|
@ -43,7 +43,7 @@ func parseRpmManifestEntry(entry string, location source.Location) (*pkg.Package
|
|||
size = converted
|
||||
}
|
||||
|
||||
metadata := pkg.RpmdbMetadata{
|
||||
metadata := pkg.RpmMetadata{
|
||||
Name: parts[0],
|
||||
Version: version,
|
||||
Epoch: epoch,
|
||||
|
@ -58,9 +58,9 @@ 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,
|
||||
MetadataType: pkg.RpmMetadataType,
|
||||
Metadata: metadata,
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package rpmdb
|
||||
package rpm
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
@ -18,10 +18,10 @@ 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{
|
||||
MetadataType: pkg.RpmMetadataType,
|
||||
Metadata: pkg.RpmMetadata{
|
||||
Name: "mariner-release",
|
||||
Epoch: nil,
|
||||
Arch: "noarch",
|
||||
|
@ -36,10 +36,10 @@ 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{
|
||||
MetadataType: pkg.RpmMetadataType,
|
||||
Metadata: pkg.RpmMetadata{
|
||||
Name: "filesystem",
|
||||
Epoch: nil,
|
||||
Arch: "x86_64",
|
||||
|
@ -54,10 +54,10 @@ 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{
|
||||
MetadataType: pkg.RpmMetadataType,
|
||||
Metadata: pkg.RpmMetadata{
|
||||
Name: "glibc",
|
||||
Epoch: nil,
|
||||
Arch: "x86_64",
|
||||
|
@ -72,10 +72,10 @@ 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{
|
||||
MetadataType: pkg.RpmMetadataType,
|
||||
Metadata: pkg.RpmMetadata{
|
||||
Name: "openssl-libs",
|
||||
Epoch: nil,
|
||||
Arch: "x86_64",
|
2
syft/pkg/cataloger/rpm/test-fixtures/.gitignore
vendored
Normal file
2
syft/pkg/cataloger/rpm/test-fixtures/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/rpms/*
|
||||
*.fingerprint
|
21
syft/pkg/cataloger/rpm/test-fixtures/Makefile
Normal file
21
syft/pkg/cataloger/rpm/test-fixtures/Makefile
Normal file
|
@ -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
|
|
@ -17,7 +17,7 @@ const (
|
|||
GemMetadataType MetadataType = "GemMetadata"
|
||||
JavaMetadataType MetadataType = "JavaMetadata"
|
||||
NpmPackageJSONMetadataType MetadataType = "NpmPackageJsonMetadata"
|
||||
RpmdbMetadataType MetadataType = "RpmdbMetadata"
|
||||
RpmMetadataType MetadataType = "RpmMetadata"
|
||||
DartPubMetadataType MetadataType = "DartPubMetadata"
|
||||
DotnetDepsMetadataType MetadataType = "DotnetDepsMetadata"
|
||||
PythonPackageMetadataType MetadataType = "PythonPackageMetadata"
|
||||
|
@ -38,7 +38,7 @@ var AllMetadataTypes = []MetadataType{
|
|||
GemMetadataType,
|
||||
JavaMetadataType,
|
||||
NpmPackageJSONMetadataType,
|
||||
RpmdbMetadataType,
|
||||
RpmMetadataType,
|
||||
DartPubMetadataType,
|
||||
DotnetDepsMetadataType,
|
||||
PythonPackageMetadataType,
|
||||
|
@ -59,7 +59,7 @@ var MetadataTypeByName = map[MetadataType]reflect.Type{
|
|||
GemMetadataType: reflect.TypeOf(GemMetadata{}),
|
||||
JavaMetadataType: reflect.TypeOf(JavaMetadata{}),
|
||||
NpmPackageJSONMetadataType: reflect.TypeOf(NpmPackageJSONMetadata{}),
|
||||
RpmdbMetadataType: reflect.TypeOf(RpmdbMetadata{}),
|
||||
RpmMetadataType: reflect.TypeOf(RpmMetadata{}),
|
||||
DartPubMetadataType: reflect.TypeOf(DartPubMetadata{}),
|
||||
DotnetDepsMetadataType: reflect.TypeOf(DotnetDepsMetadata{}),
|
||||
PythonPackageMetadataType: reflect.TypeOf(PythonPackageMetadata{}),
|
||||
|
@ -72,3 +72,10 @@ var MetadataTypeByName = map[MetadataType]reflect.Type{
|
|||
PortageMetadataType: reflect.TypeOf(PortageMetadata{}),
|
||||
HackageMetadataType: reflect.TypeOf(HackageMetadata{}),
|
||||
}
|
||||
|
||||
func CleanMetadataType(typ MetadataType) MetadataType {
|
||||
if typ == "RpmdbMetadata" {
|
||||
return RpmMetadataType
|
||||
}
|
||||
return typ
|
||||
}
|
||||
|
|
|
@ -23,8 +23,8 @@ func TestOwnershipByFilesRelationship(t *testing.T) {
|
|||
source.NewVirtualLocation("/b/path", "/bee/path"),
|
||||
),
|
||||
Type: RpmPkg,
|
||||
MetadataType: RpmdbMetadataType,
|
||||
Metadata: RpmdbMetadata{
|
||||
MetadataType: RpmMetadataType,
|
||||
Metadata: RpmMetadata{
|
||||
Files: []RpmdbFileRecord{
|
||||
{Path: "/owning/path/1"},
|
||||
{Path: "/owning/path/2"},
|
||||
|
@ -66,8 +66,8 @@ func TestOwnershipByFilesRelationship(t *testing.T) {
|
|||
source.NewVirtualLocation("/b/path", "/bee/path"),
|
||||
),
|
||||
Type: RpmPkg,
|
||||
MetadataType: RpmdbMetadataType,
|
||||
Metadata: RpmdbMetadata{
|
||||
MetadataType: RpmMetadataType,
|
||||
Metadata: RpmMetadata{
|
||||
Files: []RpmdbFileRecord{
|
||||
{Path: "/owning/path/1"},
|
||||
{Path: "/owning/path/2"},
|
||||
|
@ -108,8 +108,8 @@ func TestOwnershipByFilesRelationship(t *testing.T) {
|
|||
source.NewVirtualLocation("/b/path", "/bee/path"),
|
||||
),
|
||||
Type: RpmPkg,
|
||||
MetadataType: RpmdbMetadataType,
|
||||
Metadata: RpmdbMetadata{
|
||||
MetadataType: RpmMetadataType,
|
||||
Metadata: RpmMetadata{
|
||||
Files: []RpmdbFileRecord{
|
||||
{Path: "/owning/path/1"},
|
||||
{Path: "/owning/path/2"},
|
||||
|
|
|
@ -20,12 +20,12 @@ const RpmDBGlob = "**/var/lib/rpm/{Packages,Packages.db,rpmdb.sqlite}"
|
|||
const RpmManifestGlob = "**/var/lib/rpmmanifest/container-manifest-2"
|
||||
|
||||
var (
|
||||
_ FileOwner = (*RpmdbMetadata)(nil)
|
||||
_ urlIdentifier = (*RpmdbMetadata)(nil)
|
||||
_ FileOwner = (*RpmMetadata)(nil)
|
||||
_ urlIdentifier = (*RpmMetadata)(nil)
|
||||
)
|
||||
|
||||
// RpmdbMetadata represents all captured data for a RPM DB package entry.
|
||||
type RpmdbMetadata struct {
|
||||
// RpmMetadata represents all captured data for a RPM DB package entry.
|
||||
type RpmMetadata struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
Epoch *int `json:"epoch" cyclonedx:"epoch" jsonschema:"nullable"`
|
||||
|
@ -54,7 +54,7 @@ type RpmdbFileRecord struct {
|
|||
type RpmdbFileMode uint16
|
||||
|
||||
// PackageURL returns the PURL for the specific RHEL package (see https://github.com/package-url/purl-spec)
|
||||
func (m RpmdbMetadata) PackageURL(distro *linux.Release) string {
|
||||
func (m RpmMetadata) PackageURL(distro *linux.Release) string {
|
||||
var namespace string
|
||||
if distro != nil {
|
||||
namespace = distro.ID
|
||||
|
@ -87,7 +87,7 @@ func (m RpmdbMetadata) PackageURL(distro *linux.Release) string {
|
|||
).ToString()
|
||||
}
|
||||
|
||||
func (m RpmdbMetadata) OwnedFiles() (result []string) {
|
||||
func (m RpmMetadata) OwnedFiles() (result []string) {
|
||||
s := strset.New()
|
||||
for _, f := range m.Files {
|
||||
if f.Path != "" {
|
|
@ -14,7 +14,7 @@ func TestRpmMetadata_pURL(t *testing.T) {
|
|||
tests := []struct {
|
||||
name string
|
||||
distro *linux.Release
|
||||
metadata RpmdbMetadata
|
||||
metadata RpmMetadata
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
|
@ -23,7 +23,7 @@ func TestRpmMetadata_pURL(t *testing.T) {
|
|||
ID: "rhel",
|
||||
VersionID: "8.4",
|
||||
},
|
||||
metadata: RpmdbMetadata{
|
||||
metadata: RpmMetadata{
|
||||
Name: "p",
|
||||
Version: "v",
|
||||
Release: "r",
|
||||
|
@ -37,7 +37,7 @@ func TestRpmMetadata_pURL(t *testing.T) {
|
|||
ID: "centos",
|
||||
VersionID: "7",
|
||||
},
|
||||
metadata: RpmdbMetadata{
|
||||
metadata: RpmMetadata{
|
||||
Name: "p",
|
||||
Version: "v",
|
||||
Arch: "a",
|
||||
|
@ -48,7 +48,7 @@ func TestRpmMetadata_pURL(t *testing.T) {
|
|||
},
|
||||
{
|
||||
name: "missing distro",
|
||||
metadata: RpmdbMetadata{
|
||||
metadata: RpmMetadata{
|
||||
Name: "p",
|
||||
Version: "v",
|
||||
Release: "r",
|
||||
|
@ -62,7 +62,7 @@ func TestRpmMetadata_pURL(t *testing.T) {
|
|||
ID: "rhel",
|
||||
VersionID: "8.4",
|
||||
},
|
||||
metadata: RpmdbMetadata{
|
||||
metadata: RpmMetadata{
|
||||
Name: "p",
|
||||
Version: "v",
|
||||
Release: "r",
|
||||
|
@ -86,11 +86,11 @@ func TestRpmMetadata_pURL(t *testing.T) {
|
|||
|
||||
func TestRpmMetadata_FileOwner(t *testing.T) {
|
||||
tests := []struct {
|
||||
metadata RpmdbMetadata
|
||||
metadata RpmMetadata
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
metadata: RpmdbMetadata{
|
||||
metadata: RpmMetadata{
|
||||
Files: []RpmdbFileRecord{
|
||||
{Path: "/somewhere"},
|
||||
{Path: "/else"},
|
||||
|
@ -102,7 +102,7 @@ func TestRpmMetadata_FileOwner(t *testing.T) {
|
|||
},
|
||||
},
|
||||
{
|
||||
metadata: RpmdbMetadata{
|
||||
metadata: RpmMetadata{
|
||||
Files: []RpmdbFileRecord{
|
||||
{Path: "/somewhere"},
|
||||
{Path: ""},
|
|
@ -121,7 +121,7 @@ func TestPackageURL(t *testing.T) {
|
|||
Name: "bad-name",
|
||||
Version: "bad-v0.1.0",
|
||||
Type: RpmPkg,
|
||||
Metadata: RpmdbMetadata{
|
||||
Metadata: RpmMetadata{
|
||||
Name: "name",
|
||||
Version: "0.1.0",
|
||||
Epoch: intRef(2),
|
||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue