save audit remarks applications progress

This commit is contained in:
StellaOps Bot
2026-01-04 22:49:53 +02:00
parent 8862e112c4
commit eca4e964d3
48 changed files with 1850 additions and 112 deletions

View File

@@ -67,6 +67,7 @@ public static class VerdictEndpoints
private static async Task<IResult> StoreVerdictAsync(
[FromBody] StoreVerdictRequest request,
[FromServices] IVerdictRepository repository,
[FromServices] TimeProvider timeProvider,
[FromServices] ILogger<VerdictEndpointsLogger> logger,
CancellationToken cancellationToken)
{
@@ -105,7 +106,7 @@ public static class VerdictEndpoints
PredicateDigest = request.PredicateDigest,
DeterminismHash = request.DeterminismHash,
RekorLogIndex = request.RekorLogIndex,
CreatedAt = DateTimeOffset.UtcNow
CreatedAt = timeProvider.GetUtcNow()
};
// Store in repository
@@ -253,6 +254,7 @@ public static class VerdictEndpoints
private static async Task<IResult> VerifyVerdictAsync(
string verdictId,
[FromServices] IVerdictRepository repository,
[FromServices] TimeProvider timeProvider,
[FromServices] ILogger<VerdictEndpointsLogger> logger,
CancellationToken cancellationToken)
{
@@ -270,11 +272,12 @@ public static class VerdictEndpoints
// TODO: Implement actual signature verification
// For now, return a placeholder response
var now = timeProvider.GetUtcNow();
var response = new VerifyVerdictResponse
{
VerdictId = verdictId,
SignatureValid = true, // TODO: Implement verification
VerifiedAt = DateTimeOffset.UtcNow,
VerifiedAt = now,
Verifications = new[]
{
new SignatureVerification
@@ -289,7 +292,7 @@ public static class VerdictEndpoints
{
LogIndex = record.RekorLogIndex.Value,
InclusionProofValid = true, // TODO: Implement verification
VerifiedAt = DateTimeOffset.UtcNow
VerifiedAt = now
}
: null
};

View File

@@ -19,6 +19,7 @@ using StellaOps.EvidenceLocker.Core.Signing;
using StellaOps.EvidenceLocker.Core.Incident;
using StellaOps.EvidenceLocker.Core.Timeline;
using StellaOps.EvidenceLocker.Core.Storage;
using StellaOps.Determinism;
namespace StellaOps.EvidenceLocker.Infrastructure.Services;
@@ -37,6 +38,7 @@ public sealed class EvidenceSnapshotService
private readonly IIncidentModeState _incidentMode;
private readonly IEvidenceObjectStore _objectStore;
private readonly TimeProvider _timeProvider;
private readonly IGuidProvider _guidProvider;
private readonly ILogger<EvidenceSnapshotService> _logger;
private readonly QuotaOptions _quotas;
@@ -49,7 +51,8 @@ public sealed class EvidenceSnapshotService
IEvidenceObjectStore objectStore,
TimeProvider timeProvider,
IOptions<EvidenceLockerOptions> options,
ILogger<EvidenceSnapshotService> logger)
ILogger<EvidenceSnapshotService> logger,
IGuidProvider? guidProvider = null)
{
_repository = repository ?? throw new ArgumentNullException(nameof(repository));
_bundleBuilder = bundleBuilder ?? throw new ArgumentNullException(nameof(bundleBuilder));
@@ -61,6 +64,7 @@ public sealed class EvidenceSnapshotService
ArgumentNullException.ThrowIfNull(options);
_quotas = options.Value.Quotas ?? throw new InvalidOperationException("Quota options are required.");
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_guidProvider = guidProvider ?? SystemGuidProvider.Instance;
}
public async Task<EvidenceSnapshotResult> CreateSnapshotAsync(
@@ -76,7 +80,7 @@ public sealed class EvidenceSnapshotService
ArgumentNullException.ThrowIfNull(request);
ValidateRequest(request);
var bundleId = EvidenceBundleId.FromGuid(Guid.NewGuid());
var bundleId = EvidenceBundleId.FromGuid(_guidProvider.NewGuid());
var createdAt = _timeProvider.GetUtcNow();
var storageKey = $"tenants/{tenantId.Value:N}/bundles/{bundleId.Value:N}/bundle.tgz";
var incidentSnapshot = _incidentMode.Current;
@@ -245,7 +249,7 @@ public sealed class EvidenceSnapshotService
}
}
var holdId = EvidenceHoldId.FromGuid(Guid.NewGuid());
var holdId = EvidenceHoldId.FromGuid(_guidProvider.NewGuid());
var createdAt = _timeProvider.GetUtcNow();
var hold = new EvidenceHold(
holdId,

View File

@@ -14,6 +14,7 @@
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Cryptography\StellaOps.Cryptography.csproj" />
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Cryptography.DependencyInjection\StellaOps.Cryptography.DependencyInjection.csproj" />
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Cryptography.Plugin.BouncyCastle\StellaOps.Cryptography.Plugin.BouncyCastle.csproj" />
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Determinism.Abstractions\StellaOps.Determinism.Abstractions.csproj" />
</ItemGroup>
<ItemGroup>

View File

@@ -3,6 +3,7 @@ using Microsoft.Extensions.Logging;
using StellaOps.EvidenceLocker.Core.Configuration;
using StellaOps.EvidenceLocker.Core.Domain;
using StellaOps.EvidenceLocker.Core.Storage;
using StellaOps.Determinism;
namespace StellaOps.EvidenceLocker.Infrastructure.Storage;
@@ -11,11 +12,15 @@ internal sealed class FileSystemEvidenceObjectStore : IEvidenceObjectStore
private readonly string _rootPath;
private readonly bool _enforceWriteOnce;
private readonly ILogger<FileSystemEvidenceObjectStore> _logger;
private readonly TimeProvider _timeProvider;
private readonly IGuidProvider _guidProvider;
public FileSystemEvidenceObjectStore(
FileSystemStoreOptions options,
bool enforceWriteOnce,
ILogger<FileSystemEvidenceObjectStore> logger)
ILogger<FileSystemEvidenceObjectStore> logger,
TimeProvider? timeProvider = null,
IGuidProvider? guidProvider = null)
{
ArgumentNullException.ThrowIfNull(options);
ArgumentException.ThrowIfNullOrWhiteSpace(options.RootPath);
@@ -23,6 +28,8 @@ internal sealed class FileSystemEvidenceObjectStore : IEvidenceObjectStore
_rootPath = Path.GetFullPath(options.RootPath);
_enforceWriteOnce = enforceWriteOnce;
_logger = logger;
_timeProvider = timeProvider ?? TimeProvider.System;
_guidProvider = guidProvider ?? SystemGuidProvider.Instance;
Directory.CreateDirectory(_rootPath);
}
@@ -33,8 +40,8 @@ internal sealed class FileSystemEvidenceObjectStore : IEvidenceObjectStore
ArgumentNullException.ThrowIfNull(options);
var writeOnce = _enforceWriteOnce || options.EnforceWriteOnce;
var utcNow = DateTimeOffset.UtcNow;
var tempFilePath = Path.Combine(_rootPath, ".tmp", Guid.NewGuid().ToString("N"));
var utcNow = _timeProvider.GetUtcNow();
var tempFilePath = Path.Combine(_rootPath, ".tmp", _guidProvider.NewGuid().ToString("N"));
Directory.CreateDirectory(Path.GetDirectoryName(tempFilePath)!);

