mirror of
https://github.com/anchore/syft.git
synced 2026-02-12 02:26:42 +01:00
move source metadata upstream and fix tests
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
parent
aa0d444fd4
commit
6f7a4fd3e4
@ -50,7 +50,7 @@ func setGlobalCliOptions() {
|
||||
flag := "scope"
|
||||
rootCmd.Flags().StringP(
|
||||
"scope", "s", source.SquashedScope.String(),
|
||||
fmt.Sprintf("selection of layers to catalog, options=%v", source.Options))
|
||||
fmt.Sprintf("selection of layers to catalog, options=%v", source.AllScopes))
|
||||
if err := viper.BindPFlag(flag, rootCmd.Flags().Lookup(flag)); err != nil {
|
||||
fmt.Printf("unable to bind flag '%s': %+v", flag, err)
|
||||
os.Exit(1)
|
||||
|
||||
@ -100,7 +100,7 @@ func startWorker(userInput string) <-chan error {
|
||||
|
||||
bus.Publish(partybus.Event{
|
||||
Type: event.CatalogerFinished,
|
||||
Value: presenter.GetPresenter(appConfig.PresenterOpt, *scope, catalog, distro),
|
||||
Value: presenter.GetPresenter(appConfig.PresenterOpt, scope.Metadata, catalog, distro),
|
||||
})
|
||||
}()
|
||||
return errs
|
||||
|
||||
@ -5,10 +5,7 @@
|
||||
"items": {
|
||||
"properties": {
|
||||
"foundBy": {
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
"type": "string"
|
||||
},
|
||||
"language": {
|
||||
"type": "string"
|
||||
@ -27,33 +24,21 @@
|
||||
]
|
||||
},
|
||||
"locations": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "null"
|
||||
},
|
||||
{
|
||||
"items": {
|
||||
"properties": {
|
||||
"layerID": {
|
||||
"type": "string"
|
||||
},
|
||||
"layerIndex": {
|
||||
"type": "integer"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"layerID",
|
||||
"layerIndex",
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
"items": {
|
||||
"properties": {
|
||||
"layerID": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
}
|
||||
]
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"path"
|
||||
],
|
||||
"type": "object"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"metadata": {
|
||||
"properties": {
|
||||
@ -354,7 +339,7 @@
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"reportTimestamp": {
|
||||
"scope": {
|
||||
"type": "string"
|
||||
},
|
||||
"version": {
|
||||
@ -363,7 +348,7 @@
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"reportTimestamp",
|
||||
"scope",
|
||||
"version"
|
||||
],
|
||||
"type": "object"
|
||||
@ -432,6 +417,9 @@
|
||||
"type": "string"
|
||||
},
|
||||
"type": "array"
|
||||
},
|
||||
"userInput": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@ -439,7 +427,8 @@
|
||||
"layers",
|
||||
"mediaType",
|
||||
"size",
|
||||
"tags"
|
||||
"tags",
|
||||
"userInput"
|
||||
],
|
||||
"type": "object"
|
||||
}
|
||||
|
||||
@ -54,7 +54,7 @@ func TestDpkgCataloger(t *testing.T) {
|
||||
img, cleanup := imagetest.GetFixtureImage(t, "docker-archive", "image-dpkg")
|
||||
defer cleanup()
|
||||
|
||||
s, err := source.NewFromImage(img, source.AllLayersScope)
|
||||
s, err := source.NewFromImage(img, source.AllLayersScope, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -79,7 +79,7 @@ func TestDpkgCataloger(t *testing.T) {
|
||||
// we will test the sources separately
|
||||
var sourcesList = make([]string, len(a.Locations))
|
||||
for i, s := range a.Locations {
|
||||
sourcesList[i] = string(s.Path)
|
||||
sourcesList[i] = s.Path
|
||||
}
|
||||
a.Locations = nil
|
||||
|
||||
|
||||
@ -12,7 +12,8 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
packagesGlob = "**/var/lib/rpm/Packages"
|
||||
packagesGlob = "**/var/lib/rpm/Packages"
|
||||
catalogerName = "rpmdb-cataloger"
|
||||
)
|
||||
|
||||
type Cataloger struct{}
|
||||
@ -24,7 +25,7 @@ func NewRpmdbCataloger() *Cataloger {
|
||||
|
||||
// Name returns a string that uniquely describes a cataloger
|
||||
func (c *Cataloger) Name() string {
|
||||
return "rpmdb-cataloger"
|
||||
return catalogerName
|
||||
}
|
||||
|
||||
// Catalog is given an object to resolve file references and content, this function returns any discovered Packages after analyzing rpm db installation.
|
||||
|
||||
@ -55,6 +55,7 @@ func parseRpmDB(resolver source.FileResolver, dbLocation source.Location, reader
|
||||
Version: fmt.Sprintf("%s-%s", entry.Version, entry.Release), // this is what engine does
|
||||
//Version: fmt.Sprintf("%d:%s-%s.%s", entry.Epoch, entry.Version, entry.Release, entry.Arch),
|
||||
Locations: []source.Location{dbLocation},
|
||||
FoundBy: catalogerName,
|
||||
Type: pkg.RpmPkg,
|
||||
MetadataType: pkg.RpmdbMetadataType,
|
||||
Metadata: pkg.RpmdbMetadata{
|
||||
|
||||
@ -43,7 +43,7 @@ func (r *rpmdbTestFileResolverMock) RelativeFileByPath(source.Location, string)
|
||||
}
|
||||
|
||||
func TestParseRpmDB(t *testing.T) {
|
||||
dbRef := file.NewFileReference("test-path")
|
||||
dbLocation := source.NewLocation("test-path")
|
||||
|
||||
tests := []struct {
|
||||
fixture string
|
||||
@ -58,7 +58,8 @@ func TestParseRpmDB(t *testing.T) {
|
||||
"dive": {
|
||||
Name: "dive",
|
||||
Version: "0.9.2-1",
|
||||
Source: []file.Reference{dbRef},
|
||||
Locations: []source.Location{dbLocation},
|
||||
FoundBy: catalogerName,
|
||||
Type: pkg.RpmPkg,
|
||||
MetadataType: pkg.RpmdbMetadataType,
|
||||
Metadata: pkg.RpmdbMetadata{
|
||||
@ -84,7 +85,8 @@ func TestParseRpmDB(t *testing.T) {
|
||||
"dive": {
|
||||
Name: "dive",
|
||||
Version: "0.9.2-1",
|
||||
Source: []file.Reference{dbRef},
|
||||
Locations: []source.Location{dbLocation},
|
||||
FoundBy: catalogerName,
|
||||
Type: pkg.RpmPkg,
|
||||
MetadataType: pkg.RpmdbMetadataType,
|
||||
Metadata: pkg.RpmdbMetadata{
|
||||
@ -120,7 +122,7 @@ func TestParseRpmDB(t *testing.T) {
|
||||
|
||||
fileResolver := newTestFileResolver(test.ignorePaths)
|
||||
|
||||
actual, err := parseRpmDB(fileResolver, dbRef, fixture)
|
||||
actual, err := parseRpmDB(fileResolver, dbLocation, fixture)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse rpmdb: %+v", err)
|
||||
}
|
||||
|
||||
@ -36,7 +36,7 @@ import (
|
||||
// set of packages, the identified Linux distribution, and the source object used to wrap the data source.
|
||||
func Catalog(userInput string, scoptOpt source.Scope) (*pkg.Catalog, *source.Source, *distro.Distro, error) {
|
||||
log.Info("cataloging image")
|
||||
s, cleanup, err := source.NewSource(userInput, scoptOpt)
|
||||
s, cleanup, err := source.New(userInput, scoptOpt)
|
||||
defer cleanup()
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
@ -70,13 +70,13 @@ func CatalogFromScope(s source.Source) (*pkg.Catalog, error) {
|
||||
|
||||
// conditionally have two sets of catalogers
|
||||
var catalogers []cataloger.Cataloger
|
||||
switch s.Scheme {
|
||||
switch s.Metadata.Scheme {
|
||||
case source.ImageScheme:
|
||||
catalogers = cataloger.ImageCatalogers()
|
||||
case source.DirectoryScheme:
|
||||
catalogers = cataloger.DirectoryCatalogers()
|
||||
default:
|
||||
return nil, fmt.Errorf("unable to determine cataloger set from scheme=%+v", s.Scheme)
|
||||
return nil, fmt.Errorf("unable to determine cataloger set from scheme=%+v", s.Metadata.Scheme)
|
||||
}
|
||||
|
||||
return cataloger.Catalog(s.Resolver, catalogers...)
|
||||
|
||||
@ -9,7 +9,7 @@ import (
|
||||
// at http://manpages.ubuntu.com/manpages/xenial/man1/dpkg-query.1.html in the --showformat section.
|
||||
type DpkgMetadata struct {
|
||||
Package string `mapstructure:"Package" json:"package"`
|
||||
Source string `mapstructure:"Locations" json:"source"`
|
||||
Source string `mapstructure:"Source" json:"source"`
|
||||
Version string `mapstructure:"Version" json:"version"`
|
||||
Architecture string `mapstructure:"Architecture" json:"architecture"`
|
||||
Maintainer string `mapstructure:"Maintainer" json:"maintainer"`
|
||||
|
||||
@ -19,16 +19,16 @@ type ID int64
|
||||
// Package represents an application or library that has been bundled into a distributable format.
|
||||
type Package struct {
|
||||
id ID // uniquely identifies a package, set by the cataloger
|
||||
Name string `json:"manifest"` // the package name
|
||||
Version string `json:"version"` // the version of the package
|
||||
FoundBy string `json:"foundBy"` // the specific cataloger that discovered this package
|
||||
Locations []source.Location `json:"-"` // the locations that lead to the discovery of this package (note: this is not necessarily the locations that make up this package)
|
||||
Name string // the package name
|
||||
Version string // the version of the package
|
||||
FoundBy string // the specific cataloger that discovered this package
|
||||
Locations []source.Location // the locations that lead to the discovery of this package (note: this is not necessarily the locations that make up this package)
|
||||
// TODO: should we move licenses into metadata?
|
||||
Licenses []string `json:"licenses"` // licenses discovered with the package metadata
|
||||
Language Language `json:"language"` // the language ecosystem this package belongs to (e.g. JavaScript, Python, etc)
|
||||
Type Type `json:"type"` // the package type (e.g. Npm, Yarn, Python, Rpm, Deb, etc)
|
||||
MetadataType MetadataType `json:"metadataType,omitempty"` // the shape of the additional data in the "metadata" field
|
||||
Metadata interface{} `json:"metadata,omitempty"` // additional data found while parsing the package source
|
||||
Licenses []string // licenses discovered with the package metadata
|
||||
Language Language // the language ecosystem this package belongs to (e.g. JavaScript, Python, etc)
|
||||
Type Type // the package type (e.g. Npm, Yarn, Python, Rpm, Deb, etc)
|
||||
MetadataType MetadataType // the shape of the additional data in the "metadata" field
|
||||
Metadata interface{} // additional data found while parsing the package source
|
||||
}
|
||||
|
||||
// ID returns the package ID, which is unique relative to a package catalog.
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
@ -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,
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@ -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
|
||||
}
|
||||
|
||||
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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...
|
||||
|
||||
@ -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 {
|
||||
|
||||
44
syft/source/image_metadata.go
Normal file
44
syft/source/image_metadata.go
Normal file
@ -0,0 +1,44 @@
|
||||
package source
|
||||
|
||||
import "github.com/anchore/stereoscope/pkg/image"
|
||||
|
||||
type ImageMetadata struct {
|
||||
UserInput string `json:"userInput"`
|
||||
Layers []LayerMetadata `json:"layers"`
|
||||
Size int64 `json:"size"`
|
||||
Digest string `json:"digest"`
|
||||
MediaType string `json:"mediaType"`
|
||||
Tags []string `json:"tags"`
|
||||
}
|
||||
|
||||
type LayerMetadata struct {
|
||||
MediaType string `json:"mediaType"`
|
||||
Digest string `json:"digest"`
|
||||
Size int64 `json:"size"`
|
||||
}
|
||||
|
||||
func NewImageMetadata(img *image.Image, userInput string) ImageMetadata {
|
||||
// populate artifacts...
|
||||
tags := make([]string, len(img.Metadata.Tags))
|
||||
for idx, tag := range img.Metadata.Tags {
|
||||
tags[idx] = tag.String()
|
||||
}
|
||||
theImg := ImageMetadata{
|
||||
UserInput: userInput,
|
||||
Digest: img.Metadata.Digest,
|
||||
Size: img.Metadata.Size,
|
||||
MediaType: string(img.Metadata.MediaType),
|
||||
Tags: tags,
|
||||
Layers: make([]LayerMetadata, len(img.Layers)),
|
||||
}
|
||||
|
||||
// populate image metadata
|
||||
for idx, l := range img.Layers {
|
||||
theImg.Layers[idx] = LayerMetadata{
|
||||
MediaType: string(l.Metadata.MediaType),
|
||||
Digest: l.Metadata.Digest,
|
||||
Size: l.Metadata.Size,
|
||||
}
|
||||
}
|
||||
return theImg
|
||||
}
|
||||
@ -8,10 +8,9 @@ import (
|
||||
)
|
||||
|
||||
type Location struct {
|
||||
Path string `json:"path"`
|
||||
LayerIndex uint `json:"layerIndex"`
|
||||
LayerID string `json:"layerID"`
|
||||
ref file.Reference
|
||||
Path string `json:"path"`
|
||||
FileSystemID string `json:"layerID,omitempty"` // TODO: comment
|
||||
ref file.Reference
|
||||
}
|
||||
|
||||
func NewLocation(path string) Location {
|
||||
@ -31,9 +30,8 @@ func NewLocationFromImage(ref file.Reference, img *image.Image) Location {
|
||||
}
|
||||
|
||||
return Location{
|
||||
Path: string(ref.Path),
|
||||
LayerIndex: entry.Source.Metadata.Index,
|
||||
LayerID: entry.Source.Metadata.Digest,
|
||||
ref: ref,
|
||||
Path: string(ref.Path),
|
||||
FileSystemID: entry.Source.Metadata.Digest,
|
||||
ref: ref,
|
||||
}
|
||||
}
|
||||
|
||||
8
syft/source/metadata.go
Normal file
8
syft/source/metadata.go
Normal file
@ -0,0 +1,8 @@
|
||||
package source
|
||||
|
||||
type Metadata struct {
|
||||
Scope Scope // specific perspective to catalog
|
||||
Scheme Scheme // the source data scheme type (directory or image)
|
||||
ImageMetadata ImageMetadata // all image info (image only)
|
||||
Path string // the root path to be cataloged (directory only)
|
||||
}
|
||||
@ -2,21 +2,15 @@ package source
|
||||
|
||||
import "strings"
|
||||
|
||||
type Scope string
|
||||
|
||||
const (
|
||||
UnknownScope Scope = iota
|
||||
SquashedScope
|
||||
AllLayersScope
|
||||
UnknownScope Scope = "UnknownScope"
|
||||
SquashedScope Scope = "Squashed"
|
||||
AllLayersScope Scope = "AllLayers"
|
||||
)
|
||||
|
||||
type Scope int
|
||||
|
||||
var optionStr = []string{
|
||||
"UnknownScope",
|
||||
"Squashed",
|
||||
"AllLayers",
|
||||
}
|
||||
|
||||
var Options = []Scope{
|
||||
var AllScopes = []Scope{
|
||||
SquashedScope,
|
||||
AllLayersScope,
|
||||
}
|
||||
@ -32,9 +26,5 @@ func ParseScope(userStr string) Scope {
|
||||
}
|
||||
|
||||
func (o Scope) String() string {
|
||||
if int(o) >= len(optionStr) || o < 0 {
|
||||
return optionStr[0]
|
||||
}
|
||||
|
||||
return optionStr[o]
|
||||
return string(o)
|
||||
}
|
||||
|
||||
@ -1,17 +0,0 @@
|
||||
package source
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestOptionStringerBoundary(t *testing.T) {
|
||||
var _ fmt.Stringer = Scope(0)
|
||||
|
||||
for _, c := range []int{-1, 0, 3} {
|
||||
option := Scope(c)
|
||||
if option.String() != UnknownScope.String() {
|
||||
t.Errorf("expected Scope(%d) to be unknown, found '%+v'", c, option)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -15,29 +15,18 @@ import (
|
||||
"github.com/anchore/stereoscope/pkg/image"
|
||||
)
|
||||
|
||||
// ImageSource represents a data source that is a container image
|
||||
type ImageSource struct {
|
||||
Img *image.Image // the image object to be cataloged
|
||||
}
|
||||
|
||||
// DirSource represents a data source that is a filesystem directory tree
|
||||
type DirSource struct {
|
||||
Path string // the root path to be cataloged
|
||||
}
|
||||
|
||||
// Source is an object that captures the data source to be cataloged, configuration, and a specific resolver used
|
||||
// in cataloging (based on the data source and configuration)
|
||||
type Source struct {
|
||||
Scope Scope // specific perspective to catalog
|
||||
Resolver Resolver // a Resolver object to use in file path/glob resolution and file contents resolution
|
||||
Target interface{} // the specific source object to be cataloged
|
||||
Scheme Scheme // the source data scheme type (directory or image)
|
||||
Resolver Resolver // a Resolver object to use in file path/glob resolution and file contents resolution
|
||||
Image *image.Image // the image object to be cataloged (image only)
|
||||
Metadata Metadata
|
||||
}
|
||||
|
||||
type sourceDetector func(string) (image.Source, string, error)
|
||||
|
||||
// NewSource produces a Source based on userInput like dir: or image:tag
|
||||
func NewSource(userInput string, o Scope) (Source, func(), error) {
|
||||
// New produces a Source based on userInput like dir: or image:tag
|
||||
func New(userInput string, o Scope) (Source, func(), error) {
|
||||
fs := afero.NewOsFs()
|
||||
parsedScheme, location, err := detectScheme(fs, image.DetectSource, userInput)
|
||||
if err != nil {
|
||||
@ -71,7 +60,7 @@ func NewSource(userInput string, o Scope) (Source, func(), error) {
|
||||
return Source{}, cleanup, fmt.Errorf("could not fetch image '%s': %w", location, err)
|
||||
}
|
||||
|
||||
s, err := NewFromImage(img, o)
|
||||
s, err := NewFromImage(img, o, location)
|
||||
if err != nil {
|
||||
return Source{}, cleanup, fmt.Errorf("could not populate source with image: %w", err)
|
||||
}
|
||||
@ -87,16 +76,16 @@ func NewFromDirectory(path string) (Source, error) {
|
||||
Resolver: &DirectoryResolver{
|
||||
Path: path,
|
||||
},
|
||||
Target: DirSource{
|
||||
Path: path,
|
||||
Metadata: Metadata{
|
||||
Scheme: DirectoryScheme,
|
||||
Path: path,
|
||||
},
|
||||
Scheme: DirectoryScheme,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewFromImage creates a new source object tailored to catalog a given container image, relative to the
|
||||
// option given (e.g. all-layers, squashed, etc)
|
||||
func NewFromImage(img *image.Image, option Scope) (Source, error) {
|
||||
func NewFromImage(img *image.Image, option Scope, userImageStr string) (Source, error) {
|
||||
if img == nil {
|
||||
return Source{}, fmt.Errorf("no image given")
|
||||
}
|
||||
@ -107,11 +96,12 @@ func NewFromImage(img *image.Image, option Scope) (Source, error) {
|
||||
}
|
||||
|
||||
return Source{
|
||||
Scope: option,
|
||||
Resolver: resolver,
|
||||
Target: ImageSource{
|
||||
Img: img,
|
||||
Image: img,
|
||||
Metadata: Metadata{
|
||||
Scope: option,
|
||||
Scheme: ImageScheme,
|
||||
ImageMetadata: NewImageMetadata(img, userImageStr),
|
||||
},
|
||||
Scheme: ImageScheme,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -9,41 +9,41 @@ import (
|
||||
"github.com/spf13/afero"
|
||||
)
|
||||
|
||||
func TestNewScopeFromImageFails(t *testing.T) {
|
||||
func TestNewFromImageFails(t *testing.T) {
|
||||
t.Run("no image given", func(t *testing.T) {
|
||||
_, err := NewFromImage(nil, AllLayersScope)
|
||||
_, err := NewFromImage(nil, AllLayersScope, "")
|
||||
if err == nil {
|
||||
t.Errorf("expected an error condition but none was given")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestNewScopeFromImageUnknownOption(t *testing.T) {
|
||||
func TestNewFromImageUnknownOption(t *testing.T) {
|
||||
img := image.Image{}
|
||||
|
||||
t.Run("unknown option is an error", func(t *testing.T) {
|
||||
_, err := NewFromImage(&img, UnknownScope)
|
||||
_, err := NewFromImage(&img, UnknownScope, "")
|
||||
if err == nil {
|
||||
t.Errorf("expected an error condition but none was given")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestNewScopeFromImage(t *testing.T) {
|
||||
func TestNewFromImage(t *testing.T) {
|
||||
layer := image.NewLayer(nil)
|
||||
img := image.Image{
|
||||
Layers: []*image.Layer{layer},
|
||||
}
|
||||
|
||||
t.Run("create a new Locations object from image", func(t *testing.T) {
|
||||
_, err := NewFromImage(&img, AllLayersScope)
|
||||
_, err := NewFromImage(&img, AllLayersScope, "")
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error when creating a new Locations from img: %+v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestDirectoryScope(t *testing.T) {
|
||||
func TestNewFromDirectory(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
input string
|
||||
@ -78,16 +78,16 @@ func TestDirectoryScope(t *testing.T) {
|
||||
}
|
||||
for _, test := range testCases {
|
||||
t.Run(test.desc, func(t *testing.T) {
|
||||
p, err := NewFromDirectory(test.input)
|
||||
src, err := NewFromDirectory(test.input)
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("could not create NewDirScope: %+v", err)
|
||||
}
|
||||
if p.Target.(DirSource).Path != test.input {
|
||||
t.Errorf("mismatched stringer: '%s' != '%s'", p.Target.(DirSource).Path, test.input)
|
||||
if src.Metadata.Path != test.input {
|
||||
t.Errorf("mismatched stringer: '%s' != '%s'", src.Metadata.Path, test.input)
|
||||
}
|
||||
|
||||
refs, err := p.Resolver.FilesByPath(test.inputPaths...)
|
||||
refs, err := src.Resolver.FilesByPath(test.inputPaths...)
|
||||
if err != nil {
|
||||
t.Errorf("FilesByPath call produced an error: %+v", err)
|
||||
}
|
||||
@ -100,7 +100,7 @@ func TestDirectoryScope(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultipleFileContentsByRefContents(t *testing.T) {
|
||||
func TestMultipleFileContentsByLocation(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
input string
|
||||
@ -136,7 +136,8 @@ func TestMultipleFileContentsByRefContents(t *testing.T) {
|
||||
}
|
||||
location := locations[0]
|
||||
|
||||
content, err := p.Resolver.FileContentsByLocation(location)
|
||||
contents, err := p.Resolver.MultipleFileContentsByLocation([]Location{location})
|
||||
content := contents[location]
|
||||
|
||||
if content != test.expected {
|
||||
t.Errorf("unexpected contents from file: '%s' != '%s'", content, test.expected)
|
||||
@ -146,7 +147,7 @@ func TestMultipleFileContentsByRefContents(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultipleFileContentsByRefNoContents(t *testing.T) {
|
||||
func TestFilesByPathDoesNotExist(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
input string
|
||||
|
||||
@ -37,7 +37,7 @@ func TestCatalogFromJSON(t *testing.T) {
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
jsonPres := json.NewPresenter(expectedCatalog, *s, *expectedDistro)
|
||||
jsonPres := json.NewPresenter(expectedCatalog, s.Metadata, *expectedDistro)
|
||||
if err = jsonPres.Present(&buf); err != nil {
|
||||
t.Fatalf("failed to write to presenter: %+v", err)
|
||||
}
|
||||
@ -73,8 +73,6 @@ func TestCatalogFromJSON(t *testing.T) {
|
||||
a := actualPackages[i]
|
||||
|
||||
// omit fields that should be missing
|
||||
e.Locations = nil
|
||||
e.FoundBy = ""
|
||||
if e.MetadataType == pkg.JavaMetadataType {
|
||||
metadata := e.Metadata.(pkg.JavaMetadata)
|
||||
metadata.Parent = nil
|
||||
|
||||
@ -67,7 +67,7 @@ func testJsonSchema(t *testing.T, catalog *pkg.Catalog, theScope *source.Source,
|
||||
t.Fatalf("bad distro: %+v", err)
|
||||
}
|
||||
|
||||
p := presenter.GetPresenter(presenter.JSONPresenter, *theScope, catalog, &d)
|
||||
p := presenter.GetPresenter(presenter.JSONPresenter, theScope.Metadata, catalog, &d)
|
||||
if p == nil {
|
||||
t.Fatal("unable to get presenter")
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user