up
Some checks failed
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
Build Test Deploy / authority-container (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled

This commit is contained in:
2025-10-12 20:37:18 +03:00
parent b97fc7685a
commit 607e72e2a1
306 changed files with 21409 additions and 4449 deletions

View File

@@ -35,12 +35,14 @@ public sealed class CertCcConnectorSnapshotTests : IAsyncLifetime
{
private static readonly Uri SeptemberSummaryUri = new("https://www.kb.cert.org/vuls/api/2025/09/summary/");
private static readonly Uri OctoberSummaryUri = new("https://www.kb.cert.org/vuls/api/2025/10/summary/");
private static readonly Uri YearlySummaryUri = new("https://www.kb.cert.org/vuls/api/2025/summary/");
private static readonly Uri NovemberSummaryUri = new("https://www.kb.cert.org/vuls/api/2025/11/summary/");
private static readonly Uri NoteDetailUri = new("https://www.kb.cert.org/vuls/api/294418/");
private static readonly Uri VendorsDetailUri = new("https://www.kb.cert.org/vuls/api/294418/vendors/");
private static readonly Uri VulsDetailUri = new("https://www.kb.cert.org/vuls/api/294418/vuls/");
private static readonly Uri VendorStatusesDetailUri = new("https://www.kb.cert.org/vuls/api/294418/vendors/vuls/");
private static readonly Uri YearlySummaryUri = new("https://www.kb.cert.org/vuls/api/2025/summary/");
private readonly MongoIntegrationFixture _fixture;
private ConnectorTestHarness? _harness;
@@ -75,9 +77,24 @@ public sealed class CertCcConnectorSnapshotTests : IAsyncLifetime
harness.TimeProvider.Advance(TimeSpan.FromMinutes(30));
RegisterSummaryNotModifiedResponses(harness.Handler);
RegisterDetailNotModifiedResponses(harness.Handler);
await connector.FetchAsync(harness.ServiceProvider, CancellationToken.None);
var recordedRequests = harness.Handler.Requests
.Select(request => request.Uri.ToString())
.ToArray();
recordedRequests.Should().Equal(new[]
{
SeptemberSummaryUri.ToString(),
OctoberSummaryUri.ToString(),
NoteDetailUri.ToString(),
VendorsDetailUri.ToString(),
VulsDetailUri.ToString(),
VendorStatusesDetailUri.ToString(),
YearlySummaryUri.ToString(),
OctoberSummaryUri.ToString(),
NovemberSummaryUri.ToString(),
YearlySummaryUri.ToString(),
});
harness.Handler.AssertNoPendingResponses();
var requestsSnapshot = BuildRequestsSnapshot(harness.Handler.Requests);
@@ -128,7 +145,7 @@ public sealed class CertCcConnectorSnapshotTests : IAsyncLifetime
{
SeptemberSummaryUri,
OctoberSummaryUri,
new Uri("https://www.kb.cert.org/vuls/api/2025/11/summary/"),
NovemberSummaryUri,
YearlySummaryUri,
NoteDetailUri,
VendorsDetailUri,
@@ -255,17 +272,13 @@ public sealed class CertCcConnectorSnapshotTests : IAsyncLifetime
{
AddJsonResponse(handler, SeptemberSummaryUri, "summary-2025-09.json", "\"certcc-summary-2025-09\"", new DateTimeOffset(2025, 9, 30, 12, 0, 0, TimeSpan.Zero));
AddJsonResponse(handler, OctoberSummaryUri, "summary-2025-10.json", "\"certcc-summary-2025-10\"", new DateTimeOffset(2025, 10, 31, 12, 0, 0, TimeSpan.Zero));
var novemberUri = new Uri("https://www.kb.cert.org/vuls/api/2025/11/summary/");
AddJsonResponse(handler, novemberUri, "summary-2025-11.json", "\"certcc-summary-2025-11\"", new DateTimeOffset(2025, 11, 1, 8, 0, 0, TimeSpan.Zero));
AddJsonResponse(handler, YearlySummaryUri, "summary-2025.json", "\"certcc-summary-2025\"", new DateTimeOffset(2025, 10, 31, 12, 1, 0, TimeSpan.Zero));
}
private static void RegisterSummaryNotModifiedResponses(CannedHttpMessageHandler handler)
{
AddNotModified(handler, SeptemberSummaryUri, "\"certcc-summary-2025-09\"");
AddNotModified(handler, OctoberSummaryUri, "\"certcc-summary-2025-10\"");
var novemberUri = new Uri("https://www.kb.cert.org/vuls/api/2025/11/summary/");
AddNotModified(handler, novemberUri, "\"certcc-summary-2025-11\"");
AddNotModified(handler, NovemberSummaryUri, "\"certcc-summary-2025-11\"");
AddNotModified(handler, YearlySummaryUri, "\"certcc-summary-2025\"");
}
@@ -277,14 +290,6 @@ public sealed class CertCcConnectorSnapshotTests : IAsyncLifetime
AddJsonResponse(handler, VendorStatusesDetailUri, "vendor-statuses-294418.json", "\"certcc-vendor-statuses-294418\"", new DateTimeOffset(2025, 10, 9, 17, 12, 0, TimeSpan.Zero));
}
private static void RegisterDetailNotModifiedResponses(CannedHttpMessageHandler handler)
{
AddNotModified(handler, NoteDetailUri, "\"certcc-note-294418\"");
AddNotModified(handler, VendorsDetailUri, "\"certcc-vendors-294418\"");
AddNotModified(handler, VulsDetailUri, "\"certcc-vuls-294418\"");
AddNotModified(handler, VendorStatusesDetailUri, "\"certcc-vendor-statuses-294418\"");
}
private static void AddJsonResponse(CannedHttpMessageHandler handler, Uri uri, string fixtureName, string etag, DateTimeOffset lastModified)
{
var payload = ReadFixture(fixtureName);

View File

@@ -227,6 +227,46 @@ public sealed class CertCcConnectorTests : IAsyncLifetime
pendingSummaries.Should().Be(0);
}
[Fact]
public async Task Fetch_PartialDetailEndpointsMissing_CompletesAndMaps()
{
await using var provider = await BuildServiceProviderAsync();
SeedSummaryResponses();
SeedDetailResponses(
vulsStatus: HttpStatusCode.NotFound,
vendorStatusesStatus: HttpStatusCode.NotFound);
var connector = provider.GetRequiredService<CertCcConnector>();
await connector.FetchAsync(provider, CancellationToken.None);
await connector.ParseAsync(provider, CancellationToken.None);
await connector.MapAsync(provider, CancellationToken.None);
var advisoryStore = provider.GetRequiredService<IAdvisoryStore>();
var advisories = await advisoryStore.GetRecentAsync(10, CancellationToken.None);
advisories.Should().NotBeNull();
advisories!.Should().Contain(advisory => advisory.AdvisoryKey == "certcc/vu-294418");
var documentStore = provider.GetRequiredService<IDocumentStore>();
var vendorsDocument = await documentStore.FindBySourceAndUriAsync(CertCcConnectorPlugin.SourceName, VendorsUri.ToString(), CancellationToken.None);
vendorsDocument.Should().NotBeNull();
vendorsDocument!.Status.Should().Be(DocumentStatuses.Mapped);
var vulsDocument = await documentStore.FindBySourceAndUriAsync(CertCcConnectorPlugin.SourceName, VulsUri.ToString(), CancellationToken.None);
vulsDocument.Should().BeNull();
var noteDocument = await documentStore.FindBySourceAndUriAsync(CertCcConnectorPlugin.SourceName, NoteDetailUri.ToString(), CancellationToken.None);
noteDocument.Should().NotBeNull();
noteDocument!.Status.Should().Be(DocumentStatuses.Mapped);
var stateRepository = provider.GetRequiredService<ISourceStateRepository>();
var state = await stateRepository.TryGetAsync(CertCcConnectorPlugin.SourceName, CancellationToken.None);
state.Should().NotBeNull();
state!.Cursor.TryGetValue("pendingNotes", out var pendingNotesValue).Should().BeTrue();
pendingNotesValue!.AsBsonArray.Should().BeEmpty();
state.Cursor.TryGetValue("pendingDocuments", out var pendingDocsValue).Should().BeTrue();
pendingDocsValue!.AsBsonArray.Should().BeEmpty();
state.Cursor.TryGetValue("pendingMappings", out var pendingMappingsValue).Should().BeTrue();
pendingMappingsValue!.AsBsonArray.Should().BeEmpty();
}
public Task InitializeAsync() => Task.CompletedTask;
public async Task DisposeAsync()
@@ -333,7 +373,9 @@ public sealed class CertCcConnectorTests : IAsyncLifetime
string vendorsEtag = "\"vendors-etag\"",
string vulsEtag = "\"vuls-etag\"",
string vendorStatusesEtag = "\"vendor-statuses-etag\"",
HttpStatusCode vendorsStatus = HttpStatusCode.OK)
HttpStatusCode vendorsStatus = HttpStatusCode.OK,
HttpStatusCode vulsStatus = HttpStatusCode.OK,
HttpStatusCode vendorStatusesStatus = HttpStatusCode.OK)
{
AddJsonResponse(NoteDetailUri, ReadFixture("vu-294418.json"), detailEtag);
@@ -354,8 +396,39 @@ public sealed class CertCcConnectorTests : IAsyncLifetime
});
}
AddJsonResponse(VulsUri, ReadFixture("vu-294418-vuls.json"), vulsEtag);
AddJsonResponse(VendorStatusesUri, ReadFixture("vendor-statuses-294418.json"), vendorStatusesEtag);
if (vulsStatus == HttpStatusCode.OK)
{
AddJsonResponse(VulsUri, ReadFixture("vu-294418-vuls.json"), vulsEtag);
}
else
{
_handler.AddResponse(VulsUri, () =>
{
var response = new HttpResponseMessage(vulsStatus)
{
Content = new StringContent("vuls error", Encoding.UTF8, "text/plain"),
};
response.Headers.ETag = new EntityTagHeaderValue(vulsEtag);
return response;
});
}
if (vendorStatusesStatus == HttpStatusCode.OK)
{
AddJsonResponse(VendorStatusesUri, ReadFixture("vendor-statuses-294418.json"), vendorStatusesEtag);
}
else
{
_handler.AddResponse(VendorStatusesUri, () =>
{
var response = new HttpResponseMessage(vendorStatusesStatus)
{
Content = new StringContent("vendor statuses error", Encoding.UTF8, "text/plain"),
};
response.Headers.ETag = new EntityTagHeaderValue(vendorStatusesEtag);
return response;
});
}
}
private void SeedDetailNotModifiedResponses(string detailEtag, string vendorsEtag, string vulsEtag, string vendorStatusesEtag)