-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7ceeeb8
commit 32abd52
Showing
11 changed files
with
263 additions
and
43 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,6 +26,7 @@ import ( | |
"github.com/stretchr/testify/assert" | ||
|
||
"github.com/snyk/parlay/ecosystems/packages" | ||
"github.com/snyk/parlay/lib/sbom" | ||
) | ||
|
||
func TestEnrichSBOM(t *testing.T) { | ||
|
@@ -42,23 +43,23 @@ func TestEnrichSBOM(t *testing.T) { | |
}) | ||
}) | ||
|
||
bom := new(cdx.BOM) | ||
|
||
components := []cdx.Component{ | ||
{ | ||
BOMRef: "pkg:golang/github.com/CycloneDX/[email protected]", | ||
Type: cdx.ComponentTypeLibrary, | ||
Name: "cyclonedx-go", | ||
Version: "v0.3.0", | ||
PackageURL: "pkg:golang/github.com/CycloneDX/[email protected]", | ||
doc := &sbom.SBOMDocument{ | ||
BOM: &cdx.BOM{ | ||
Components: &[]cdx.Component{ | ||
{ | ||
BOMRef: "pkg:golang/github.com/CycloneDX/[email protected]", | ||
Type: cdx.ComponentTypeLibrary, | ||
Name: "cyclonedx-go", | ||
Version: "v0.3.0", | ||
PackageURL: "pkg:golang/github.com/CycloneDX/[email protected]", | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
bom.Components = &components | ||
EnrichSBOM(doc) | ||
|
||
bom = EnrichSBOM(bom) | ||
|
||
components = *bom.Components | ||
components := *doc.BOM.Components | ||
component := components[0] | ||
licenses := *component.Licenses | ||
|
||
|
@@ -84,23 +85,23 @@ func TestEnrichSBOMWithoutLicense(t *testing.T) { | |
}) | ||
}) | ||
|
||
bom := new(cdx.BOM) | ||
|
||
components := []cdx.Component{ | ||
{ | ||
BOMRef: "pkg:golang/github.com/CycloneDX/[email protected]", | ||
Type: cdx.ComponentTypeLibrary, | ||
Name: "cyclonedx-go", | ||
Version: "v0.3.0", | ||
PackageURL: "pkg:golang/github.com/CycloneDX/[email protected]", | ||
doc := &sbom.SBOMDocument{ | ||
BOM: &cdx.BOM{ | ||
Components: &[]cdx.Component{ | ||
{ | ||
BOMRef: "pkg:golang/github.com/CycloneDX/[email protected]", | ||
Type: cdx.ComponentTypeLibrary, | ||
Name: "cyclonedx-go", | ||
Version: "v0.3.0", | ||
PackageURL: "pkg:golang/github.com/CycloneDX/[email protected]", | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
bom.Components = &components | ||
|
||
bom = EnrichSBOM(bom) | ||
EnrichSBOM(doc) | ||
|
||
components = *bom.Components | ||
components := *doc.BOM.Components | ||
|
||
assert.Equal(t, "description", components[0].Description) | ||
|
||
|
@@ -140,9 +141,11 @@ func TestEnrichLicense(t *testing.T) { | |
} | ||
|
||
func TestEnrichBlankSBOM(t *testing.T) { | ||
bom := new(cdx.BOM) | ||
bom = EnrichSBOM(bom) | ||
assert.Nil(t, bom.Components) | ||
doc := &sbom.SBOMDocument{ | ||
BOM: new(cdx.BOM), | ||
} | ||
EnrichSBOM(doc) | ||
assert.Nil(t, doc.BOM.Components) | ||
} | ||
|
||
func TestEnrichExternalReferenceWithNilURL(t *testing.T) { | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package sbom | ||
|
||
import ( | ||
"bytes" | ||
"io" | ||
|
||
cdx "github.com/CycloneDX/cyclonedx-go" | ||
) | ||
|
||
func decodeCycloneDX1_4JSON(b []byte) (*cdx.BOM, error) { | ||
return decodeCycloneDX(b, cdx.BOMFileFormatJSON) | ||
} | ||
|
||
func decodeCycloneDX1_4XML(b []byte) (*cdx.BOM, error) { | ||
return decodeCycloneDX(b, cdx.BOMFileFormatXML) | ||
} | ||
|
||
func decodeCycloneDX(b []byte, f cdx.BOMFileFormat) (*cdx.BOM, error) { | ||
bom := new(cdx.BOM) | ||
decoder := cdx.NewBOMDecoder(bytes.NewReader(b), f) | ||
if err := decoder.Decode(bom); err != nil { | ||
return nil, err | ||
} | ||
return bom, nil | ||
} | ||
|
||
func encodeCycloneDX1_4JSON(bom *cdx.BOM) encoderFn { | ||
return encodeCycloneDX(bom, cdx.BOMFileFormatJSON) | ||
} | ||
|
||
func encodeCycloneDX1_4XML(bom *cdx.BOM) encoderFn { | ||
return encodeCycloneDX(bom, cdx.BOMFileFormatXML) | ||
} | ||
|
||
func encodeCycloneDX(bom *cdx.BOM, f cdx.BOMFileFormat) encoderFn { | ||
return func(w io.Writer) error { | ||
return cdx.NewBOMEncoder(w, f).Encode(bom) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package sbom | ||
|
||
import ( | ||
"bytes" | ||
"errors" | ||
"fmt" | ||
) | ||
|
||
func DecodeSBOMDocument(b []byte) (*SBOMDocument, error) { | ||
doc := new(SBOMDocument) | ||
|
||
format, err := identifySBOMFormat(b) | ||
if err != nil { | ||
return nil, err | ||
} | ||
doc.Format = format | ||
|
||
switch doc.Format { | ||
case SBOMFormatCycloneDX1_4JSON: | ||
bom, err := decodeCycloneDX1_4JSON(b) | ||
if err != nil { | ||
return nil, fmt.Errorf("could not decode input: %w", err) | ||
} | ||
doc.BOM = bom | ||
doc.encode = encodeCycloneDX1_4JSON(doc.BOM) | ||
case SBOMFormatCycloneDX1_4XML: | ||
bom, err := decodeCycloneDX1_4XML(b) | ||
if err != nil { | ||
return nil, fmt.Errorf("could not decode input: %w", err) | ||
} | ||
doc.BOM = bom | ||
doc.encode = encodeCycloneDX1_4XML(doc.BOM) | ||
default: | ||
return nil, fmt.Errorf("no decoder for format %s", doc.Format) | ||
} | ||
|
||
return doc, nil | ||
} | ||
|
||
func identifySBOMFormat(b []byte) (SBOMFormat, error) { | ||
if bytes.Contains(b, []byte("bomFormat")) && bytes.Contains(b, []byte("CycloneDX")) { | ||
return SBOMFormatCycloneDX1_4JSON, nil | ||
} | ||
|
||
if bytes.Contains(b, []byte("xmlns")) && bytes.Contains(b, []byte("cyclonedx")) { | ||
return SBOMFormatCycloneDX1_4XML, nil | ||
} | ||
|
||
return "", errors.New("could not identify SBOM format") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package sbom | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/CycloneDX/cyclonedx-go" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
var ( | ||
fixedCycloneDX1_4JSON = []byte(`{"bomFormat":"CycloneDX","specVersion":"1.4","version":1}`) | ||
fixedCycloneDX1_4XML = []byte(`<bom xmlns="http://cyclonedx.org/schema/bom/1.4" version="1"></bom>`) | ||
fixedSPDX2_2JSON = []byte(`{"SPDXID":"SPDXRef-DOCUMENT","spdxVersion":"SPDX-2.2"}`) | ||
) | ||
|
||
func TestDecodeSBOMDocument_CycloneDX1_4JSON(t *testing.T) { | ||
doc, err := DecodeSBOMDocument(fixedCycloneDX1_4JSON) | ||
require.NoError(t, err) | ||
|
||
assert.Equal(t, SBOMFormatCycloneDX1_4JSON, doc.Format) | ||
assert.NotNil(t, doc.Encode) | ||
assert.IsType(t, &cyclonedx.BOM{}, doc.BOM) | ||
assert.Equal(t, cyclonedx.SpecVersion1_4, doc.BOM.SpecVersion) | ||
} | ||
|
||
func TestDecodeSBOMDocument_CycloneDX1_4XML(t *testing.T) { | ||
doc, err := DecodeSBOMDocument(fixedCycloneDX1_4XML) | ||
require.NoError(t, err) | ||
|
||
assert.Equal(t, SBOMFormatCycloneDX1_4XML, doc.Format) | ||
assert.NotNil(t, doc.Encode) | ||
assert.IsType(t, &cyclonedx.BOM{}, doc.BOM) | ||
assert.Equal(t, cyclonedx.SpecVersion1_4, doc.BOM.SpecVersion) | ||
} | ||
|
||
func TestDecodeSBOMDocument_Unknown(t *testing.T) { | ||
doc, err := DecodeSBOMDocument(fixedSPDX2_2JSON) | ||
|
||
assert.ErrorContains(t, err, "could not identify SBOM format") | ||
assert.Nil(t, doc) | ||
} | ||
|
||
func Test_identifySBOMFormat(t *testing.T) { | ||
tc := map[string]struct { | ||
input []byte | ||
format string | ||
err string | ||
}{ | ||
"CycloneDX 1.4 JSON": { | ||
input: fixedCycloneDX1_4JSON, | ||
format: "CycloneDX 1.4 JSON", | ||
err: "", | ||
}, | ||
"CycloneDX 1.4 XML": { | ||
input: fixedCycloneDX1_4XML, | ||
format: "CycloneDX 1.4 XML", | ||
err: "", | ||
}, | ||
"Unknown format": { | ||
input: fixedSPDX2_2JSON, | ||
format: "", | ||
err: "could not identify SBOM format", | ||
}, | ||
} | ||
|
||
for name, tt := range tc { | ||
t.Run(name, func(t *testing.T) { | ||
format, err := identifySBOMFormat(tt.input) | ||
|
||
if err != nil { | ||
assert.ErrorContains(t, err, tt.err) | ||
} | ||
assert.Equal(t, tt.format, string(format)) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package sbom | ||
|
||
import "io" | ||
|
||
type ( | ||
SBOMEncoder interface { | ||
Encode(w io.Writer) error | ||
} | ||
|
||
encoderFn func(io.Writer) error | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package sbom | ||
|
||
type SBOMFormat string | ||
|
||
const ( | ||
SBOMFormatCycloneDX1_4JSON = SBOMFormat("CycloneDX 1.4 JSON") | ||
SBOMFormatCycloneDX1_4XML = SBOMFormat("CycloneDX 1.4 XML") | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package sbom | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
|
||
cdx "github.com/CycloneDX/cyclonedx-go" | ||
) | ||
|
||
type SBOMDocument struct { | ||
BOM *cdx.BOM | ||
Format SBOMFormat | ||
|
||
encode encoderFn | ||
} | ||
|
||
var _ SBOMEncoder = (*SBOMDocument)(nil) | ||
|
||
func (d *SBOMDocument) Encode(w io.Writer) error { | ||
if d.encode == nil { | ||
return fmt.Errorf("no encoder for format %s", d.Format) | ||
} | ||
|
||
return d.encode(w) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
<bom xmlns="http://cyclonedx.org/schema/bom/1.4" version="1"><metadata><timestamp>2023-06-12T19:17:47Z</timestamp><tools><tool><vendor>Snyk</vendor><name>Snyk Open Source</name></tool></tools><component bom-ref="[email protected]" type="application"><name>package-file-basic</name><version>1.0.0</version><purl>pkg:npm/[email protected]</purl></component></metadata><components><component bom-ref="[email protected]" type="library"><name>debug</name><version>1.0.5</version><purl>pkg:npm/[email protected]</purl></component><component bom-ref="[email protected]" type="library"><name>ms</name><version>2.0.0</version><purl>pkg:npm/[email protected]</purl></component><component bom-ref="[email protected]" type="library"><name>minimatch</name><version>3.0.0</version><purl>pkg:npm/[email protected]</purl></component><component bom-ref="[email protected]" type="library"><name>brace-expansion</name><version>1.1.11</version><purl>pkg:npm/[email protected]</purl></component><component bom-ref="[email protected]" type="library"><name>balanced-match</name><version>1.0.2</version><purl>pkg:npm/[email protected]</purl></component><component bom-ref="[email protected]" type="library"><name>concat-map</name><version>0.0.1</version><purl>pkg:npm/[email protected]</purl></component></components><dependencies><dependency ref="[email protected]"><dependency ref="[email protected]"></dependency><dependency ref="[email protected]"></dependency></dependency><dependency ref="[email protected]"><dependency ref="[email protected]"></dependency></dependency><dependency ref="[email protected]"></dependency><dependency ref="[email protected]"><dependency ref="[email protected]"></dependency></dependency><dependency ref="[email protected]"><dependency ref="[email protected]"></dependency><dependency ref="[email protected]"></dependency></dependency><dependency ref="[email protected]"></dependency><dependency ref="[email protected]"></dependency></dependencies></bom> |