diff --git a/go.mod b/go.mod index ce12af73fc6..8c988e1bc0d 100644 --- a/go.mod +++ b/go.mod @@ -50,6 +50,7 @@ require ( require ( github.com/CycloneDX/cyclonedx-go v0.7.1 + github.com/Masterminds/semver v1.5.0 github.com/Masterminds/sprig/v3 v3.2.3 github.com/anchore/go-logger v0.0.0-20220728155337-03b66a5207d8 github.com/anchore/stereoscope v0.0.0-20230412183729-8602f1afc574 diff --git a/go.sum b/go.sum index e96635aad6a..f7c61e853b5 100644 --- a/go.sum +++ b/go.sum @@ -62,6 +62,8 @@ github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g= github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= diff --git a/syft/formats/syftjson/decoder.go b/syft/formats/syftjson/decoder.go index b6286bd97c6..845c1fc0ba3 100644 --- a/syft/formats/syftjson/decoder.go +++ b/syft/formats/syftjson/decoder.go @@ -5,6 +5,10 @@ import ( "fmt" "io" + "github.com/Masterminds/semver" + + "github.com/anchore/syft/internal" + "github.com/anchore/syft/internal/log" "github.com/anchore/syft/syft/formats/syftjson/model" "github.com/anchore/syft/syft/sbom" ) @@ -18,5 +22,27 @@ func decoder(reader io.Reader) (*sbom.SBOM, error) { return nil, fmt.Errorf("unable to decode syft-json: %w", err) } + if err := checkSupportedSchema(doc.Schema.Version, internal.JSONSchemaVersion); err != nil { + log.Warn(err) + } + return toSyftModel(doc) } + +func checkSupportedSchema(documentVerion string, parserVersion string) error { + documentV, err := semver.NewVersion(documentVerion) + if err != nil { + return fmt.Errorf("error comparing document schema version with parser schema version: %w", err) + } + + parserV, err := semver.NewVersion(parserVersion) + if err != nil { + return fmt.Errorf("error comparing document schema version with parser schema version: %w", err) + } + + if documentV.GreaterThan(parserV) { + return fmt.Errorf("document has schema version %s, but parser has older schema version (%s)", documentVerion, parserVersion) + } + + return nil +} diff --git a/syft/formats/syftjson/decoder_test.go b/syft/formats/syftjson/decoder_test.go index de9ab7bcf7c..e0de5fffbc4 100644 --- a/syft/formats/syftjson/decoder_test.go +++ b/syft/formats/syftjson/decoder_test.go @@ -2,6 +2,8 @@ package syftjson import ( "bytes" + "errors" + "fmt" "strings" "testing" @@ -49,3 +51,38 @@ func TestEncodeDecodeCycle(t *testing.T) { } } } + +func TestOutOfDateParser(t *testing.T) { + tests := []struct { + name string + documentVersion string + parserVersion string + want error + }{{ + name: "no warning when doc version is older", + documentVersion: "1.0.9", + parserVersion: "3.1.0", + }, { + name: "warning when parser is older", + documentVersion: "4.3.2", + parserVersion: "3.1.0", + want: fmt.Errorf("document has schema version %s, but parser has older schema version (%s)", "4.3.2", "3.1.0"), + }, { + name: "warning when document version is unparseable", + documentVersion: "some-nonsense", + parserVersion: "3.1.0", + want: fmt.Errorf("error comparing document schema version with parser schema version: %w", errors.New("Invalid Semantic Version")), + }, { + name: "warning when parser version is unparseable", + documentVersion: "7.1.0", + parserVersion: "some-nonsense", + want: fmt.Errorf("error comparing document schema version with parser schema version: %w", errors.New("Invalid Semantic Version")), + }} + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := checkSupportedSchema(tt.documentVersion, tt.parserVersion) + assert.Equal(t, tt.want, got) + }) + } +}