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:
Jonas Galvão Xavier 2021-12-03 17:06:23 -08:00 committed by GitHub
parent 22c4b275e7
commit 5374a1dc6f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 2857 additions and 1419 deletions

View File

@ -82,7 +82,7 @@ help:
.PHONY: ci-bootstrap .PHONY: ci-bootstrap
ci-bootstrap: ci-bootstrap:
DEBIAN_FRONTEND=noninteractive sudo apt update && sudo -E apt install -y bc jq libxml2-utils DEBIAN_FRONTEND=noninteractive sudo apt update && sudo -E apt install -y bc jq libxml2-utils && go install github.com/neilpa/yajsv@latest
.PHONY: .PHONY:
ci-bootstrap-mac: ci-bootstrap-mac:

1
go.mod
View File

@ -3,6 +3,7 @@ module github.com/anchore/syft
go 1.16 go 1.16
require ( require (
github.com/CycloneDX/cyclonedx-go v0.4.0
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d
github.com/adrg/xdg v0.2.1 github.com/adrg/xdg v0.2.1
github.com/alecthomas/jsonschema v0.0.0-20210301060011-54c507b6f074 github.com/alecthomas/jsonschema v0.0.0-20210301060011-54c507b6f074

4
go.sum
View File

@ -60,6 +60,8 @@ github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZ
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/CycloneDX/cyclonedx-go v0.4.0 h1:Wz4QZ9B4RXGWIWTypVLEOVJgOdFfy5mcS5PGNzUkZxU=
github.com/CycloneDX/cyclonedx-go v0.4.0/go.mod h1:rmRcf//gT7PIzovatusbWi377xqCg1FS4jyST0GH20E=
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw=
@ -138,6 +140,8 @@ github.com/bmatcuk/doublestar/v2 v2.0.4/go.mod h1:QMmcs3H2AUQICWhfzLXz+IYln8lRQm
github.com/bmatcuk/doublestar/v4 v4.0.2 h1:X0krlUVAVmtr2cRoTqR8aDMrDqnB36ht8wpWTiQ3jsA= github.com/bmatcuk/doublestar/v4 v4.0.2 h1:X0krlUVAVmtr2cRoTqR8aDMrDqnB36ht8wpWTiQ3jsA=
github.com/bmatcuk/doublestar/v4 v4.0.2/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/bmatcuk/doublestar/v4 v4.0.2/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
github.com/bradleyjkemp/cupaloy/v2 v2.6.0 h1:knToPYa2xtfg42U3I6punFEjaGFKWQRXJwj0JTv4mTs=
github.com/bradleyjkemp/cupaloy/v2 v2.6.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0=
github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= github.com/bshuster-repo/logrus-logstash-hook v0.4.1/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk=
github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8= github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=

View File

@ -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
}

View File

@ -60,6 +60,8 @@ func AssertPresenterAgainstGoldenImageSnapshot(t *testing.T, pres presenter.Pres
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(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)) 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) { if !bytes.Equal(expected, actual) {
dmp := diffmatchpatch.New() dmp := diffmatchpatch.New()
diffs := dmp.DiffMain(string(expected), string(actual), true) 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)) t.Errorf("mismatched output:\n%s", dmp.DiffPrettyText(diffs))
} }
} }

View File

@ -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
}

View File

@ -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
}

View File

@ -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.)
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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,
)
}

View File

@ -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"
}
]
}

View File

@ -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"
}
]
}

View File

@ -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
}

View File

