diff --git a/src/CycloneDX.Core/BomUtils.cs b/src/CycloneDX.Core/BomUtils.cs index d64161e4..eb18c2ed 100644 --- a/src/CycloneDX.Core/BomUtils.cs +++ b/src/CycloneDX.Core/BomUtils.cs @@ -282,6 +282,12 @@ public static Bom Copy(this Bom bom) { var protoBom = Protobuf.Serializer.SerializeForDeepCopy(bom); var bomCopy = Protobuf.Serializer.Deserialize(protoBom); + // workaround for the incorrect Protobuf serialization of Tools + if (bom?.Metadata?.Tools?.Tools?.Count > 0 || bom?.Metadata?.Tools?.Components?.Count > 0 || bom?.Metadata?.Tools?.Services?.Count > 0) + { + var serializedTools = Json.Serializer.Serialize(bom.Metadata.Tools); + bomCopy.Metadata.Tools = Json.Serializer.DeserializeToolChoices(serializedTools); + } return bomCopy; } diff --git a/src/CycloneDX.Core/Json/Serializer.Deserialization.cs b/src/CycloneDX.Core/Json/Serializer.Deserialization.cs index 5b47c948..298038a1 100644 --- a/src/CycloneDX.Core/Json/Serializer.Deserialization.cs +++ b/src/CycloneDX.Core/Json/Serializer.Deserialization.cs @@ -47,5 +47,11 @@ public static Bom Deserialize(string jsonString) Contract.Requires(!string.IsNullOrEmpty(jsonString)); return JsonSerializer.Deserialize(jsonString, _options); } + + public static ToolChoices DeserializeToolChoices(string jsonString) + { + Contract.Requires(!string.IsNullOrEmpty(jsonString)); + return JsonSerializer.Deserialize(jsonString, _options); + } } } diff --git a/src/CycloneDX.Core/Json/Serializer.Serialization.cs b/src/CycloneDX.Core/Json/Serializer.Serialization.cs index d4cd2063..d934af43 100644 --- a/src/CycloneDX.Core/Json/Serializer.Serialization.cs +++ b/src/CycloneDX.Core/Json/Serializer.Serialization.cs @@ -84,6 +84,12 @@ internal static string Serialize(Tool tool) } #pragma warning restore 618 + internal static string Serialize(ToolChoices toolChoices) + { + Contract.Requires(toolChoices != null); + return JsonSerializer.Serialize(toolChoices, _options); + } + internal static string Serialize(Models.Vulnerabilities.Vulnerability vulnerability) { Contract.Requires(vulnerability != null); diff --git a/src/CycloneDX.Core/Models/ToolChoices.cs b/src/CycloneDX.Core/Models/ToolChoices.cs index e9059e57..45fdc973 100644 --- a/src/CycloneDX.Core/Models/ToolChoices.cs +++ b/src/CycloneDX.Core/Models/ToolChoices.cs @@ -33,12 +33,12 @@ public class ToolChoices : IXmlSerializable public List Tools { get; set; } #pragma warning restore 618 - [ProtoMember(2)] + [ProtoMember(6)] public List Components { get; set; } public bool ShouldSerializeComponents() => Components?.Count > 0; - [ProtoMember(3)] + [ProtoMember(7)] public List Services { get; set; } public bool ShouldSerializeServices() => Services?.Count > 0; diff --git a/tests/CycloneDX.Core.Tests/Json/v1.5/__snapshots__/SerializationTests.JsonRoundTripAsyncTest_valid-metadata-tool-1.5.json.snap b/tests/CycloneDX.Core.Tests/Json/v1.5/__snapshots__/SerializationTests.JsonRoundTripAsyncTest_valid-metadata-tool-1.5.json.snap index 605dd7ba..12add5a9 100644 --- a/tests/CycloneDX.Core.Tests/Json/v1.5/__snapshots__/SerializationTests.JsonRoundTripAsyncTest_valid-metadata-tool-1.5.json.snap +++ b/tests/CycloneDX.Core.Tests/Json/v1.5/__snapshots__/SerializationTests.JsonRoundTripAsyncTest_valid-metadata-tool-1.5.json.snap @@ -42,6 +42,5 @@ } ] } - }, - "components": [] + } } diff --git a/tests/CycloneDX.Core.Tests/Json/v1.5/__snapshots__/SerializationTests.JsonRoundTripTest_valid-metadata-tool-1.5.json.snap b/tests/CycloneDX.Core.Tests/Json/v1.5/__snapshots__/SerializationTests.JsonRoundTripTest_valid-metadata-tool-1.5.json.snap index 605dd7ba..12add5a9 100644 --- a/tests/CycloneDX.Core.Tests/Json/v1.5/__snapshots__/SerializationTests.JsonRoundTripTest_valid-metadata-tool-1.5.json.snap +++ b/tests/CycloneDX.Core.Tests/Json/v1.5/__snapshots__/SerializationTests.JsonRoundTripTest_valid-metadata-tool-1.5.json.snap @@ -42,6 +42,5 @@ } ] } - }, - "components": [] + } } diff --git a/tests/CycloneDX.Core.Tests/Protobuf/v1.5/__snapshots__/ValidationTests.ValidProtobufTest_valid-vulnerability-1.5.json.snap b/tests/CycloneDX.Core.Tests/Protobuf/v1.5/__snapshots__/ValidationTests.ValidProtobufTest_valid-vulnerability-1.5.json.snap index ed336183..78bf5257 100644 --- a/tests/CycloneDX.Core.Tests/Protobuf/v1.5/__snapshots__/ValidationTests.ValidProtobufTest_valid-vulnerability-1.5.json.snap +++ b/tests/CycloneDX.Core.Tests/Protobuf/v1.5/__snapshots__/ValidationTests.ValidProtobufTest_valid-vulnerability-1.5.json.snap @@ -70,8 +70,23 @@ vulnerabilities { } } tools { - name: "\010\001:\004SnykB\020Snyk CLI (Linux)J\0071.729.0bD\010\003\022@2eaf8c62831a1658c95d41fdc683cd177c147733c64a93e59cb2362829e45b7d" - version: "\022\n\n\010Acme Inc\"\021Acme BOM Analyzer:\033https://example.com/analyze" + components { + type: CLASSIFICATION_APPLICATION + group: "Snyk" + name: "Snyk CLI (Linux)" + version: "1.729.0" + hashes { + alg: HASH_ALG_SHA_256 + value: "2eaf8c62831a1658c95d41fdc683cd177c147733c64a93e59cb2362829e45b7d" + } + } + services { + provider { + name: "Acme Inc" + } + name: "Acme BOM Analyzer" + endpoints: "https://example.com/analyze" + } } analysis { state: IMPACT_ANALYSIS_STATE_NOT_AFFECTED