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
				
			
		
		
	
	
				
					
				
			
		
			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:
		| @@ -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; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user