This commit is contained in:
master
2025-10-12 20:37:18 +03:00
parent 016c5a3fe7
commit d3a98326d1
306 changed files with 21409 additions and 4449 deletions

View File

@@ -0,0 +1,160 @@
{
"advisoryKey": "CVE-2025-4242",
"affectedPackages": [
{
"type": "cpe",
"identifier": "cpe:2.3:a:conflict:package:1.0:*:*:*:*:*:*:*",
"platform": null,
"versionRanges": [
{
"fixedVersion": "1.4",
"introducedVersion": "1.0",
"lastAffectedVersion": "1.0",
"primitives": {
"evr": null,
"hasVendorExtensions": true,
"nevra": null,
"semVer": {
"constraintExpression": ">=1.0 <1.4 ==1.0",
"exactValue": "1.0.0",
"fixed": "1.4.0",
"fixedInclusive": false,
"introduced": "1.0.0",
"introducedInclusive": true,
"lastAffected": "1.0.0",
"lastAffectedInclusive": true,
"style": "exact"
},
"vendorExtensions": {
"versionStartIncluding": "1.0",
"versionEndExcluding": "1.4",
"version": "1.0"
}
},
"provenance": {
"source": "nvd",
"kind": "cpe",
"value": "https://services.nvd.nist.gov/rest/json/cve/2.0?cveId=CVE-2025-4242",
"decisionReason": null,
"recordedAt": "2025-03-04T02:00:00+00:00",
"fieldMask": [
"affectedpackages[].versionranges[]"
]
},
"rangeExpression": ">=1.0 <1.4 ==1.0",
"rangeKind": "cpe"
}
],
"normalizedVersions": [
{
"scheme": "semver",
"type": "exact",
"min": null,
"minInclusive": null,
"max": null,
"maxInclusive": null,
"value": "1.0.0",
"notes": "nvd:CVE-2025-4242"
}
],
"statuses": [],
"provenance": [
{
"source": "nvd",
"kind": "cpe",
"value": "https://services.nvd.nist.gov/rest/json/cve/2.0?cveId=CVE-2025-4242",
"decisionReason": null,
"recordedAt": "2025-03-04T02:00:00+00:00",
"fieldMask": [
"affectedpackages[]"
]
}
]
}
],
"aliases": [
"CVE-2025-4242"
],
"credits": [],
"cvssMetrics": [
{
"baseScore": 9.8,
"baseSeverity": "critical",
"provenance": {
"source": "nvd",
"kind": "cvss",
"value": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"decisionReason": null,
"recordedAt": "2025-03-04T02:00:00+00:00",
"fieldMask": [
"cvssmetrics[]"
]
},
"vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"version": "3.1"
}
],
"exploitKnown": false,
"language": "en",
"modified": "2025-03-03T09:45:00+00:00",
"provenance": [
{
"source": "nvd",
"kind": "document",
"value": "https://services.nvd.nist.gov/rest/json/cve/2.0?cveId=CVE-2025-4242",
"decisionReason": null,
"recordedAt": "2025-03-03T10:00:00+00:00",
"fieldMask": [
"advisory"
]
},
{
"source": "nvd",
"kind": "mapping",
"value": "CVE-2025-4242",
"decisionReason": null,
"recordedAt": "2025-03-04T02:00:00+00:00",
"fieldMask": [
"advisory"
]
}
],
"published": "2025-03-01T10:15:00+00:00",
"references": [
{
"kind": "weakness",
"provenance": {
"source": "nvd",
"kind": "reference",
"value": "https://cwe.mitre.org/data/definitions/269.html",
"decisionReason": null,
"recordedAt": "2025-03-04T02:00:00+00:00",
"fieldMask": [
"references[]"
]
},
"sourceTag": "CWE-269",
"summary": null,
"url": "https://cwe.mitre.org/data/definitions/269.html"
},
{
"kind": "vendor advisory",
"provenance": {
"source": "nvd",
"kind": "reference",
"value": "https://nvd.nist.gov/vuln/detail/CVE-2025-4242",
"decisionReason": null,
"recordedAt": "2025-03-04T02:00:00+00:00",
"fieldMask": [
"references[]"
]
},
"sourceTag": "NVD",
"summary": null,
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-4242"
}
],
"severity": "critical",
"summary": "NVD baseline summary for conflict-package allowing container escape.",
"title": "CVE-2025-4242"
}

