up
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Export Center CI / export-ci (push) Has been cancelled
devportal-offline / build-offline (push) Has been cancelled

This commit is contained in:
StellaOps Bot
2025-12-03 00:10:19 +02:00
parent ea1d58a89b
commit 37cba83708
158 changed files with 147438 additions and 867 deletions

View File

@@ -12,6 +12,7 @@ public sealed class PackRepositoryTests : IAsyncLifetime
{
private readonly PolicyPostgresFixture _fixture;
private readonly PackRepository _repository;
private readonly PackVersionRepository _packVersionRepository;
private readonly string _tenantId = Guid.NewGuid().ToString();
public PackRepositoryTests(PolicyPostgresFixture fixture)
@@ -22,6 +23,7 @@ public sealed class PackRepositoryTests : IAsyncLifetime
options.SchemaName = fixture.SchemaName;
var dataSource = new PolicyDataSource(Options.Create(options), NullLogger<PolicyDataSource>.Instance);
_repository = new PackRepository(dataSource, NullLogger<PackRepository>.Instance);
_packVersionRepository = new PackVersionRepository(dataSource, NullLogger<PackVersionRepository>.Instance);
}
public Task InitializeAsync() => _fixture.TruncateAllTablesAsync();
@@ -161,14 +163,49 @@ public sealed class PackRepositoryTests : IAsyncLifetime
// Arrange
var pack = CreatePack("version-test");
await _repository.CreateAsync(pack);
await CreatePackVersionAsync(pack.Id, 1, publish: true);
// Act
var result = await _repository.SetActiveVersionAsync(_tenantId, pack.Id, 2);
var result = await _repository.SetActiveVersionAsync(_tenantId, pack.Id, 1);
var fetched = await _repository.GetByIdAsync(_tenantId, pack.Id);
// Assert
result.Should().BeTrue();
fetched!.ActiveVersion.Should().Be(2);
fetched!.ActiveVersion.Should().Be(1);
}
[Fact]
public async Task PublishAndActivateVersions_FollowsWorkflow()
{
// Arrange
var pack = CreatePack("workflow-pack");
await _repository.CreateAsync(pack);
// Unpublished version cannot be activated
var version1 = await CreatePackVersionAsync(pack.Id, 1);
var activationBeforePublish = await _repository.SetActiveVersionAsync(_tenantId, pack.Id, 1);
activationBeforePublish.Should().BeFalse();
// Publish v1 and activate
await _packVersionRepository.PublishAsync(version1.Id, "tester");
await _repository.SetActiveVersionAsync(_tenantId, pack.Id, 1);
var activeAfterV1 = await _repository.GetByIdAsync(_tenantId, pack.Id);
activeAfterV1!.ActiveVersion.Should().Be(1);
// Create and publish v2, then promote to active
var nextVersion = await _packVersionRepository.GetNextVersionAsync(pack.Id);
var version2 = await CreatePackVersionAsync(pack.Id, nextVersion);
await _packVersionRepository.PublishAsync(version2.Id, "tester");
await _repository.SetActiveVersionAsync(_tenantId, pack.Id, version2.Version);
// Assert ordering and active marker
var versions = await _packVersionRepository.GetByPackIdAsync(pack.Id, publishedOnly: true);
versions.Select(v => v.Version).Should().ContainInOrder(new[] { 2, 1 });
var latest = await _packVersionRepository.GetLatestAsync(pack.Id);
latest!.Version.Should().Be(2);
var finalPack = await _repository.GetByIdAsync(_tenantId, pack.Id);
finalPack!.ActiveVersion.Should().Be(2);
}
[Fact]
@@ -210,4 +247,27 @@ public sealed class PackRepositoryTests : IAsyncLifetime
Name = name,
IsBuiltin = false
};
private async Task<PackVersionEntity> CreatePackVersionAsync(Guid packId, int version, bool publish = false)
{
var packVersion = new PackVersionEntity
{
Id = Guid.NewGuid(),
PackId = packId,
Version = version,
Description = $"v{version}",
RulesHash = $"rules-hash-{version}",
IsPublished = false
};
var created = await _packVersionRepository.CreateAsync(packVersion);
if (publish)
{
await _packVersionRepository.PublishAsync(created.Id, "tester");
created = (await _packVersionRepository.GetByIdAsync(created.Id))!;
}
return created;
}
}

