From b9988df0962fe42569c01d7a3b5eb9425ce3ef56 Mon Sep 17 00:00:00 2001 From: Christopher Phillips Date: Tue, 12 Sep 2023 12:07:07 -0400 Subject: [PATCH 1/9] wip: add cyclonedx schema version selection Signed-off-by: Christopher Phillips --- go.mod | 2 +- go.sum | 6 +- syft/formats/cyclonedxjson/decoder_test.go | 5 +- syft/formats/cyclonedxjson/encoder.go | 35 +++++++++++- syft/formats/cyclonedxjson/encoder_test.go | 5 +- syft/formats/cyclonedxjson/format.go | 58 ++++++++++++++++++- syft/formats/cyclonedxjson/format_test.go | 66 ++++++++++++++++++++++ syft/formats/cyclonedxxml/encoder.go | 37 ++++++++++-- syft/formats/cyclonedxxml/format.go | 60 ++++++++++++++++++-- syft/formats/formats.go | 22 ++++++-- syft/formats/formats_test.go | 1 - syft/formats/syftjson/format_test.go | 33 +++++++++++ 12 files changed, 302 insertions(+), 28 deletions(-) create mode 100644 syft/formats/cyclonedxjson/format_test.go create mode 100644 syft/formats/syftjson/format_test.go diff --git a/go.mod b/go.mod index 18980352fd3..b6cc8b52d69 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/anchore/syft go 1.21.0 require ( - github.com/CycloneDX/cyclonedx-go v0.7.1 + github.com/CycloneDX/cyclonedx-go v0.7.2 github.com/Masterminds/semver v1.5.0 github.com/Masterminds/sprig/v3 v3.2.3 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d diff --git a/go.sum b/go.sum index 4bc3adbd2c5..b75b602406d 100644 --- a/go.sum +++ b/go.sum @@ -57,8 +57,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/CycloneDX/cyclonedx-go v0.7.1 h1:5w1SxjGm9MTMNTuRbEPyw21ObdbaagTWF/KfF0qHTRE= -github.com/CycloneDX/cyclonedx-go v0.7.1/go.mod h1:N/nrdWQI2SIjaACyyDs/u7+ddCkyl/zkNs8xFsHF2Ps= +github.com/CycloneDX/cyclonedx-go v0.7.2 h1:kKQ0t1dPOlugSIYVOMiMtFqeXI2wp/f5DBIdfux8gnQ= +github.com/CycloneDX/cyclonedx-go v0.7.2/go.mod h1:K2bA+324+Og0X84fA8HhN2X066K7Bxz4rpMQ4ZhjtSk= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= @@ -683,6 +683,8 @@ github.com/sylabs/sif/v2 v2.11.5 h1:7ssPH3epSonsTrzbS1YxeJ9KuqAN7ISlSM61a7j/mQM= github.com/sylabs/sif/v2 v2.11.5/go.mod h1:GBoZs9LU3e4yJH1dcZ3Akf/jsqYgy5SeguJQC+zd75Y= github.com/sylabs/squashfs v0.6.1 h1:4hgvHnD9JGlYWwT0bPYNt9zaz23mAV3Js+VEgQoRGYQ= github.com/sylabs/squashfs v0.6.1/go.mod h1:ZwpbPCj0ocIvMy2br6KZmix6Gzh6fsGQcCnydMF+Kx8= +github.com/terminalstatic/go-xsd-validate v0.1.5 h1:RqpJnf6HGE2CB/lZB1A8BYguk8uRtcvYAPLCF15qguo= +github.com/terminalstatic/go-xsd-validate v0.1.5/go.mod h1:18lsvYFofBflqCrvo1umpABZ99+GneNTw2kEEc8UPJw= github.com/therootcompany/xz v1.0.1 h1:CmOtsn1CbtmyYiusbfmhmkpAAETj0wBIH6kCYaX+xzw= github.com/therootcompany/xz v1.0.1/go.mod h1:3K3UH1yCKgBneZYhuQUvJ9HPD19UEXEI0BWbMn8qNMY= github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= diff --git a/syft/formats/cyclonedxjson/decoder_test.go b/syft/formats/cyclonedxjson/decoder_test.go index f969732a160..6c204323ed4 100644 --- a/syft/formats/cyclonedxjson/decoder_test.go +++ b/syft/formats/cyclonedxjson/decoder_test.go @@ -10,6 +10,7 @@ import ( ) func Test_decodeJSON(t *testing.T) { + defaultVersion := "" tests := []struct { file string err bool @@ -37,12 +38,12 @@ func Test_decodeJSON(t *testing.T) { assert.NoError(t, err) if test.err { - err = Format().Validate(reader) + err = Format(defaultVersion).Validate(reader) assert.Error(t, err) return } - bom, err := Format().Decode(reader) + bom, err := Format(defaultVersion).Decode(reader) assert.NoError(t, err) diff --git a/syft/formats/cyclonedxjson/encoder.go b/syft/formats/cyclonedxjson/encoder.go index 13ad32f682e..6110779ed0c 100644 --- a/syft/formats/cyclonedxjson/encoder.go +++ b/syft/formats/cyclonedxjson/encoder.go @@ -9,11 +9,40 @@ import ( "github.com/anchore/syft/syft/sbom" ) -func encoder(output io.Writer, s sbom.SBOM) error { +func encoder_v1_0(output io.Writer, s sbom.SBOM) error { + enc, bom := buildEncoder(output, s) + return enc.EncodeVersion(bom, cyclonedx.SpecVersion1_0) +} + +func encoder_v1_1(output io.Writer, s sbom.SBOM) error { + enc, bom := buildEncoder(output, s) + return enc.EncodeVersion(bom, cyclonedx.SpecVersion1_1) +} + +func encoder_v1_2(output io.Writer, s sbom.SBOM) error { + enc, bom := buildEncoder(output, s) + return enc.EncodeVersion(bom, cyclonedx.SpecVersion1_2) +} + +func encoder_v1_3(output io.Writer, s sbom.SBOM) error { + enc, bom := buildEncoder(output, s) + return enc.EncodeVersion(bom, cyclonedx.SpecVersion1_3) +} + +func encoder_v1_4(output io.Writer, s sbom.SBOM) error { + enc, bom := buildEncoder(output, s) + return enc.EncodeVersion(bom, cyclonedx.SpecVersion1_4) +} + +func encoder_v1_5(output io.Writer, s sbom.SBOM) error { + enc, bom := buildEncoder(output, s) + return enc.EncodeVersion(bom, cyclonedx.SpecVersion1_5) +} + +func buildEncoder(output io.Writer, s sbom.SBOM) (cyclonedx.BOMEncoder, *cyclonedx.BOM) { bom := cyclonedxhelpers.ToFormatModel(s) enc := cyclonedx.NewBOMEncoder(output, cyclonedx.BOMFileFormatJSON) enc.SetPretty(true) enc.SetEscapeHTML(false) - err := enc.Encode(bom) - return err + return enc, bom } diff --git a/syft/formats/cyclonedxjson/encoder_test.go b/syft/formats/cyclonedxjson/encoder_test.go index dec29164e06..89b5a8aa013 100644 --- a/syft/formats/cyclonedxjson/encoder_test.go +++ b/syft/formats/cyclonedxjson/encoder_test.go @@ -9,13 +9,14 @@ import ( var updateSnapshot = flag.Bool("update-cyclonedx-json", false, "update the *.golden files for cyclone-dx JSON encoders") var updateImage = flag.Bool("update-image", false, "update the golden image used for image encoder testing") +var latestVersion = "" func TestCycloneDxDirectoryEncoder(t *testing.T) { dir := t.TempDir() testutils.AssertEncoderAgainstGoldenSnapshot(t, testutils.EncoderSnapshotTestConfig{ Subject: testutils.DirectoryInput(t, dir), - Format: Format(), + Format: Format(latestVersion), UpdateSnapshot: *updateSnapshot, PersistRedactionsInSnapshot: true, IsJSON: true, @@ -33,7 +34,7 @@ func TestCycloneDxImageEncoder(t *testing.T) { }, testutils.EncoderSnapshotTestConfig{ Subject: testutils.ImageInput(t, testImage), - Format: Format(), + Format: Format(latestVersion), UpdateSnapshot: *updateSnapshot, PersistRedactionsInSnapshot: true, IsJSON: true, diff --git a/syft/formats/cyclonedxjson/format.go b/syft/formats/cyclonedxjson/format.go index 8c1e2e01643..77d6ed6a556 100644 --- a/syft/formats/cyclonedxjson/format.go +++ b/syft/formats/cyclonedxjson/format.go @@ -9,10 +9,62 @@ import ( const ID sbom.FormatID = "cyclonedx-json" -func Format() sbom.Format { +var Format = Format1_4 + +func Format1_0() sbom.Format { + return sbom.NewFormat( + cyclonedx.SpecVersion1_0.String(), + encoder_v1_0, + cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatJSON), + cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatJSON), + ID, + ) +} + +func Format1_1() sbom.Format { + return sbom.NewFormat( + cyclonedx.SpecVersion1_1.String(), + encoder_v1_1, + cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatJSON), + cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatJSON), + ID, + ) +} + +func Format1_2() sbom.Format { + return sbom.NewFormat( + cyclonedx.SpecVersion1_2.String(), + encoder_v1_2, + cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatJSON), + cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatJSON), + ID, + ) +} + +func Format1_3() sbom.Format { + return sbom.NewFormat( + cyclonedx.SpecVersion1_3.String(), + encoder_v1_3, + cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatJSON), + cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatJSON), + ID, + ) +} + +func Format1_4() sbom.Format { + return sbom.NewFormat( + cyclonedx.SpecVersion1_4.String(), + encoder_v1_4, + cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatJSON), + cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatJSON), + ID, + ) +} + +func Format1_5() sbom.Format { return sbom.NewFormat( - sbom.AnyVersion, - encoder, + cyclonedx.SpecVersion1_5.String(), + encoder_v1_5, cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatJSON), cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatJSON), ID, diff --git a/syft/formats/cyclonedxjson/format_test.go b/syft/formats/cyclonedxjson/format_test.go new file mode 100644 index 00000000000..7ec3f7e6312 --- /dev/null +++ b/syft/formats/cyclonedxjson/format_test.go @@ -0,0 +1,66 @@ +package cyclonedxjson + +import ( + "testing" + + "github.com/CycloneDX/cyclonedx-go" +) + +func TestFormatVersions(t *testing.T) { + tests := []struct { + name string + version string + expectedVersion string + }{ + { + + "cyclonedx-json should default to v1.4", + "", + cyclonedx.SpecVersion1_4.String(), + }, + { + + "cyclonedx-json should encode for v1.5", + "v1.5", + cyclonedx.SpecVersion1_5.String(), + }, + { + + "cyclonedx-json should encode for v1.3", + "v1.3", + cyclonedx.SpecVersion1_3.String(), + }, + { + + "cyclonedx-json should encode for v1.2", + "v1.2", + cyclonedx.SpecVersion1_2.String(), + }, + { + + "cyclonedx-json should encode for v1.1", + "v1.1", + cyclonedx.SpecVersion1_1.String(), + }, + { + + "cyclonedx-json should encode for v1.0", + "v1.0", + cyclonedx.SpecVersion1_0.String(), + }, + } + + for _, c := range tests { + c := c + t.Run(c.name, func(t *testing.T) { + sbomFormat := Format(c.version) + if sbomFormat.ID() != ID { + t.Errorf("expected ID %q, got %q", ID, sbomFormat.ID()) + } + + if sbomFormat.Version() != c.expectedVersion { + t.Errorf("expected version %q, got %q", c.version, sbomFormat.Version()) + } + }) + } +} diff --git a/syft/formats/cyclonedxxml/encoder.go b/syft/formats/cyclonedxxml/encoder.go index b8abdf81a15..04930e0c3eb 100644 --- a/syft/formats/cyclonedxxml/encoder.go +++ b/syft/formats/cyclonedxxml/encoder.go @@ -9,11 +9,40 @@ import ( "github.com/anchore/syft/syft/sbom" ) -func encoder(output io.Writer, s sbom.SBOM) error { +func encoder_v1_0(output io.Writer, s sbom.SBOM) error { + enc, bom := buildEncoder(output, s) + return enc.EncodeVersion(bom, cyclonedx.SpecVersion1_0) +} + +func encoder_v1_1(output io.Writer, s sbom.SBOM) error { + enc, bom := buildEncoder(output, s) + return enc.EncodeVersion(bom, cyclonedx.SpecVersion1_1) +} + +func encoder_v1_2(output io.Writer, s sbom.SBOM) error { + enc, bom := buildEncoder(output, s) + return enc.EncodeVersion(bom, cyclonedx.SpecVersion1_2) +} + +func encoder_v1_3(output io.Writer, s sbom.SBOM) error { + enc, bom := buildEncoder(output, s) + return enc.EncodeVersion(bom, cyclonedx.SpecVersion1_3) +} + +func encoder_v1_4(output io.Writer, s sbom.SBOM) error { + enc, bom := buildEncoder(output, s) + return enc.EncodeVersion(bom, cyclonedx.SpecVersion1_4) +} + +func encoder_v1_5(output io.Writer, s sbom.SBOM) error { + enc, bom := buildEncoder(output, s) + return enc.EncodeVersion(bom, cyclonedx.SpecVersion1_5) +} + +func buildEncoder(output io.Writer, s sbom.SBOM) (cyclonedx.BOMEncoder, *cyclonedx.BOM) { bom := cyclonedxhelpers.ToFormatModel(s) enc := cyclonedx.NewBOMEncoder(output, cyclonedx.BOMFileFormatXML) enc.SetPretty(true) - - err := enc.Encode(bom) - return err + enc.SetEscapeHTML(false) + return enc, bom } diff --git a/syft/formats/cyclonedxxml/format.go b/syft/formats/cyclonedxxml/format.go index 7fe53c4f7f1..baf1350119c 100644 --- a/syft/formats/cyclonedxxml/format.go +++ b/syft/formats/cyclonedxxml/format.go @@ -9,12 +9,64 @@ import ( const ID sbom.FormatID = "cyclonedx-xml" -func Format() sbom.Format { +var Format = Format1_4 + +func Format1_0() sbom.Format { + return sbom.NewFormat( + cyclonedx.SpecVersion1_0.String(), + encoder_v1_0, + cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatXML), + cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatXML), + ID, "cyclonedx-xml", "cyclone-xml", + ) +} + +func Format1_1() sbom.Format { + return sbom.NewFormat( + cyclonedx.SpecVersion1_1.String(), + encoder_v1_1, + cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatXML), + cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatXML), + ID, "cyclonedx-xml", "cyclone-xml", + ) +} + +func Format1_2() sbom.Format { + return sbom.NewFormat( + cyclonedx.SpecVersion1_2.String(), + encoder_v1_2, + cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatXML), + cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatXML), + ID, "cyclonedx-xml", "cyclone-xml", + ) +} + +func Format1_3() sbom.Format { + return sbom.NewFormat( + cyclonedx.SpecVersion1_3.String(), + encoder_v1_3, + cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatXML), + cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatXML), + ID, "cyclonedx-xml", "cyclone-xml", + ) +} + +func Format1_4() sbom.Format { + return sbom.NewFormat( + cyclonedx.SpecVersion1_4.String(), + encoder_v1_4, + cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatXML), + cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatXML), + ID, "cyclonedx-xml", "cyclone-xml", + ) +} + +func Format1_5() sbom.Format { return sbom.NewFormat( - sbom.AnyVersion, - encoder, + cyclonedx.SpecVersion1_5.String(), + encoder_v1_5, cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatXML), cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatXML), - ID, "cyclonedx", "cyclone", + ID, "cyclonedx-xml", "cyclone-xml", ) } diff --git a/syft/formats/formats.go b/syft/formats/formats.go index 13af6cf058f..8eae184a9cd 100644 --- a/syft/formats/formats.go +++ b/syft/formats/formats.go @@ -26,17 +26,27 @@ import ( func Formats() []sbom.Format { return []sbom.Format{ syftjson.Format(), - cyclonedxxml.Format(), - cyclonedxjson.Format(), github.Format(), + table.Format(), + text.Format(), + template.Format(), + cyclonedxxml.Format1_0(), + cyclonedxxml.Format1_1(), + cyclonedxxml.Format1_2(), + cyclonedxxml.Format1_3(), + cyclonedxxml.Format1_4(), + cyclonedxxml.Format1_5(), + cyclonedxjson.Format1_0(), + cyclonedxjson.Format1_1(), + cyclonedxjson.Format1_2(), + cyclonedxjson.Format1_3(), + cyclonedxjson.Format1_4(), + cyclonedxjson.Format1_5(), spdxtagvalue.Format2_1(), spdxtagvalue.Format2_2(), spdxtagvalue.Format2_3(), spdxjson.Format2_2(), spdxjson.Format2_3(), - table.Format(), - text.Format(), - template.Format(), } } @@ -55,7 +65,7 @@ func Identify(by []byte) sbom.Format { // ByName accepts a name@version string, such as: // -// spdx-json@2.1 or cyclonedx@2 +// spdx-json@2.1 or cyclonedx@1.5 func ByName(name string) sbom.Format { parts := strings.SplitN(name, "@", 2) version := sbom.AnyVersion diff --git a/syft/formats/formats_test.go b/syft/formats/formats_test.go index 60dae72c9b3..2cdc99b8a52 100644 --- a/syft/formats/formats_test.go +++ b/syft/formats/formats_test.go @@ -70,7 +70,6 @@ func TestFormats_EmptyInput(t *testing.T) { } func TestByName(t *testing.T) { - tests := []struct { name string want sbom.FormatID diff --git a/syft/formats/syftjson/format_test.go b/syft/formats/syftjson/format_test.go new file mode 100644 index 00000000000..4ef7a21a167 --- /dev/null +++ b/syft/formats/syftjson/format_test.go @@ -0,0 +1,33 @@ +package syftjson + +import ( + "testing" + + "github.com/anchore/syft/internal" +) + +func TestFormat(t *testing.T) { + tests := []struct { + name string + version string + }{ + { + name: "default version should use latest internal version", + version: "", + }, + } + + for _, c := range tests { + c := c + t.Run(c.name, func(t *testing.T) { + sbomFormat := Format() + if sbomFormat.ID() != ID { + t.Errorf("expected ID %q, got %q", ID, sbomFormat.ID()) + } + + if sbomFormat.Version() != internal.JSONSchemaVersion { + t.Errorf("expected version %q, got %q", c.version, sbomFormat.Version()) + } + }) + } +} From eb009e8a5a1506af94eadf1714cefb1e86daea35 Mon Sep 17 00:00:00 2001 From: Christopher Phillips Date: Tue, 12 Sep 2023 12:42:02 -0400 Subject: [PATCH 2/9] fix: fix static analysis Signed-off-by: Christopher Phillips --- syft/formats/cyclonedxjson/encoder.go | 12 ++++++------ syft/formats/cyclonedxjson/format.go | 12 ++++++------ syft/formats/cyclonedxxml/encoder.go | 12 ++++++------ syft/formats/cyclonedxxml/format.go | 12 ++++++------ 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/syft/formats/cyclonedxjson/encoder.go b/syft/formats/cyclonedxjson/encoder.go index 6110779ed0c..297b8026580 100644 --- a/syft/formats/cyclonedxjson/encoder.go +++ b/syft/formats/cyclonedxjson/encoder.go @@ -9,32 +9,32 @@ import ( "github.com/anchore/syft/syft/sbom" ) -func encoder_v1_0(output io.Writer, s sbom.SBOM) error { +func encoderV1_0(output io.Writer, s sbom.SBOM) error { enc, bom := buildEncoder(output, s) return enc.EncodeVersion(bom, cyclonedx.SpecVersion1_0) } -func encoder_v1_1(output io.Writer, s sbom.SBOM) error { +func encoderV1_1(output io.Writer, s sbom.SBOM) error { enc, bom := buildEncoder(output, s) return enc.EncodeVersion(bom, cyclonedx.SpecVersion1_1) } -func encoder_v1_2(output io.Writer, s sbom.SBOM) error { +func encoderV1_2(output io.Writer, s sbom.SBOM) error { enc, bom := buildEncoder(output, s) return enc.EncodeVersion(bom, cyclonedx.SpecVersion1_2) } -func encoder_v1_3(output io.Writer, s sbom.SBOM) error { +func encoderV1_3(output io.Writer, s sbom.SBOM) error { enc, bom := buildEncoder(output, s) return enc.EncodeVersion(bom, cyclonedx.SpecVersion1_3) } -func encoder_v1_4(output io.Writer, s sbom.SBOM) error { +func encoderV1_4(output io.Writer, s sbom.SBOM) error { enc, bom := buildEncoder(output, s) return enc.EncodeVersion(bom, cyclonedx.SpecVersion1_4) } -func encoder_v1_5(output io.Writer, s sbom.SBOM) error { +func encoderV1_5(output io.Writer, s sbom.SBOM) error { enc, bom := buildEncoder(output, s) return enc.EncodeVersion(bom, cyclonedx.SpecVersion1_5) } diff --git a/syft/formats/cyclonedxjson/format.go b/syft/formats/cyclonedxjson/format.go index 77d6ed6a556..97a088aaea7 100644 --- a/syft/formats/cyclonedxjson/format.go +++ b/syft/formats/cyclonedxjson/format.go @@ -14,7 +14,7 @@ var Format = Format1_4 func Format1_0() sbom.Format { return sbom.NewFormat( cyclonedx.SpecVersion1_0.String(), - encoder_v1_0, + encoderV1_0, cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatJSON), cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatJSON), ID, @@ -24,7 +24,7 @@ func Format1_0() sbom.Format { func Format1_1() sbom.Format { return sbom.NewFormat( cyclonedx.SpecVersion1_1.String(), - encoder_v1_1, + encoderV1_1, cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatJSON), cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatJSON), ID, @@ -34,7 +34,7 @@ func Format1_1() sbom.Format { func Format1_2() sbom.Format { return sbom.NewFormat( cyclonedx.SpecVersion1_2.String(), - encoder_v1_2, + encoderV1_2, cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatJSON), cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatJSON), ID, @@ -44,7 +44,7 @@ func Format1_2() sbom.Format { func Format1_3() sbom.Format { return sbom.NewFormat( cyclonedx.SpecVersion1_3.String(), - encoder_v1_3, + encoderV1_3, cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatJSON), cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatJSON), ID, @@ -54,7 +54,7 @@ func Format1_3() sbom.Format { func Format1_4() sbom.Format { return sbom.NewFormat( cyclonedx.SpecVersion1_4.String(), - encoder_v1_4, + encoderV1_4, cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatJSON), cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatJSON), ID, @@ -64,7 +64,7 @@ func Format1_4() sbom.Format { func Format1_5() sbom.Format { return sbom.NewFormat( cyclonedx.SpecVersion1_5.String(), - encoder_v1_5, + encoderV1_5, cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatJSON), cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatJSON), ID, diff --git a/syft/formats/cyclonedxxml/encoder.go b/syft/formats/cyclonedxxml/encoder.go index 04930e0c3eb..3941feca00b 100644 --- a/syft/formats/cyclonedxxml/encoder.go +++ b/syft/formats/cyclonedxxml/encoder.go @@ -9,32 +9,32 @@ import ( "github.com/anchore/syft/syft/sbom" ) -func encoder_v1_0(output io.Writer, s sbom.SBOM) error { +func encoderV1_0(output io.Writer, s sbom.SBOM) error { enc, bom := buildEncoder(output, s) return enc.EncodeVersion(bom, cyclonedx.SpecVersion1_0) } -func encoder_v1_1(output io.Writer, s sbom.SBOM) error { +func encoderV1_1(output io.Writer, s sbom.SBOM) error { enc, bom := buildEncoder(output, s) return enc.EncodeVersion(bom, cyclonedx.SpecVersion1_1) } -func encoder_v1_2(output io.Writer, s sbom.SBOM) error { +func encoderV1_2(output io.Writer, s sbom.SBOM) error { enc, bom := buildEncoder(output, s) return enc.EncodeVersion(bom, cyclonedx.SpecVersion1_2) } -func encoder_v1_3(output io.Writer, s sbom.SBOM) error { +func encoderV1_3(output io.Writer, s sbom.SBOM) error { enc, bom := buildEncoder(output, s) return enc.EncodeVersion(bom, cyclonedx.SpecVersion1_3) } -func encoder_v1_4(output io.Writer, s sbom.SBOM) error { +func encoderV1_4(output io.Writer, s sbom.SBOM) error { enc, bom := buildEncoder(output, s) return enc.EncodeVersion(bom, cyclonedx.SpecVersion1_4) } -func encoder_v1_5(output io.Writer, s sbom.SBOM) error { +func encoderV1_5(output io.Writer, s sbom.SBOM) error { enc, bom := buildEncoder(output, s) return enc.EncodeVersion(bom, cyclonedx.SpecVersion1_5) } diff --git a/syft/formats/cyclonedxxml/format.go b/syft/formats/cyclonedxxml/format.go index baf1350119c..e5072572274 100644 --- a/syft/formats/cyclonedxxml/format.go +++ b/syft/formats/cyclonedxxml/format.go @@ -14,7 +14,7 @@ var Format = Format1_4 func Format1_0() sbom.Format { return sbom.NewFormat( cyclonedx.SpecVersion1_0.String(), - encoder_v1_0, + encoderV1_0, cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatXML), cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatXML), ID, "cyclonedx-xml", "cyclone-xml", @@ -24,7 +24,7 @@ func Format1_0() sbom.Format { func Format1_1() sbom.Format { return sbom.NewFormat( cyclonedx.SpecVersion1_1.String(), - encoder_v1_1, + encoderV1_1, cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatXML), cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatXML), ID, "cyclonedx-xml", "cyclone-xml", @@ -34,7 +34,7 @@ func Format1_1() sbom.Format { func Format1_2() sbom.Format { return sbom.NewFormat( cyclonedx.SpecVersion1_2.String(), - encoder_v1_2, + encoderV1_2, cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatXML), cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatXML), ID, "cyclonedx-xml", "cyclone-xml", @@ -44,7 +44,7 @@ func Format1_2() sbom.Format { func Format1_3() sbom.Format { return sbom.NewFormat( cyclonedx.SpecVersion1_3.String(), - encoder_v1_3, + encoderV1_3, cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatXML), cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatXML), ID, "cyclonedx-xml", "cyclone-xml", @@ -54,7 +54,7 @@ func Format1_3() sbom.Format { func Format1_4() sbom.Format { return sbom.NewFormat( cyclonedx.SpecVersion1_4.String(), - encoder_v1_4, + encoderV1_4, cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatXML), cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatXML), ID, "cyclonedx-xml", "cyclone-xml", @@ -64,7 +64,7 @@ func Format1_4() sbom.Format { func Format1_5() sbom.Format { return sbom.NewFormat( cyclonedx.SpecVersion1_5.String(), - encoder_v1_5, + encoderV1_5, cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatXML), cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatXML), ID, "cyclonedx-xml", "cyclone-xml", From 12355d883b81561c679a501c4d0b2bcdb26464ba Mon Sep 17 00:00:00 2001 From: Christopher Phillips Date: Tue, 12 Sep 2023 12:55:49 -0400 Subject: [PATCH 3/9] fix: update unit tests back to correct state Signed-off-by: Christopher Phillips --- syft/formats/cyclonedxjson/decoder_test.go | 5 ++- syft/formats/cyclonedxjson/encoder_test.go | 5 ++- syft/formats/cyclonedxjson/format_test.go | 36 ++-------------------- syft/formats/cyclonedxxml/format.go | 2 +- 4 files changed, 7 insertions(+), 41 deletions(-) diff --git a/syft/formats/cyclonedxjson/decoder_test.go b/syft/formats/cyclonedxjson/decoder_test.go index 6c204323ed4..f969732a160 100644 --- a/syft/formats/cyclonedxjson/decoder_test.go +++ b/syft/formats/cyclonedxjson/decoder_test.go @@ -10,7 +10,6 @@ import ( ) func Test_decodeJSON(t *testing.T) { - defaultVersion := "" tests := []struct { file string err bool @@ -38,12 +37,12 @@ func Test_decodeJSON(t *testing.T) { assert.NoError(t, err) if test.err { - err = Format(defaultVersion).Validate(reader) + err = Format().Validate(reader) assert.Error(t, err) return } - bom, err := Format(defaultVersion).Decode(reader) + bom, err := Format().Decode(reader) assert.NoError(t, err) diff --git a/syft/formats/cyclonedxjson/encoder_test.go b/syft/formats/cyclonedxjson/encoder_test.go index 89b5a8aa013..dec29164e06 100644 --- a/syft/formats/cyclonedxjson/encoder_test.go +++ b/syft/formats/cyclonedxjson/encoder_test.go @@ -9,14 +9,13 @@ import ( var updateSnapshot = flag.Bool("update-cyclonedx-json", false, "update the *.golden files for cyclone-dx JSON encoders") var updateImage = flag.Bool("update-image", false, "update the golden image used for image encoder testing") -var latestVersion = "" func TestCycloneDxDirectoryEncoder(t *testing.T) { dir := t.TempDir() testutils.AssertEncoderAgainstGoldenSnapshot(t, testutils.EncoderSnapshotTestConfig{ Subject: testutils.DirectoryInput(t, dir), - Format: Format(latestVersion), + Format: Format(), UpdateSnapshot: *updateSnapshot, PersistRedactionsInSnapshot: true, IsJSON: true, @@ -34,7 +33,7 @@ func TestCycloneDxImageEncoder(t *testing.T) { }, testutils.EncoderSnapshotTestConfig{ Subject: testutils.ImageInput(t, testImage), - Format: Format(latestVersion), + Format: Format(), UpdateSnapshot: *updateSnapshot, PersistRedactionsInSnapshot: true, IsJSON: true, diff --git a/syft/formats/cyclonedxjson/format_test.go b/syft/formats/cyclonedxjson/format_test.go index 7ec3f7e6312..2cfd5e54504 100644 --- a/syft/formats/cyclonedxjson/format_test.go +++ b/syft/formats/cyclonedxjson/format_test.go @@ -9,57 +9,25 @@ import ( func TestFormatVersions(t *testing.T) { tests := []struct { name string - version string expectedVersion string }{ { "cyclonedx-json should default to v1.4", - "", cyclonedx.SpecVersion1_4.String(), }, - { - - "cyclonedx-json should encode for v1.5", - "v1.5", - cyclonedx.SpecVersion1_5.String(), - }, - { - - "cyclonedx-json should encode for v1.3", - "v1.3", - cyclonedx.SpecVersion1_3.String(), - }, - { - - "cyclonedx-json should encode for v1.2", - "v1.2", - cyclonedx.SpecVersion1_2.String(), - }, - { - - "cyclonedx-json should encode for v1.1", - "v1.1", - cyclonedx.SpecVersion1_1.String(), - }, - { - - "cyclonedx-json should encode for v1.0", - "v1.0", - cyclonedx.SpecVersion1_0.String(), - }, } for _, c := range tests { c := c t.Run(c.name, func(t *testing.T) { - sbomFormat := Format(c.version) + sbomFormat := Format() if sbomFormat.ID() != ID { t.Errorf("expected ID %q, got %q", ID, sbomFormat.ID()) } if sbomFormat.Version() != c.expectedVersion { - t.Errorf("expected version %q, got %q", c.version, sbomFormat.Version()) + t.Errorf("expected version %q, got %q", c.expectedVersion, sbomFormat.Version()) } }) } diff --git a/syft/formats/cyclonedxxml/format.go b/syft/formats/cyclonedxxml/format.go index e5072572274..43c2d2b97b3 100644 --- a/syft/formats/cyclonedxxml/format.go +++ b/syft/formats/cyclonedxxml/format.go @@ -7,7 +7,7 @@ import ( "github.com/anchore/syft/syft/sbom" ) -const ID sbom.FormatID = "cyclonedx-xml" +const ID sbom.FormatID = "cyclonedx" var Format = Format1_4 From beffca20984ae7802a4fbd0600fa2e15b8fe1a9c Mon Sep 17 00:00:00 2001 From: Christopher Phillips Date: Tue, 12 Sep 2023 13:39:04 -0400 Subject: [PATCH 4/9] fix: update cli tests by pinning default cyclonedx to v1.4 Signed-off-by: Christopher Phillips --- schema/cyclonedx/README.md | 2 +- syft/formats/formats.go | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/schema/cyclonedx/README.md b/schema/cyclonedx/README.md index 200d6393e30..b9278db66c4 100644 --- a/schema/cyclonedx/README.md +++ b/schema/cyclonedx/README.md @@ -1,6 +1,6 @@ # CycloneDX Schemas -`syft` generates a CycloneDX BOm output. We want to be able to validate the CycloneDX schemas +`syft` generates a CycloneDX Bom output. We want to be able to validate the CycloneDX schemas (and dependent schemas) against generated syft output. The best way to do this is with `xmllint`, however, this tool does not know how to deal with references from HTTP, only the local filesystem. For this reason we've included a copy of all schemas needed to validate `syft` output, modified diff --git a/syft/formats/formats.go b/syft/formats/formats.go index 8eae184a9cd..4462928b7cc 100644 --- a/syft/formats/formats.go +++ b/syft/formats/formats.go @@ -81,6 +81,13 @@ func ByNameAndVersion(name string, version string) sbom.Format { for _, f := range Formats() { for _, n := range f.IDs() { if cleanFormatName(string(n)) == name && versionMatches(f.Version(), version) { + if version == sbom.AnyVersion && strings.Contains(string(n), "cyclonedx") { + // if the version is not specified and the format is cyclonedx, then we want to return the most recent version up to 1.4 + // https://github.com/CycloneDX/cyclonedx-go/pull/90 + if f.Version() == "1.5" { + continue + } + } if mostRecentFormat == nil || f.Version() > mostRecentFormat.Version() { mostRecentFormat = f } From 1f62e19f23f5f03d554a5da9ee3c798c0f3f3494 Mon Sep 17 00:00:00 2001 From: Christopher Phillips Date: Wed, 13 Sep 2023 10:02:06 -0400 Subject: [PATCH 5/9] fix: reorient FormatID and alias for cyclonedx-xml Signed-off-by: Christopher Phillips --- syft/formats/cyclonedxxml/format.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/syft/formats/cyclonedxxml/format.go b/syft/formats/cyclonedxxml/format.go index 43c2d2b97b3..05649c0577b 100644 --- a/syft/formats/cyclonedxxml/format.go +++ b/syft/formats/cyclonedxxml/format.go @@ -7,7 +7,7 @@ import ( "github.com/anchore/syft/syft/sbom" ) -const ID sbom.FormatID = "cyclonedx" +const ID sbom.FormatID = "cyclonedx-xml" var Format = Format1_4 @@ -17,7 +17,7 @@ func Format1_0() sbom.Format { encoderV1_0, cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatXML), cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatXML), - ID, "cyclonedx-xml", "cyclone-xml", + ID, "cyclonedx", "cyclone-xml", ) } @@ -27,7 +27,7 @@ func Format1_1() sbom.Format { encoderV1_1, cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatXML), cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatXML), - ID, "cyclonedx-xml", "cyclone-xml", + ID, "cyclonedx", "cyclone-xml", ) } @@ -37,7 +37,7 @@ func Format1_2() sbom.Format { encoderV1_2, cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatXML), cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatXML), - ID, "cyclonedx-xml", "cyclone-xml", + ID, "cyclonedx", "cyclone-xml", ) } @@ -47,7 +47,7 @@ func Format1_3() sbom.Format { encoderV1_3, cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatXML), cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatXML), - ID, "cyclonedx-xml", "cyclone-xml", + ID, "cyclonedx", "cyclone-xml", ) } @@ -57,7 +57,7 @@ func Format1_4() sbom.Format { encoderV1_4, cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatXML), cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatXML), - ID, "cyclonedx-xml", "cyclone-xml", + ID, "cyclonedx", "cyclone-xml", ) } @@ -67,6 +67,6 @@ func Format1_5() sbom.Format { encoderV1_5, cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatXML), cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatXML), - ID, "cyclonedx-xml", "cyclone-xml", + ID, "cyclonedx", "cyclone-xml", ) } From 9aec01d254c96bc504aa99b6b655a7b6ceadb8e8 Mon Sep 17 00:00:00 2001 From: Christopher Phillips Date: Wed, 13 Sep 2023 10:04:27 -0400 Subject: [PATCH 6/9] fix: update TODO with comment on when 1.5 is stable Signed-off-by: Christopher Phillips --- syft/formats/formats.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/syft/formats/formats.go b/syft/formats/formats.go index 4462928b7cc..73ad9a48c8c 100644 --- a/syft/formats/formats.go +++ b/syft/formats/formats.go @@ -81,9 +81,10 @@ func ByNameAndVersion(name string, version string) sbom.Format { for _, f := range Formats() { for _, n := range f.IDs() { if cleanFormatName(string(n)) == name && versionMatches(f.Version(), version) { + // if the version is not specified and the format is cyclonedx, then we want to return the most recent version up to 1.4 + // TODO: remove this check when 1.5 is stable. PR below should be merged. + // https://github.com/CycloneDX/cyclonedx-go/pull/90 if version == sbom.AnyVersion && strings.Contains(string(n), "cyclonedx") { - // if the version is not specified and the format is cyclonedx, then we want to return the most recent version up to 1.4 - // https://github.com/CycloneDX/cyclonedx-go/pull/90 if f.Version() == "1.5" { continue } From 0e2ddc4811620ee2869904f9b5ede7005e8172d1 Mon Sep 17 00:00:00 2001 From: Christopher Phillips Date: Wed, 13 Sep 2023 10:27:51 -0400 Subject: [PATCH 7/9] fix: keep aliases to the original format Signed-off-by: Christopher Phillips --- syft/formats/cyclonedxxml/format.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/syft/formats/cyclonedxxml/format.go b/syft/formats/cyclonedxxml/format.go index 05649c0577b..1b22cee1476 100644 --- a/syft/formats/cyclonedxxml/format.go +++ b/syft/formats/cyclonedxxml/format.go @@ -17,7 +17,7 @@ func Format1_0() sbom.Format { encoderV1_0, cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatXML), cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatXML), - ID, "cyclonedx", "cyclone-xml", + ID, "cyclonedx", "cyclone", ) } @@ -27,7 +27,7 @@ func Format1_1() sbom.Format { encoderV1_1, cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatXML), cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatXML), - ID, "cyclonedx", "cyclone-xml", + ID, "cyclonedx", "cyclone", ) } @@ -37,7 +37,7 @@ func Format1_2() sbom.Format { encoderV1_2, cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatXML), cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatXML), - ID, "cyclonedx", "cyclone-xml", + ID, "cyclonedx", "cyclone", ) } @@ -47,7 +47,7 @@ func Format1_3() sbom.Format { encoderV1_3, cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatXML), cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatXML), - ID, "cyclonedx", "cyclone-xml", + ID, "cyclonedx", "cyclone", ) } @@ -57,7 +57,7 @@ func Format1_4() sbom.Format { encoderV1_4, cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatXML), cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatXML), - ID, "cyclonedx", "cyclone-xml", + ID, "cyclonedx", "cyclone", ) } @@ -67,6 +67,6 @@ func Format1_5() sbom.Format { encoderV1_5, cyclonedxhelpers.GetDecoder(cyclonedx.BOMFileFormatXML), cyclonedxhelpers.GetValidator(cyclonedx.BOMFileFormatXML), - ID, "cyclonedx", "cyclone-xml", + ID, "cyclonedx", "cyclone", ) } From 8cffa745f8f028e5df1a4b15b98be9dafbf905a6 Mon Sep 17 00:00:00 2001 From: Christopher Phillips Date: Wed, 13 Sep 2023 10:42:53 -0400 Subject: [PATCH 8/9] fix: comment with more context Signed-off-by: Christopher Phillips --- syft/formats/formats.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/syft/formats/formats.go b/syft/formats/formats.go index 73ad9a48c8c..1acaf3acf1e 100644 --- a/syft/formats/formats.go +++ b/syft/formats/formats.go @@ -82,7 +82,9 @@ func ByNameAndVersion(name string, version string) sbom.Format { for _, n := range f.IDs() { if cleanFormatName(string(n)) == name && versionMatches(f.Version(), version) { // if the version is not specified and the format is cyclonedx, then we want to return the most recent version up to 1.4 - // TODO: remove this check when 1.5 is stable. PR below should be merged. + // If more aliases like cdx are added this will not catch those - we want to eventually provide a way for + // formats to inform this function what their default version is + // TODO: remove this check when 1.5 is stable or default formats are designed. PR below should be merged. // https://github.com/CycloneDX/cyclonedx-go/pull/90 if version == sbom.AnyVersion && strings.Contains(string(n), "cyclonedx") { if f.Version() == "1.5" { From 0f80accf06773dc4ac8deb4c6306981e06a55ea1 Mon Sep 17 00:00:00 2001 From: Christopher Phillips Date: Wed, 13 Sep 2023 12:56:45 -0400 Subject: [PATCH 9/9] fix: more generic match for other alias Signed-off-by: Christopher Phillips --- syft/formats/formats.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/syft/formats/formats.go b/syft/formats/formats.go index 1acaf3acf1e..b61027ed4d4 100644 --- a/syft/formats/formats.go +++ b/syft/formats/formats.go @@ -86,7 +86,7 @@ func ByNameAndVersion(name string, version string) sbom.Format { // formats to inform this function what their default version is // TODO: remove this check when 1.5 is stable or default formats are designed. PR below should be merged. // https://github.com/CycloneDX/cyclonedx-go/pull/90 - if version == sbom.AnyVersion && strings.Contains(string(n), "cyclonedx") { + if version == sbom.AnyVersion && strings.Contains(string(n), "cyclone") { if f.Version() == "1.5" { continue }