View File

@@ -0,0 +1,108 @@
{
"advisoryKey": "GHSA-credit-parity",
"affectedPackages": [],
"aliases": [
"CVE-2025-5555",
"GHSA-credit-parity"
],
"credits": [
{
"displayName": "Bob Maintainer",
"role": "remediation_developer",
"contacts": [
"https://github.com/acme/bob-maintainer"
],
"provenance": {
"source": "ghsa",
"kind": "credit",
"value": "ghsa:bob-maintainer",
"decisionReason": null,
"recordedAt": "2025-10-10T15:00:00+00:00",
"fieldMask": [
"credits[]"
]
}
},
{
"displayName": "Alice Researcher",
"role": "reporter",
"contacts": [
"mailto:alice.researcher@example.com"
],
"provenance": {
"source": "ghsa",
"kind": "credit",
"value": "ghsa:alice-researcher",
"decisionReason": null,
"recordedAt": "2025-10-10T15:00:00+00:00",
"fieldMask": [
"credits[]"
]
}
}
],
"cvssMetrics": [],
"exploitKnown": false,
"language": "en",
"modified": "2025-10-10T12:00:00+00:00",
"provenance": [
{
"source": "ghsa",
"kind": "document",
"value": "security/advisories/GHSA-credit-parity",
"decisionReason": null,
"recordedAt": "2025-10-10T15:00:00+00:00",
"fieldMask": [
"advisory"
]
},
{
"source": "ghsa",
"kind": "mapping",
"value": "GHSA-credit-parity",
"decisionReason": null,
"recordedAt": "2025-10-10T15:00:00+00:00",
"fieldMask": [
"advisory"
]
}
],
"published": "2025-10-09T18:30:00+00:00",
"references": [
{
"kind": "patch",
"provenance": {
"source": "ghsa",
"kind": "reference",
"value": "https://example.com/ghsa/patch",
"decisionReason": null,
"recordedAt": "2025-10-10T15:00:00+00:00",
"fieldMask": [
"references[]"
]
},
"sourceTag": null,
"summary": null,
"url": "https://example.com/ghsa/patch"
},
{
"kind": "advisory",
"provenance": {
"source": "ghsa",
"kind": "reference",
"value": "https://github.com/advisories/GHSA-credit-parity",
"decisionReason": null,
"recordedAt": "2025-10-10T15:00:00+00:00",
"fieldMask": [
"references[]"
]
},
"sourceTag": null,
"summary": null,
"url": "https://github.com/advisories/GHSA-credit-parity"
}
],
"severity": "medium",
"summary": "Credit parity regression fixture",
"title": "Credit parity regression fixture"
}

View File