@ -1,4 +1,4 @@
package cyclonedx12xml package cyclonedx13xml
import ( import (
"flag" "flag"

View File

@ -1,10 +1,10 @@
package cyclonedx12xml package cyclonedx13xml
import "github.com/anchore/syft/syft/format" import "github.com/anchore/syft/syft/format"
func Format() format.Format { func Format() format.Format {
return format.NewFormat( return format.NewFormat(
format.CycloneDxOption, format.CycloneDxXMLOption,
encoder, encoder,
nil, nil,
nil, nil,

View File

@ -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

View File

@ -0,0 +1 @@
this file has contents

View File

@ -0,0 +1 @@
file-2 contents!

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?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> <metadata>
<timestamp>2021-06-23T13:40:33-04:00</timestamp> <timestamp>2021-12-03T13:16:45-08:00</timestamp>
<tools> <tools>
<tool> <tool>
<vendor>anchore</vendor> <vendor>anchore</vendor>
@ -31,4 +31,4 @@
<purl>a-purl-2</purl> <purl>a-purl-2</purl>
</component> </component>
</components> </components>
</bom> </bom>

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?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> <metadata>
<timestamp>2021-06-23T13:40:33-04:00</timestamp> <timestamp>2021-12-03T13:16:45-08:00</timestamp>
<tools> <tools>
<tool> <tool>
<vendor>anchore</vendor> <vendor>anchore</vendor>
@ -31,4 +31,4 @@
<purl>a-purl-2</purl> <purl>a-purl-2</purl>
</component> </component>
</components> </components>
</bom> </bom>

View File

@ -3,7 +3,8 @@ package formats
import ( import (
"bytes" "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/spdx22json"
"github.com/anchore/syft/internal/formats/spdx22tagvalue" "github.com/anchore/syft/internal/formats/spdx22tagvalue"
"github.com/anchore/syft/internal/formats/syftjson" "github.com/anchore/syft/internal/formats/syftjson"
@ -17,7 +18,8 @@ func All() []format.Format {
return []format.Format{ return []format.Format{
syftjson.Format(), syftjson.Format(),
table.Format(), table.Format(),
cyclonedx12xml.Format(), cyclonedx13xml.Format(),
cyclonedx13json.Format(),
spdx22json.Format(), spdx22json.Format(),
spdx22tagvalue.Format(), spdx22tagvalue.Format(),
text.Format(), text.Format(),

View File

@ -1 +1,2 @@
bom.xml bom.xml
bom.json

View File

@ -2,4 +2,6 @@
.PHONY: validate-schema .PHONY: validate-schema
validate-schema: validate-schema:
go run ../../main.go ubuntu:latest -vv -o cyclonedx > bom.xml go run ../../main.go ubuntu:latest -vv -o cyclonedx > bom.xml
xmllint --noout --schema ./cyclonedx.xsd bom.xml xmllint --noout --schema ./cyclonedx.xsd bom.xml
go run ../../main.go ubuntu:latest -vv -o cyclonedx-json > bom.json
yajsv -s bom-1.3.schema.json bom.json

File diff suppressed because it is too large Load Diff

View File

@ -16,13 +16,13 @@ limitations under the License.
--> -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
xmlns:bom="http://cyclonedx.org/schema/bom/1.2" xmlns:bom="http://cyclonedx.org/schema/bom/1.3"
xmlns:spdx="http://cyclonedx.org/schema/spdx" xmlns:spdx="http://cyclonedx.org/schema/spdx"
elementFormDefault="qualified" elementFormDefault="qualified"
targetNamespace="http://cyclonedx.org/schema/bom/1.2" targetNamespace="http://cyclonedx.org/schema/bom/1.3"
vc:minVersion="1.0" vc:minVersion="1.0"
vc:maxVersion="1.1" vc:maxVersion="1.1"
version="1.2"> version="1.3">
<xs:import namespace="http://cyclonedx.org/schema/spdx" schemaLocation="spdx.xsd"/> <xs:import namespace="http://cyclonedx.org/schema/spdx" schemaLocation="spdx.xsd"/>
@ -32,9 +32,6 @@ limitations under the License.
<url>https://cyclonedx.org/</url> <url>https://cyclonedx.org/</url>
<license uri="http://www.apache.org/licenses/LICENSE-2.0" <license uri="http://www.apache.org/licenses/LICENSE-2.0"
version="2.0">Apache License, Version 2.0</license> version="2.0">Apache License, Version 2.0</license>
<authors>
<author>Steve Springett</author>
</authors>
</xs:documentation> </xs:documentation>
</xs:annotation> </xs:annotation>
@ -71,15 +68,23 @@ limitations under the License.
<xs:documentation>The component that the BOM describes.</xs:documentation> <xs:documentation>The component that the BOM describes.</xs:documentation>
</xs:annotation> </xs:annotation>
</xs:element> </xs:element>
<xs:element name="manufacture" type="bom:organizationalEntity" minOccurs="0" maxOccurs="unbounded"> <xs:element name="manufacture" type="bom:organizationalEntity" minOccurs="0" maxOccurs="1">
<xs:annotation> <xs:annotation>
<xs:documentation>The organization that manufactured the component that the BOM describes.</xs:documentation> <xs:documentation>The organization that manufactured the component that the BOM describes.</xs:documentation>
</xs:annotation> </xs:annotation>
</xs:element> </xs:element>
<xs:element name="supplier" type="bom:organizationalEntity" minOccurs="0" maxOccurs="unbounded"> <xs:element name="supplier" type="bom:organizationalEntity" minOccurs="0" maxOccurs="1">
<xs:annotation> <xs:annotation>
<xs:documentation>The organization that supplied the component that the BOM describes. The <xs:documentation>The organization that supplied the component that the BOM describes. The
supplier may often be the manufacture, but may also be a distributor or repackager.</xs:documentation> supplier may often be the manufacturer, but may also be a distributor or repackager.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="licenses" type="bom:licenseChoiceType" minOccurs="0" maxOccurs="1"/>
<xs:element name="properties" type="bom:propertiesType" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>Provides the ability to document properties in a key/value store.
This provides flexibility to include data not officially supported in the standard
without having to use additional namespaces or create extensions.</xs:documentation>
</xs:annotation> </xs:annotation>
</xs:element> </xs:element>
<xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"> <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded">
@ -181,14 +186,14 @@ limitations under the License.
<xs:documentation>The name of the contact</xs:documentation> <xs:documentation>The name of the contact</xs:documentation>
</xs:annotation> </xs:annotation>
</xs:element> </xs:element>
<xs:element name="email" type="xs:normalizedString" minOccurs="0" maxOccurs="unbounded"> <xs:element name="email" type="xs:normalizedString" minOccurs="0" maxOccurs="1">
<xs:annotation> <xs:annotation>
<xs:documentation>The email address of the contact. Multiple email addresses are allowed.</xs:documentation> <xs:documentation>The email address of the contact.</xs:documentation>
</xs:annotation> </xs:annotation>
</xs:element> </xs:element>
<xs:element name="phone" type="xs:normalizedString" minOccurs="0" maxOccurs="unbounded"> <xs:element name="phone" type="xs:normalizedString" minOccurs="0" maxOccurs="1">
<xs:annotation> <xs:annotation>
<xs:documentation>The phone number of the contact. Multiple phone numbers are allowed.</xs:documentation> <xs:documentation>The phone number of the contact.</xs:documentation>
</xs:annotation> </xs:annotation>
</xs:element> </xs:element>
<xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"> <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded">
@ -231,7 +236,7 @@ limitations under the License.
<xs:element name="supplier" type="bom:organizationalEntity" minOccurs="0" maxOccurs="1"> <xs:element name="supplier" type="bom:organizationalEntity" minOccurs="0" maxOccurs="1">
<xs:annotation> <xs:annotation>
<xs:documentation>The organization that supplied the component. The supplier may often <xs:documentation>The organization that supplied the component. The supplier may often
be the manufacture, but may also be a distributor or repackager.</xs:documentation> be the manufacturer, but may also be a distributor or repackager.</xs:documentation>
</xs:annotation> </xs:annotation>
</xs:element> </xs:element>
<xs:element name="author" type="xs:normalizedString" minOccurs="0" maxOccurs="1"> <xs:element name="author" type="xs:normalizedString" minOccurs="0" maxOccurs="1">
@ -282,19 +287,7 @@ limitations under the License.
</xs:sequence> </xs:sequence>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:element name="licenses" minOccurs="0" maxOccurs="1"> <xs:element name="licenses" type="bom:licenseChoiceType" minOccurs="0" maxOccurs="1"/>
<xs:complexType>
<xs:choice>
<xs:element name="license" type="bom:licenseType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="expression" type="xs:normalizedString" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>A valid SPDX license expression.
Refer to https://spdx.org/specifications for syntax requirements</xs:documentation>
</xs:annotation>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
<xs:element name="copyright" type="xs:normalizedString" minOccurs="0" maxOccurs="1"> <xs:element name="copyright" type="xs:normalizedString" minOccurs="0" maxOccurs="1">
<xs:annotation> <xs:annotation>
<xs:documentation>An optional copyright notice informing users of the underlying claims to <xs:documentation>An optional copyright notice informing users of the underlying claims to
@ -349,6 +342,13 @@ limitations under the License.
component or to the project the component describes.</xs:documentation> component or to the project the component describes.</xs:documentation>
</xs:annotation> </xs:annotation>
</xs:element> </xs:element>
<xs:element name="properties" type="bom:propertiesType" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>Provides the ability to document properties in a key/value store.
This provides flexibility to include data not officially supported in the standard
without having to use additional namespaces or create extensions.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="components" minOccurs="0" maxOccurs="1"> <xs:element name="components" minOccurs="0" maxOccurs="1">
<xs:annotation> <xs:annotation>
<xs:documentation> <xs:documentation>
@ -370,6 +370,11 @@ limitations under the License.
</xs:sequence> </xs:sequence>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:element name="evidence" type="bom:componentEvidenceType" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>Provides the ability to document evidence collected through various forms of extraction or analysis.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"> <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded">
<xs:annotation> <xs:annotation>
<xs:documentation> <xs:documentation>
@ -512,45 +517,45 @@ limitations under the License.
<xs:simpleType name="classification"> <xs:simpleType name="classification">
<xs:restriction base="xs:string"> <xs:restriction base="xs:string">
<xs:enumeration value="application"> <xs:enumeration value="application">
<xs:annotation> <xs:annotation>
<xs:documentation>A software application. Refer to https://en.wikipedia.org/wiki/Application_software <xs:documentation>A software application. Refer to https://en.wikipedia.org/wiki/Application_software
for information about applications.</xs:documentation> for information about applications.</xs:documentation>
</xs:annotation> </xs:annotation>
</xs:enumeration> </xs:enumeration>
<xs:enumeration value="framework"> <xs:enumeration value="framework">
<xs:annotation> <xs:annotation>
<xs:documentation>A software framework. Refer to https://en.wikipedia.org/wiki/Software_framework <xs:documentation>A software framework. Refer to https://en.wikipedia.org/wiki/Software_framework
for information on how frameworks vary slightly from libraries.</xs:documentation> for information on how frameworks vary slightly from libraries.</xs:documentation>
</xs:annotation> </xs:annotation>
</xs:enumeration> </xs:enumeration>
<xs:enumeration value="library"> <xs:enumeration value="library">
<xs:annotation> <xs:annotation>
<xs:documentation>A software library. Refer to https://en.wikipedia.org/wiki/Library_(computing) <xs:documentation>A software library. Refer to https://en.wikipedia.org/wiki/Library_(computing)
for information about libraries. All third-party and open source reusable components will likely for information about libraries. All third-party and open source reusable components will likely
be a library. If the library also has key features of a framework, then it should be classified be a library. If the library also has key features of a framework, then it should be classified
as a framework. If not, or is unknown, then specifying library is recommended.</xs:documentation> as a framework. If not, or is unknown, then specifying library is recommended.</xs:documentation>
</xs:annotation> </xs:annotation>
</xs:enumeration> </xs:enumeration>
<xs:enumeration value="container"> <xs:enumeration value="container">
<xs:annotation> <xs:annotation>
<xs:documentation>A packaging and/or runtime format, not specific to any particular technology, <xs:documentation>A packaging and/or runtime format, not specific to any particular technology,
which isolates software inside the container from software outside of a container through which isolates software inside the container from software outside of a container through
virtualization technology. Refer to https://en.wikipedia.org/wiki/OS-level_virtualization</xs:documentation> virtualization technology. Refer to https://en.wikipedia.org/wiki/OS-level_virtualization</xs:documentation>
</xs:annotation> </xs:annotation>
</xs:enumeration> </xs:enumeration>
<xs:enumeration value="operating-system"> <xs:enumeration value="operating-system">
<xs:annotation> <xs:annotation>
<xs:documentation>A software operating system without regard to deployment model <xs:documentation>A software operating system without regard to deployment model
(i.e. installed on physical hardware, virtual machine, image, etc) Refer to (i.e. installed on physical hardware, virtual machine, image, etc) Refer to
https://en.wikipedia.org/wiki/Operating_system</xs:documentation> https://en.wikipedia.org/wiki/Operating_system</xs:documentation>
</xs:annotation> </xs:annotation>
</xs:enumeration> </xs:enumeration>
<xs:enumeration value="device"> <xs:enumeration value="device">
<xs:annotation> <xs:annotation>
<xs:documentation>A hardware device such as a processor, or chip-set. A hardware device <xs:documentation>A hardware device such as a processor, or chip-set. A hardware device
containing firmware should include a component for the physical hardware itself, and another containing firmware should include a component for the physical hardware itself, and another
component of type 'firmware' or 'operating-system' (whichever is relevant), describing component of type 'firmware' or 'operating-system' (whichever is relevant), describing
information about the software running on the device.</xs:documentation> information about the software running on the device.</xs:documentation>
</xs:annotation> </xs:annotation>
</xs:enumeration> </xs:enumeration>
<xs:enumeration value="firmware"> <xs:enumeration value="firmware">
@ -562,7 +567,7 @@ limitations under the License.
<xs:enumeration value="file"> <xs:enumeration value="file">
<xs:annotation> <xs:annotation>
<xs:documentation>A computer file. Refer to https://en.wikipedia.org/wiki/Computer_file <xs:documentation>A computer file. Refer to https://en.wikipedia.org/wiki/Computer_file
for information about files.</xs:documentation> for information about files.</xs:documentation>
</xs:annotation> </xs:annotation>
</xs:enumeration> </xs:enumeration>
</xs:restriction> </xs:restriction>
@ -782,6 +787,13 @@ limitations under the License.
<xs:documentation xml:lang="en">An optional comment describing the external reference</xs:documentation> <xs:documentation xml:lang="en">An optional comment describing the external reference</xs:documentation>
</xs:annotation> </xs:annotation>
</xs:element> </xs:element>
<xs:element name="hashes" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="hash" type="bom:hashType"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence> </xs:sequence>
<xs:attribute name="type" type="bom:externalReferenceType" use="required"> <xs:attribute name="type" type="bom:externalReferenceType" use="required">
<xs:annotation> <xs:annotation>
@ -927,7 +939,7 @@ limitations under the License.
<xs:enumeration value="backport"> <xs:enumeration value="backport">
<xs:annotation> <xs:annotation>
<xs:documentation>A patch which takes code from a newer version of software and applies <xs:documentation>A patch which takes code from a newer version of software and applies
it to older versions of the same software. Refer to https://en.wikipedia.org/wiki/Backporting</xs:documentation> it to older versions of the same software. Refer to https://en.wikipedia.org/wiki/Backporting</xs:documentation>
</xs:annotation> </xs:annotation>
</xs:enumeration> </xs:enumeration>
<xs:enumeration value="cherry-pick"> <xs:enumeration value="cherry-pick">
@ -1255,24 +1267,19 @@ limitations under the License.
</xs:sequence> </xs:sequence>
</xs:complexType> </xs:complexType>
</xs:element> </xs:element>
<xs:element name="licenses" minOccurs="0" maxOccurs="1"> <xs:element name="licenses" type="bom:licenseChoiceType" minOccurs="0" maxOccurs="1"/>
<xs:complexType>
<xs:choice>
<xs:element name="license" type="bom:licenseType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="expression" type="xs:normalizedString" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>A valid SPDX license expression.
Refer to https://spdx.org/specifications for syntax requirements</xs:documentation>
</xs:annotation>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
<xs:element name="externalReferences" type="bom:externalReferences" minOccurs="0" maxOccurs="1"> <xs:element name="externalReferences" type="bom:externalReferences" minOccurs="0" maxOccurs="1">
<xs:annotation> <xs:annotation>
<xs:documentation>Provides the ability to document external references related to the service.</xs:documentation> <xs:documentation>Provides the ability to document external references related to the service.</xs:documentation>
</xs:annotation> </xs:annotation>
</xs:element> </xs:element>
<xs:element name="properties" type="bom:propertiesType" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>Provides the ability to document properties in a key/value store.
This provides flexibility to include data not officially supported in the standard
without having to use additional namespaces or create extensions.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="services" minOccurs="0" maxOccurs="1"> <xs:element name="services" minOccurs="0" maxOccurs="1">
<xs:annotation> <xs:annotation>
<xs:documentation> <xs:documentation>
@ -1349,6 +1356,199 @@ limitations under the License.
</xs:restriction> </xs:restriction>
</xs:simpleType> </xs:simpleType>
<xs:complexType name="licenseChoiceType">
<xs:choice>
<xs:element name="license" type="bom:licenseType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="expression" type="xs:normalizedString" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>A valid SPDX license expression.
Refer to https://spdx.org/specifications for syntax requirements</xs:documentation>
</xs:annotation>
</xs:element>
</xs:choice>
</xs:complexType>
<xs:complexType name="copyrightsType">
<xs:sequence>
<xs:element name="text" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="componentEvidenceType">
<xs:sequence>
<xs:element name="licenses" type="bom:licenseChoiceType" minOccurs="0" maxOccurs="1"/>
<xs:element name="copyright" type="bom:copyrightsType" minOccurs="0" maxOccurs="1"/>
<xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded">
<xs:annotation>
<xs:documentation>
Allows any undeclared elements as long as the elements are placed in a different namespace.
</xs:documentation>
</xs:annotation>
</xs:any>
</xs:sequence>
<xs:anyAttribute namespace="##any" processContents="lax">
<xs:annotation>
<xs:documentation>User-defined attributes may be used on this element as long as they
do not have the same name as an existing attribute used by the schema.</xs:documentation>
</xs:annotation>
</xs:anyAttribute>
</xs:complexType>
<xs:complexType name="compositionsType">
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="composition" type="bom:compositionType"/>
<xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded">
<xs:annotation>
<xs:documentation>
Allows any undeclared elements as long as the elements are placed in a different namespace.
</xs:documentation>
</xs:annotation>
</xs:any>
</xs:sequence>
<xs:anyAttribute namespace="##any" processContents="lax">
<xs:annotation>
<xs:documentation>User-defined attributes may be used on this element as long as they
do not have the same name as an existing attribute used by the schema.</xs:documentation>
</xs:annotation>
</xs:anyAttribute>
</xs:complexType>
<xs:complexType name="compositionType">
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="aggregate" type="bom:aggregateType" default="not_specified">
<xs:annotation>
<xs:documentation>Specifies an aggregate type that describe how complete a relationship is.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="assemblies" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>
The bom-ref identifiers of the components or services being described. Assemblies refer to
nested relationships whereby a constituent part may include other constituent parts. References
do not cascade to child parts. References are explicit for the specified constituent part only.
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="assembly" type="bom:bomReferenceType"/>
<xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded">
<xs:annotation>
<xs:documentation>
Allows any undeclared elements as long as the elements are placed in a different namespace.
</xs:documentation>
</xs:annotation>
</xs:any>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="dependencies" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>
The bom-ref identifiers of the components or services being described. Dependencies refer to a
relationship whereby an independent constituent part requires another independent constituent
part. References do not cascade to transitive dependencies. References are explicit for the
specified dependency only.
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="dependency" type="bom:bomReferenceType"/>
<xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded">
<xs:annotation>
<xs:documentation>
Allows any undeclared elements as long as the elements are placed in a different namespace.
</xs:documentation>
</xs:annotation>
</xs:any>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:simpleType name="aggregateType">
<xs:restriction base="xs:string">
<xs:enumeration value="complete">
<xs:annotation>
<xs:documentation>The relationship is complete. No further relationships including constituent components, services, or dependencies exist.</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="incomplete">
<xs:annotation>
<xs:documentation>The relationship is incomplete. Additional relationships exist and may include constituent components, services, or dependencies.</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="incomplete_first_party_only">
<xs:annotation>
<xs:documentation>The relationship is incomplete. Only relationships for first-party components, services, or their dependencies are represented.</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="incomplete_third_party_only">
<xs:annotation>
<xs:documentation>The relationship is incomplete. Only relationships for third-party components, services, or their dependencies are represented.</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="unknown">
<xs:annotation>
<xs:documentation>The relationship may be complete or incomplete. This usually signifies a 'best-effort' to obtain constituent components, services, or dependencies but the completeness is inconclusive.</xs:documentation>
</xs:annotation>
</xs:enumeration>
<xs:enumeration value="not_specified">
<xs:annotation>
<xs:documentation>The relationship completeness is not specified.</xs:documentation>
</xs:annotation>
</xs:enumeration>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="bomReferenceType">
<xs:attribute name="ref" type="xs:string" use="required">
<xs:annotation>
<xs:documentation>References a component or service by the its bom-ref attribute</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:anyAttribute namespace="##other" processContents="lax">
<xs:annotation>
<xs:documentation>User-defined attributes may be used on this element as long as they
do not have the same name as an existing attribute used by the schema.</xs:documentation>
</xs:annotation>
</xs:anyAttribute>
</xs:complexType>
<xs:complexType name="propertiesType">
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="property" type="bom:propertyType"/>
<xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded">
<xs:annotation>
<xs:documentation>
Allows any undeclared elements as long as the elements are placed in a different namespace.
</xs:documentation>
</xs:annotation>
</xs:any>
</xs:sequence>
<xs:anyAttribute namespace="##any" processContents="lax">
<xs:annotation>
<xs:documentation>User-defined attributes may be used on this element as long as they
do not have the same name as an existing attribute used by the schema.</xs:documentation>
</xs:annotation>
</xs:anyAttribute>
</xs:complexType>
<xs:complexType name="propertyType">
<xs:annotation>
<xs:documentation>Specifies an individual property with a name and value.</xs:documentation>
</xs:annotation>
<xs:simpleContent>
<xs:extension base="xs:normalizedString">
<xs:attribute name="name" type="xs:string" use="required">
<xs:annotation>
<xs:documentation>The name of the property. Duplicate names are allowed, each potentially having a different value.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:element name="bom"> <xs:element name="bom">
<xs:complexType> <xs:complexType>
<xs:sequence> <xs:sequence>
@ -1378,6 +1578,19 @@ limitations under the License.
<xs:documentation>Provides the ability to document dependency relationships.</xs:documentation> <xs:documentation>Provides the ability to document dependency relationships.</xs:documentation>
</xs:annotation> </xs:annotation>
</xs:element> </xs:element>
<xs:element name="compositions" type="bom:compositionsType" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>Compositions describe constituent parts (including components, services, and dependency relationships) and their completeness.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="properties" type="bom:propertiesType" minOccurs="0" maxOccurs="1">
<xs:annotation>
<xs:documentation>Provides the ability to document properties in a name-value store.
This provides flexibility to include data not officially supported in the standard
without having to use additional namespaces or create extensions. Unlike key-value
stores, properties support duplicate names, each potentially having different values.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"> <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded">
<xs:annotation> <xs:annotation>
<xs:documentation> <xs:documentation>

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,8 @@ const (
JSONOption Option = "json" JSONOption Option = "json"
TextOption Option = "text" TextOption Option = "text"
TableOption Option = "table" TableOption Option = "table"
CycloneDxOption Option = "cyclonedx" CycloneDxXMLOption Option = "cyclonedx"
CycloneDxJSONOption Option = "cyclonedx-json"
SPDXTagValueOption Option = "spdx-tag-value" SPDXTagValueOption Option = "spdx-tag-value"
SPDXJSONOption Option = "spdx-json" SPDXJSONOption Option = "spdx-json"
) )
@ -16,7 +17,8 @@ var AllOptions = []Option{
JSONOption, JSONOption,
TextOption, TextOption,
TableOption, TableOption,
CycloneDxOption, CycloneDxXMLOption,
CycloneDxJSONOption,
SPDXTagValueOption, SPDXTagValueOption,
SPDXJSONOption, SPDXJSONOption,
} }
@ -31,8 +33,12 @@ func ParseOption(userStr string) Option {
return TextOption return TextOption
case string(TableOption): case string(TableOption):
return TableOption return TableOption
case string(CycloneDxOption), "cyclone", "cyclone-dx": case string(CycloneDxXMLOption), "cyclone", "cyclone-dx", "cyclone-dx-xml", "cyclone-xml":
return CycloneDxOption // NOTE(jonasagx): setting "cyclone" to XML by default for retro-compatibility.
// If we want to show no preference between XML and JSON please remove it.
return CycloneDxXMLOption
case string(CycloneDxJSONOption), "cyclone-json", "cyclone-dx-json":
return CycloneDxJSONOption
case string(SPDXTagValueOption), "spdx", "spdx-tagvalue", "spdxtagvalue", "spdx-tv", "spdxtv": case string(SPDXTagValueOption), "spdx", "spdx-tagvalue", "spdxtagvalue", "spdx-tv", "spdxtv":
return SPDXTagValueOption return SPDXTagValueOption
case string(SPDXJSONOption), "spdxjson": case string(SPDXJSONOption), "spdxjson":