move source metadata upstream and fix tests

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
Alex Goodman
2020-11-17 12:37:12 -05:00
parent aa0d444fd4
commit 6f7a4fd3e4
36 changed files with 305 additions and 294 deletions
+15 -22
View File
@@ -16,17 +16,17 @@ import (
// Presenter writes a CycloneDX report from the given Catalog and Locations contents
type Presenter struct {
catalog *pkg.Catalog
source source.Source
distro distro.Distro
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, s source.Source, d distro.Distro) *Presenter {
func NewPresenter(catalog *pkg.Catalog, s source.Metadata, d distro.Distro) *Presenter {
return &Presenter{
catalog: catalog,
source: s,
distro: d,
catalog: catalog,
srcMetadata: s,
distro: d,
}
}
@@ -34,33 +34,26 @@ func NewPresenter(catalog *pkg.Catalog, s source.Source, d distro.Distro) *Prese
func (pres *Presenter) Present(output io.Writer) error {
bom := NewDocumentFromCatalog(pres.catalog, pres.distro)
switch src := pres.source.Target.(type) {
case source.DirSource:
switch pres.srcMetadata.Scheme {
case source.DirectoryScheme:
bom.BomDescriptor.Component = &BdComponent{
Component: Component{
Type: "file",
Name: src.Path,
Name: pres.srcMetadata.Path,
Version: "",
},
}
case source.ImageSource:
var imageID string
var versionStr string
if len(src.Img.Metadata.Tags) > 0 {
imageID = src.Img.Metadata.Tags[0].Context().Name()
versionStr = src.Img.Metadata.Tags[0].TagStr()
} else {
imageID = src.Img.Metadata.Digest
}
case source.ImageScheme:
// TODO: can we use the tags a bit better?
bom.BomDescriptor.Component = &BdComponent{
Component: Component{
Type: "container",
Name: imageID,
Version: versionStr,
Name: pres.srcMetadata.ImageMetadata.UserInput,
Version: pres.srcMetadata.ImageMetadata.Digest,
},
}
default:
return fmt.Errorf("unsupported source: %T", src)
return fmt.Errorf("unsupported source: %T", pres.srcMetadata.Scheme)
}
encoder := xml.NewEncoder(output)
+4 -4
View File
@@ -66,7 +66,7 @@ func TestCycloneDxDirsPresenter(t *testing.T) {
t.Fatal(err)
}
pres := NewPresenter(catalog, s, d)
pres := NewPresenter(catalog, s.Metadata, d)
// run presenter
err = pres.Present(&buffer)
@@ -146,7 +146,7 @@ func TestCycloneDxImgsPresenter(t *testing.T) {
},
})
s, err := source.NewFromImage(img, source.AllLayersScope)
s, err := source.NewFromImage(img, source.AllLayersScope, "user-image-input")
if err != nil {
t.Fatal(err)
}
@@ -156,7 +156,7 @@ func TestCycloneDxImgsPresenter(t *testing.T) {
t.Fatal(err)
}
pres := NewPresenter(catalog, s, d)
pres := NewPresenter(catalog, s.Metadata, d)
// run presenter
err = pres.Present(&buffer)
@@ -177,7 +177,7 @@ func TestCycloneDxImgsPresenter(t *testing.T) {
if !bytes.Equal(expected, actual) {
dmp := diffmatchpatch.New()
diffs := dmp.DiffMain(string(actual), string(expected), true)
diffs := dmp.DiffMain(string(expected), string(actual), true)
t.Errorf("mismatched output:\n%s", dmp.DiffPrettyText(diffs))
}
}
+11 -9
View File
@@ -16,11 +16,11 @@ type Artifact struct {
type ArtifactBasicMetadata struct {
Name string `json:"name"`
Version string `json:"version"`
Type string `json:"type"`
FoundBy []string `json:"foundBy"`
Type pkg.Type `json:"type"`
FoundBy string `json:"foundBy"`
Locations []source.Location `json:"locations"`
Licenses []string `json:"licenses"`
Language string `json:"language"`
Language pkg.Language `json:"language"`
}
type ArtifactCustomMetadata struct {
@@ -33,17 +33,17 @@ type ArtifactMetadataUnpacker struct {
Metadata json.RawMessage `json:"metadata"`
}
func NewArtifact(p *pkg.Package, s source.Source) (Artifact, error) {
func NewArtifact(p *pkg.Package) (Artifact, error) {
return Artifact{
ArtifactBasicMetadata: ArtifactBasicMetadata{
Name: p.Name,
Version: p.Version,
Type: string(p.Type),
FoundBy: []string{p.FoundBy},
Type: p.Type,
FoundBy: p.FoundBy,
Locations: p.Locations,
Licenses: p.Licenses,
Language: string(p.Language),
Language: p.Language,
},
ArtifactCustomMetadata: ArtifactCustomMetadata{
MetadataType: p.MetadataType,
@@ -57,9 +57,11 @@ func (a Artifact) ToPackage() pkg.Package {
// does not include found-by and locations
Name: a.Name,
Version: a.Version,
FoundBy: a.FoundBy,
Licenses: a.Licenses,
Language: pkg.Language(a.Language),
Type: pkg.Type(a.Type),
Language: a.Language,
Locations: a.Locations,
Type: a.Type,
MetadataType: a.MetadataType,
Metadata: a.Metadata,
}
+9 -12
View File
@@ -1,8 +1,6 @@
package json
import (
"time"
"github.com/anchore/syft/internal"
"github.com/anchore/syft/internal/version"
"github.com/anchore/syft/syft/distro"
@@ -19,10 +17,9 @@ type Document struct {
// Descriptor describes what created the document as well as surrounding metadata
type Descriptor struct {
Name string `json:"name"`
Version string `json:"version"`
ReportTimestamp string `json:"reportTimestamp"`
// TODO: we should include source option here as well (or in source)
Name string `json:"name"`
Version string `json:"version"`
Scope string `json:"scope"`
}
// Distribution provides information about a detected Linux Distribution
@@ -32,8 +29,8 @@ type Distribution struct {
IDLike string `json:"idLike"`
}
func NewDocument(catalog *pkg.Catalog, s source.Source, d distro.Distro) (Document, error) {
src, err := NewSource(s)
func NewDocument(catalog *pkg.Catalog, srcMetadata source.Metadata, d distro.Distro) (Document, error) {
src, err := NewSource(srcMetadata)
if err != nil {
return Document{}, nil
}
@@ -52,14 +49,14 @@ func NewDocument(catalog *pkg.Catalog, s source.Source, d distro.Distro) (Docume
IDLike: d.IDLike,
},
Descriptor: Descriptor{
Name: internal.ApplicationName,
Version: version.FromBuild().Version,
ReportTimestamp: time.Now().Format(time.RFC3339),
Name: internal.ApplicationName,
Version: version.FromBuild().Version,
Scope: srcMetadata.Scope.String(),
},
}
for _, p := range catalog.Sorted() {
art, err := NewArtifact(p, s)
art, err := NewArtifact(p)
if err != nil {
return Document{}, err
}
-44
View File
@@ -1,44 +0,0 @@
package json
import (
"github.com/anchore/syft/syft/source"
)
type Image struct {
Layers []Layer `json:"layers"`
Size int64 `json:"size"`
Digest string `json:"digest"`
MediaType string `json:"mediaType"`
Tags []string `json:"tags"`
}
type Layer struct {
MediaType string `json:"mediaType"`
Digest string `json:"digest"`
Size int64 `json:"size"`
}
func NewImage(src source.ImageSource) *Image {
// populate artifacts...
tags := make([]string, len(src.Img.Metadata.Tags))
for idx, tag := range src.Img.Metadata.Tags {
tags[idx] = tag.String()
}
img := Image{
Digest: src.Img.Metadata.Digest,
Size: src.Img.Metadata.Size,
MediaType: string(src.Img.Metadata.MediaType),
Tags: tags,
Layers: make([]Layer, len(src.Img.Layers)),
}
// populate image metadata
for idx, l := range src.Img.Layers {
img.Layers[idx] = Layer{
MediaType: string(l.Metadata.MediaType),
Digest: l.Metadata.Digest,
Size: l.Metadata.Size,
}
}
return &img
}
+8 -8
View File
@@ -10,21 +10,21 @@ import (
)
type Presenter struct {
catalog *pkg.Catalog
source source.Source
distro distro.Distro
catalog *pkg.Catalog
srcMetadata source.Metadata
distro distro.Distro
}
func NewPresenter(catalog *pkg.Catalog, s source.Source, d distro.Distro) *Presenter {
func NewPresenter(catalog *pkg.Catalog, s source.Metadata, d distro.Distro) *Presenter {
return &Presenter{
catalog: catalog,
source: s,
distro: d,
catalog: catalog,
srcMetadata: s,
distro: d,
}
}
func (pres *Presenter) Present(output io.Writer) error {
doc, err := NewDocument(pres.catalog, pres.source, pres.distro)
doc, err := NewDocument(pres.catalog, pres.srcMetadata, pres.distro)
if err != nil {
return err
}
+5 -5
View File
@@ -56,7 +56,7 @@ func TestJsonDirsPresenter(t *testing.T) {
if err != nil {
t.Fatal(err)
}
pres := NewPresenter(catalog, s, d)
pres := NewPresenter(catalog, s.Metadata, d)
// run presenter
err = pres.Present(&buffer)
@@ -73,7 +73,7 @@ func TestJsonDirsPresenter(t *testing.T) {
if !bytes.Equal(expected, actual) {
dmp := diffmatchpatch.New()
diffs := dmp.DiffMain(string(actual), string(expected), true)
diffs := dmp.DiffMain(string(expected), string(actual), true)
t.Errorf("mismatched output:\n%s", dmp.DiffPrettyText(diffs))
}
@@ -123,9 +123,9 @@ func TestJsonImgsPresenter(t *testing.T) {
},
})
s, err := source.NewFromImage(img, source.AllLayersScope)
s, err := source.NewFromImage(img, source.AllLayersScope, "user-image-input")
d := distro.NewUnknownDistro()
pres := NewPresenter(catalog, s, d)
pres := NewPresenter(catalog, s.Metadata, d)
// run presenter
err = pres.Present(&buffer)
@@ -142,7 +142,7 @@ func TestJsonImgsPresenter(t *testing.T) {
if !bytes.Equal(expected, actual) {
dmp := diffmatchpatch.New()
diffs := dmp.DiffMain(string(actual), string(expected), true)
diffs := dmp.DiffMain(string(expected), string(actual), true)
t.Errorf("mismatched output:\n%s", dmp.DiffPrettyText(diffs))
}
}
+6 -6
View File
@@ -17,14 +17,14 @@ type SourceUnpacker struct {
Target json.RawMessage `json:"target"`
}
func NewSource(s source.Source) (Source, error) {
switch src := s.Target.(type) {
case source.ImageSource:
func NewSource(src source.Metadata) (Source, error) {
switch src.Scheme {
case source.ImageScheme:
return Source{
Type: "image",
Target: NewImage(src),
Target: src.ImageMetadata,
}, nil
case source.DirSource:
case source.DirectoryScheme:
return Source{
Type: "directory",
Target: src.Path,
@@ -44,7 +44,7 @@ func (s *Source) UnmarshalJSON(b []byte) error {
switch s.Type {
case "image":
var payload Image
var payload source.ImageMetadata
if err := json.Unmarshal(unpacker.Target, &payload); err != nil {
return err
}
@@ -3,14 +3,29 @@
{
"name": "package-1",
"version": "1.0.1",
"type": "deb",
"type": "python",
"foundBy": [
"the-cataloger-1"
],
"locations": [
"/some/path/pkg1"
{
"path": "/some/path/pkg1"
}
],
"licenses": null
"licenses": [
"MIT"
],
"language": "python",
"metadataType": "python-package-metadata",
"metadata": {
"name": "package-1",
"version": "1.0.1",
"license": "",
"author": "",
"authorEmail": "",
"platform": "",
"sitePackagesRootPath": ""
}
},
{
"name": "package-2",
@@ -20,9 +35,22 @@
"the-cataloger-2"
],
"locations": [
"/some/path/pkg1"
{
"path": "/some/path/pkg1"
}
],
"licenses": null
"licenses": null,
"language": "",
"metadataType": "dpkg-metadata",
"metadata": {
"package": "package-2",
"source": "",
"version": "2.0.1",
"architecture": "",
"maintainer": "",
"installedSize": 0,
"files": null
}
}
],
"source": {
@@ -33,5 +61,10 @@
"name": "",
"version": "",
"idLike": ""
},
"descriptor": {
"name": "syft",
"version": "[not provided]",
"scope": ""
}
}
@@ -3,17 +3,30 @@
{
"name": "package-1",
"version": "1.0.1",
"type": "deb",
"type": "python",
"foundBy": [
"the-cataloger-1"
],
"locations": [
{
"path": "/somefile-1.txt",
"layerIndex": 0
"layerID": "sha256:e158b57d6f5a96ef5fd22f2fe76c70b5ba6ff5b2619f9d83125b2aad0492ac7b"
}
],
"licenses": null
"licenses": [
"MIT"
],
"language": "python",
"metadataType": "python-package-metadata",
"metadata": {
"name": "package-1",
"version": "1.0.1",
"license": "",
"author": "",
"authorEmail": "",
"platform": "",
"sitePackagesRootPath": ""
}
},
{
"name": "package-2",
@@ -25,10 +38,21 @@
"locations": [
{
"path": "/somefile-2.txt",
"layerIndex": 1
"layerID": "sha256:da21056e7bf4308ecea0c0836848a7fe92f38fdcf35bc09ee6d98e7ab7beeebf"
}
],
"licenses": null
"licenses": null,
"language": "",
"metadataType": "dpkg-metadata",
"metadata": {
"package": "package-2",
"source": "",
"version": "2.0.1",
"architecture": "",
"maintainer": "",
"installedSize": 0,
"files": null
}
}
],
"source": {
@@ -37,22 +61,22 @@
"layers": [
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"digest": "sha256:78783bfc74fef84f899b4977561ad1172f87753f82cc2157b06bf097e56dfbce",
"digest": "sha256:e158b57d6f5a96ef5fd22f2fe76c70b5ba6ff5b2619f9d83125b2aad0492ac7b",
"size": 22
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"digest": "sha256:54ec7f643dafbf9f27032a5e60afe06248c0e99b50aed54bb0fe28ea4825ccaf",
"digest": "sha256:da21056e7bf4308ecea0c0836848a7fe92f38fdcf35bc09ee6d98e7ab7beeebf",
"size": 16
},
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"digest": "sha256:ec4775a139c45b1ddf9ea8e1cb43385e92e5c0bf6ec2e3f4192372785b18c106",
"digest": "sha256:f0e18aa6032c24659a9c741fc36ca56f589782ea132061ccf6f52b952403da94",
"size": 27
}
],
"size": 65,
"digest": "sha256:fedd7bcc0b90f071501b662d8e7c9ac7548b88daba6b3deedfdf33f22ed8d95b",
"digest": "sha256:2731251dc34951c0e50fcc643b4c5f74922dad1a5d98f302b504cf46cd5d9368",
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"tags": [
"stereoscope-fixture-image-simple:04e16e44161c8888a1a963720fd0443cbf7eef8101434c431de8725cd98cc9f7"
@@ -63,5 +87,10 @@
"name": "",
"version": "",
"idLike": ""
},
"descriptor": {
"name": "syft",
"version": "[not provided]",
"scope": "AllLayers"
}
}
+5 -5
View File
@@ -25,16 +25,16 @@ type Presenter interface {
}
// GetPresenter returns a presenter for images or directories
func GetPresenter(option Option, s source.Source, 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, s, *d)
return json.NewPresenter(catalog, srcMetadata, *d)
case TextPresenter:
return text.NewPresenter(catalog, s)
return text.NewPresenter(catalog, srcMetadata)
case TablePresenter:
return table.NewPresenter(catalog, s)
return table.NewPresenter(catalog)
case CycloneDxPresenter:
return cyclonedx.NewPresenter(catalog, s, *d)
return cyclonedx.NewPresenter(catalog, srcMetadata, *d)
default:
return nil
}
+1 -4
View File
@@ -9,18 +9,15 @@ import (
"github.com/olekukonko/tablewriter"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/source"
)
type Presenter struct {
catalog *pkg.Catalog
source source.Source
}
func NewPresenter(catalog *pkg.Catalog, s source.Source) *Presenter {
func NewPresenter(catalog *pkg.Catalog) *Presenter {
return &Presenter{
catalog: catalog,
source: s,
}
}
+2 -3
View File
@@ -43,11 +43,10 @@ func TestTablePresenter(t *testing.T) {
Type: pkg.DebPkg,
})
s, err := source.NewFromImage(img, source.AllLayersScope)
pres := NewPresenter(catalog, s)
pres := NewPresenter(catalog)
// run presenter
err = pres.Present(&buffer)
err := pres.Present(&buffer)
if err != nil {
t.Fatal(err)
}
+14 -14
View File
@@ -11,14 +11,14 @@ import (
)
type Presenter struct {
catalog *pkg.Catalog
source source.Source
catalog *pkg.Catalog
srcMetadata source.Metadata
}
func NewPresenter(catalog *pkg.Catalog, s source.Source) *Presenter {
func NewPresenter(catalog *pkg.Catalog, srcMetadata source.Metadata) *Presenter {
return &Presenter{
catalog: catalog,
source: s,
catalog: catalog,
srcMetadata: srcMetadata,
}
}
@@ -28,22 +28,22 @@ func (pres *Presenter) Present(output io.Writer) error {
w := new(tabwriter.Writer)
w.Init(output, 0, 8, 0, '\t', tabwriter.AlignRight)
switch src := pres.source.Target.(type) {
case source.DirSource:
fmt.Fprintln(w, fmt.Sprintf("[Path: %s]", src.Path))
case source.ImageSource:
switch pres.srcMetadata.Scheme {
case source.DirectoryScheme:
fmt.Fprintln(w, fmt.Sprintf("[Path: %s]", pres.srcMetadata.Path))
case source.ImageScheme:
fmt.Fprintln(w, "[Image]")
for idx, l := range src.Img.Layers {
for idx, l := range pres.srcMetadata.ImageMetadata.Layers {
fmt.Fprintln(w, " Layer:\t", idx)
fmt.Fprintln(w, " Digest:\t", l.Metadata.Digest)
fmt.Fprintln(w, " Size:\t", l.Metadata.Size)
fmt.Fprintln(w, " MediaType:\t", l.Metadata.MediaType)
fmt.Fprintln(w, " Digest:\t", l.Digest)
fmt.Fprintln(w, " Size:\t", l.Size)
fmt.Fprintln(w, " MediaType:\t", l.MediaType)
fmt.Fprintln(w)
w.Flush()
}
default:
return fmt.Errorf("unsupported source: %T", src)
return fmt.Errorf("unsupported source: %T", pres.srcMetadata.Scheme)
}
// populate artifacts...
+3 -3
View File
@@ -35,7 +35,7 @@ func TestTextDirPresenter(t *testing.T) {
if err != nil {
t.Fatalf("unable to create source: %+v", err)
}
pres := NewPresenter(catalog, s)
pres := NewPresenter(catalog, s.Metadata)
// run presenter
err = pres.Present(&buffer)
@@ -97,11 +97,11 @@ func TestTextImgPresenter(t *testing.T) {
l.Metadata.Digest = "sha256:ad8ecdc058976c07e7e347cb89fa9ad86a294b5ceaae6d09713fb035f84115abf3c4a2388a4af3aa60f13b94f4c6846930bdf53"
}
s, err := source.NewFromImage(img, source.AllLayersScope)
s, err := source.NewFromImage(img, source.AllLayersScope, "user-image-input")
if err != nil {
t.Fatal(err)
}
pres := NewPresenter(catalog, s)
pres := NewPresenter(catalog, s.Metadata)
// run presenter
err = pres.Present(&buffer)
if err != nil {