View File

@@ -6,6 +6,7 @@ using Microsoft.Extensions.Logging;
using StellaOps.EvidenceLocker.Core.Configuration;
using StellaOps.EvidenceLocker.Core.Domain;
using StellaOps.EvidenceLocker.Core.Storage;
using StellaOps.Determinism;
namespace StellaOps.EvidenceLocker.Infrastructure.Storage;
@@ -15,17 +16,23 @@ internal sealed class S3EvidenceObjectStore : IEvidenceObjectStore, IDisposable
private readonly AmazonS3StoreOptions _options;
private readonly bool _enforceWriteOnce;
private readonly ILogger<S3EvidenceObjectStore> _logger;
private readonly TimeProvider _timeProvider;
private readonly IGuidProvider _guidProvider;
public S3EvidenceObjectStore(
IAmazonS3 s3,
AmazonS3StoreOptions options,
bool enforceWriteOnce,
ILogger<S3EvidenceObjectStore> logger)
ILogger<S3EvidenceObjectStore> logger,
TimeProvider? timeProvider = null,
IGuidProvider? guidProvider = null)
{
_s3 = s3 ?? throw new ArgumentNullException(nameof(s3));
_options = options ?? throw new ArgumentNullException(nameof(options));
_enforceWriteOnce = enforceWriteOnce;
_logger = logger;
_timeProvider = timeProvider ?? TimeProvider.System;
_guidProvider = guidProvider ?? SystemGuidProvider.Instance;
}
public async Task<EvidenceObjectMetadata> StoreAsync(
@@ -37,7 +44,7 @@ internal sealed class S3EvidenceObjectStore : IEvidenceObjectStore, IDisposable
ArgumentNullException.ThrowIfNull(options);
var writeOnce = _enforceWriteOnce || options.EnforceWriteOnce;
var tempFilePath = Path.Combine(Path.GetTempPath(), $"evidence-{Guid.NewGuid():N}.tmp");
var tempFilePath = Path.Combine(Path.GetTempPath(), $"evidence-{_guidProvider.NewGuid():N}.tmp");
using var sha = SHA256.Create();
long totalBytes = 0;
@@ -83,7 +90,7 @@ internal sealed class S3EvidenceObjectStore : IEvidenceObjectStore, IDisposable
SizeBytes: totalBytes,
Sha256: sha256,
ETag: eTag,
CreatedAt: DateTimeOffset.UtcNow);
CreatedAt: _timeProvider.GetUtcNow());
}
public async Task<Stream> OpenReadAsync(string storageKey, CancellationToken cancellationToken)

