move package purl and cpes (identities) to pkg.Package

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
Alex Goodman
2020-11-19 11:25:51 -05:00
parent 71939557e6
commit 3aaa0e5566
35 changed files with 580 additions and 206 deletions
+2 -3
View File
@@ -5,7 +5,6 @@ import (
"github.com/anchore/syft/internal"
"github.com/anchore/syft/internal/version"
"github.com/anchore/syft/syft/distro"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/source"
"github.com/google/uuid"
@@ -25,7 +24,7 @@ type Document struct {
}
// NewDocumentFromCatalog returns a CycloneDX Document object populated with the catalog contents.
func NewDocument(catalog *pkg.Catalog, d distro.Distro, srcMetadata source.Metadata) Document {
func NewDocument(catalog *pkg.Catalog, srcMetadata source.Metadata) Document {
versionInfo := version.FromBuild()
doc := Document{
@@ -42,7 +41,7 @@ func NewDocument(catalog *pkg.Catalog, d distro.Distro, srcMetadata source.Metad
Type: "library", // TODO: this is not accurate
Name: p.Name,
Version: p.Version,
PackageURL: p.PackageURL(d),
PackageURL: p.PURL,
}
var licenses []License
for _, licenseName := range p.Licenses {
+2 -6
View File
@@ -7,8 +7,6 @@ import (
"encoding/xml"
"io"
"github.com/anchore/syft/syft/distro"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/source"
)
@@ -17,21 +15,19 @@ import (
type Presenter struct {
catalog *pkg.Catalog
srcMetadata source.Metadata
distro distro.Distro
}
// NewPresenter creates a CycloneDX presenter from the given Catalog and Locations objects.
func NewPresenter(catalog *pkg.Catalog, srcMetadata source.Metadata, d distro.Distro) *Presenter {
func NewPresenter(catalog *pkg.Catalog, srcMetadata source.Metadata) *Presenter {
return &Presenter{
catalog: catalog,
srcMetadata: srcMetadata,
distro: d,
}
}
// Present writes the CycloneDX report to the given io.Writer.
func (pres *Presenter) Present(output io.Writer) error {
bom := NewDocument(pres.catalog, pres.distro, pres.srcMetadata)
bom := NewDocument(pres.catalog, pres.srcMetadata)
encoder := xml.NewEncoder(output)
encoder.Indent("", " ")
+4 -35
View File
@@ -7,7 +7,6 @@ import (
"testing"
"github.com/anchore/stereoscope/pkg/imagetest"
"github.com/anchore/syft/syft/distro"
"github.com/anchore/go-testutils"
"github.com/anchore/syft/syft/pkg"
@@ -61,12 +60,7 @@ func TestCycloneDxDirsPresenter(t *testing.T) {
t.Fatal(err)
}
d, err := distro.NewDistro(distro.Ubuntu, "20.04", "debian")
if err != nil {
t.Fatal(err)
}
pres := NewPresenter(catalog, s.Metadata, d)
pres := NewPresenter(catalog, s.Metadata)
// run presenter
err = pres.Present(&buffer)
@@ -109,17 +103,7 @@ func TestCycloneDxImgsPresenter(t *testing.T) {
},
Type: pkg.RpmPkg,
FoundBy: "the-cataloger-1",
Metadata: pkg.RpmdbMetadata{
Name: "package1",
Epoch: 0,
Arch: "x86_64",
Release: "1",
Version: "1.0.1",
SourceRpm: "package1-1.0.1-1.src.rpm",
Size: 12406784,
License: "MIT",
Vendor: "",
},
PURL: "the-purl-1",
})
catalog.Add(pkg.Package{
Name: "package2",
@@ -133,17 +117,7 @@ func TestCycloneDxImgsPresenter(t *testing.T) {
"MIT",
"Apache-v2",
},
Metadata: pkg.RpmdbMetadata{
Name: "package2",
Epoch: 0,
Arch: "x86_64",
Release: "1",
Version: "1.0.2",
SourceRpm: "package2-1.0.2-1.src.rpm",
Size: 12406784,
License: "MIT",
Vendor: "",
},
PURL: "the-purl-2",
})
s, err := source.NewFromImage(img, source.AllLayersScope, "user-image-input")
@@ -151,11 +125,6 @@ func TestCycloneDxImgsPresenter(t *testing.T) {
t.Fatal(err)
}
d, err := distro.NewDistro(distro.RedHat, "8", "")
if err != nil {
t.Fatal(err)
}
// This accounts for the non-deterministic digest value that we end up with when
// we build a container image dynamically during testing. Ultimately, we should
// use a golden image as a test fixture in place of building this image during
@@ -164,7 +133,7 @@ func TestCycloneDxImgsPresenter(t *testing.T) {
// This value is sourced from the "version" node in "./test-fixtures/snapshot/TestCycloneDxImgsPresenter.golden"
s.Metadata.ImageMetadata.Digest = "sha256:2731251dc34951c0e50fcc643b4c5f74922dad1a5d98f302b504cf46cd5d9368"
pres := NewPresenter(catalog, s.Metadata, d)
pres := NewPresenter(catalog, s.Metadata)
// run presenter
err = pres.Present(&buffer)
@@ -1,10 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<bom xmlns="http://cyclonedx.org/schema/bom/1.2" xmlns:bd="http://cyclonedx.org/schema/ext/bom-descriptor/1.0" version="1" serialNumber="urn:uuid:815fdd6b-917e-423d-8c91-1fe648141505">
<bom xmlns="http://cyclonedx.org/schema/bom/1.2" xmlns:bd="http://cyclonedx.org/schema/ext/bom-descriptor/1.0" version="1" serialNumber="urn:uuid:aa1738d1-1c6e-45e4-a530-5a04d2c2b1a7">
<components>
<component type="library">
<name>package1</name>
<version>1.0.1</version>
<purl>pkg:deb/ubuntu/package1@1.0.1?arch=amd64</purl>
</component>
<component type="library">
<name>package2</name>
@@ -17,11 +16,10 @@
<name>Apache-v2</name>
</license>
</licenses>
<purl>pkg:deb/ubuntu/package2@1.0.2?arch=amd64</purl>
</component>
</components>
<bd:metadata>
<bd:timestamp>2020-11-16T08:45:54-05:00</bd:timestamp>
<bd:timestamp>2020-11-19T10:11:26-05:00</bd:timestamp>
<bd:tool>
<bd:vendor>anchore</bd:vendor>
<bd:name>syft</bd:name>
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<bom xmlns="http://cyclonedx.org/schema/bom/1.2" xmlns:bd="http://cyclonedx.org/schema/ext/bom-descriptor/1.0" version="1" serialNumber="urn:uuid:3cb10332-1645-44f6-be4a-4f8be5a60cf8">
<bom xmlns="http://cyclonedx.org/schema/bom/1.2" xmlns:bd="http://cyclonedx.org/schema/ext/bom-descriptor/1.0" version="1" serialNumber="urn:uuid:8a4c332c-365c-454d-a43c-d9344577d105">
<components>
<component type="library">
<name>package1</name>
<version>1.0.1</version>
<purl>pkg:rpm/redhat/package1@0:1.0.1-1?arch=x86_64</purl>
<purl>the-purl-1</purl>
</component>
<component type="library">
<name>package2</name>
@@ -17,11 +17,11 @@
<name>Apache-v2</name>
</license>
</licenses>
<purl>pkg:rpm/redhat/package2@0:1.0.2-1?arch=x86_64</purl>
<purl>the-purl-2</purl>
</component>
</components>
<bd:metadata>
<bd:timestamp>2020-11-16T08:45:54-05:00</bd:timestamp>
<bd:timestamp>2020-11-19T10:11:26-05:00</bd:timestamp>
<bd:tool>
<bd:vendor>anchore</bd:vendor>
<bd:name>syft</bd:name>
+4 -5
View File
@@ -10,14 +10,13 @@ type Distribution struct {
}
// NewDistribution creates a struct with the Linux distribution to be represented in JSON.
func NewDistribution(d distro.Distro) Distribution {
distroName := d.Name()
if distroName == "UnknownDistroType" {
distroName = ""
func NewDistribution(d *distro.Distro) Distribution {
if d == nil {
return Distribution{}
}
return Distribution{
Name: distroName,
Name: d.Name(),
Version: d.FullVersion(),
IDLike: d.IDLike,
}
+1 -1
View File
@@ -17,7 +17,7 @@ type Document struct {
}
// NewDocument creates and populates a new JSON document struct from the given cataloging results.
func NewDocument(catalog *pkg.Catalog, srcMetadata source.Metadata, d distro.Distro) (Document, error) {
func NewDocument(catalog *pkg.Catalog, srcMetadata source.Metadata, d *distro.Distro) (Document, error) {
src, err := NewSource(srcMetadata)
if err != nil {
return Document{}, nil
@@ -23,6 +23,8 @@ type packageBasicMetadata struct {
Locations []source.Location `json:"locations"`
Licenses []string `json:"licenses"`
Language pkg.Language `json:"language"`
CPEs []string `json:"cpes"`
PURL string `json:"purl"`
}
// packageCustomMetadata contains ambiguous values (type-wise) from pkg.Package.
@@ -39,6 +41,10 @@ type packageMetadataUnpacker struct {
// NewPackage crates a new Package from the given pkg.Package.
func NewPackage(p *pkg.Package) (Package, error) {
var cpes = make([]string, len(p.CPEs))
for i, c := range p.CPEs {
cpes[i] = c.BindToFmtString()
}
return Package{
packageBasicMetadata: packageBasicMetadata{
Name: p.Name,
@@ -48,6 +54,8 @@ func NewPackage(p *pkg.Package) (Package, error) {
Locations: p.Locations,
Licenses: p.Licenses,
Language: p.Language,
CPEs: cpes,
PURL: p.PURL,
},
packageCustomMetadata: packageCustomMetadata{
MetadataType: p.MetadataType,
@@ -57,7 +65,15 @@ func NewPackage(p *pkg.Package) (Package, error) {
}
// ToPackage generates a pkg.Package from the current Package.
func (a Package) ToPackage() pkg.Package {
func (a Package) ToPackage() (pkg.Package, error) {
var cpes = make([]pkg.CPE, len(a.CPEs))
var err error
for i, c := range a.CPEs {
cpes[i], err = pkg.NewCPE(c)
if err != nil {
return pkg.Package{}, fmt.Errorf("unable to parse CPE from JSON package: %w", err)
}
}
return pkg.Package{
// does not include found-by and locations
Name: a.Name,
@@ -66,10 +82,12 @@ func (a Package) ToPackage() pkg.Package {
Licenses: a.Licenses,
Language: a.Language,
Locations: a.Locations,
CPEs: cpes,
PURL: a.PURL,
Type: a.Type,
MetadataType: a.MetadataType,
Metadata: a.Metadata,
}
}, nil
}
// UnmarshalJSON is a custom unmarshaller for handling basic values and values with ambiguous types.
+2 -2
View File
@@ -13,11 +13,11 @@ import (
type Presenter struct {
catalog *pkg.Catalog
srcMetadata source.Metadata
distro distro.Distro
distro *distro.Distro
}
// NewPresenter creates a new JSON presenter object for the given cataloging results.
func NewPresenter(catalog *pkg.Catalog, s source.Metadata, d distro.Distro) *Presenter {
func NewPresenter(catalog *pkg.Catalog, s source.Metadata, d *distro.Distro) *Presenter {
return &Presenter{
catalog: catalog,
srcMetadata: s,
+25 -2
View File
@@ -15,6 +15,13 @@ import (
var update = flag.Bool("update", false, "update the *.golden files for json presenters")
func must(c pkg.CPE, e error) pkg.CPE {
if e != nil {
panic(e)
}
return c
}
func TestJsonDirsPresenter(t *testing.T) {
var buffer bytes.Buffer
@@ -36,6 +43,10 @@ func TestJsonDirsPresenter(t *testing.T) {
Name: "package-1",
Version: "1.0.1",
},
PURL: "a-purl-2",
CPEs: []pkg.CPE{
must(pkg.NewCPE("cpe:2.3:*:some:package:2:*:*:*:*:*:*:*")),
},
})
catalog.Add(pkg.Package{
Name: "package-2",
@@ -50,8 +61,12 @@ func TestJsonDirsPresenter(t *testing.T) {
Package: "package-2",
Version: "2.0.1",
},
PURL: "a-purl-2",
CPEs: []pkg.CPE{
must(pkg.NewCPE("cpe:2.3:*:some:package:2:*:*:*:*:*:*:*")),
},
})
d := distro.NewUnknownDistro()
var d *distro.Distro
s, err := source.NewFromDirectory("/some/path")
if err != nil {
t.Fatal(err)
@@ -107,6 +122,10 @@ func TestJsonImgsPresenter(t *testing.T) {
Name: "package-1",
Version: "1.0.1",
},
PURL: "a-purl-1",
CPEs: []pkg.CPE{
must(pkg.NewCPE("cpe:2.3:*:some:package:1:*:*:*:*:*:*:*")),
},
})
catalog.Add(pkg.Package{
Name: "package-2",
@@ -121,10 +140,14 @@ func TestJsonImgsPresenter(t *testing.T) {
Package: "package-2",
Version: "2.0.1",
},
PURL: "a-purl-2",
CPEs: []pkg.CPE{
must(pkg.NewCPE("cpe:2.3:*:some:package:2:*:*:*:*:*:*:*")),
},
})
s, err := source.NewFromImage(img, source.AllLayersScope, "user-image-input")
d := distro.NewUnknownDistro()
var d *distro.Distro
pres := NewPresenter(catalog, s.Metadata, d)
// run presenter
@@ -14,6 +14,10 @@
"MIT"
],
"language": "python",
"cpes": [
"cpe:2.3:*:some:package:2:*:*:*:*:*:*:*"
],
"purl": "a-purl-2",
"metadataType": "PythonPackageMetadata",
"metadata": {
"name": "package-1",
@@ -37,6 +41,10 @@
],
"licenses": null,
"language": "",
"cpes": [
"cpe:2.3:*:some:package:2:*:*:*:*:*:*:*"
],
"purl": "a-purl-2",
"metadataType": "DpkgMetadata",
"metadata": {
"package": "package-2",
@@ -15,6 +15,10 @@
"MIT"
],
"language": "python",
"cpes": [
"cpe:2.3:*:some:package:1:*:*:*:*:*:*:*"
],
"purl": "a-purl-1",
"metadataType": "PythonPackageMetadata",
"metadata": {
"name": "package-1",
@@ -39,6 +43,10 @@
],
"licenses": null,
"language": "",
"cpes": [
"cpe:2.3:*:some:package:2:*:*:*:*:*:*:*"
],
"purl": "a-purl-2",
"metadataType": "DpkgMetadata",
"metadata": {
"package": "package-2",
+2 -2
View File
@@ -25,7 +25,7 @@ type Presenter interface {
}
// GetPresenter returns a presenter for images or directories
func GetPresenter(option Option, srcMetadata source.Metadata, catalog *pkg.Catalog, d distro.Distro) Presenter {
func GetPresenter(option Option, srcMetadata source.Metadata, catalog *pkg.Catalog, d *distro.Distro) Presenter {
switch option {
case JSONPresenter:
return json.NewPresenter(catalog, srcMetadata, d)
@@ -34,7 +34,7 @@ func GetPresenter(option Option, srcMetadata source.Metadata, catalog *pkg.Catal
case TablePresenter:
return table.NewPresenter(catalog)
case CycloneDxPresenter:
return cyclonedx.NewPresenter(catalog, srcMetadata, d)
return cyclonedx.NewPresenter(catalog, srcMetadata)
default:
return nil
}