@@ -0,0 +1,108 @@
{
"advisoryKey": "CVE-2025-5555",
"affectedPackages": [],
"aliases": [
"CVE-2025-5555",
"GHSA-credit-parity"
],
"credits": [
{
"displayName": "Bob Maintainer",
"role": "remediation_developer",
"contacts": [
"https://github.com/acme/bob-maintainer"
],
"provenance": {
"source": "nvd",
"kind": "credit",
"value": "nvd:bob-maintainer",
"decisionReason": null,
"recordedAt": "2025-10-10T15:00:00+00:00",
"fieldMask": [
"credits[]"
]
}
},
{
"displayName": "Alice Researcher",
"role": "reporter",
"contacts": [
"mailto:alice.researcher@example.com"
],
"provenance": {
"source": "nvd",
"kind": "credit",
"value": "nvd:alice-researcher",
"decisionReason": null,
"recordedAt": "2025-10-10T15:00:00+00:00",
"fieldMask": [
"credits[]"
]
}
}
],
"cvssMetrics": [],
"exploitKnown": false,
"language": "en",
"modified": "2025-10-10T12:00:00+00:00",
"provenance": [
{
"source": "nvd",
"kind": "document",
"value": "https://services.nvd.nist.gov/vuln/detail/CVE-2025-5555",
"decisionReason": null,
"recordedAt": "2025-10-10T15:00:00+00:00",
"fieldMask": [
"advisory"
]
},
{
"source": "nvd",
"kind": "mapping",
"value": "CVE-2025-5555",
"decisionReason": null,
"recordedAt": "2025-10-10T15:00:00+00:00",
"fieldMask": [
"advisory"
]
}
],
"published": "2025-10-09T18:30:00+00:00",
"references": [
{
"kind": "report",
"provenance": {
"source": "nvd",
"kind": "reference",
"value": "https://example.com/nvd/reference",
"decisionReason": null,
"recordedAt": "2025-10-10T15:00:00+00:00",
"fieldMask": [
"references[]"
]
},
"sourceTag": null,
"summary": null,
"url": "https://example.com/nvd/reference"
},
{
"kind": "advisory",
"provenance": {
"source": "nvd",
"kind": "reference",
"value": "https://services.nvd.nist.gov/vuln/detail/CVE-2025-5555",
"decisionReason": null,
"recordedAt": "2025-10-10T15:00:00+00:00",
"fieldMask": [
"references[]"
]
},
"sourceTag": null,
"summary": null,
"url": "https://services.nvd.nist.gov/vuln/detail/CVE-2025-5555"
}
],
"severity": "medium",
"summary": "Credit parity regression fixture",
"title": "Credit parity regression fixture"
}

View File

@@ -0,0 +1,108 @@
{
"advisoryKey": "GHSA-credit-parity",
"affectedPackages": [],
"aliases": [
"CVE-2025-5555",
"GHSA-credit-parity"
],
"credits": [
{
"displayName": "Bob Maintainer",
"role": "remediation_developer",
"contacts": [
"https://github.com/acme/bob-maintainer"
],
"provenance": {
"source": "osv",
"kind": "credit",
"value": "osv:bob-maintainer",
"decisionReason": null,
"recordedAt": "2025-10-10T15:00:00+00:00",
"fieldMask": [
"credits[]"
]
}
},
{
"displayName": "Alice Researcher",
"role": "reporter",
"contacts": [
"mailto:alice.researcher@example.com"
],
"provenance": {
"source": "osv",
"kind": "credit",
"value": "osv:alice-researcher",
"decisionReason": null,
"recordedAt": "2025-10-10T15:00:00+00:00",
"fieldMask": [
"credits[]"
]
}
}
],
"cvssMetrics": [],
"exploitKnown": false,
"language": "en",
"modified": "2025-10-10T12:00:00+00:00",
"provenance": [
{
"source": "osv",
"kind": "document",
"value": "https://osv.dev/vulnerability/GHSA-credit-parity",
"decisionReason": null,
"recordedAt": "2025-10-10T15:00:00+00:00",
"fieldMask": [
"advisory"
]
},
{
"source": "osv",
"kind": "mapping",
"value": "GHSA-credit-parity",
"decisionReason": null,
"recordedAt": "2025-10-10T15:00:00+00:00",
"fieldMask": [
"advisory"
]
}
],
"published": "2025-10-09T18:30:00+00:00",
"references": [
{
"kind": "advisory",
"provenance": {
"source": "osv",
"kind": "reference",
"value": "https://github.com/advisories/GHSA-credit-parity",
"decisionReason": null,
"recordedAt": "2025-10-10T15:00:00+00:00",
"fieldMask": [
"references[]"
]
},
"sourceTag": null,
"summary": null,
"url": "https://github.com/advisories/GHSA-credit-parity"
},
{
"kind": "advisory",
"provenance": {
"source": "osv",
"kind": "reference",
"value": "https://osv.dev/vulnerability/GHSA-credit-parity",
"decisionReason": null,
"recordedAt": "2025-10-10T15:00:00+00:00",
"fieldMask": [
"references[]"
]
},
"sourceTag": null,
"summary": null,
"url": "https://osv.dev/vulnerability/GHSA-credit-parity"
}
],
"severity": "medium",
"summary": "Credit parity regression fixture",
"title": "Credit parity regression fixture"
}

