mirror of
https://github.com/anchore/syft.git
synced 2026-11-01 23:16:30 +01:00
add cyclone-json output format (#635)
* add cyclone json format Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com> * adapt format to sbom.SBOM structure Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com> * cycloneDX json output with official lib Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com> * add cycloneDX 1.3 schema output in xml Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com> * fix lints errors Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com> * tidying go mod Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com> * remove cycloneDX 1.2 format Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com> * update cycloneDX xml schema Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com> * fix cyclone according to schema Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com> * use RFC 2141 URN form of uuid for serial number add schema validation for cycloneDX 1.3 JSON output add yajsv cli for JSON schema validation during tests Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com> * tidying go mod up Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com> * go get json schema validator Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com> * install yajsv without mess with go mod Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com> * reuse code between cycloneDX json & xml encoders Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com> * add output options for cyclone XML add bom.json to .gitignore Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com> * add cyclone json format Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com> * adapt format to sbom.SBOM structure Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com> * cycloneDX json output with official lib Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com> * add cycloneDX 1.3 schema output in xml Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com> * fix lints errors Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com> * tidying go mod Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com> * remove cycloneDX 1.2 format Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com> * update cycloneDX xml schema Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com> * fix cyclone according to schema Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com> * use RFC 2141 URN form of uuid for serial number add schema validation for cycloneDX 1.3 JSON output add yajsv cli for JSON schema validation during tests Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com> * tidying go mod up Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com> * go get json schema validator Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com> * install yajsv without mess with go mod Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com> * reuse code between cycloneDX json & xml encoders Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com> * add output options for cyclone XML add bom.json to .gitignore Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com> * fix cyclone12xml removal Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com> * feedback changes Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com> * go mod tidy Signed-off-by: Jonas Galvão Xavier <jonas.agx@gmail.com>
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
package cyclonedxhelpers
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/CycloneDX/cyclonedx-go"
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/internal/version"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/sbom"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
func ToFormatModel(s sbom.SBOM) *cyclonedx.BOM {
|
||||
cdxBOM := cyclonedx.NewBOM()
|
||||
versionInfo := version.FromBuild()
|
||||
|
||||
// NOTE(jonasagx): cycloneDX requires URN uuids (URN returns the RFC 2141 URN form of uuid):
|
||||
// https://github.com/CycloneDX/specification/blob/master/schema/bom-1.3-strict.schema.json#L36
|
||||
// "pattern": "^urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
|
||||
cdxBOM.SerialNumber = uuid.New().URN()
|
||||
cdxBOM.Metadata = toBomDescriptor(internal.ApplicationName, versionInfo.Version, s.Source)
|
||||
|
||||
packages := s.Artifacts.PackageCatalog.Sorted()
|
||||
components := make([]cyclonedx.Component, len(packages))
|
||||
for i, p := range packages {
|
||||
components[i] = toComponent(p)
|
||||
}
|
||||
cdxBOM.Components = &components
|
||||
|
||||
return cdxBOM
|
||||
}
|
||||
|
||||
// NewBomDescriptor returns a new BomDescriptor tailored for the current time and "syft" tool details.
|
||||
func toBomDescriptor(name, version string, srcMetadata source.Metadata) *cyclonedx.Metadata {
|
||||
return &cyclonedx.Metadata{
|
||||
Timestamp: time.Now().Format(time.RFC3339),
|
||||
Tools: &[]cyclonedx.Tool{
|
||||
{
|
||||
Vendor: "anchore",
|
||||
Name: name,
|
||||
Version: version,
|
||||
},
|
||||
},
|
||||
Component: toBomDescriptorComponent(srcMetadata),
|
||||
}
|
||||
}
|
||||
|
||||
func toComponent(p pkg.Package) cyclonedx.Component {
|
||||
return cyclonedx.Component{
|
||||
Type: cyclonedx.ComponentTypeLibrary,
|
||||
Name: p.Name,
|
||||
Version: p.Version,
|
||||
PackageURL: p.PURL,
|
||||
Licenses: toLicenses(p.Licenses),
|
||||
}
|
||||
}
|
||||
|
||||
func toBomDescriptorComponent(srcMetadata source.Metadata) *cyclonedx.Component {
|
||||
switch srcMetadata.Scheme {
|
||||
case source.ImageScheme:
|
||||
return &cyclonedx.Component{
|
||||
Type: cyclonedx.ComponentTypeContainer,
|
||||
Name: srcMetadata.ImageMetadata.UserInput,
|
||||
Version: srcMetadata.ImageMetadata.ManifestDigest,
|
||||
}
|
||||
case source.DirectoryScheme, source.FileScheme:
|
||||
return &cyclonedx.Component{
|
||||
Type: cyclonedx.ComponentTypeFile,
|
||||
Name: srcMetadata.Path,
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func toLicenses(ls []string) *cyclonedx.Licenses {
|
||||
if len(ls) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
lc := make(cyclonedx.Licenses, len(ls))
|
||||
for i, licenseName := range ls {
|
||||
lc[i] = cyclonedx.LicenseChoice{
|
||||
License: &cyclonedx.License{
|
||||
Name: licenseName,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return &lc
|
||||
}
|
||||
@@ -60,6 +60,8 @@ func AssertPresenterAgainstGoldenImageSnapshot(t *testing.T, pres presenter.Pres
|
||||
if !bytes.Equal(expected, actual) {
|
||||
dmp := diffmatchpatch.New()
|
||||
diffs := dmp.DiffMain(string(expected), string(actual), true)
|
||||
t.Logf("len: %d\nexpected: %v", len(expected), expected)
|
||||
t.Logf("len: %d\nactual: %v", len(actual), actual)
|
||||
t.Errorf("mismatched output:\n%s", dmp.DiffPrettyText(diffs))
|
||||
}
|
||||
}
|
||||
@@ -87,6 +89,8 @@ func AssertPresenterAgainstGoldenSnapshot(t *testing.T, pres presenter.Presenter
|
||||
if !bytes.Equal(expected, actual) {
|
||||
dmp := diffmatchpatch.New()
|
||||
diffs := dmp.DiffMain(string(expected), string(actual), true)
|
||||
t.Logf("len: %d\nexpected: %s", len(expected), expected)
|
||||
t.Logf("len: %d\nactual: %s", len(actual), actual)
|
||||
t.Errorf("mismatched output:\n%s", dmp.DiffPrettyText(diffs))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
package cyclonedx12xml
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"io"
|
||||
|
||||
"github.com/anchore/syft/syft/sbom"
|
||||
)
|
||||
|
||||
func encoder(output io.Writer, s sbom.SBOM) error {
|
||||
enc := xml.NewEncoder(output)
|
||||
enc.Indent("", " ")
|
||||
|
||||
_, err := output.Write([]byte(xml.Header))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = enc.Encode(toFormatModel(s))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = output.Write([]byte("\n"))
|
||||
return err
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
)
|
||||
|
||||
// Source: https://cyclonedx.org/ext/bom-descriptor/
|
||||
|
||||
// BomDescriptor represents all metadata surrounding the BOM report (such as when the BOM was made, with which tool, and the item being cataloged).
|
||||
type BomDescriptor struct {
|
||||
XMLName xml.Name `xml:"metadata"`
|
||||
Timestamp string `xml:"timestamp,omitempty"` // The date and time (timestamp) when the document was created
|
||||
Tools []BomDescriptorTool `xml:"tools>tool"` // The tool used to create the BOM.
|
||||
Component *BomDescriptorComponent `xml:"component"` // The component that the BOM describes.
|
||||
}
|
||||
|
||||
// BomDescriptorTool represents the tool that created the BOM report.
|
||||
type BomDescriptorTool struct {
|
||||
XMLName xml.Name `xml:"tool"`
|
||||
Vendor string `xml:"vendor,omitempty"` // The vendor of the tool used to create the BOM.
|
||||
Name string `xml:"name,omitempty"` // The name of the tool used to create the BOM.
|
||||
Version string `xml:"version,omitempty"` // The version of the tool used to create the BOM.
|
||||
// TODO: hashes, author, manufacture, supplier
|
||||
// TODO: add user-defined fields for the remaining build/version parameters
|
||||
}
|
||||
|
||||
// BomDescriptorComponent represents the software/package being cataloged.
|
||||
type BomDescriptorComponent struct {
|
||||
XMLName xml.Name `xml:"component"`
|
||||
Component
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package model
|
||||
|
||||
import "encoding/xml"
|
||||
|
||||
// Component represents a single element in the CycloneDX BOM
|
||||
type Component struct {
|
||||
XMLName xml.Name `xml:"component"`
|
||||
Type string `xml:"type,attr"` // Required; Describes if the component is a library, framework, application, container, operating system, firmware, hardware device, or file
|
||||
Supplier string `xml:"supplier,omitempty"` // The organization that supplied the component. The supplier may often be the manufacture, but may also be a distributor or repackager.
|
||||
Author string `xml:"author,omitempty"` // The person(s) or organization(s) that authored the component
|
||||
Publisher string `xml:"publisher,omitempty"` // The person(s) or organization(s) that published the component
|
||||
Group string `xml:"group,omitempty"` // The high-level classification that a project self-describes as. This will often be a shortened, single name of the company or project that produced the component, or the source package or domain name.
|
||||
Name string `xml:"name"` // Required; The name of the component as defined by the project
|
||||
Version string `xml:"version"` // Required; The version of the component as defined by the project
|
||||
Description string `xml:"description,omitempty"` // A description of the component
|
||||
Licenses *[]License `xml:"licenses>license"` // A node describing zero or more license names, SPDX license IDs or expressions
|
||||
PackageURL string `xml:"purl,omitempty"` // Specifies the package-url (PackageURL). The purl, if specified, must be valid and conform to the specification defined at: https://github.com/package-url/purl-spec
|
||||
// TODO: source, hashes, copyright, cpe, purl, swid, modified, pedigree, externalReferences
|
||||
// TODO: add user-defined parameters for syft-specific values (image layer index, cataloger, location path, etc.)
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
)
|
||||
|
||||
// Source: https://github.com/CycloneDX/specification
|
||||
|
||||
// Document represents a CycloneDX BOM Document.
|
||||
type Document struct {
|
||||
XMLName xml.Name `xml:"bom"`
|
||||
XMLNs string `xml:"xmlns,attr"`
|
||||
Version int `xml:"version,attr"`
|
||||
SerialNumber string `xml:"serialNumber,attr"`
|
||||
BomDescriptor *BomDescriptor `xml:"metadata"` // The BOM descriptor extension
|
||||
Components []Component `xml:"components>component"` // The BOM contents
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package model
|
||||
|
||||
import "encoding/xml"
|
||||
|
||||
// License represents a single software license for a Component
|
||||
type License struct {
|
||||
XMLName xml.Name `xml:"license"`
|
||||
ID string `xml:"id,omitempty"` // A valid SPDX license ID
|
||||
Name string `xml:"name,omitempty"` // If SPDX does not define the license used, this field may be used to provide the license name
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
package cyclonedx12xml
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"time"
|
||||
|
||||
"github.com/anchore/syft/syft/sbom"
|
||||
|
||||
"github.com/anchore/syft/internal"
|
||||
"github.com/anchore/syft/internal/formats/cyclonedx12xml/model"
|
||||
"github.com/anchore/syft/internal/version"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/source"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// toFormatModel creates and populates a new in-memory representation of a CycloneDX 1.2 document
|
||||
func toFormatModel(s sbom.SBOM) model.Document {
|
||||
versionInfo := version.FromBuild()
|
||||
|
||||
doc := model.Document{
|
||||
XMLNs: "http://cyclonedx.org/schema/bom/1.2",
|
||||
Version: 1,
|
||||
SerialNumber: uuid.New().URN(),
|
||||
BomDescriptor: toBomDescriptor(internal.ApplicationName, versionInfo.Version, s.Source),
|
||||
}
|
||||
|
||||
// attach components
|
||||
for _, p := range s.Artifacts.PackageCatalog.Sorted() {
|
||||
doc.Components = append(doc.Components, toComponent(p))
|
||||
}
|
||||
|
||||
return doc
|
||||
}
|
||||
|
||||
func toComponent(p pkg.Package) model.Component {
|
||||
return model.Component{
|
||||
Type: "library", // TODO: this is not accurate
|
||||
Name: p.Name,
|
||||
Version: p.Version,
|
||||
PackageURL: p.PURL,
|
||||
Licenses: toLicenses(p.Licenses),
|
||||
}
|
||||
}
|
||||
|
||||
// NewBomDescriptor returns a new BomDescriptor tailored for the current time and "syft" tool details.
|
||||
func toBomDescriptor(name, version string, srcMetadata source.Metadata) *model.BomDescriptor {
|
||||
return &model.BomDescriptor{
|
||||
XMLName: xml.Name{},
|
||||
Timestamp: time.Now().Format(time.RFC3339),
|
||||
Tools: []model.BomDescriptorTool{
|
||||
{
|
||||
Vendor: "anchore",
|
||||
Name: name,
|
||||
Version: version,
|
||||
},
|
||||
},
|
||||
Component: toBomDescriptorComponent(srcMetadata),
|
||||
}
|
||||
}
|
||||
|
||||
func toBomDescriptorComponent(srcMetadata source.Metadata) *model.BomDescriptorComponent {
|
||||
switch srcMetadata.Scheme {
|
||||
case source.ImageScheme:
|
||||
return &model.BomDescriptorComponent{
|
||||
Component: model.Component{
|
||||
Type: "container",
|
||||
Name: srcMetadata.ImageMetadata.UserInput,
|
||||
Version: srcMetadata.ImageMetadata.ManifestDigest,
|
||||
},
|
||||
}
|
||||
case source.DirectoryScheme, source.FileScheme:
|
||||
return &model.BomDescriptorComponent{
|
||||
Component: model.Component{
|
||||
Type: "file",
|
||||
Name: srcMetadata.Path,
|
||||
},
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func toLicenses(licenses []string) *[]model.License {
|
||||
if len(licenses) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var result []model.License
|
||||
for _, licenseName := range licenses {
|
||||
result = append(result, model.License{
|
||||
Name: licenseName,
|
||||
})
|
||||
}
|
||||
return &result
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package cyclonedx13json
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/CycloneDX/cyclonedx-go"
|
||||
"github.com/anchore/syft/internal/formats/common/cyclonedxhelpers"
|
||||
"github.com/anchore/syft/syft/sbom"
|
||||
)
|
||||
|
||||
func encoder(output io.Writer, s sbom.SBOM) error {
|
||||
bom := cyclonedxhelpers.ToFormatModel(s)
|
||||
enc := cyclonedx.NewBOMEncoder(output, cyclonedx.BOMFileFormatJSON)
|
||||
enc.SetPretty(true)
|
||||
|
||||
err := enc.Encode(bom)
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package cyclonedx13json
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"regexp"
|
||||
"testing"
|
||||
|
||||
"github.com/anchore/syft/internal/formats/common/testutils"
|
||||
)
|
||||
|
||||
var updateCycloneDx = flag.Bool("update-cyclonedx", false, "update the *.golden files for cyclone-dx presenters")
|
||||
|
||||
func TestCycloneDxDirectoryPresenter(t *testing.T) {
|
||||
testutils.AssertPresenterAgainstGoldenSnapshot(t,
|
||||
Format().Presenter(testutils.DirectoryInput(t)),
|
||||
*updateCycloneDx,
|
||||
cycloneDxRedactor,
|
||||
)
|
||||
}
|
||||
|
||||
func TestCycloneDxImagePresenter(t *testing.T) {
|
||||
testImage := "image-simple"
|
||||
testutils.AssertPresenterAgainstGoldenImageSnapshot(t,
|
||||
Format().Presenter(testutils.ImageInput(t, testImage)),
|
||||
testImage,
|
||||
*updateCycloneDx,
|
||||
cycloneDxRedactor,
|
||||
)
|
||||
}
|
||||
|
||||
func cycloneDxRedactor(s []byte) []byte {
|
||||
serialPattern := regexp.MustCompile(`urn:uuid:[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}`)
|
||||
rfc3339Pattern := regexp.MustCompile(`([0-9]+)-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01])[Tt]([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9]|60)(\.[0-9]+)?(([Zz])|([\+|\-]([01][0-9]|2[0-3]):[0-5][0-9]))`)
|
||||
|
||||
for _, pattern := range []*regexp.Regexp{serialPattern, rfc3339Pattern} {
|
||||
s = pattern.ReplaceAll(s, []byte("redacted"))
|
||||
}
|
||||
return s
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package cyclonedx13json
|
||||
|
||||
import "github.com/anchore/syft/syft/format"
|
||||
|
||||
func Format() format.Format {
|
||||
return format.NewFormat(
|
||||
format.CycloneDxJSONOption,
|
||||
encoder,
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"bomFormat": "CycloneDX",
|
||||
"specVersion": "1.3",
|
||||
"serialNumber": "urn:uuid:a81dc685-cf22-48e0-bda5-65ea1a8bca5b",
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"timestamp": "2021-12-03T13:17:26-08:00",
|
||||
"tools": [
|
||||
{
|
||||
"vendor": "anchore",
|
||||
"name": "syft",
|
||||
"version": "[not provided]"
|
||||
}
|
||||
],
|
||||
"component": {
|
||||
"type": "file",
|
||||
"name": "/some/path",
|
||||
"version": ""
|
||||
}
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"type": "library",
|
||||
"name": "package-1",
|
||||
"version": "1.0.1",
|
||||
"licenses": [
|
||||
{
|
||||
"license": {
|
||||
"name": "MIT"
|
||||
}
|
||||
}
|
||||
],
|
||||
"purl": "a-purl-2"
|
||||
},
|
||||
{
|
||||
"type": "library",
|
||||
"name": "package-2",
|
||||
"version": "2.0.1",
|
||||
"purl": "a-purl-2"
|
||||
}
|
||||
]
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
{
|
||||
"bomFormat": "CycloneDX",
|
||||
"specVersion": "1.3",
|
||||
"serialNumber": "urn:uuid:2156ac1f-c838-4e93-8dc5-a3874ffeb967",
|
||||
"version": 1,
|
||||
"metadata": {
|
||||
"timestamp": "2021-12-03T13:17:26-08:00",
|
||||
"tools": [
|
||||
{
|
||||
"vendor": "anchore",
|
||||
"name": "syft",
|
||||
"version": "[not provided]"
|
||||
}
|
||||
],
|
||||
"component": {
|
||||
"type": "container",
|
||||
"name": "user-image-input",
|
||||
"version": "sha256:2731251dc34951c0e50fcc643b4c5f74922dad1a5d98f302b504cf46cd5d9368"
|
||||
}
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"type": "library",
|
||||
"name": "package-1",
|
||||
"version": "1.0.1",
|
||||
"licenses": [
|
||||
{
|
||||
"license": {
|
||||
"name": "MIT"
|
||||
}
|
||||
}
|
||||
],
|
||||
"purl": "a-purl-1"
|
||||
},
|
||||
{
|
||||
"type": "library",
|
||||
"name": "package-2",
|
||||
"version": "2.0.1",
|
||||
"purl": "a-purl-2"
|
||||
}
|
||||
]
|
||||
}
|
||||
BIN
Binary file not shown.
@@ -0,0 +1,18 @@
|
||||
package cyclonedx13xml
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/CycloneDX/cyclonedx-go"
|
||||
"github.com/anchore/syft/internal/formats/common/cyclonedxhelpers"
|
||||
"github.com/anchore/syft/syft/sbom"
|
||||
)
|
||||
|
||||
func encoder(output io.Writer, s sbom.SBOM) error {
|
||||
bom := cyclonedxhelpers.ToFormatModel(s)
|
||||
enc := cyclonedx.NewBOMEncoder(output, cyclonedx.BOMFileFormatXML)
|
||||
enc.SetPretty(true)
|
||||
|
||||
err := enc.Encode(bom)
|
||||
return err
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package cyclonedx12xml
|
||||
package cyclonedx13xml
|
||||
|
||||
import (
|
||||
"flag"
|
||||
+2
-2
@@ -1,10 +1,10 @@
|
||||
package cyclonedx12xml
|
||||
package cyclonedx13xml
|
||||
|
||||
import "github.com/anchore/syft/syft/format"
|
||||
|
||||
func Format() format.Format {
|
||||
return format.NewFormat(
|
||||
format.CycloneDxOption,
|
||||
format.CycloneDxXMLOption,
|
||||
encoder,
|
||||
nil,
|
||||
nil,
|
||||
@@ -0,0 +1,4 @@
|
||||
# Note: changes to this file will result in updating several test values. Consider making a new image fixture instead of editing this one.
|
||||
FROM scratch
|
||||
ADD file-1.txt /somefile-1.txt
|
||||
ADD file-2.txt /somefile-2.txt
|
||||
@@ -0,0 +1 @@
|
||||
this file has contents
|
||||
@@ -0,0 +1 @@
|
||||
file-2 contents!
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<bom xmlns="http://cyclonedx.org/schema/bom/1.2" version="1" serialNumber="urn:uuid:5404937f-72d6-44a2-8e9b-954305ecb4f6">
|
||||
<bom xmlns="http://cyclonedx.org/schema/bom/1.3" serialNumber="urn:uuid:7b1c3b1d-ea3b-4022-9dcc-80f4b4cbce36" version="1">
|
||||
<metadata>
|
||||
<timestamp>2021-06-23T13:40:33-04:00</timestamp>
|
||||
<timestamp>2021-12-03T13:16:45-08:00</timestamp>
|
||||
<tools>
|
||||
<tool>
|
||||
<vendor>anchore</vendor>
|
||||
@@ -31,4 +31,4 @@
|
||||
<purl>a-purl-2</purl>
|
||||
</component>
|
||||
</components>
|
||||
</bom>
|
||||
</bom>
|
||||
+3
-3
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<bom xmlns="http://cyclonedx.org/schema/bom/1.2" version="1" serialNumber="urn:uuid:e34bad2e-cd27-483c-86dc-f4e26d6103b0">
|
||||
<bom xmlns="http://cyclonedx.org/schema/bom/1.3" serialNumber="urn:uuid:66bda3e1-888a-4d43-b906-7fd96d428753" version="1">
|
||||
<metadata>
|
||||
<timestamp>2021-06-23T13:40:33-04:00</timestamp>
|
||||
<timestamp>2021-12-03T13:16:45-08:00</timestamp>
|
||||
<tools>
|
||||
<tool>
|
||||
<vendor>anchore</vendor>
|
||||
@@ -31,4 +31,4 @@
|
||||
<purl>a-purl-2</purl>
|
||||
</component>
|
||||
</components>
|
||||
</bom>
|
||||
</bom>
|
||||
BIN
Binary file not shown.
@@ -3,7 +3,8 @@ package formats
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/anchore/syft/internal/formats/cyclonedx12xml"
|
||||
"github.com/anchore/syft/internal/formats/cyclonedx13json"
|
||||
"github.com/anchore/syft/internal/formats/cyclonedx13xml"
|
||||
"github.com/anchore/syft/internal/formats/spdx22json"
|
||||
"github.com/anchore/syft/internal/formats/spdx22tagvalue"
|
||||
"github.com/anchore/syft/internal/formats/syftjson"
|
||||
@@ -17,7 +18,8 @@ func All() []format.Format {
|
||||
return []format.Format{
|
||||
syftjson.Format(),
|
||||
table.Format(),
|
||||
cyclonedx12xml.Format(),
|
||||
cyclonedx13xml.Format(),
|
||||
cyclonedx13json.Format(),
|
||||
spdx22json.Format(),
|
||||
spdx22tagvalue.Format(),
|
||||
text.Format(),
|
||||
|
||||
Reference in New Issue
Block a user