View File

@@ -190,7 +190,7 @@ public sealed class RiskProfileRepositoryTests : IAsyncLifetime
{
// Arrange
var original = CreateProfile("version-create");
await _repository.CreateAsync(original);
original = await _repository.CreateAsync(original);
// Act
var newVersion = new RiskProfileEntity
@@ -207,6 +207,8 @@ public sealed class RiskProfileRepositoryTests : IAsyncLifetime
// Assert
created.Should().NotBeNull();
created.Version.Should().Be(2);
var originalAfter = await _repository.GetByIdAsync(_tenantId, original.Id);
originalAfter!.IsActive.Should().BeFalse();
}
[Fact]
@@ -263,12 +265,84 @@ public sealed class RiskProfileRepositoryTests : IAsyncLifetime
fetched.Should().BeNull();
}
private RiskProfileEntity CreateProfile(string name) => new()
[Fact]
public async Task CreateVersion_HistoryRemainsQueryableAndOrdered()
{
// Arrange
var v1 = await _repository.CreateAsync(CreateProfile(
name: "history-profile",
thresholds: "{\"critical\":9.0}",
scoringWeights: "{\"vulnerability\":1.0}"));
var v2 = new RiskProfileEntity
{
Id = Guid.NewGuid(),
TenantId = _tenantId,
Name = "history-profile",
DisplayName = "History V2",
Description = "Second revision with tuned thresholds",
Thresholds = "{\"critical\":8.0,\"high\":6.5}",
ScoringWeights = "{\"vulnerability\":0.9}",
Exemptions = "[]",
Metadata = "{\"source\":\"unit-test\"}"
};
// Act
var createdV2 = await _repository.CreateVersionAsync(_tenantId, "history-profile", v2);
// Assert
createdV2.Version.Should().Be(2);
createdV2.IsActive.Should().BeTrue();
var versions = await _repository.GetVersionsByNameAsync(_tenantId, "history-profile");
versions.Select(x => x.Version).Should().ContainInOrder(new[] { 2, 1 });
versions.Single(x => x.Version == 1).IsActive.Should().BeFalse();
versions.Single(x => x.Version == 1).Thresholds.Should().Contain("9.0");
var active = await _repository.GetActiveByNameAsync(_tenantId, "history-profile");
active!.Version.Should().Be(2);
}
[Fact]
public async Task Activate_RevertsToPriorVersionAndDeactivatesCurrent()
{
// Arrange
var v1 = await _repository.CreateAsync(CreateProfile("toggle-profile"));
var v2 = await _repository.CreateVersionAsync(_tenantId, "toggle-profile", new RiskProfileEntity
{
Id = Guid.NewGuid(),
TenantId = _tenantId,
Name = "toggle-profile",
DisplayName = "Toggle V2",
Thresholds = "{\"critical\":8.5}"
});
// Act
var activated = await _repository.ActivateAsync(_tenantId, v1.Id);
// Assert
activated.Should().BeTrue();
var versions = await _repository.GetVersionsByNameAsync(_tenantId, "toggle-profile");
versions.Single(x => x.Id == v1.Id).IsActive.Should().BeTrue();
versions.Single(x => x.Id == v2.Id).IsActive.Should().BeFalse();
var active = await _repository.GetActiveByNameAsync(_tenantId, "toggle-profile");
active!.Id.Should().Be(v1.Id);
}
private RiskProfileEntity CreateProfile(
string name,
int version = 1,
bool isActive = true,
string? thresholds = null,
string? scoringWeights = null) => new()
{
Id = Guid.NewGuid(),
TenantId = _tenantId,
Name = name,
Version = 1,
IsActive = true
Version = version,
IsActive = isActive,
Thresholds = thresholds ?? "{}",
ScoringWeights = scoringWeights ?? "{}"
};
}