View File

@@ -0,0 +1,103 @@
using System.Text.Json;
using StellaOps.Feedser.Models;
using StellaOps.Feedser.Source.Nvd.Internal;
using StellaOps.Feedser.Storage.Mongo.Documents;
namespace StellaOps.Feedser.Source.Nvd.Tests;
public sealed class NvdConflictFixtureTests
{
[Fact]
public void ConflictFixture_MatchesSnapshot()
{
const string payload = """
{
"vulnerabilities": [
{
"cve": {
"id": "CVE-2025-4242",
"published": "2025-03-01T10:15:00Z",
"lastModified": "2025-03-03T09:45:00Z",
"descriptions": [
{ "lang": "en", "value": "NVD baseline summary for conflict-package allowing container escape." }
],
"references": [
{
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-4242",
"source": "NVD",
"tags": ["Vendor Advisory"]
}
],
"weaknesses": [
{
"description": [
{ "lang": "en", "value": "CWE-269" }
]
}
],
"metrics": {
"cvssMetricV31": [
{
"cvssData": {
"vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"baseScore": 9.8,
"baseSeverity": "CRITICAL"
},
"exploitabilityScore": 3.9,
"impactScore": 5.9
}
]
},
"configurations": {
"nodes": [
{
"cpeMatch": [
{
"criteria": "cpe:2.3:a:conflict:package:1.0:*:*:*:*:*:*:*",
"vulnerable": true,
"versionStartIncluding": "1.0",
"versionEndExcluding": "1.4"
}
]
}
]
}
}
}
]
}
""";
using var document = JsonDocument.Parse(payload);
var sourceDocument = new DocumentRecord(
Id: Guid.Parse("1a6a0700-2dd0-4f69-bb37-64ca77e51c91"),
SourceName: NvdConnectorPlugin.SourceName,
Uri: "https://services.nvd.nist.gov/rest/json/cve/2.0?cveId=CVE-2025-4242",
FetchedAt: new DateTimeOffset(2025, 3, 3, 10, 0, 0, TimeSpan.Zero),
Sha256: "sha256-nvd-conflict-fixture",
Status: "completed",
ContentType: "application/json",
Headers: null,
Metadata: null,
Etag: "\"etag-nvd-conflict\"",
LastModified: new DateTimeOffset(2025, 3, 3, 9, 45, 0, TimeSpan.Zero),
GridFsId: null);
var advisories = NvdMapper.Map(document, sourceDocument, new DateTimeOffset(2025, 3, 4, 2, 0, 0, TimeSpan.Zero));
var advisory = Assert.Single(advisories);
var snapshot = SnapshotSerializer.ToSnapshot(advisory).Replace("\r\n", "\n").TrimEnd();
var expectedPath = Path.Combine(AppContext.BaseDirectory, "Nvd", "Fixtures", "conflict-nvd.canonical.json");
var expected = File.ReadAllText(expectedPath).Replace("\r\n", "\n").TrimEnd();
if (!string.Equals(expected, snapshot, StringComparison.Ordinal))
{
var actualPath = Path.Combine(AppContext.BaseDirectory, "Nvd", "Fixtures", "conflict-nvd.canonical.actual.json");
Directory.CreateDirectory(Path.GetDirectoryName(actualPath)!);
File.WriteAllText(actualPath, snapshot);
}
Assert.Equal(expected, snapshot);
}
}

View File

