Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cdx1.6 #318

Merged
merged 29 commits into from
Aug 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a27d923
activate snapshooter_strict_mode (#286)
mtsfoni May 19, 2024
3124860
fix: JSON validation fails on timestamp wither longer fractional digi…
andreas-hilti May 19, 2024
c7f1d64
fix: xml serialization order inside component was wrong (#246)
andreas-hilti May 19, 2024
1aab1d0
fix: remove redundant enum WorkflowTaskType
jimklimov May 19, 2024
805ddaf
fix: serialization of enum EvidenceFieldType resulted in values start…
andreas-hilti May 19, 2024
7a0682d
chore: update SPDX license schemas to v3.23 (#281)
nodeax May 19, 2024
93fc4a2
fix: serialization of enums VolumeMode and DataType (#290)
andreas-hilti May 19, 2024
44a5ff9
fix: tools serialization (for versions < 1.5) (#291)
andreas-hilti May 20, 2024
1d88805
fix: Add XML 1.4 valid-properties-components testcases snapshoot.
mtsfoni May 20, 2024
3c14e5b
fix: wrong XML-element order in evidence (#295)
mtsfoni May 20, 2024
fde870a
Set version to 7.0.0
mtsfoni May 20, 2024
81cfdbc
fix: ScoreMethod.CVSSV31 serialization (#261)
dzsibi May 20, 2024
a8801db
Release-Pipeline: add symlink to /_/ before tests
mtsfoni May 20, 2024
fac1caf
fix: xml (de-)serialization for multiple licenses
mtsfoni May 28, 2024
57972c2
chore: version to 7.0.1
mtsfoni May 28, 2024
08d1025
Bump System.Text.Json from 7.0.2 to 8.0.4 (#309)
dependabot[bot] Jul 12, 2024
d8057d3
chore: version to 7.0.1
mtsfoni Jul 12, 2024
ad9c7d2
Improve merge performance (#300)
andreas-hilti Aug 4, 2024
e516bdb
Fix metadata tools components (#304)
andreas-hilti Aug 4, 2024
dcd19d1
Update SPDX license schemas to v3.24.0 (#305)
nodeax Aug 4, 2024
5433727
Use invariant culture when de-/serializing DateTime (#312)
andreas-hilti Aug 4, 2024
58a9e90
Bump Microsoft.NET.Test.Sdk from 17.6.3 to 17.10.0 (#299)
dependabot[bot] Aug 4, 2024
1fa9177
Bump xunit.runner.visualstudio from 2.5.0 to 2.8.2 (#308)
dependabot[bot] Aug 4, 2024
a42f0bf
chore: set version to 7.1.0
mtsfoni Aug 4, 2024
12be76e
Merge branch 'main' into cdx1.6
andreas-hilti Aug 18, 2024
3af1a24
Adapt interop and merge tests
andreas-hilti Aug 18, 2024
b7b46c0
Adapt core tests
andreas-hilti Aug 18, 2024
4484786
Further adapt core tests
andreas-hilti Aug 18, 2024
0cb39b2
Add missing snapshots
andreas-hilti Aug 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion .github/workflows/dotnetcore.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ name: .NET Core CI

on: [pull_request, workflow_dispatch]

env:
SNAPSHOOTER_STRICT_MODE: true

jobs:
# Fail if there are build warnings
#
Expand Down Expand Up @@ -30,11 +33,21 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
# os: [ubuntu-latest, windows-latest, macos-latest]
# macos currently disabled. see issue #285 for more info.
os: [ubuntu-latest, windows-latest]
timeout-minutes: 30

steps:
- uses: actions/checkout@v3
- name: SnapshooterHotfixSymlinkLinux
if: matrix.os == 'ubuntu-latest'
run: sudo ln -s "$GITHUB_WORKSPACE" /_
shell: bash
- name: SnapshooterHotfixSymlinkWindows
if: matrix.os == 'windows-latest'
run: New-Item -ItemType SymbolicLink -Path "/_" -Target "$env:GITHUB_WORKSPACE"
shell: pwsh
- uses: actions/setup-dotnet@v3
with:
dotnet-version: '6.0.x'
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ jobs:
export PATH="$PATH:$HOME/.local/bin"

# The tests should have already been run during the PR workflow, so this is really just a sanity check
# See issue #285 for info why the symlink is necessary.
- name: SnapshooterHotfixSymlinkLinux
run: sudo ln -s "$GITHUB_WORKSPACE" /_
shell: bash

- name: Tests
run: dotnet test

Expand Down
2 changes: 1 addition & 1 deletion semver.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
6.0.0
7.1.0
4 changes: 2 additions & 2 deletions src/CycloneDX.Core/CycloneDX.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="JsonSchema.Net" Version="3.3.2" />
<PackageReference Include="JsonSchema.Net" Version="5.3.1" />
<PackageReference Include="protobuf-net" Version="3.2.26" />
<PackageReference Include="protobuf-net.BuildTools" Version="3.2.12" PrivateAssets="all" IncludeAssets="runtime;build;native;contentfiles;analyzers;buildtransitive" />
<PackageReference Include="System.Text.Json" Version="7.0.2" />
<PackageReference Include="System.Text.Json" Version="8.0.4" />
</ItemGroup>

<ItemGroup>
Expand Down
5 changes: 3 additions & 2 deletions src/CycloneDX.Core/Json/Converters/DateTimeConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

using System;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;

Expand All @@ -40,7 +41,7 @@ public class DateTimeConverter : JsonConverter<DateTime?>
}

var valueString = reader.GetString();
var value = DateTime.Parse(valueString);
var value = DateTime.Parse(valueString, CultureInfo.InvariantCulture);
return value;
}

Expand All @@ -51,7 +52,7 @@ public override void Write(
{
Contract.Requires(writer != null);

writer.WriteStringValue(value?.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"));
writer.WriteStringValue(value?.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ", CultureInfo.InvariantCulture));
}
}
}
4 changes: 0 additions & 4 deletions src/CycloneDX.Core/Json/Converters/ScoreMethodConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,6 @@ public override void Write(
{
writer.WriteStringValue("other");
}
else if (value == ScoreMethod.CVSSV31)
{
writer.WriteStringValue("CVSSv3.1");
}
else if (value.ToString().StartsWith("CVSSV"))
{
writer.WriteStringValue("CVSSv" + value.ToString().Substring(5));
Expand Down
15 changes: 7 additions & 8 deletions src/CycloneDX.Core/Json/Converters/ToolChoicesConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,19 @@ public override void Write(
Contract.Requires(writer != null);
Contract.Requires(value != null);

if (value.Tools != null)
if (value.Tools != null || value.SpecVersion < SpecificationVersion.v1_5)
{
writer.WriteStartArray();
foreach (var tool in value.Tools)
if (value.Tools != null)
{
JsonSerializer.Serialize(writer, tool, options);
foreach (var tool in value.Tools)
{
JsonSerializer.Serialize(writer, tool, options);
}
}
writer.WriteEndArray();
}
else if (value.Components != null || value.Services != null)
else
{
writer.WriteStartObject();
if (value.Components != null)
Expand All @@ -97,10 +100,6 @@ public override void Write(
}
writer.WriteEndObject();
}
else
{
writer.WriteNullValue();
}
}
}
}
13 changes: 13 additions & 0 deletions src/CycloneDX.Core/Json/Serializer.Serialization.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,5 +89,18 @@ internal static string Serialize(Models.Vulnerabilities.Vulnerability vulnerabil
Contract.Requires(vulnerability != null);
return JsonSerializer.Serialize(vulnerability, _options);
}

internal static string Serialize(Models.Composition composition)
{
Contract.Requires(composition != null);
return JsonSerializer.Serialize(composition, _options);
}

internal static string Serialize(Models.ExternalReference externalReference)
{
Contract.Requires(externalReference != null);
return JsonSerializer.Serialize(externalReference, _options);
}

}
}
6 changes: 4 additions & 2 deletions src/CycloneDX.Core/Json/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,16 +67,18 @@ public static JsonSerializerOptions GetJsonSerializerOptions()

options.Converters.Add(new EnvironmentVarChoiceConverter());
options.Converters.Add(new ToolChoicesConverter());


options.Converters.Add(new HyphenEnumConverter<EvidenceIdentity.EvidenceFieldType>());
options.Converters.Add(new HyphenEnumConverter<EvidenceMethods.EvidenceTechnique>());
options.Converters.Add(new ScoreMethodConverter());
options.Converters.Add(new HyphenEnumConverter<Severity>());
options.Converters.Add(new HyphenEnumConverter<Trigger.TriggerType>());
options.Converters.Add(new HyphenEnumConverter<WorkflowTask.TaskType>());
options.Converters.Add(new HyphenEnumConverter<WorkflowTaskType>());
options.Converters.Add(new HyphenEnumConverter<Output.OutputType>());
options.Converters.Add(new HyphenEnumConverter<ModelCard.ModelParameterApproachType>());
options.Converters.Add(new UnderscoreEnumConverter<Status>());
options.Converters.Add(new HyphenEnumConverter<Volume.VolumeMode>());
options.Converters.Add(new HyphenEnumConverter<Data.DataType>());

options.Converters.Add(new JsonStringEnumConverter());

Expand Down
40 changes: 13 additions & 27 deletions src/CycloneDX.Core/Json/Validator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -173,13 +173,13 @@ public static ValidationResult Validate(string jsonString, SpecificationVersion
private static ValidationResult Validate(JsonSchema schema, JsonDocument jsonDocument, string schemaVersionString)
{
var validationMessages = new List<string>();
var validationOptions = new ValidationOptions
var validationOptions = new EvaluationOptions
{
OutputFormat = OutputFormat.Detailed,
OutputFormat = OutputFormat.List,
RequireFormatValidation = true
};

var result = schema.Validate(jsonDocument.RootElement, validationOptions);
var result = schema.Evaluate(jsonDocument.RootElement, validationOptions);

if (result.IsValid)
{
Expand All @@ -197,34 +197,20 @@ private static ValidationResult Validate(JsonSchema schema, JsonDocument jsonDoc
}
else
{
validationMessages.Add($"Validation failed: {result.Message}");
validationMessages.Add(result.SchemaLocation.ToString());
validationMessages.Add($"On instance: {result.InstanceLocation}:");
validationMessages.Add(result.InstanceLocation.Evaluate(jsonDocument.RootElement).ToString());

if (result.NestedResults != null)
validationMessages.Add("Validation failed:");
// because we requested the results as a flat list
// there will be no nested results
foreach (var detail in result.Details)
{
var nestedResults = new Queue<ValidationResults>(result.NestedResults);

while (nestedResults.Count > 0)
if (detail.HasErrors)
{
var nestedResult = nestedResults.Dequeue();

if (
!string.IsNullOrEmpty(nestedResult.Message)
&& nestedResult.NestedResults != null
&& nestedResult.NestedResults.Count > 0)
{
validationMessages.Add($"{nestedResult.InstanceLocation}: {nestedResult.Message}");
}

if (nestedResult.NestedResults != null)
foreach (var error in detail.Errors)
{
foreach (var newNestedResult in nestedResult.NestedResults)
{
nestedResults.Enqueue(newNestedResult);
}
validationMessages.Add(error.Value);
}
validationMessages.Add(detail.SchemaLocation.ToString());
validationMessages.Add($"On instance: {detail.InstanceLocation}:");
validationMessages.Add(detail.InstanceLocation.Evaluate(jsonDocument.RootElement).ToString());
}
}
}
Expand Down
37 changes: 33 additions & 4 deletions src/CycloneDX.Core/Models/Component.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Net;
using System.Text.Json.Serialization;
using System.Xml.Serialization;
using CycloneDX.Core.Models;
Expand Down Expand Up @@ -141,10 +143,23 @@ public ComponentScope NonNullableScope
public List<Hash> Hashes { get; set; }
public bool ShouldSerializeHashes() { return Hashes?.Count > 0; }

[XmlElement("licenses")]
[XmlIgnore]
[ProtoMember(13)]
public List<LicenseChoice> Licenses { get; set; }


[XmlElement("licenses")]
[JsonIgnore, ProtoIgnore]
[EditorBrowsable(EditorBrowsableState.Never)]
// This is a serialization workaround
public LicenseChoiceList LicensesSerialized
{
get { return Licenses != null ? new LicenseChoiceList(Licenses) : null; }
set { Licenses = value.Licenses; }
}
[EditorBrowsable(EditorBrowsableState.Never)]
public bool ShouldSerializeLicensesSerialized() { return Licenses?.Count > 0; }

[XmlElement("copyright")]
[ProtoMember(14)]
public string Copyright { get; set; }
Expand Down Expand Up @@ -190,16 +205,19 @@ public bool NonNullableModified
public List<ExternalReference> ExternalReferences { get; set; }
public bool ShouldSerializeExternalReferences() { return ExternalReferences?.Count > 0; }

[XmlArray("components")]
[ProtoMember(21)]
public List<Component> Components { get; set; }
//In the xml format, Properties is in front of Components.
//XML serialization uses the member order unless explicitly specified differently.
public bool ShouldSerializeComponents() { return Components?.Count > 0; }

[XmlArray("properties")]
[XmlArrayItem("property")]
[ProtoMember(22)]
public List<Property> Properties { get; set; }
public bool ShouldSerializeProperties() { return Properties?.Count > 0; }

[XmlArray("components")]
[ProtoMember(21)]
public List<Component> Components { get; set; }

[XmlElement("evidence")]
[ProtoMember(23)]
Expand All @@ -223,6 +241,17 @@ public bool NonNullableModified
public CryptoProperties CryptoProperties { get; set; }


public override bool Equals(object obj)
{
var other = obj as Component;
if (other == null)
{
return false;
}

return Json.Serializer.Serialize(this) == Json.Serializer.Serialize(other);
}

public bool Equals(Component obj)
{
return Json.Serializer.Serialize(this) == Json.Serializer.Serialize(obj);
Expand Down
23 changes: 22 additions & 1 deletion src/CycloneDX.Core/Models/Composition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
namespace CycloneDX.Models
{
[ProtoContract]
public class Composition : IXmlSerializable
public class Composition : IXmlSerializable, IEquatable<Composition>
{
[ProtoContract]
public enum AggregateType
Expand Down Expand Up @@ -194,5 +194,26 @@ public void WriteXml(System.Xml.XmlWriter writer) {
writer.WriteEndElement();
}
}

public override bool Equals(object obj)
{
var other = obj as Composition;
if (other == null)
{
return false;
}

return Json.Serializer.Serialize(this) == Json.Serializer.Serialize(other);
}

public bool Equals(Composition obj)
{
return CycloneDX.Json.Serializer.Serialize(this) == CycloneDX.Json.Serializer.Serialize(obj);
}

public override int GetHashCode()
{
return CycloneDX.Json.Serializer.Serialize(this).GetHashCode();
}
}
}
11 changes: 11 additions & 0 deletions src/CycloneDX.Core/Models/Dependency.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,17 @@ public class Dependency: IEquatable<Dependency>
[ProtoMember(3)]
public List<Provides> Provides { get; set; }

public override bool Equals(object obj)
{
var other = obj as Dependency;
if (other == null)
{
return false;
}

return Json.Serializer.Serialize(this) == Json.Serializer.Serialize(other);
}

public bool Equals(Dependency obj)
{
return CycloneDX.Json.Serializer.Serialize(this) == CycloneDX.Json.Serializer.Serialize(obj);
Expand Down
14 changes: 13 additions & 1 deletion src/CycloneDX.Core/Models/Evidence.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq.Expressions;
using System.Text.Json.Serialization;
Expand All @@ -30,9 +31,20 @@ namespace CycloneDX.Models
[ProtoContract]
public class Evidence
{
[XmlElement("licenses", Order = 3)]
[XmlIgnore]
[ProtoMember(1)]
public List<LicenseChoice> Licenses { get; set; }

[XmlElement("licenses", Order = 3)]
[JsonIgnore, ProtoIgnore]
[EditorBrowsable(EditorBrowsableState.Never)]
public LicenseChoiceList LicensesSerialized
{
get { return Licenses != null ? new LicenseChoiceList(Licenses) : null; }
set { Licenses = value.Licenses; }
}
[EditorBrowsable(EditorBrowsableState.Never)]
public bool ShouldSerializeLicensesSerialized() { return Licenses?.Count > 0; }

[XmlArray("copyright", Order = 4)]
[XmlArrayItem("text")]
Expand Down
Loading
Loading