public void MergeComponentsTest() { var sbom1 = new Bom { Components = new List <Component> { new Component { Name = "Component1", Version = "1" } } }; var sbom2 = new Bom { Components = new List <Component> { new Component { Name = "Component2", Version = "1" } } }; var result = CycloneDXUtils.Merge(sbom1, sbom2); Assert.Equal(2, result.Components.Count); }
public void MetadataPropertiesTest() { var bom = new Bom { Metadata = new Metadata { Properties = new List <Property> { new Property { Name = "cdx:test", Value = "test", }, new Property { Name = "internal:test", Value = "test", }, } } }; CycloneDXUtils.RemoveInternalProperties(bom); Assert.Collection <Property>( bom.Metadata.Properties, item => { Assert.Equal("cdx:test", item.Name); Assert.Equal("test", item.Value); } ); }
public void FlatMergeComponentsTest() { var sbom1 = new Bom { Components = new List <Component> { new Component { Name = "Component1", Version = "1" } } }; var sbom2 = new Bom { Components = new List <Component> { new Component { Name = "Component2", Version = "1" } } }; var result = CycloneDXUtils.FlatMerge(sbom1, sbom2); Snapshot.Match(result); }
public void MergeToolsTest() { var sbom1 = new Bom { Metadata = new Metadata { Tools = new List <Tool> { new Tool { Name = "Tool1", Version = "1" } } } }; var sbom2 = new Bom { Metadata = new Metadata { Tools = new List <Tool> { new Tool { Name = "Tool2", Version = "1" } } } }; var result = CycloneDXUtils.Merge(sbom1, sbom2); Assert.Equal(2, result.Metadata.Tools.Count); }
public void FlatMergeToolsTest() { var sbom1 = new Bom { Metadata = new Metadata { Tools = new List <Tool> { new Tool { Name = "Tool1", Version = "1" } } } }; var sbom2 = new Bom { Metadata = new Metadata { Tools = new List <Tool> { new Tool { Name = "Tool2", Version = "1" } } } }; var result = CycloneDXUtils.FlatMerge(sbom1, sbom2); Snapshot.Match(result); }
public void SerialNumbersAreUnique() { var serialNumber1 = CycloneDXUtils.GenerateSerialNumber(); var serialNumber2 = CycloneDXUtils.GenerateSerialNumber(); Assert.NotEqual(serialNumber1, serialNumber2); }
public void MultipleComponentVersionTest() { var bom = Helpers.ComponentBomHelper(new List <string> { "component@1", "component@2" }); var result = CycloneDXUtils.MultipleComponentVersions(bom); Assert.Equal(2, result["component"].Count); }
public void ComponentAddedTest() { var fromBom = Helpers.ComponentBomHelper(new List <string>()); var toBom = Helpers.ComponentBomHelper(new List <string> { "component@1" }); var result = CycloneDXUtils.ComponentVersionDiff(fromBom, toBom); Assert.Single(result["component"].Added); }
public void SubComponentPropertiesTest() { var bom = new Bom { Components = new List <Component> { new Component { Components = new List <Component> { new Component { Properties = new List <Property> { new Property { Name = "cdx:test", Value = "test", }, new Property { Name = "internal:test", Value = "test", }, } }, }, }, } }; CycloneDXUtils.RemoveInternalProperties(bom); Assert.Collection <Property>( bom.Components[0].Components[0].Properties, item => { Assert.Equal("cdx:test", item.Name); Assert.Equal("test", item.Value); } ); }
public void ServicePropertiesTest() { var bom = new Bom { Services = new List <Service> { new Service { Properties = new List <Property> { new Property { Name = "cdx:test", Value = "test", }, new Property { Name = "internal:test", Value = "test", }, } }, } }; CycloneDXUtils.RemoveInternalProperties(bom); Assert.Collection <Property>( bom.Services[0].Properties, item => { Assert.Equal("cdx:test", item.Name); Assert.Equal("test", item.Value); } ); }
public static async Task <int> Diff( string fromFile, string toFile, InputFormat fromFormat, InputFormat toFormat, StandardOutputFormat outputFormat, bool componentVersions) { var fromBomFormat = InputFormatHelper(fromFile, fromFormat); var toBomFormat = InputFormatHelper(toFile, toFormat); if (fromBomFormat == BomFormat.Unsupported || toBomFormat == BomFormat.Unsupported) { return((int)ExitCode.ParameterValidationError); } var fromBomString = await File.ReadAllTextAsync(fromFile); var toBomString = await File.ReadAllTextAsync(toFile); var fromBom = CLIUtils.BomDeserializer(fromBomString, fromBomFormat); var toBom = CLIUtils.BomDeserializer(toBomString, toBomFormat); var result = new DiffResult(); if (componentVersions) { result.ComponentVersions = CycloneDXUtils.ComponentVersionDiff(fromBom, toBom); } if (outputFormat == StandardOutputFormat.json) { var options = new JsonSerializerOptions { WriteIndented = true, PropertyNamingPolicy = JsonNamingPolicy.CamelCase, IgnoreNullValues = true, }; options.Converters.Add(new Json.Converters.v1_2.ComponentTypeConverter()); options.Converters.Add(new Json.Converters.v1_2.DataFlowConverter()); options.Converters.Add(new Json.Converters.v1_2.DateTimeConverter()); options.Converters.Add(new Json.Converters.v1_2.DependencyConverter()); options.Converters.Add(new Json.Converters.v1_2.ExternalReferenceTypeConverter()); options.Converters.Add(new Json.Converters.v1_2.HashAlgorithmConverter()); options.Converters.Add(new Json.Converters.v1_2.IssueClassificationConverter()); options.Converters.Add(new Json.Converters.v1_2.LicenseConverter()); options.Converters.Add(new Json.Converters.v1_2.PatchClassificationConverter()); Console.WriteLine(JsonSerializer.Serialize(result, options)); } else { if (result.ComponentVersions != null) { Console.WriteLine("Component versions that have changed:"); Console.WriteLine(); var changes = false; foreach (var entry in result.ComponentVersions) { var componentDiffItem = entry.Value; if (componentDiffItem.Added.Count > 0 || componentDiffItem.Removed.Count > 0) { changes = true; foreach (var component in componentDiffItem.Removed) { Console.WriteLine($"- {component.Group} {component.Name} @ {component.Version}"); } foreach (var component in componentDiffItem.Unchanged) { Console.WriteLine($"= {component.Group} {component.Name} @ {component.Version}"); } foreach (var component in componentDiffItem.Added) { Console.WriteLine($"+ {component.Group} {component.Name} @ {component.Version}"); } Console.WriteLine(); } } if (!changes) { Console.WriteLine("None"); } Console.WriteLine(); } } return((int)ExitCode.Ok); }
public static async Task <int> Merge(MergeCommandOptions options) { Contract.Requires(options != null); var outputToConsole = string.IsNullOrEmpty(options.OutputFile); var outputFormat = options.OutputFormat; if (outputFormat == StandardInputOutputSbomFormat.autodetect) { if (options.OutputFile != null && options.OutputFile.EndsWith(".json", StringComparison.InvariantCulture)) { outputFormat = StandardInputOutputSbomFormat.json; } else if (options.OutputFile != null && options.OutputFile.EndsWith(".xml", StringComparison.InvariantCulture)) { outputFormat = StandardInputOutputSbomFormat.xml; } else { Console.WriteLine($"Unable to auto-detect output format"); return((int)ExitCode.ParameterValidationError); } } var outputBom = new Bom(); foreach (var inputFilename in options.InputFiles) { if (!outputToConsole) { Console.WriteLine($"Processing input file {inputFilename}"); } var inputFormat = options.InputFormat; if (inputFormat == StandardInputOutputSbomFormat.autodetect) { if (inputFilename.EndsWith(".json", StringComparison.InvariantCulture)) { inputFormat = StandardInputOutputSbomFormat.json; } else if (inputFilename.EndsWith(".xml", StringComparison.InvariantCulture)) { inputFormat = StandardInputOutputSbomFormat.xml; } else { Console.WriteLine($"Unable to auto-detect format of {inputFilename}"); return((int)ExitCode.ParameterValidationError); } } var bomContents = await File.ReadAllTextAsync(inputFilename); Bom inputBom; if (inputFormat == StandardInputOutputSbomFormat.json) { inputBom = Json.Deserializer.Deserialize(bomContents); } else { inputBom = Xml.Deserializer.Deserialize(bomContents); } outputBom = CycloneDXUtils.Merge(outputBom, inputBom); if (inputBom.Components != null && !outputToConsole) { Console.WriteLine($" Contains {inputBom.Components.Count} components"); } } string outputBomString; if (outputFormat == StandardInputOutputSbomFormat.json) { outputBomString = Json.Serializer.Serialize(outputBom); } else { outputBomString = Xml.Serializer.Serialize(outputBom); } if (outputToConsole) { Console.WriteLine(outputBomString); } else { Console.WriteLine("Writing output file..."); Console.WriteLine($" Total {outputBom.Components.Count} components"); await File.WriteAllTextAsync(options.OutputFile, outputBomString); } return((int)ExitCode.Ok); }
public void HierarchicalMergeComponentsTest() { var subject = new Component { Name = "Thing", Version = "1", }; var sbom1 = new Bom { Metadata = new Metadata { Component = new Component { Name = "System1", Version = "1", BomRef = "System1@1" } }, Components = new List <Component> { new Component { Name = "Component1", Version = "1", BomRef = "Component1@1" } }, Dependencies = new List <Dependency> { new Dependency { Ref = "System1@1", Dependencies = new List <Dependency> { new Dependency { Ref = "Component1@1" } } } }, Compositions = new List <Composition> { new Composition { Aggregate = Composition.AggregateType.Complete, Assemblies = new List <string> { "System1@1" }, Dependencies = new List <string> { "System1@1" } } } }; var sbom2 = new Bom { Metadata = new Metadata { Component = new Component { Name = "System2", Version = "1", BomRef = "System2@1" } }, Components = new List <Component> { new Component { Name = "Component2", Version = "1", BomRef = "Component2@1" } }, Dependencies = new List <Dependency> { new Dependency { Ref = "System2@1", Dependencies = new List <Dependency> { new Dependency { Ref = "Component2@1" } } } }, Compositions = new List <Composition> { new Composition { Aggregate = Composition.AggregateType.Complete, Assemblies = new List <string> { "System2@1" }, Dependencies = new List <string> { "System2@1" } } } }; var result = CycloneDXUtils.HierarchicalMerge(new [] { sbom1, sbom2 }, subject); Snapshot.Match(result); }
public static async Task <int> Analyze( string inputFile, InputFormat inputFormat, StandardOutputFormat outputFormat, bool multipleComponentVersions) { var inputBomFormat = InputFormatHelper(inputFile, inputFormat); if (inputBomFormat == BomFormat.Unsupported) { return((int)ExitCode.ParameterValidationError); } var inputBomString = await InputFileHelper(inputFile); if (inputBomString == null) { return((int)ExitCode.ParameterValidationError); } var inputBom = CLIUtils.BomDeserializer(inputBomString, inputBomFormat); var result = new AnalyzeResult(); if (multipleComponentVersions) { result.MultipleComponentVersions = CycloneDXUtils.MultipleComponentVersions(inputBom); } if (outputFormat == StandardOutputFormat.json) { var options = new JsonSerializerOptions { WriteIndented = true, PropertyNamingPolicy = JsonNamingPolicy.CamelCase, IgnoreNullValues = true, }; options.Converters.Add(new Json.Converters.v1_2.ComponentTypeConverter()); options.Converters.Add(new Json.Converters.v1_2.DataFlowConverter()); options.Converters.Add(new Json.Converters.v1_2.DateTimeConverter()); options.Converters.Add(new Json.Converters.v1_2.DependencyConverter()); options.Converters.Add(new Json.Converters.v1_2.ExternalReferenceTypeConverter()); options.Converters.Add(new Json.Converters.v1_2.HashAlgorithmConverter()); options.Converters.Add(new Json.Converters.v1_2.IssueClassificationConverter()); options.Converters.Add(new Json.Converters.v1_2.LicenseConverter()); options.Converters.Add(new Json.Converters.v1_2.PatchClassificationConverter()); Console.WriteLine(JsonSerializer.Serialize(result, options)); } else { if (inputBom.Metadata?.Component != null) { var component = inputBom.Metadata.Component; Console.WriteLine($"Analysis results for {component.Name}@{component.Version}:"); } else { Console.WriteLine("Analysis results:"); } Console.WriteLine(); if (result.MultipleComponentVersions != null) { Console.WriteLine("Components with multiple versions:"); Console.WriteLine(); if (result.MultipleComponentVersions.Count == 0) { Console.WriteLine("None"); } else { foreach (var componentEntry in result.MultipleComponentVersions) { Console.Write(componentEntry.Key); Console.Write(" versions:"); foreach (var component in componentEntry.Value) { Console.Write(" "); Console.Write(component.Version); } Console.WriteLine(); } } Console.WriteLine(); } } return((int)ExitCode.Ok); }