@@ -0,0 +1,98 @@
using System;
using System.IO;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using StellaOps.Feedser.Core;
using StellaOps.Feedser.Exporter.Json;
using StellaOps.Feedser.Models;
using Xunit;
namespace StellaOps.Feedser.Source.Nvd.Tests.Nvd;
public sealed class NvdMergeExportParityTests
{
private static readonly JsonSerializerOptions SerializerOptions = new(JsonSerializerDefaults.Web);
[Fact]
public async Task CanonicalMerge_PreservesCreditsAndReferences_ExporterMaintainsParity()
{
var ghsa = LoadFixture("credit-parity.ghsa.json");
var osv = LoadFixture("credit-parity.osv.json");
var nvd = LoadFixture("credit-parity.nvd.json");
var merger = new CanonicalMerger();
var result = merger.Merge("CVE-2025-5555", ghsa, nvd, osv);
var merged = result.Advisory;
Assert.NotNull(merged);
var creditKeys = merged!.Credits
.Select(static credit => $"{credit.Role}|{credit.DisplayName}|{string.Join("|", credit.Contacts.OrderBy(static c => c, StringComparer.Ordinal))}")
.ToHashSet(StringComparer.Ordinal);
Assert.Equal(2, creditKeys.Count);
Assert.Contains("reporter|Alice Researcher|mailto:alice.researcher@example.com", creditKeys);
Assert.Contains("remediation_developer|Bob Maintainer|https://github.com/acme/bob-maintainer", creditKeys);
var referenceUrls = merged.References.Select(static reference => reference.Url).ToHashSet(StringComparer.OrdinalIgnoreCase);
Assert.Equal(5, referenceUrls.Count);
Assert.Contains($"https://github.com/advisories/GHSA-credit-parity", referenceUrls);
Assert.Contains("https://example.com/ghsa/patch", referenceUrls);
Assert.Contains($"https://osv.dev/vulnerability/GHSA-credit-parity", referenceUrls);
Assert.Contains($"https://services.nvd.nist.gov/vuln/detail/CVE-2025-5555", referenceUrls);
Assert.Contains("https://example.com/nvd/reference", referenceUrls);
using var tempDirectory = new TempDirectory();
var options = new JsonExportOptions { OutputRoot = tempDirectory.Path };
var builder = new JsonExportSnapshotBuilder(options, new VulnListJsonExportPathResolver());
var exportResult = await builder.WriteAsync(new[] { merged }, new DateTimeOffset(2025, 10, 11, 0, 0, 0, TimeSpan.Zero));
Assert.Single(exportResult.Files);
var exportFile = exportResult.Files[0];
var exportPath = Path.Combine(exportResult.ExportDirectory, exportFile.RelativePath.Replace('/', Path.DirectorySeparatorChar));
Assert.True(File.Exists(exportPath));
var exported = JsonSerializer.Deserialize<Advisory>(await File.ReadAllTextAsync(exportPath), SerializerOptions);
Assert.NotNull(exported);
var exportedCredits = exported!.Credits
.Select(static credit => $"{credit.Role}|{credit.DisplayName}|{string.Join("|", credit.Contacts.OrderBy(static c => c, StringComparer.Ordinal))}")
.ToHashSet(StringComparer.Ordinal);
Assert.Equal(creditKeys, exportedCredits);
var exportedReferences = exported.References.Select(static reference => reference.Url).ToHashSet(StringComparer.OrdinalIgnoreCase);
Assert.Equal(referenceUrls, exportedReferences);
}
private static Advisory LoadFixture(string fileName)
{
var path = Path.Combine(AppContext.BaseDirectory, "Nvd", "Fixtures", fileName);
return JsonSerializer.Deserialize<Advisory>(File.ReadAllText(path), SerializerOptions)
?? throw new InvalidOperationException($"Failed to deserialize fixture '{fileName}'.");
}
private sealed class TempDirectory : IDisposable
{
public TempDirectory()
{
Path = Directory.CreateTempSubdirectory("nvd-merge-export").FullName;
}
public string Path { get; }
public void Dispose()
{
try
{
if (Directory.Exists(Path))
{
Directory.Delete(Path, recursive: true);
}
}
catch
{
// best effort cleanup
}
}
}
}