diff --git a/internal/schemavalidators/schemavalidators.go b/internal/schemavalidators/schemavalidators.go index 3d09c9925..4f2734dcd 100644 --- a/internal/schemavalidators/schemavalidators.go +++ b/internal/schemavalidators/schemavalidators.go @@ -138,11 +138,16 @@ func ValidateCycloneDX(data interface{}, version CycloneDXVersion) error { } var validationError *jsonschema.ValidationError if errors.As(err, &validationError) { - if slices.ContainsFunc(validationError.Causes, func(v0 *jsonschema.ValidationError) bool { - return slices.ContainsFunc(v0.Causes, func(v1 *jsonschema.ValidationError) bool { - // workaround: Some scanners like Jfrog Xray might report null `cwes` element ("cwes": null) + if slices.ContainsFunc(validationError.Causes, func(cause *jsonschema.ValidationError) bool { + // Jfrog Xray: Do not fail in case of duplicated components. Policies will take care of validation and deduplication + if cause.KeywordLocation == "/properties/components/uniqueItems" { + return true + } + // Some validation errors are found deeper in the tree + return slices.ContainsFunc(cause.Causes, func(c1 *jsonschema.ValidationError) bool { + // Some scanners like Jfrog Xray might report null `cwes` element ("cwes": null) // the validator would fail with "expected array, but got null" - return v1.KeywordLocation == "/properties/vulnerabilities/items/$ref/properties/cwes/type" + return c1.KeywordLocation == "/properties/vulnerabilities/items/$ref/properties/cwes/type" }) }) { return nil diff --git a/internal/schemavalidators/schemavalidators_test.go b/internal/schemavalidators/schemavalidators_test.go index 13b2ba2d2..75402a4df 100644 --- a/internal/schemavalidators/schemavalidators_test.go +++ b/internal/schemavalidators/schemavalidators_test.go @@ -102,6 +102,10 @@ func TestValidateCycloneDX1_6(t *testing.T) { name: "1.6 version", filePath: "./testdata/sbom.cyclonedx-1.6.json", }, + { + name: "1.6 version with duplicated element", + filePath: "./testdata/sbom.cyclonedx-duplicated.json", + }, } for _, tc := range testCases { diff --git a/internal/schemavalidators/testdata/sbom.cyclonedx-duplicated.json b/internal/schemavalidators/testdata/sbom.cyclonedx-duplicated.json new file mode 100644 index 000000000..60bc30d74 --- /dev/null +++ b/internal/schemavalidators/testdata/sbom.cyclonedx-duplicated.json @@ -0,0 +1,72 @@ +{ + "bomFormat": "CycloneDX", + "specVersion": "1.6", + "serialNumber": "urn:uuid:e8c355aa-2142-4084-a8c7-6d42c8610ba2", + "version": 1, + "metadata": { + "timestamp": "2024-01-09T12:00:00Z", + "component": { + "type": "application", + "name": "my application", + "version": "1.0" + } + }, + "components": [ + { + "name": "TLSv1.2", + "type": "cryptographic-asset", + "bom-ref": "crypto/protocol/tls@1.2", + "cryptoProperties": { + "assetType": "protocol", + "protocolProperties": { + "type": "tls", + "version": "1.2", + "cipherSuites": [ + { + "name": "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "algorithms": [ + "crypto/algorithm/ecdh-curve25519@1.3.132.1.12", + "crypto/algorithm/rsa-2048@1.2.840.113549.1.1.1", + "crypto/algorithm/aes-128-gcm@2.16.840.1.101.3.4.1.6", + "crypto/algorithm/sha-384@2.16.840.1.101.3.4.2.9" + ], + "identifiers": [ "0xC0", "0x30" ] + } + ], + "cryptoRefArray": [ + "crypto/certificate/google.com@sha256:1e15e0fbd3ce95bde5945633ae96add551341b11e5bae7bba12e98ad84a5beb4" + ] + }, + "oid": "1.3.18.0.2.32.104" + } + }, + { + "name": "TLSv1.2", + "type": "cryptographic-asset", + "bom-ref": "crypto/protocol/tls@1.2", + "cryptoProperties": { + "assetType": "protocol", + "protocolProperties": { + "type": "tls", + "version": "1.2", + "cipherSuites": [ + { + "name": "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", + "algorithms": [ + "crypto/algorithm/ecdh-curve25519@1.3.132.1.12", + "crypto/algorithm/rsa-2048@1.2.840.113549.1.1.1", + "crypto/algorithm/aes-128-gcm@2.16.840.1.101.3.4.1.6", + "crypto/algorithm/sha-384@2.16.840.1.101.3.4.2.9" + ], + "identifiers": [ "0xC0", "0x30" ] + } + ], + "cryptoRefArray": [ + "crypto/certificate/google.com@sha256:1e15e0fbd3ce95bde5945633ae96add551341b11e5bae7bba12e98ad84a5beb4" + ] + }, + "oid": "1.3.18.0.2.32.104" + } + } + ] +} \ No newline at end of file