mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 16:33:21 +01:00
make cyclonedx presenter generally reusable (for grype)
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
parent
f46de19c6b
commit
4b45c42f5a
@ -4,8 +4,7 @@ import (
|
|||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/anchore/syft/internal"
|
"github.com/anchore/syft/syft/source"
|
||||||
"github.com/anchore/syft/internal/version"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Source: https://cyclonedx.org/ext/bom-descriptor/
|
// Source: https://cyclonedx.org/ext/bom-descriptor/
|
||||||
@ -35,15 +34,34 @@ type BdComponent struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewBomDescriptor returns a new BomDescriptor tailored for the current time and "syft" tool details.
|
// NewBomDescriptor returns a new BomDescriptor tailored for the current time and "syft" tool details.
|
||||||
func NewBomDescriptor() *BomDescriptor {
|
func NewBomDescriptor(name, version string, srcMetadata source.Metadata) *BomDescriptor {
|
||||||
versionInfo := version.FromBuild()
|
descriptor := BomDescriptor{
|
||||||
return &BomDescriptor{
|
|
||||||
XMLName: xml.Name{},
|
XMLName: xml.Name{},
|
||||||
Timestamp: time.Now().Format(time.RFC3339),
|
Timestamp: time.Now().Format(time.RFC3339),
|
||||||
Tool: &BdTool{
|
Tool: &BdTool{
|
||||||
Vendor: "anchore",
|
Vendor: "anchore",
|
||||||
Name: internal.ApplicationName,
|
Name: name,
|
||||||
Version: versionInfo.Version,
|
Version: version,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch srcMetadata.Scheme {
|
||||||
|
case source.ImageScheme:
|
||||||
|
descriptor.Component = &BdComponent{
|
||||||
|
Component: Component{
|
||||||
|
Type: "container",
|
||||||
|
Name: srcMetadata.ImageMetadata.UserInput,
|
||||||
|
Version: srcMetadata.ImageMetadata.Digest,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
case source.DirectoryScheme:
|
||||||
|
descriptor.Component = &BdComponent{
|
||||||
|
Component: Component{
|
||||||
|
Type: "file",
|
||||||
|
Name: srcMetadata.Path,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &descriptor
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,9 +3,11 @@ package cyclonedx
|
|||||||
import (
|
import (
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/internal"
|
||||||
|
"github.com/anchore/syft/internal/version"
|
||||||
"github.com/anchore/syft/syft/distro"
|
"github.com/anchore/syft/syft/distro"
|
||||||
|
|
||||||
"github.com/anchore/syft/syft/pkg"
|
"github.com/anchore/syft/syft/pkg"
|
||||||
|
"github.com/anchore/syft/syft/source"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -22,19 +24,19 @@ type Document struct {
|
|||||||
BomDescriptor *BomDescriptor `xml:"bd:metadata"` // The BOM descriptor extension
|
BomDescriptor *BomDescriptor `xml:"bd:metadata"` // The BOM descriptor extension
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDocument returns an empty CycloneDX Document object.
|
// NewDocumentFromCatalog returns a CycloneDX Document object populated with the catalog contents.
|
||||||
func NewDocument() Document {
|
func NewDocument(catalog *pkg.Catalog, d distro.Distro, srcMetadata source.Metadata) Document {
|
||||||
return Document{
|
versionInfo := version.FromBuild()
|
||||||
|
|
||||||
|
doc := Document{
|
||||||
XMLNs: "http://cyclonedx.org/schema/bom/1.2",
|
XMLNs: "http://cyclonedx.org/schema/bom/1.2",
|
||||||
XMLNsBd: "http://cyclonedx.org/schema/ext/bom-descriptor/1.0",
|
XMLNsBd: "http://cyclonedx.org/schema/ext/bom-descriptor/1.0",
|
||||||
Version: 1,
|
Version: 1,
|
||||||
SerialNumber: uuid.New().URN(),
|
SerialNumber: uuid.New().URN(),
|
||||||
|
BomDescriptor: NewBomDescriptor(internal.ApplicationName, versionInfo.Version, srcMetadata),
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// NewDocumentFromCatalog returns a CycloneDX Document object populated with the catalog contents.
|
// attach components
|
||||||
func NewDocumentFromCatalog(catalog *pkg.Catalog, d distro.Distro) Document {
|
|
||||||
bom := NewDocument()
|
|
||||||
for p := range catalog.Enumerate() {
|
for p := range catalog.Enumerate() {
|
||||||
component := Component{
|
component := Component{
|
||||||
Type: "library", // TODO: this is not accurate
|
Type: "library", // TODO: this is not accurate
|
||||||
@ -51,10 +53,8 @@ func NewDocumentFromCatalog(catalog *pkg.Catalog, d distro.Distro) Document {
|
|||||||
if len(licenses) > 0 {
|
if len(licenses) > 0 {
|
||||||
component.Licenses = &licenses
|
component.Licenses = &licenses
|
||||||
}
|
}
|
||||||
bom.Components = append(bom.Components, component)
|
doc.Components = append(doc.Components, component)
|
||||||
}
|
}
|
||||||
|
|
||||||
bom.BomDescriptor = NewBomDescriptor()
|
return doc
|
||||||
|
|
||||||
return bom
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,6 @@ package cyclonedx
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/anchore/syft/syft/distro"
|
"github.com/anchore/syft/syft/distro"
|
||||||
@ -22,39 +21,17 @@ type Presenter struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewPresenter creates a CycloneDX presenter from the given Catalog and Locations objects.
|
// NewPresenter creates a CycloneDX presenter from the given Catalog and Locations objects.
|
||||||
func NewPresenter(catalog *pkg.Catalog, s source.Metadata, d distro.Distro) *Presenter {
|
func NewPresenter(catalog *pkg.Catalog, srcMetadata source.Metadata, d distro.Distro) *Presenter {
|
||||||
return &Presenter{
|
return &Presenter{
|
||||||
catalog: catalog,
|
catalog: catalog,
|
||||||
srcMetadata: s,
|
srcMetadata: srcMetadata,
|
||||||
distro: d,
|
distro: d,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Present writes the CycloneDX report to the given io.Writer.
|
// Present writes the CycloneDX report to the given io.Writer.
|
||||||
func (pres *Presenter) Present(output io.Writer) error {
|
func (pres *Presenter) Present(output io.Writer) error {
|
||||||
bom := NewDocumentFromCatalog(pres.catalog, pres.distro)
|
bom := NewDocument(pres.catalog, pres.distro, pres.srcMetadata)
|
||||||
|
|
||||||
switch pres.srcMetadata.Scheme {
|
|
||||||
case source.DirectoryScheme:
|
|
||||||
bom.BomDescriptor.Component = &BdComponent{
|
|
||||||
Component: Component{
|
|
||||||
Type: "file",
|
|
||||||
Name: pres.srcMetadata.Path,
|
|
||||||
Version: "",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
case source.ImageScheme:
|
|
||||||
// TODO: can we use the tags a bit better?
|
|
||||||
bom.BomDescriptor.Component = &BdComponent{
|
|
||||||
Component: Component{
|
|
||||||
Type: "container",
|
|
||||||
Name: pres.srcMetadata.ImageMetadata.UserInput,
|
|
||||||
Version: pres.srcMetadata.ImageMetadata.Digest,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unsupported source: %T", pres.srcMetadata.Scheme)
|
|
||||||
}
|
|
||||||
|
|
||||||
encoder := xml.NewEncoder(output)
|
encoder := xml.NewEncoder(output)
|
||||||
encoder.Indent("", " ")
|
encoder.Indent("", " ")
|
||||||
|
|||||||
@ -177,7 +177,7 @@ func TestCycloneDxImgsPresenter(t *testing.T) {
|
|||||||
|
|
||||||
if !bytes.Equal(expected, actual) {
|
if !bytes.Equal(expected, actual) {
|
||||||
dmp := diffmatchpatch.New()
|
dmp := diffmatchpatch.New()
|
||||||
diffs := dmp.DiffMain(string(expected), string(actual), true)
|
diffs := dmp.DiffMain(string(actual), string(expected), true)
|
||||||
t.Errorf("mismatched output:\n%s", dmp.DiffPrettyText(diffs))
|
t.Errorf("mismatched output:\n%s", dmp.DiffPrettyText(diffs))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,23 @@
|
|||||||
package json
|
package json
|
||||||
|
|
||||||
|
import "github.com/anchore/syft/syft/distro"
|
||||||
|
|
||||||
// Distribution provides information about a detected Linux Distribution
|
// Distribution provides information about a detected Linux Distribution
|
||||||
type Distribution struct {
|
type Distribution struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
IDLike string `json:"idLike"`
|
IDLike string `json:"idLike"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewDistribution(d distro.Distro) Distribution {
|
||||||
|
distroName := d.Name()
|
||||||
|
if distroName == "UnknownDistroType" {
|
||||||
|
distroName = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return Distribution{
|
||||||
|
Name: distroName,
|
||||||
|
Version: d.FullVersion(),
|
||||||
|
IDLike: d.IDLike,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -21,19 +21,10 @@ func NewDocument(catalog *pkg.Catalog, srcMetadata source.Metadata, d distro.Dis
|
|||||||
return Document{}, nil
|
return Document{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
distroName := d.Name()
|
|
||||||
if distroName == "UnknownDistroType" {
|
|
||||||
distroName = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
doc := Document{
|
doc := Document{
|
||||||
Artifacts: make([]Artifact, 0),
|
Artifacts: make([]Artifact, 0),
|
||||||
Source: src,
|
Source: src,
|
||||||
Distro: Distribution{
|
Distro: NewDistribution(d),
|
||||||
Name: distroName,
|
|
||||||
Version: d.FullVersion(),
|
|
||||||
IDLike: d.IDLike,
|
|
||||||
},
|
|
||||||
Descriptor: Descriptor{
|
Descriptor: Descriptor{
|
||||||
Name: internal.ApplicationName,
|
Name: internal.ApplicationName,
|
||||||
Version: version.FromBuild().Version,
|
Version: version.FromBuild().Version,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user