View File

@@ -15,6 +15,7 @@ using StellaOps.EvidenceLocker.Core.Configuration;
using StellaOps.EvidenceLocker.Core.Domain;
using StellaOps.EvidenceLocker.Core.Incident;
using StellaOps.EvidenceLocker.Core.Timeline;
using StellaOps.Determinism;
namespace StellaOps.EvidenceLocker.Infrastructure.Timeline;
@@ -29,12 +30,14 @@ internal sealed class TimelineIndexerEvidenceTimelinePublisher : IEvidenceTimeli
private readonly TimelineOptions _options;
private readonly ILogger<TimelineIndexerEvidenceTimelinePublisher> _logger;
private readonly Uri _endpoint;
private readonly IGuidProvider _guidProvider;
public TimelineIndexerEvidenceTimelinePublisher(
HttpClient httpClient,
IOptions<EvidenceLockerOptions> options,
TimeProvider timeProvider,
ILogger<TimelineIndexerEvidenceTimelinePublisher> logger)
ILogger<TimelineIndexerEvidenceTimelinePublisher> logger,
IGuidProvider? guidProvider = null)
{
_httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
ArgumentNullException.ThrowIfNull(options);
@@ -53,6 +56,7 @@ internal sealed class TimelineIndexerEvidenceTimelinePublisher : IEvidenceTimeli
_endpoint = new Uri(_options.Endpoint, UriKind.Absolute);
ArgumentNullException.ThrowIfNull(timeProvider);
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_guidProvider = guidProvider ?? SystemGuidProvider.Instance;
}
public async Task PublishBundleSealedAsync(
@@ -85,7 +89,7 @@ internal sealed class TimelineIndexerEvidenceTimelinePublisher : IEvidenceTimeli
private TimelineEventEnvelope BuildBundleEvent(EvidenceBundleSignature signature, EvidenceBundleManifest manifest, string rootHash)
{
var eventId = Guid.NewGuid();
var eventId = _guidProvider.NewGuid();
var occurredAt = signature.TimestampedAt ?? signature.SignedAt;
var attributes = new SortedDictionary<string, string>(StringComparer.Ordinal)
{
@@ -139,7 +143,7 @@ internal sealed class TimelineIndexerEvidenceTimelinePublisher : IEvidenceTimeli
private TimelineEventEnvelope BuildHoldEvent(EvidenceHold hold)
{
var eventId = Guid.NewGuid();
var eventId = _guidProvider.NewGuid();
var occurredAt = hold.CreatedAt;
var attributes = new SortedDictionary<string, string>(StringComparer.Ordinal)
{
@@ -175,7 +179,7 @@ internal sealed class TimelineIndexerEvidenceTimelinePublisher : IEvidenceTimeli
private TimelineEventEnvelope BuildIncidentEvent(IncidentModeChange change)
{
var eventId = Guid.NewGuid();
var eventId = _guidProvider.NewGuid();
var attributes = new SortedDictionary<string, string>(StringComparer.Ordinal)
{
["state"] = change.IsActive ? "enabled" : "disabled",

View File

@@ -63,7 +63,7 @@ public sealed record VerdictAttestationRecord
public required string PredicateDigest { get; init; }
public string? DeterminismHash { get; init; }
public long? RekorLogIndex { get; init; }
public DateTimeOffset CreatedAt { get; init; } = DateTimeOffset.UtcNow;
public required DateTimeOffset CreatedAt { get; init; }
}
/// <summary>