mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 08:23:15 +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"
|
||||
"time"
|
||||
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/internal/version"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
// 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.
|
||||
func NewBomDescriptor() *BomDescriptor {
|
||||
versionInfo := version.FromBuild()
|
||||
return &BomDescriptor{
|
||||
func NewBomDescriptor(name, version string, srcMetadata source.Metadata) *BomDescriptor {
|
||||
descriptor := BomDescriptor{
|
||||
XMLName: xml.Name{},
|
||||
Timestamp: time.Now().Format(time.RFC3339),
|
||||
Tool: &BdTool{
|
||||
Vendor: "anchore",
|
||||
Name: internal.ApplicationName,
|
||||
Version: versionInfo.Version,
|
||||
Name: name,
|
||||
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 (
|
||||
"encoding/xml"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
@ -22,19 +24,19 @@ type Document struct {
|
||||
BomDescriptor *BomDescriptor `xml:"bd:metadata"` // The BOM descriptor extension
|
||||
}
|
||||
|
||||
// NewDocument returns an empty CycloneDX Document object.
|
||||
func NewDocument() Document {
|
||||
return Document{
|
||||
XMLNs: "http://cyclonedx.org/schema/bom/1.2",
|
||||
XMLNsBd: "http://cyclonedx.org/schema/ext/bom-descriptor/1.0",
|
||||
Version: 1,
|
||||
SerialNumber: uuid.New().URN(),
|
||||
}
|
||||
}
|
||||
|
||||
// NewDocumentFromCatalog returns a CycloneDX Document object populated with the catalog contents.
|
||||
func NewDocumentFromCatalog(catalog *pkg.Catalog, d distro.Distro) Document {
|
||||
bom := NewDocument()
|
||||
func NewDocument(catalog *pkg.Catalog, d distro.Distro, srcMetadata source.Metadata) Document {
|
||||
versionInfo := version.FromBuild()
|
||||
|
||||
doc := Document{
|
||||
XMLNs: "http://cyclonedx.org/schema/bom/1.2",
|
||||
XMLNsBd: "http://cyclonedx.org/schema/ext/bom-descriptor/1.0",
|
||||
Version: 1,
|
||||
SerialNumber: uuid.New().URN(),
|
||||
BomDescriptor: NewBomDescriptor(internal.ApplicationName, versionInfo.Version, srcMetadata),
|
||||
}
|
||||
|
||||
// attach components
|
||||
for p := range catalog.Enumerate() {
|
||||
component := Component{
|
||||
Type: "library", // TODO: this is not accurate
|
||||
@ -51,10 +53,8 @@ func NewDocumentFromCatalog(catalog *pkg.Catalog, d distro.Distro) Document {
|
||||
if len(licenses) > 0 {
|
||||
component.Licenses = &licenses
|
||||
}
|
||||
bom.Components = append(bom.Components, component)
|
||||
doc.Components = append(doc.Components, component)
|
||||
}
|
||||
|
||||
bom.BomDescriptor = NewBomDescriptor()
|
||||
|
||||
return bom
|
||||
return doc
|
||||
}
|
||||
|
||||
@ -5,7 +5,6 @@ package cyclonedx
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"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.
|
||||
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{
|
||||
catalog: catalog,
|
||||
srcMetadata: s,
|
||||
srcMetadata: srcMetadata,
|
||||
distro: d,
|
||||
}
|
||||
}
|
||||
|
||||
// Present writes the CycloneDX report to the given io.Writer.
|
||||
func (pres *Presenter) Present(output io.Writer) error {
|
||||
bom := NewDocumentFromCatalog(pres.catalog, pres.distro)
|
||||
|
||||
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)
|
||||
}
|
||||
bom := NewDocument(pres.catalog, pres.distro, pres.srcMetadata)
|
||||
|
||||
encoder := xml.NewEncoder(output)
|
||||
encoder.Indent("", " ")
|
||||
|
||||
@ -177,7 +177,7 @@ func TestCycloneDxImgsPresenter(t *testing.T) {
|
||||
|
||||
if !bytes.Equal(expected, actual) {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,23 @@
|
||||
package json
|
||||
|
||||
import "github.com/anchore/syft/syft/distro"
|
||||
|
||||
// Distribution provides information about a detected Linux Distribution
|
||||
type Distribution struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
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
|
||||
}
|
||||
|
||||
distroName := d.Name()
|
||||
if distroName == "UnknownDistroType" {
|
||||
distroName = ""
|
||||
}
|
||||
|
||||
doc := Document{
|
||||
Artifacts: make([]Artifact, 0),
|
||||
Source: src,
|
||||
Distro: Distribution{
|
||||
Name: distroName,
|
||||
Version: d.FullVersion(),
|
||||
IDLike: d.IDLike,
|
||||
},
|
||||
Distro: NewDistribution(d),
|
||||
Descriptor: Descriptor{
|
||||
Name: internal.ApplicationName,
|
||||
Version: version.FromBuild().Version,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user