Introduce a single SBOM document (#606)

* [wip] single sbom doc

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* fix tests

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* fix more tests

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* fix linting

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update cli tests

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* remove scope in import path

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* swap SPDX tag-value formatter to single sbom document

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* bust CLI cache

Signed-off-by: Alex Goodman <alex.goodman@anchore.com>

* update fixture to byte diff

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>

* byte for byte

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>

* bust the cache

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>

* who needs cache

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>

* add jar for testing

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>

* no more bit flips

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>

* update apk with the delta for image and directory cases

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>

* restore cache workflow

Signed-off-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>

Co-authored-by: Christopher Angelo Phillips <christopher.phillips@anchore.com>
This commit is contained in:
Alex Goodman
2021-11-05 10:05:49 -04:00
committed by GitHub
co-authored by Christopher Angelo Phillips
parent 6d0ee326d8
commit bb0f35bac4
80 changed files with 408 additions and 386 deletions
@@ -3,6 +3,7 @@ package poweruser
import (
"github.com/anchore/syft/internal/formats/syftjson"
"github.com/anchore/syft/internal/formats/syftjson/model"
"github.com/anchore/syft/syft/sbom"
)
type JSONDocument struct {
@@ -18,17 +19,17 @@ type JSONDocument struct {
}
// NewJSONDocument creates and populates a new JSON document struct from the given cataloging results.
func NewJSONDocument(config JSONDocumentConfig) (JSONDocument, error) {
fileMetadata, err := NewJSONFileMetadata(config.FileMetadata, config.FileDigests)
func NewJSONDocument(s sbom.SBOM, appConfig interface{}) (JSONDocument, error) {
fileMetadata, err := NewJSONFileMetadata(s.Artifacts.FileMetadata, s.Artifacts.FileDigests)
if err != nil {
return JSONDocument{}, err
}
return JSONDocument{
FileClassifications: NewJSONFileClassifications(config.FileClassifications),
FileContents: NewJSONFileContents(config.FileContents),
FileClassifications: NewJSONFileClassifications(s.Artifacts.FileClassifications),
FileContents: NewJSONFileContents(s.Artifacts.FileContents),
FileMetadata: fileMetadata,
Secrets: NewJSONSecrets(config.Secrets),
Document: syftjson.ToFormatModel(config.PackageCatalog, &config.SourceMetadata, config.Distro, config.ApplicationConfig.Package.Cataloger.ScopeOpt, config.ApplicationConfig),
Secrets: NewJSONSecrets(s.Artifacts.Secrets),
Document: syftjson.ToFormatModel(s, appConfig),
}, nil
}
@@ -1,21 +0,0 @@
package poweruser
import (
"github.com/anchore/syft/internal/config"
"github.com/anchore/syft/syft/distro"
"github.com/anchore/syft/syft/file"
"github.com/anchore/syft/syft/pkg"
"github.com/anchore/syft/syft/source"
)
type JSONDocumentConfig struct {
ApplicationConfig config.Application
PackageCatalog *pkg.Catalog
FileMetadata map[source.Location]source.FileMetadata
FileDigests map[source.Location][]file.Digest
FileClassifications map[source.Location][]file.Classification
FileContents map[source.Location]string
Secrets map[source.Location][]file.SearchResult
Distro *distro.Distro
SourceMetadata source.Metadata
}
@@ -3,23 +3,27 @@ package poweruser
import (
"encoding/json"
"io"
"github.com/anchore/syft/syft/sbom"
)
// JSONPresenter is a JSON presentation object for the syft results
type JSONPresenter struct {
config JSONDocumentConfig
sbom sbom.SBOM
config interface{}
}
// NewJSONPresenter creates a new JSON presenter object for the given cataloging results.
func NewJSONPresenter(config JSONDocumentConfig) *JSONPresenter {
func NewJSONPresenter(s sbom.SBOM, appConfig interface{}) *JSONPresenter {
return &JSONPresenter{
config: config,
sbom: s,
config: appConfig,
}
}
// Present the PackageCatalog results to the given writer.
func (p *JSONPresenter) Present(output io.Writer) error {
doc, err := NewJSONDocument(p.config)
doc, err := NewJSONDocument(p.sbom, p.config)
if err != nil {
return err
}
@@ -5,6 +5,8 @@ import (
"flag"
"testing"
"github.com/anchore/syft/syft/sbom"
"github.com/sergi/go-diff/diffmatchpatch"
"github.com/anchore/syft/syft/file"
@@ -77,63 +79,66 @@ func TestJSONPresenter(t *testing.T) {
},
})
cfg := JSONDocumentConfig{
ApplicationConfig: config.Application{
FileMetadata: config.FileMetadata{
Digests: []string{"sha256"},
},
appConfig := config.Application{
FileMetadata: config.FileMetadata{
Digests: []string{"sha256"},
},
PackageCatalog: catalog,
FileMetadata: map[source.Location]source.FileMetadata{
source.NewLocation("/a/place"): {
Mode: 0775,
Type: "directory",
UserID: 0,
GroupID: 0,
},
source.NewLocation("/a/place/a"): {
Mode: 0775,
Type: "regularFile",
UserID: 0,
GroupID: 0,
},
source.NewLocation("/b"): {
Mode: 0775,
Type: "symbolicLink",
LinkDestination: "/c",
UserID: 0,
GroupID: 0,
},
source.NewLocation("/b/place/b"): {
Mode: 0644,
Type: "regularFile",
UserID: 1,
GroupID: 2,
},
},
FileDigests: map[source.Location][]file.Digest{
source.NewLocation("/a/place/a"): {
{
Algorithm: "sha256",
Value: "366a3f5653e34673b875891b021647440d0127c2ef041e3b1a22da2a7d4f3703",
}
cfg := sbom.SBOM{
Artifacts: sbom.Artifacts{
PackageCatalog: catalog,
FileMetadata: map[source.Location]source.FileMetadata{
source.NewLocation("/a/place"): {
Mode: 0775,
Type: "directory",
UserID: 0,
GroupID: 0,
},
source.NewLocation("/a/place/a"): {
Mode: 0775,
Type: "regularFile",
UserID: 0,
GroupID: 0,
},
source.NewLocation("/b"): {
Mode: 0775,
Type: "symbolicLink",
LinkDestination: "/c",
UserID: 0,
GroupID: 0,
},
source.NewLocation("/b/place/b"): {
Mode: 0644,
Type: "regularFile",
UserID: 1,
GroupID: 2,
},
},
source.NewLocation("/b/place/b"): {
{
Algorithm: "sha256",
Value: "1b3722da2a7d90d033b87581a2a3f12021647445653e34666ef041e3b4f3707c",
FileDigests: map[source.Location][]file.Digest{
source.NewLocation("/a/place/a"): {
{
Algorithm: "sha256",
Value: "366a3f5653e34673b875891b021647440d0127c2ef041e3b1a22da2a7d4f3703",
},
},
source.NewLocation("/b/place/b"): {
{
Algorithm: "sha256",
Value: "1b3722da2a7d90d033b87581a2a3f12021647445653e34666ef041e3b4f3707c",
},
},
},
FileContents: map[source.Location]string{
source.NewLocation("/a/place/a"): "the-contents",
},
Distro: &distro.Distro{
Type: distro.RedHat,
RawVersion: "7",
IDLike: "rhel",
},
},
FileContents: map[source.Location]string{
source.NewLocation("/a/place/a"): "the-contents",
},
Distro: &distro.Distro{
Type: distro.RedHat,
RawVersion: "7",
IDLike: "rhel",
},
SourceMetadata: source.Metadata{
Source: source.Metadata{
Scheme: source.ImageScheme,
ImageMetadata: source.ImageMetadata{
UserInput: "user-image-input",
@@ -163,7 +168,7 @@ func TestJSONPresenter(t *testing.T) {
},
}
if err := NewJSONPresenter(cfg).Present(&buffer); err != nil {
if err := NewJSONPresenter(cfg, appConfig).Present(&buffer); err != nil {
t.Fatal(err)
}
actual := buffer.Bytes()
@@ -157,8 +157,7 @@
],
"manifest": "ZXlKelkyaGxiV0ZXWlhKemFXOXVJam95TENKdFpXUnBZVlI1Y0dVaU9pSmguLi4=",
"config": "ZXlKaGNtTm9hWFJsWTNSMWNtVWlPaUpoYldRMk5DSXNJbU52Ym1acC4uLg==",
"repoDigests": [],
"scope": ""
"repoDigests": []
}
},
"distro": {