Files
git.stella-ops.org/src/Scanner/__Tests/StellaOps.Scanner.WebService.Tests/LinksetResolverTests.cs
StellaOps Bot 28823a8960 save progress
2025-12-18 09:10:36 +02:00

121 lines
4.8 KiB
C#

using System.Collections.Immutable;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using Microsoft.Extensions.Logging.Abstractions;
using StellaOps.Concelier.Core.Linksets;
using StellaOps.Scanner.Surface.Env;
using StellaOps.Scanner.WebService.Contracts;
using StellaOps.Scanner.WebService.Services;
namespace StellaOps.Scanner.WebService.Tests;
public sealed class LinksetResolverTests
{
[Fact]
public async Task ResolveAsync_MapsSeveritiesAndConflicts()
{
var linkset = new AdvisoryLinkset(
TenantId: "tenant-a",
Source: "osv",
AdvisoryId: "CVE-2025-0001",
ObservationIds: ImmutableArray<string>.Empty,
Normalized: new AdvisoryLinksetNormalized(
Purls: new[] { "pkg:npm/demo@1.0.0" },
Cpes: Array.Empty<string>(),
Versions: Array.Empty<string>(),
Ranges: Array.Empty<Dictionary<string, object?>>(),
Severities: new[]
{
new Dictionary<string, object?>(StringComparer.Ordinal)
{
["source"] = "nvd",
["type"] = "cvssv3",
["score"] = 9.8,
["vector"] = "AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
["labels"] = new Dictionary<string, object?> { ["preferred"] = "true" }
}
}),
Provenance: null,
Confidence: 0.91,
Conflicts: new[] { new AdvisoryLinksetConflict("severity", "disagree", new[] { "cvssv2", "cvssv3" }) },
CreatedAt: DateTimeOffset.UtcNow,
BuiltByJobId: "job-1");
var resolver = new LinksetResolver(
new FakeLinksetQueryService(linkset),
new FakeSurfaceEnvironment(),
NullLogger<LinksetResolver>.Instance);
var result = await resolver.ResolveAsync(new[]
{
new PolicyPreviewFindingDto { Id = "CVE-2025-0001" }
}, CancellationToken.None);
var summary = Assert.Single(result);
Assert.Equal("CVE-2025-0001", summary.AdvisoryId);
Assert.Equal("osv", summary.Source);
Assert.Equal(0.91, summary.Confidence);
var severity = Assert.Single(summary.Severities!);
Assert.Equal("nvd", severity.Source);
Assert.Equal("cvssv3", severity.Type);
Assert.Equal(9.8, severity.Score);
Assert.Equal("AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", severity.Vector);
Assert.NotNull(severity.Labels);
var conflict = Assert.Single(summary.Conflicts!);
Assert.Equal("severity", conflict.Field);
Assert.Equal("disagree", conflict.Reason);
}
[Fact]
public async Task ResolveAsync_ReturnsEmptyWhenNoIds()
{
var resolver = new LinksetResolver(
new FakeLinksetQueryService(),
new FakeSurfaceEnvironment(),
NullLogger<LinksetResolver>.Instance);
var result = await resolver.ResolveAsync(Array.Empty<PolicyPreviewFindingDto>(), CancellationToken.None);
Assert.Empty(result);
}
private sealed class FakeLinksetQueryService : IAdvisoryLinksetQueryService
{
private readonly AdvisoryLinkset[] _linksets;
public FakeLinksetQueryService(params AdvisoryLinkset[] linksets)
{
_linksets = linksets;
}
public Task<AdvisoryLinksetQueryResult> QueryAsync(AdvisoryLinksetQueryOptions options, CancellationToken cancellationToken)
{
var matched = _linksets
.Where(ls => options.AdvisoryIds?.Contains(ls.AdvisoryId, StringComparer.OrdinalIgnoreCase) == true)
.ToImmutableArray();
return Task.FromResult(new AdvisoryLinksetQueryResult(matched, null, false));
}
}
private sealed class FakeSurfaceEnvironment : ISurfaceEnvironment
{
public SurfaceEnvironmentSettings Settings { get; } = new SurfaceEnvironmentSettings(
SurfaceFsEndpoint: new Uri("https://surface.local"),
SurfaceFsBucket: "surface-bucket",
SurfaceFsRegion: null,
CacheRoot: new DirectoryInfo(Path.Combine(Path.GetTempPath(), $"stellaops-tests-{Guid.NewGuid():N}")),
CacheQuotaMegabytes: 16,
PrefetchEnabled: false,
FeatureFlags: Array.Empty<string>(),
Secrets: new SurfaceSecretsConfiguration("file", "tenant-a", "/etc/secrets", null, null, false),
Tenant: "tenant-a",
Tls: new SurfaceTlsConfiguration(null, null, new X509Certificate2Collection()));
public IReadOnlyDictionary<string, string> RawVariables { get; } = new Dictionary<string, string>(StringComparer.Ordinal)
{
["SCANNER__TENANT"] = "tenant-a"
};
}
}