Refactor code structure for improved readability and maintainability; optimize performance in key functions.
This commit is contained in:
@@ -50,6 +50,45 @@ public sealed class PostgresExceptionObjectRepositoryTests : IAsyncLifetime
|
||||
created.Version.Should().Be(1);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreateAsync_PersistsRecheckTrackingFields()
|
||||
{
|
||||
// Arrange
|
||||
var lastResult = new RecheckEvaluationResult
|
||||
{
|
||||
IsTriggered = true,
|
||||
TriggeredConditions = ImmutableArray.Create(
|
||||
new TriggeredCondition(
|
||||
RecheckConditionType.EPSSAbove,
|
||||
"EPSS above threshold",
|
||||
CurrentValue: 0.7m,
|
||||
ThresholdValue: 0.5m,
|
||||
Action: RecheckAction.Block)),
|
||||
RecommendedAction = RecheckAction.Block,
|
||||
EvaluatedAt = DateTimeOffset.UtcNow
|
||||
};
|
||||
|
||||
var exception = CreateVulnerabilityException("CVE-2024-12345") with
|
||||
{
|
||||
RecheckPolicyId = "policy-critical",
|
||||
LastRecheckResult = lastResult,
|
||||
LastRecheckAt = DateTimeOffset.UtcNow
|
||||
};
|
||||
|
||||
// Act
|
||||
await _repository.CreateAsync(exception, "creator@example.com");
|
||||
var fetched = await _repository.GetByIdAsync(exception.ExceptionId);
|
||||
|
||||
// Assert
|
||||
fetched.Should().NotBeNull();
|
||||
fetched!.RecheckPolicyId.Should().Be("policy-critical");
|
||||
fetched.LastRecheckResult.Should().NotBeNull();
|
||||
fetched.LastRecheckResult!.RecommendedAction.Should().Be(RecheckAction.Block);
|
||||
fetched.LastRecheckResult!.TriggeredConditions.Should().ContainSingle(
|
||||
c => c.Type == RecheckConditionType.EPSSAbove);
|
||||
fetched.LastRecheckAt.Should().BeCloseTo(exception.LastRecheckAt!.Value, TimeSpan.FromSeconds(1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CreateAsync_RecordsCreatedEvent()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Npgsql;
|
||||
using StellaOps.Policy.Storage.Postgres;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Policy.Storage.Postgres.Tests;
|
||||
|
||||
[Collection(PolicyPostgresCollection.Name)]
|
||||
public sealed class RecheckEvidenceMigrationTests : IAsyncLifetime
|
||||
{
|
||||
private readonly PolicyPostgresFixture _fixture;
|
||||
private readonly PolicyDataSource _dataSource;
|
||||
|
||||
public RecheckEvidenceMigrationTests(PolicyPostgresFixture fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
|
||||
var options = fixture.Fixture.CreateOptions();
|
||||
options.SchemaName = fixture.SchemaName;
|
||||
_dataSource = new PolicyDataSource(Options.Create(options), NullLogger<PolicyDataSource>.Instance);
|
||||
}
|
||||
|
||||
public Task InitializeAsync() => _fixture.TruncateAllTablesAsync();
|
||||
|
||||
public Task DisposeAsync() => Task.CompletedTask;
|
||||
|
||||
[Fact]
|
||||
public async Task Migration_CreatesRecheckAndEvidenceTables()
|
||||
{
|
||||
await using var connection = await _dataSource.OpenConnectionAsync("default", "reader", CancellationToken.None);
|
||||
|
||||
await AssertTableExistsAsync(connection, "policy.recheck_policies");
|
||||
await AssertTableExistsAsync(connection, "policy.evidence_hooks");
|
||||
await AssertTableExistsAsync(connection, "policy.submitted_evidence");
|
||||
}
|
||||
|
||||
private static async Task AssertTableExistsAsync(NpgsqlConnection connection, string tableName)
|
||||
{
|
||||
await using var command = new NpgsqlCommand("SELECT to_regclass(@name)", connection);
|
||||
command.Parameters.AddWithValue("name", tableName);
|
||||
var result = await command.ExecuteScalarAsync();
|
||||
result.Should().NotBeNull($"{tableName} should exist after migrations");
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\__Libraries\StellaOps.Policy.Storage.Postgres\StellaOps.Policy.Storage.Postgres.csproj" />
|
||||
<ProjectReference Include="..\..\__Libraries\StellaOps.Policy.Exceptions\StellaOps.Policy.Exceptions.csproj" />
|
||||
<ProjectReference Include="..\..\__Libraries\StellaOps.Policy.Unknowns\StellaOps.Policy.Unknowns.csproj" />
|
||||
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Infrastructure.Postgres.Testing\StellaOps.Infrastructure.Postgres.Testing.csproj" />
|
||||
<ProjectReference Include="..\..\StellaOps.Policy.Scoring\StellaOps.Policy.Scoring.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using StellaOps.Policy.Storage.Postgres;
|
||||
using StellaOps.Policy.Unknowns.Models;
|
||||
using StellaOps.Policy.Unknowns.Repositories;
|
||||
using Xunit;
|
||||
|
||||
namespace StellaOps.Policy.Storage.Postgres.Tests;
|
||||
|
||||
[Collection(PolicyPostgresCollection.Name)]
|
||||
public sealed class UnknownsRepositoryTests : IAsyncLifetime
|
||||
{
|
||||
private readonly PolicyPostgresFixture _fixture;
|
||||
private readonly PolicyDataSource _dataSource;
|
||||
private readonly Guid _tenantId = Guid.NewGuid();
|
||||
|
||||
public UnknownsRepositoryTests(PolicyPostgresFixture fixture)
|
||||
{
|
||||
_fixture = fixture;
|
||||
|
||||
var options = fixture.Fixture.CreateOptions();
|
||||
options.SchemaName = fixture.SchemaName;
|
||||
_dataSource = new PolicyDataSource(Options.Create(options), NullLogger<PolicyDataSource>.Instance);
|
||||
}
|
||||
|
||||
public Task InitializeAsync() => _fixture.TruncateAllTablesAsync();
|
||||
public async Task DisposeAsync() => await _dataSource.DisposeAsync();
|
||||
|
||||
[Fact]
|
||||
public async Task CreateAndGetById_RoundTripsReasonCodeAndEvidence()
|
||||
{
|
||||
await using var connection = await _dataSource.OpenConnectionAsync(_tenantId.ToString());
|
||||
var repository = new UnknownsRepository(connection);
|
||||
var now = new DateTimeOffset(2025, 1, 2, 3, 4, 5, TimeSpan.Zero);
|
||||
|
||||
var unknown = CreateUnknown(
|
||||
reasonCode: UnknownReasonCode.Reachability,
|
||||
remediationHint: "Run reachability analysis",
|
||||
evidenceRefs: new List<EvidenceRef>
|
||||
{
|
||||
new("reachability", "proofs/unknowns/unk-123/evidence.json", "sha256:abc123")
|
||||
},
|
||||
assumptions: new List<string> { "assume-dynamic-imports" },
|
||||
timestamp: now);
|
||||
|
||||
var created = await repository.CreateAsync(unknown);
|
||||
var fetched = await repository.GetByIdAsync(_tenantId, created.Id);
|
||||
|
||||
fetched.Should().NotBeNull();
|
||||
fetched!.ReasonCode.Should().Be(UnknownReasonCode.Reachability);
|
||||
fetched.RemediationHint.Should().Be("Run reachability analysis");
|
||||
fetched.EvidenceRefs.Should().ContainSingle();
|
||||
fetched.EvidenceRefs[0].Type.Should().Be("reachability");
|
||||
fetched.EvidenceRefs[0].Uri.Should().Contain("evidence.json");
|
||||
fetched.Assumptions.Should().ContainSingle("assume-dynamic-imports");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task UpdateAsync_PersistsReasonCodeAndAssumptions()
|
||||
{
|
||||
await using var connection = await _dataSource.OpenConnectionAsync(_tenantId.ToString());
|
||||
var repository = new UnknownsRepository(connection);
|
||||
var now = new DateTimeOffset(2025, 2, 3, 4, 5, 6, TimeSpan.Zero);
|
||||
|
||||
var unknown = CreateUnknown(
|
||||
reasonCode: UnknownReasonCode.Identity,
|
||||
remediationHint: null,
|
||||
evidenceRefs: Array.Empty<EvidenceRef>(),
|
||||
assumptions: Array.Empty<string>(),
|
||||
timestamp: now);
|
||||
|
||||
var created = await repository.CreateAsync(unknown);
|
||||
|
||||
var updated = created with
|
||||
{
|
||||
ReasonCode = UnknownReasonCode.VexConflict,
|
||||
RemediationHint = "Publish authoritative VEX",
|
||||
EvidenceRefs = new List<EvidenceRef>
|
||||
{
|
||||
new("vex", "proofs/unknowns/unk-123/vex.json", "sha256:def456")
|
||||
},
|
||||
Assumptions = new List<string> { "assume-vex-defaults" }
|
||||
};
|
||||
|
||||
var result = await repository.UpdateAsync(updated);
|
||||
var fetched = await repository.GetByIdAsync(_tenantId, created.Id);
|
||||
|
||||
result.Should().BeTrue();
|
||||
fetched.Should().NotBeNull();
|
||||
fetched!.ReasonCode.Should().Be(UnknownReasonCode.VexConflict);
|
||||
fetched.RemediationHint.Should().Be("Publish authoritative VEX");
|
||||
fetched.Assumptions.Should().ContainSingle("assume-vex-defaults");
|
||||
}
|
||||
|
||||
private Unknown CreateUnknown(
|
||||
UnknownReasonCode reasonCode,
|
||||
string? remediationHint,
|
||||
IReadOnlyList<EvidenceRef> evidenceRefs,
|
||||
IReadOnlyList<string> assumptions,
|
||||
DateTimeOffset timestamp) => new()
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
TenantId = _tenantId,
|
||||
PackageId = "pkg:npm/lodash",
|
||||
PackageVersion = "4.17.21",
|
||||
Band = UnknownBand.Hot,
|
||||
Score = 90.5m,
|
||||
UncertaintyFactor = 0.75m,
|
||||
ExploitPressure = 0.9m,
|
||||
ReasonCode = reasonCode,
|
||||
RemediationHint = remediationHint,
|
||||
EvidenceRefs = evidenceRefs,
|
||||
Assumptions = assumptions,
|
||||
FirstSeenAt = timestamp,
|
||||
LastEvaluatedAt = timestamp,
|
||||
CreatedAt = timestamp,
|
||||
UpdatedAt = timestamp
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user