feat: add Reachability Center and Why Drawer components with tests
- Implemented ReachabilityCenterComponent for displaying asset reachability status with summary and filtering options. - Added ReachabilityWhyDrawerComponent to show detailed reachability evidence and call paths. - Created unit tests for both components to ensure functionality and correctness. - Updated accessibility test results for the new components.
This commit is contained in:
@@ -8,9 +8,9 @@ using StellaOps.Concelier.Core;
|
||||
using StellaOps.Concelier.Core.Events;
|
||||
using StellaOps.Concelier.Merge.Services;
|
||||
using StellaOps.Concelier.Models;
|
||||
using StellaOps.Concelier.Storage.Mongo.Advisories;
|
||||
using StellaOps.Concelier.Storage.Mongo.Aliases;
|
||||
using StellaOps.Concelier.Storage.Mongo.MergeEvents;
|
||||
using StellaOps.Concelier.Storage.Advisories;
|
||||
using StellaOps.Concelier.Storage.Aliases;
|
||||
using StellaOps.Concelier.Storage.MergeEvents;
|
||||
using StellaOps.Provenance.Mongo;
|
||||
|
||||
namespace StellaOps.Concelier.Merge.Tests;
|
||||
|
||||
@@ -1,34 +1,20 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using MongoDB.Driver;
|
||||
using StellaOps.Concelier.Merge.Services;
|
||||
using StellaOps.Concelier.Storage.Mongo;
|
||||
using StellaOps.Concelier.Storage.Mongo.Aliases;
|
||||
using StellaOps.Concelier.Testing;
|
||||
|
||||
namespace StellaOps.Concelier.Merge.Tests;
|
||||
|
||||
[Collection("mongo-fixture")]
|
||||
public sealed class AliasGraphResolverTests : IClassFixture<MongoIntegrationFixture>
|
||||
{
|
||||
private readonly MongoIntegrationFixture _fixture;
|
||||
|
||||
public AliasGraphResolverTests(MongoIntegrationFixture fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ResolveAsync_ReturnsCollisions_WhenAliasesOverlap()
|
||||
{
|
||||
await DropAliasCollectionAsync();
|
||||
|
||||
var aliasStore = new AliasStore(_fixture.Database, NullLogger<AliasStore>.Instance);
|
||||
var resolver = new AliasGraphResolver(aliasStore);
|
||||
|
||||
var timestamp = DateTimeOffset.UtcNow;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using StellaOps.Concelier.Merge.Services;
|
||||
using StellaOps.Concelier.Storage.Aliases;
|
||||
|
||||
namespace StellaOps.Concelier.Merge.Tests;
|
||||
|
||||
public sealed class AliasGraphResolverTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task ResolveAsync_ReturnsCollisions_WhenAliasesOverlap()
|
||||
{
|
||||
var aliasStore = new AliasStore();
|
||||
var resolver = new AliasGraphResolver(aliasStore);
|
||||
|
||||
var timestamp = DateTimeOffset.UtcNow;
|
||||
await aliasStore.ReplaceAsync(
|
||||
"ADV-1",
|
||||
new[] { new AliasEntry("CVE", "CVE-2025-2000"), new AliasEntry(AliasStoreConstants.PrimaryScheme, "ADV-1") },
|
||||
@@ -50,13 +36,12 @@ public sealed class AliasGraphResolverTests : IClassFixture<MongoIntegrationFixt
|
||||
Assert.Contains("ADV-1", collision.AdvisoryKeys);
|
||||
Assert.Contains("ADV-2", collision.AdvisoryKeys);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BuildComponentAsync_TracesConnectedAdvisories()
|
||||
{
|
||||
await DropAliasCollectionAsync();
|
||||
var aliasStore = new AliasStore(_fixture.Database, NullLogger<AliasStore>.Instance);
|
||||
var resolver = new AliasGraphResolver(aliasStore);
|
||||
|
||||
[Fact]
|
||||
public async Task BuildComponentAsync_TracesConnectedAdvisories()
|
||||
{
|
||||
var aliasStore = new AliasStore();
|
||||
var resolver = new AliasGraphResolver(aliasStore);
|
||||
|
||||
var timestamp = DateTimeOffset.UtcNow;
|
||||
await aliasStore.ReplaceAsync(
|
||||
@@ -83,28 +68,15 @@ public sealed class AliasGraphResolverTests : IClassFixture<MongoIntegrationFixt
|
||||
Assert.Contains("ADV-C", component.AdvisoryKeys, StringComparer.OrdinalIgnoreCase);
|
||||
Assert.NotEmpty(component.Collisions);
|
||||
Assert.True(component.AliasMap.ContainsKey("ADV-A"));
|
||||
Assert.Contains(component.AliasMap["ADV-B"], record => record.Scheme == "OSV" && record.Value == "OSV-2025-1");
|
||||
}
|
||||
|
||||
private async Task DropAliasCollectionAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
await _fixture.Database.DropCollectionAsync(MongoStorageDefaults.Collections.Alias);
|
||||
}
|
||||
catch (MongoDB.Driver.MongoCommandException ex) when (ex.CodeName == "NamespaceNotFound" || ex.Message.Contains("ns not found", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BuildComponentAsync_LinksOsvAndGhsaAliases()
|
||||
{
|
||||
await DropAliasCollectionAsync();
|
||||
|
||||
var aliasStore = new AliasStore(_fixture.Database, NullLogger<AliasStore>.Instance);
|
||||
var resolver = new AliasGraphResolver(aliasStore);
|
||||
var timestamp = DateTimeOffset.UtcNow;
|
||||
Assert.Contains(component.AliasMap["ADV-B"], record => record.Scheme == "OSV" && record.Value == "OSV-2025-1");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task BuildComponentAsync_LinksOsvAndGhsaAliases()
|
||||
{
|
||||
var aliasStore = new AliasStore();
|
||||
var resolver = new AliasGraphResolver(aliasStore);
|
||||
var timestamp = DateTimeOffset.UtcNow;
|
||||
|
||||
await aliasStore.ReplaceAsync(
|
||||
"ADV-OSV",
|
||||
|
||||
@@ -2,7 +2,7 @@ using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Time.Testing;
|
||||
using StellaOps.Concelier.Merge.Services;
|
||||
using StellaOps.Concelier.Models;
|
||||
using StellaOps.Concelier.Storage.Mongo.MergeEvents;
|
||||
using StellaOps.Concelier.Storage.MergeEvents;
|
||||
|
||||
namespace StellaOps.Concelier.Merge.Tests;
|
||||
|
||||
|
||||
@@ -1,30 +1,20 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Time.Testing;
|
||||
using MongoDB.Driver;
|
||||
using StellaOps.Concelier.Merge.Services;
|
||||
using StellaOps.Concelier.Models;
|
||||
using StellaOps.Concelier.Storage.Mongo;
|
||||
using StellaOps.Concelier.Storage.Mongo.MergeEvents;
|
||||
using StellaOps.Concelier.Testing;
|
||||
|
||||
namespace StellaOps.Concelier.Merge.Tests;
|
||||
|
||||
[Collection("mongo-fixture")]
|
||||
public sealed class MergePrecedenceIntegrationTests : IAsyncLifetime
|
||||
{
|
||||
private readonly MongoIntegrationFixture _fixture;
|
||||
private MergeEventStore? _mergeEventStore;
|
||||
private MergeEventWriter? _mergeEventWriter;
|
||||
private AdvisoryPrecedenceMerger? _merger;
|
||||
private FakeTimeProvider? _timeProvider;
|
||||
|
||||
public MergePrecedenceIntegrationTests(MongoIntegrationFixture fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
}
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Time.Testing;
|
||||
using StellaOps.Concelier.Merge.Services;
|
||||
using StellaOps.Concelier.Models;
|
||||
using StellaOps.Concelier.Storage.MergeEvents;
|
||||
|
||||
namespace StellaOps.Concelier.Merge.Tests;
|
||||
|
||||
public sealed class MergePrecedenceIntegrationTests : IAsyncLifetime
|
||||
{
|
||||
private MergeEventStore? _mergeEventStore;
|
||||
private MergeEventWriter? _mergeEventWriter;
|
||||
private AdvisoryPrecedenceMerger? _merger;
|
||||
private FakeTimeProvider? _timeProvider;
|
||||
|
||||
[Fact]
|
||||
public async Task MergePipeline_PsirtOverridesNvd_AndKevOnlyTogglesExploitKnown()
|
||||
@@ -82,29 +72,28 @@ public sealed class MergePrecedenceIntegrationTests : IAsyncLifetime
|
||||
AutoAdvanceAmount = TimeSpan.Zero,
|
||||
};
|
||||
_merger = new AdvisoryPrecedenceMerger(new AffectedPackagePrecedenceResolver(), _timeProvider);
|
||||
_mergeEventStore = new MergeEventStore(_fixture.Database, NullLogger<MergeEventStore>.Instance);
|
||||
_mergeEventWriter = new MergeEventWriter(_mergeEventStore, new CanonicalHashCalculator(), _timeProvider, NullLogger<MergeEventWriter>.Instance);
|
||||
await DropMergeCollectionAsync();
|
||||
}
|
||||
_mergeEventStore = new MergeEventStore();
|
||||
_mergeEventWriter = new MergeEventWriter(_mergeEventStore, new CanonicalHashCalculator(), _timeProvider, NullLogger<MergeEventWriter>.Instance);
|
||||
}
|
||||
|
||||
public Task DisposeAsync() => Task.CompletedTask;
|
||||
|
||||
private async Task EnsureInitializedAsync()
|
||||
{
|
||||
if (_mergeEventWriter is null)
|
||||
{
|
||||
await InitializeAsync();
|
||||
}
|
||||
}
|
||||
private async Task EnsureInitializedAsync()
|
||||
{
|
||||
if (_mergeEventWriter is null)
|
||||
{
|
||||
await InitializeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DropMergeCollectionAsync()
|
||||
private Task DropMergeCollectionAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
await _fixture.Database.DropCollectionAsync(MongoStorageDefaults.Collections.MergeEvent);
|
||||
}
|
||||
catch (MongoCommandException ex) when (ex.CodeName == "NamespaceNotFound" || ex.Message.Contains("ns not found", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
// {
|
||||
// await _fixture.Database.DropCollectionAsync(MongoStorageDefaults.Collections.MergeEvent);
|
||||
// }
|
||||
// catch (MongoCommandException ex) when (ex.CodeName == "NamespaceNotFound" || ex.Message.Contains("ns not found", StringComparison.OrdinalIgnoreCase))
|
||||
// {
|
||||
// Collection has not been created yet – safe to ignore.
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user