up
Some checks failed
Build Test Deploy / authority-container (push) Has been cancelled
Build Test Deploy / docs (push) Has been cancelled
Build Test Deploy / deploy (push) Has been cancelled
Build Test Deploy / build-test (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled

This commit is contained in:
root
2025-10-15 19:20:13 +03:00
parent 8d153522b0
commit 0d8233dfb4
125 changed files with 9383 additions and 3306 deletions

View File

@@ -144,9 +144,9 @@ public sealed class CanonicalMergerTests
provenance: new[] { CreateProvenance("osv", ProvenanceFieldMasks.AffectedPackages) },
normalizedVersions: Array.Empty<NormalizedVersionRule>());
var ghsa = CreateAdvisory("ghsa", "GHSA-1234", "GHSA Title", null, BaseTimestamp.AddHours(1), packages: new[] { ghsaPackage });
var nvd = CreateAdvisory("nvd", "CVE-2025-1111", "NVD Title", null, BaseTimestamp.AddHours(2), packages: new[] { nvdPackage });
var osv = CreateAdvisory("osv", "OSV-2025-xyz", "OSV Title", null, BaseTimestamp.AddHours(3), packages: new[] { osvPackage });
var ghsa = CreateAdvisory("ghsa", "GHSA-1234", "GHSA Title", modified: BaseTimestamp.AddHours(1), packages: new[] { ghsaPackage });
var nvd = CreateAdvisory("nvd", "CVE-2025-1111", "NVD Title", modified: BaseTimestamp.AddHours(2), packages: new[] { nvdPackage });
var osv = CreateAdvisory("osv", "OSV-2025-xyz", "OSV Title", modified: BaseTimestamp.AddHours(3), packages: new[] { osvPackage });
var result = merger.Merge("CVE-2025-1111", ghsa, nvd, osv);
@@ -181,6 +181,119 @@ public sealed class CanonicalMergerTests
Assert.Equal("critical", result.Advisory.Severity);
Assert.Contains(result.Advisory.CvssMetrics, metric => metric.Vector == "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H");
Assert.Contains(result.Advisory.CvssMetrics, metric => metric.Vector == "CVSS:3.0/AV:L/AC:L/PR:L/UI:R/S:U/C:H/I:H/A:H");
Assert.Equal("3.1|CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H", result.Advisory.CanonicalMetricId);
}
[Fact]
public void Merge_ReferencesNormalizedAndFreshnessOverrides()
{
var merger = new CanonicalMerger(new FixedTimeProvider(BaseTimestamp.AddHours(80)));
var ghsa = CreateAdvisory(
source: "ghsa",
advisoryKey: "GHSA-ref",
title: "GHSA Title",
references: new[]
{
new AdvisoryReference(
"http://Example.COM/path/resource?b=2&a=1#section",
kind: "advisory",
sourceTag: null,
summary: null,
CreateProvenance("ghsa", ProvenanceFieldMasks.References))
},
modified: BaseTimestamp);
var osv = CreateAdvisory(
source: "osv",
advisoryKey: "OSV-ref",
title: "OSV Title",
references: new[]
{
new AdvisoryReference(
"https://example.com/path/resource?a=1&b=2",
kind: "advisory",
sourceTag: null,
summary: null,
CreateProvenance("osv", ProvenanceFieldMasks.References))
},
modified: BaseTimestamp.AddHours(80));
var result = merger.Merge("CVE-REF-2025-01", ghsa, null, osv);
var reference = Assert.Single(result.Advisory.References);
Assert.Equal("https://example.com/path/resource?a=1&b=2", reference.Url);
var unionDecision = Assert.Single(result.Decisions.Where(decision => decision.Field == "references"));
Assert.Null(unionDecision.SelectedSource);
Assert.Equal("union", unionDecision.DecisionReason);
var itemDecision = Assert.Single(result.Decisions.Where(decision => decision.Field.StartsWith("references[", StringComparison.OrdinalIgnoreCase)));
Assert.Equal("osv", itemDecision.SelectedSource);
Assert.Equal("freshness_override", itemDecision.DecisionReason);
Assert.Contains("https://example.com/path/resource?a=1&b=2", itemDecision.Field, StringComparison.OrdinalIgnoreCase);
}
[Fact]
public void Merge_DescriptionFreshnessOverride()
{
var merger = new CanonicalMerger(new FixedTimeProvider(BaseTimestamp.AddHours(12)));
var ghsa = CreateAdvisory(
source: "ghsa",
advisoryKey: "GHSA-desc",
title: "GHSA Title",
summary: "Summary",
description: "Initial GHSA description",
modified: BaseTimestamp.AddHours(1));
var nvd = CreateAdvisory(
source: "nvd",
advisoryKey: "CVE-2025-5555",
title: "NVD Title",
summary: "Summary",
description: "NVD baseline description",
modified: BaseTimestamp.AddHours(2));
var osv = CreateAdvisory(
source: "osv",
advisoryKey: "OSV-2025-desc",
title: "OSV Title",
summary: "Summary",
description: "OSV fresher description",
modified: BaseTimestamp.AddHours(72));
var result = merger.Merge("CVE-2025-5555", ghsa, nvd, osv);
Assert.Equal("OSV fresher description", result.Advisory.Description);
Assert.Contains(result.Decisions, decision =>
decision.Field == "description" &&
string.Equals(decision.SelectedSource, "osv", StringComparison.OrdinalIgnoreCase) &&
string.Equals(decision.DecisionReason, "freshness_override", StringComparison.OrdinalIgnoreCase));
}
[Fact]
public void Merge_CwesPreferNvdPrecedence()
{
var merger = new CanonicalMerger(new FixedTimeProvider(BaseTimestamp.AddHours(6)));
var ghsaWeakness = CreateWeakness("ghsa", "CWE-79", "cross-site scripting", BaseTimestamp.AddHours(1));
var nvdWeakness = CreateWeakness("nvd", "CWE-79", "Cross-Site Scripting", BaseTimestamp.AddHours(2));
var osvWeakness = CreateWeakness("osv", "CWE-79", "XSS", BaseTimestamp.AddHours(3));
var ghsa = CreateAdvisory("ghsa", "GHSA-weakness", "GHSA Title", weaknesses: new[] { ghsaWeakness }, modified: BaseTimestamp.AddHours(1));
var nvd = CreateAdvisory("nvd", "CVE-2025-7777", "NVD Title", weaknesses: new[] { nvdWeakness }, modified: BaseTimestamp.AddHours(2));
var osv = CreateAdvisory("osv", "OSV-weakness", "OSV Title", weaknesses: new[] { osvWeakness }, modified: BaseTimestamp.AddHours(3));
var result = merger.Merge("CVE-2025-7777", ghsa, nvd, osv);
var weakness = Assert.Single(result.Advisory.Cwes);
Assert.Equal("CWE-79", weakness.Identifier);
Assert.Equal("Cross-Site Scripting", weakness.Name);
Assert.Contains(result.Decisions, decision =>
decision.Field == "cwes[cwe|CWE-79]" &&
string.Equals(decision.SelectedSource, "nvd", StringComparison.OrdinalIgnoreCase) &&
string.Equals(decision.DecisionReason, "precedence", StringComparison.OrdinalIgnoreCase));
}
private static Advisory CreateAdvisory(
@@ -188,10 +301,14 @@ public sealed class CanonicalMergerTests
string advisoryKey,
string title,
string? summary = null,
string? description = null,
DateTimeOffset? modified = null,
string? severity = null,
IEnumerable<AffectedPackage>? packages = null,
IEnumerable<CvssMetric>? metrics = null)
IEnumerable<CvssMetric>? metrics = null,
IEnumerable<AdvisoryReference>? references = null,
IEnumerable<AdvisoryWeakness>? weaknesses = null,
string? canonicalMetricId = null)
{
var provenance = new AdvisoryProvenance(
source,
@@ -211,10 +328,13 @@ public sealed class CanonicalMergerTests
exploitKnown: false,
aliases: new[] { advisoryKey },
credits: Array.Empty<AdvisoryCredit>(),
references: Array.Empty<AdvisoryReference>(),
references: references ?? Array.Empty<AdvisoryReference>(),
affectedPackages: packages ?? Array.Empty<AffectedPackage>(),
cvssMetrics: metrics ?? Array.Empty<CvssMetric>(),
provenance: new[] { provenance });
provenance: new[] { provenance },
description: description,
cwes: weaknesses ?? Array.Empty<AdvisoryWeakness>(),
canonicalMetricId: canonicalMetricId);
}
private static AdvisoryProvenance CreateProvenance(string source, string fieldMask)
@@ -225,6 +345,18 @@ public sealed class CanonicalMergerTests
recordedAt: BaseTimestamp,
fieldMask: new[] { fieldMask });
private static AdvisoryWeakness CreateWeakness(string source, string identifier, string? name, DateTimeOffset recordedAt)
{
var provenance = new AdvisoryProvenance(
source,
kind: "map",
value: identifier,
recordedAt: recordedAt,
fieldMask: new[] { ProvenanceFieldMasks.Weaknesses });
return new AdvisoryWeakness("cwe", identifier, name, uri: null, provenance: new[] { provenance });
}
private sealed class FixedTimeProvider : TimeProvider
{
private readonly DateTimeOffset _utcNow;