feat: Add DigestUpsertRequest and LockEntity models
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
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled
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
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled
- Introduced DigestUpsertRequest for handling digest upsert requests with properties like ChannelId, Recipient, DigestKey, Events, and CollectUntil. - Created LockEntity to represent a lightweight distributed lock entry with properties such as Id, TenantId, Resource, Owner, ExpiresAt, and CreatedAt. feat: Implement ILockRepository interface and LockRepository class - Defined ILockRepository interface with methods for acquiring and releasing locks. - Implemented LockRepository class with methods to try acquiring a lock and releasing it, using SQL for upsert operations. feat: Add SurfaceManifestPointer record for manifest pointers - Introduced SurfaceManifestPointer to represent a minimal pointer to a Surface.FS manifest associated with an image digest. feat: Create PolicySimulationInputLock and related validation logic - Added PolicySimulationInputLock record to describe policy simulation inputs and expected digests. - Implemented validation logic for policy simulation inputs, including checks for digest drift and shadow mode requirements. test: Add unit tests for ReplayVerificationService and ReplayVerifier - Created ReplayVerificationServiceTests to validate the behavior of the ReplayVerificationService under various scenarios. - Developed ReplayVerifierTests to ensure the correctness of the ReplayVerifier logic. test: Implement PolicySimulationInputLockValidatorTests - Added tests for PolicySimulationInputLockValidator to verify the validation logic against expected inputs and conditions. chore: Add cosign key example and signing scripts - Included a placeholder cosign key example for development purposes. - Added a script for signing Signals artifacts using cosign with support for both v2 and v3. chore: Create script for uploading evidence to the evidence locker - Developed a script to upload evidence to the evidence locker, ensuring required environment variables are set.
This commit is contained in:
@@ -1,90 +0,0 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using StellaOps.Authority.Storage.Postgres.Backfill;
|
||||
using StellaOps.Authority.Storage.Postgres.Models;
|
||||
using StellaOps.Authority.Storage.Postgres.Repositories;
|
||||
using StellaOps.Authority.Storage.Postgres.Tests.TestDoubles;
|
||||
|
||||
namespace StellaOps.Authority.Storage.Postgres.Tests;
|
||||
|
||||
public sealed class BackfillVerificationTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task Backfill_copies_tokens_and_refresh_tokens_and_checksums_match()
|
||||
{
|
||||
var tenantId = "tenant-a";
|
||||
var primaryTokens = new InMemoryTokenRepository();
|
||||
var secondaryTokens = new InMemoryTokenRepository();
|
||||
var primaryRefresh = new InMemoryRefreshTokenRepository();
|
||||
var secondaryRefresh = new InMemoryRefreshTokenRepository();
|
||||
var primaryUsers = new InMemoryUserRepository();
|
||||
var secondaryUsers = new InMemoryUserRepository();
|
||||
var user = BuildUser(tenantId);
|
||||
await secondaryUsers.CreateAsync(user);
|
||||
|
||||
var token = BuildToken(tenantId, user.Id);
|
||||
var refresh = BuildRefreshToken(tenantId, user.Id, token.Id);
|
||||
await secondaryTokens.CreateAsync(tenantId, token);
|
||||
await secondaryRefresh.CreateAsync(tenantId, refresh);
|
||||
|
||||
var backfill = new AuthorityBackfillService(
|
||||
primaryTokens,
|
||||
secondaryTokens,
|
||||
primaryRefresh,
|
||||
secondaryRefresh,
|
||||
primaryUsers,
|
||||
secondaryUsers,
|
||||
NullLogger<AuthorityBackfillService>.Instance);
|
||||
|
||||
var result = await backfill.BackfillAsync(tenantId);
|
||||
|
||||
result.TokensCopied.Should().Be(1);
|
||||
result.RefreshTokensCopied.Should().Be(1);
|
||||
result.ChecksumsMatch.Should().BeTrue();
|
||||
primaryTokens.Snapshot().Should().ContainSingle(t => t.Id == token.Id);
|
||||
primaryRefresh.Snapshot().Should().ContainSingle(t => t.Id == refresh.Id);
|
||||
}
|
||||
|
||||
private static UserEntity BuildUser(string tenantId) => new()
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
TenantId = tenantId,
|
||||
Username = "user1",
|
||||
Email = "user1@example.com",
|
||||
Enabled = true,
|
||||
EmailVerified = true,
|
||||
MfaEnabled = false,
|
||||
FailedLoginAttempts = 0,
|
||||
Settings = "{}",
|
||||
Metadata = "{}",
|
||||
CreatedAt = DateTimeOffset.UtcNow,
|
||||
UpdatedAt = DateTimeOffset.UtcNow
|
||||
};
|
||||
|
||||
private static TokenEntity BuildToken(string tenantId, Guid userId) => new()
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
TenantId = tenantId,
|
||||
UserId = userId,
|
||||
TokenHash = "hash-primary",
|
||||
TokenType = TokenType.Access,
|
||||
Scopes = new[] { "scope-a" },
|
||||
ClientId = "client",
|
||||
IssuedAt = DateTimeOffset.UtcNow,
|
||||
ExpiresAt = DateTimeOffset.UtcNow.AddHours(1),
|
||||
Metadata = "{}"
|
||||
};
|
||||
|
||||
private static RefreshTokenEntity BuildRefreshToken(string tenantId, Guid userId, Guid accessTokenId) => new()
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
TenantId = tenantId,
|
||||
UserId = userId,
|
||||
TokenHash = "r-hash",
|
||||
AccessTokenId = accessTokenId,
|
||||
ClientId = "client",
|
||||
IssuedAt = DateTimeOffset.UtcNow,
|
||||
ExpiresAt = DateTimeOffset.UtcNow.AddDays(1),
|
||||
Metadata = "{}"
|
||||
};
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
using FluentAssertions;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using StellaOps.Authority.Storage.Postgres;
|
||||
using StellaOps.Authority.Storage.Postgres.Models;
|
||||
using StellaOps.Authority.Storage.Postgres.Repositories;
|
||||
using StellaOps.Authority.Storage.Postgres.Tests.TestDoubles;
|
||||
|
||||
namespace StellaOps.Authority.Storage.Postgres.Tests;
|
||||
|
||||
public sealed class DualWriteRepositoryTests
|
||||
{
|
||||
private static DualWriteOptions DefaultOptions() => new()
|
||||
{
|
||||
Enabled = true,
|
||||
WriteSecondary = true,
|
||||
FallbackToSecondary = true,
|
||||
LogSecondaryFailuresOnly = true
|
||||
};
|
||||
|
||||
[Fact]
|
||||
public async Task Create_writes_to_primary_and_secondary()
|
||||
{
|
||||
var primary = new InMemoryTokenRepository();
|
||||
var secondary = new InMemoryTokenRepository();
|
||||
var sut = new DualWriteTokenRepository(primary, secondary, Options.Create(DefaultOptions()), new DualWriteMetrics(), NullLogger<DualWriteTokenRepository>.Instance);
|
||||
var token = BuildToken();
|
||||
|
||||
var id = await sut.CreateAsync("tenant-a", token);
|
||||
|
||||
id.Should().NotBe(Guid.Empty);
|
||||
primary.Snapshot().Should().ContainSingle(t => t.Id == id);
|
||||
secondary.Snapshot().Should().ContainSingle(t => t.Id == id);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Read_falls_back_to_secondary_when_primary_missing()
|
||||
{
|
||||
var primary = new InMemoryTokenRepository();
|
||||
var secondary = new InMemoryTokenRepository();
|
||||
var token = BuildToken();
|
||||
await secondary.CreateAsync(token.TenantId, token);
|
||||
var sut = new DualWriteTokenRepository(primary, secondary, Options.Create(DefaultOptions()), new DualWriteMetrics(), NullLogger<DualWriteTokenRepository>.Instance);
|
||||
|
||||
var fetched = await sut.GetByIdAsync(token.TenantId, token.Id);
|
||||
|
||||
fetched.Should().NotBeNull();
|
||||
fetched!.Id.Should().Be(token.Id);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Secondary_failure_does_not_block_primary_when_failfast_disabled()
|
||||
{
|
||||
var primary = new InMemoryTokenRepository();
|
||||
var secondary = new InMemoryTokenRepository { FailWrites = true };
|
||||
var options = DefaultOptions();
|
||||
options.FailFastOnSecondary = false;
|
||||
options.LogSecondaryFailuresOnly = true;
|
||||
var sut = new DualWriteTokenRepository(primary, secondary, Options.Create(options), new DualWriteMetrics(), NullLogger<DualWriteTokenRepository>.Instance);
|
||||
var token = BuildToken();
|
||||
|
||||
await sut.Invoking(s => s.CreateAsync(token.TenantId, token)).Should().NotThrowAsync();
|
||||
primary.Snapshot().Should().ContainSingle(t => t.Id == token.Id);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Refresh_tokens_dual_write_honours_secondary()
|
||||
{
|
||||
var primary = new InMemoryRefreshTokenRepository();
|
||||
var secondary = new InMemoryRefreshTokenRepository();
|
||||
var options = DefaultOptions();
|
||||
var sut = new DualWriteRefreshTokenRepository(primary, secondary, Options.Create(options), new DualWriteMetrics(), NullLogger<DualWriteRefreshTokenRepository>.Instance);
|
||||
var token = BuildRefreshToken();
|
||||
|
||||
var id = await sut.CreateAsync(token.TenantId, token);
|
||||
|
||||
primary.Snapshot().Should().ContainSingle(t => t.Id == id);
|
||||
secondary.Snapshot().Should().ContainSingle(t => t.Id == id);
|
||||
}
|
||||
|
||||
private static TokenEntity BuildToken() => new()
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
TenantId = "tenant-a",
|
||||
UserId = Guid.NewGuid(),
|
||||
TokenHash = "hash-123",
|
||||
TokenType = TokenType.Access,
|
||||
Scopes = new[] { "scope1", "scope2" },
|
||||
ClientId = "client",
|
||||
IssuedAt = DateTimeOffset.UtcNow,
|
||||
ExpiresAt = DateTimeOffset.UtcNow.AddHours(1),
|
||||
Metadata = "{}"
|
||||
};
|
||||
|
||||
private static RefreshTokenEntity BuildRefreshToken() => new()
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
TenantId = "tenant-a",
|
||||
UserId = Guid.NewGuid(),
|
||||
TokenHash = "r-hash-1",
|
||||
AccessTokenId = Guid.NewGuid(),
|
||||
ClientId = "client",
|
||||
IssuedAt = DateTimeOffset.UtcNow,
|
||||
ExpiresAt = DateTimeOffset.UtcNow.AddDays(1),
|
||||
Metadata = "{}"
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user