save progress
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using StellaOps.Policy.Counterfactuals;
|
||||
using StellaOps.Scanner.WebService.Security;
|
||||
@@ -61,9 +62,8 @@ internal static class CounterfactualEndpoints
|
||||
}
|
||||
|
||||
private static async Task<IResult> HandleComputeAsync(
|
||||
CounterfactualRequestDto request,
|
||||
ICounterfactualApiService counterfactualService,
|
||||
HttpContext context,
|
||||
[FromBody] CounterfactualRequestDto request,
|
||||
[FromServices] ICounterfactualApiService counterfactualService,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(counterfactualService);
|
||||
@@ -93,9 +93,8 @@ internal static class CounterfactualEndpoints
|
||||
}
|
||||
|
||||
private static async Task<IResult> HandleGetForFindingAsync(
|
||||
string findingId,
|
||||
ICounterfactualApiService counterfactualService,
|
||||
HttpContext context,
|
||||
[FromRoute] string findingId,
|
||||
[FromServices] ICounterfactualApiService counterfactualService,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(counterfactualService);
|
||||
@@ -126,9 +125,8 @@ internal static class CounterfactualEndpoints
|
||||
}
|
||||
|
||||
private static async Task<IResult> HandleGetScanSummaryAsync(
|
||||
string scanId,
|
||||
ICounterfactualApiService counterfactualService,
|
||||
HttpContext context,
|
||||
[FromRoute] string scanId,
|
||||
[FromServices] ICounterfactualApiService counterfactualService,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(counterfactualService);
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.Options;
|
||||
using StellaOps.Scanner.WebService.Constants;
|
||||
@@ -49,9 +50,9 @@ internal static class RuntimeEndpoints
|
||||
}
|
||||
|
||||
private static async Task<IResult> HandleRuntimeEventsAsync(
|
||||
RuntimeEventsIngestRequestDto request,
|
||||
IRuntimeEventIngestionService ingestionService,
|
||||
IOptions<ScannerWebServiceOptions> options,
|
||||
[FromBody] RuntimeEventsIngestRequestDto request,
|
||||
[FromServices] IRuntimeEventIngestionService ingestionService,
|
||||
[FromServices] IOptions<ScannerWebServiceOptions> options,
|
||||
HttpContext context,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
@@ -244,8 +245,8 @@ internal static class RuntimeEndpoints
|
||||
}
|
||||
|
||||
private static async Task<IResult> HandleRuntimeReconcileAsync(
|
||||
RuntimeReconcileRequestDto request,
|
||||
IRuntimeInventoryReconciler reconciler,
|
||||
[FromBody] RuntimeReconcileRequestDto request,
|
||||
[FromServices] IRuntimeInventoryReconciler reconciler,
|
||||
HttpContext context,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using StellaOps.Scanner.Triage.Models;
|
||||
using StellaOps.Scanner.WebService.Security;
|
||||
@@ -38,9 +39,8 @@ internal static class ProofBundleEndpoints
|
||||
}
|
||||
|
||||
private static async Task<IResult> HandleGenerateProofBundleAsync(
|
||||
ProofBundleRequest request,
|
||||
IProofBundleGenerator bundleGenerator,
|
||||
HttpContext context,
|
||||
[FromBody] ProofBundleRequest request,
|
||||
[FromServices] IProofBundleGenerator bundleGenerator,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(bundleGenerator);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using StellaOps.Scanner.Triage.Models;
|
||||
using StellaOps.Scanner.Triage.Services;
|
||||
@@ -45,11 +46,10 @@ internal static class TriageInboxEndpoints
|
||||
}
|
||||
|
||||
private static async Task<IResult> HandleGetInboxAsync(
|
||||
string artifactDigest,
|
||||
string? filter,
|
||||
IExploitPathGroupingService groupingService,
|
||||
IFindingQueryService findingService,
|
||||
HttpContext context,
|
||||
[FromQuery] string artifactDigest,
|
||||
[FromQuery] string? filter,
|
||||
[FromServices] IExploitPathGroupingService groupingService,
|
||||
[FromServices] IFindingQueryService findingService,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(groupingService);
|
||||
|
||||
@@ -155,7 +155,9 @@ public class PoEOrchestrator
|
||||
metadata,
|
||||
context.GraphHash,
|
||||
context.ImageDigest,
|
||||
cancellationToken);
|
||||
evidenceRefs: null,
|
||||
options: null,
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
// Compute PoE hash
|
||||
var poeHash = _emitter.ComputePoEHash(poeBytes);
|
||||
|
||||
@@ -67,7 +67,14 @@ public class PoEPipelineTests : IDisposable
|
||||
.ReturnsAsync(new Dictionary<string, Subgraph?> { ["CVE-2021-44228"] = subgraph });
|
||||
|
||||
_emitterMock
|
||||
.Setup(x => x.EmitPoEAsync(It.IsAny<Subgraph>(), It.IsAny<ProofMetadata>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
||||
.Setup(x => x.EmitPoEAsync(
|
||||
It.IsAny<Subgraph>(),
|
||||
It.IsAny<ProofMetadata>(),
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<PoEEvidenceRefs>(),
|
||||
It.IsAny<PoEEmissionOptions>(),
|
||||
It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(poeBytes);
|
||||
|
||||
_emitterMock
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
// Description: Model S1 idempotency tests for Scanner scan results storage
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
using Dapper;
|
||||
using FluentAssertions;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
@@ -64,6 +65,8 @@ public sealed class ScanResultIdempotencyTests : IAsyncLifetime
|
||||
// Arrange
|
||||
var manifest1 = CreateManifest("sha256:manifest1");
|
||||
var manifest2 = CreateManifest("sha256:manifest1"); // Same hash
|
||||
await EnsureScanAsync(manifest1.ScanId);
|
||||
await EnsureScanAsync(manifest2.ScanId);
|
||||
|
||||
// Act
|
||||
var saved1 = await _manifestRepository.SaveAsync(manifest1);
|
||||
@@ -94,6 +97,7 @@ public sealed class ScanResultIdempotencyTests : IAsyncLifetime
|
||||
{
|
||||
// Arrange
|
||||
var manifest = CreateManifest("sha256:consistent");
|
||||
await EnsureScanAsync(manifest.ScanId);
|
||||
await _manifestRepository.SaveAsync(manifest);
|
||||
|
||||
// Act - Query same hash multiple times
|
||||
@@ -121,6 +125,7 @@ public sealed class ScanResultIdempotencyTests : IAsyncLifetime
|
||||
// Arrange
|
||||
var scanId = Guid.NewGuid();
|
||||
var manifest = CreateManifest("sha256:byscan", scanId);
|
||||
await EnsureScanAsync(scanId);
|
||||
await _manifestRepository.SaveAsync(manifest);
|
||||
|
||||
// Act - Query same scan ID multiple times
|
||||
@@ -144,6 +149,7 @@ public sealed class ScanResultIdempotencyTests : IAsyncLifetime
|
||||
{
|
||||
// Arrange
|
||||
var manifest = CreateManifest("sha256:complete");
|
||||
await EnsureScanAsync(manifest.ScanId);
|
||||
var saved = await _manifestRepository.SaveAsync(manifest);
|
||||
|
||||
var completedAt1 = DateTimeOffset.UtcNow;
|
||||
@@ -191,6 +197,7 @@ public sealed class ScanResultIdempotencyTests : IAsyncLifetime
|
||||
// Act
|
||||
foreach (var manifest in manifests)
|
||||
{
|
||||
await EnsureScanAsync(manifest.ScanId);
|
||||
await _manifestRepository.SaveAsync(manifest);
|
||||
}
|
||||
|
||||
@@ -210,6 +217,7 @@ public sealed class ScanResultIdempotencyTests : IAsyncLifetime
|
||||
var scanId = Guid.NewGuid();
|
||||
var manifest1 = CreateManifest("sha256:retry1", scanId);
|
||||
var manifest2 = CreateManifest("sha256:retry2", scanId);
|
||||
await EnsureScanAsync(scanId);
|
||||
|
||||
// Act
|
||||
await _manifestRepository.SaveAsync(manifest1);
|
||||
@@ -233,6 +241,19 @@ public sealed class ScanResultIdempotencyTests : IAsyncLifetime
|
||||
ManifestContent = """{"version": "1.0", "scanner": "stellaops"}""",
|
||||
ScannerVersion = "1.0.0"
|
||||
};
|
||||
|
||||
private async Task EnsureScanAsync(Guid scanId)
|
||||
{
|
||||
var schemaName = _dataSource.SchemaName ?? ScannerDataSource.DefaultSchema;
|
||||
var sql = $"""
|
||||
INSERT INTO {schemaName}.scans (scan_id)
|
||||
VALUES (@ScanId)
|
||||
ON CONFLICT DO NOTHING
|
||||
""";
|
||||
|
||||
await using var connection = await _dataSource.OpenSystemConnectionAsync();
|
||||
await connection.ExecuteAsync(sql, new { ScanId = scanId });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -267,23 +267,40 @@ public sealed class ScannerMigrationTests : IAsyncLifetime
|
||||
|
||||
private static IEnumerable<string> GetMigrationFiles()
|
||||
{
|
||||
var assembly = typeof(ScannerStorageOptions).Assembly;
|
||||
var resourceNames = assembly.GetManifestResourceNames()
|
||||
.Where(n => n.Contains("Migrations") && n.EndsWith(".sql"))
|
||||
.OrderBy(n => n);
|
||||
var root = ResolveRepoRoot();
|
||||
var migrationsPath = Path.Combine(
|
||||
root,
|
||||
"src",
|
||||
"Scanner",
|
||||
"__Libraries",
|
||||
"StellaOps.Scanner.Storage",
|
||||
"Postgres",
|
||||
"Migrations");
|
||||
|
||||
return resourceNames;
|
||||
return Directory.Exists(migrationsPath)
|
||||
? Directory.GetFiles(migrationsPath, "*.sql").OrderBy(f => f)
|
||||
: Enumerable.Empty<string>();
|
||||
}
|
||||
|
||||
private static string GetMigrationContent(string resourceName)
|
||||
private static string GetMigrationContent(string migrationPath)
|
||||
{
|
||||
var assembly = typeof(ScannerStorageOptions).Assembly;
|
||||
using var stream = assembly.GetManifestResourceStream(resourceName);
|
||||
if (stream == null)
|
||||
return string.Empty;
|
||||
return File.Exists(migrationPath)
|
||||
? File.ReadAllText(migrationPath)
|
||||
: string.Empty;
|
||||
}
|
||||
|
||||
using var reader = new StreamReader(stream);
|
||||
return reader.ReadToEnd();
|
||||
private static string ResolveRepoRoot()
|
||||
{
|
||||
var baseDir = AppContext.BaseDirectory;
|
||||
return Path.GetFullPath(Path.Combine(
|
||||
baseDir,
|
||||
"..",
|
||||
"..",
|
||||
"..",
|
||||
"..",
|
||||
"..",
|
||||
"..",
|
||||
".."));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -121,8 +121,9 @@ public sealed class SbomUploadEndpointsTests
|
||||
var repoRoot = Path.GetFullPath(Path.Combine(baseDirectory, "..", "..", "..", "..", ".."));
|
||||
var path = Path.Combine(
|
||||
repoRoot,
|
||||
"tests",
|
||||
"src",
|
||||
"AirGap",
|
||||
"__Tests",
|
||||
"StellaOps.AirGap.Importer.Tests",
|
||||
"Reconciliation",
|
||||
"Fixtures",
|
||||
|
||||
@@ -9,6 +9,7 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
using StellaOps.Infrastructure.Postgres.Testing;
|
||||
using StellaOps.Scanner.Storage;
|
||||
using StellaOps.Scanner.Surface.Validation;
|
||||
using StellaOps.Scanner.Triage;
|
||||
using StellaOps.Scanner.WebService.Diagnostics;
|
||||
|
||||
namespace StellaOps.Scanner.WebService.Tests;
|
||||
@@ -168,5 +169,11 @@ public sealed class ScannerApplicationFactory : WebApplicationFactory<ServiceSta
|
||||
protected override System.Reflection.Assembly? GetMigrationAssembly() => typeof(ScannerStorageOptions).Assembly;
|
||||
|
||||
protected override string GetModuleName() => "Scanner.Storage.WebService.Tests";
|
||||
|
||||
public override async ValueTask InitializeAsync()
|
||||
{
|
||||
await base.InitializeAsync();
|
||||
await Fixture.RunMigrationsFromAssemblyAsync<TriageDbContext>("Scanner.Triage.WebService.Tests");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,7 +117,14 @@ public class PoEGenerationStageExecutorTests : IDisposable
|
||||
.ReturnsAsync(new Dictionary<string, PoESubgraph?> { ["CVE-2021-44228"] = subgraph });
|
||||
|
||||
_emitterMock
|
||||
.Setup(x => x.EmitPoEAsync(It.IsAny<PoESubgraph>(), It.IsAny<ProofMetadata>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
||||
.Setup(x => x.EmitPoEAsync(
|
||||
It.IsAny<PoESubgraph>(),
|
||||
It.IsAny<ProofMetadata>(),
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<PoEEvidenceRefs>(),
|
||||
It.IsAny<PoEEmissionOptions>(),
|
||||
It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(poeBytes);
|
||||
|
||||
_emitterMock
|
||||
@@ -171,7 +178,14 @@ public class PoEGenerationStageExecutorTests : IDisposable
|
||||
.ReturnsAsync(new Dictionary<string, PoESubgraph?> { ["CVE-2021-44228"] = subgraph });
|
||||
|
||||
_emitterMock
|
||||
.Setup(x => x.EmitPoEAsync(It.IsAny<PoESubgraph>(), It.IsAny<ProofMetadata>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
||||
.Setup(x => x.EmitPoEAsync(
|
||||
It.IsAny<PoESubgraph>(),
|
||||
It.IsAny<ProofMetadata>(),
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<PoEEvidenceRefs>(),
|
||||
It.IsAny<PoEEmissionOptions>(),
|
||||
It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(poeBytes);
|
||||
|
||||
_emitterMock
|
||||
@@ -225,7 +239,14 @@ public class PoEGenerationStageExecutorTests : IDisposable
|
||||
});
|
||||
|
||||
_emitterMock
|
||||
.Setup(x => x.EmitPoEAsync(It.IsAny<PoESubgraph>(), It.IsAny<ProofMetadata>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
||||
.Setup(x => x.EmitPoEAsync(
|
||||
It.IsAny<PoESubgraph>(),
|
||||
It.IsAny<ProofMetadata>(),
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<PoEEvidenceRefs>(),
|
||||
It.IsAny<PoEEmissionOptions>(),
|
||||
It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(poeBytes);
|
||||
|
||||
_emitterMock
|
||||
@@ -272,7 +293,14 @@ public class PoEGenerationStageExecutorTests : IDisposable
|
||||
.ReturnsAsync(new Dictionary<string, PoESubgraph?> { ["CVE-2021-44228"] = subgraph });
|
||||
|
||||
_emitterMock
|
||||
.Setup(x => x.EmitPoEAsync(It.IsAny<PoESubgraph>(), It.IsAny<ProofMetadata>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
||||
.Setup(x => x.EmitPoEAsync(
|
||||
It.IsAny<PoESubgraph>(),
|
||||
It.IsAny<ProofMetadata>(),
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<PoEEvidenceRefs>(),
|
||||
It.IsAny<PoEEmissionOptions>(),
|
||||
It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(poeBytes);
|
||||
|
||||
_emitterMock
|
||||
|
||||
@@ -91,7 +91,14 @@ public class PoEOrchestratorDirectTests : IDisposable
|
||||
|
||||
_output.WriteLine("Setting up emitter mocks...");
|
||||
_emitterMock
|
||||
.Setup(x => x.EmitPoEAsync(It.IsAny<PoESubgraph>(), It.IsAny<ProofMetadata>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
||||
.Setup(x => x.EmitPoEAsync(
|
||||
It.IsAny<PoESubgraph>(),
|
||||
It.IsAny<ProofMetadata>(),
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<string>(),
|
||||
It.IsAny<PoEEvidenceRefs>(),
|
||||
It.IsAny<PoEEmissionOptions>(),
|
||||
It.IsAny<CancellationToken>()))
|
||||
.ReturnsAsync(poeBytes)
|
||||
.Verifiable();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user