save audit remarks applications progress
This commit is contained in:
@@ -12,6 +12,7 @@ using System.Text.Json;
|
||||
using StellaOps.AirGap.Bundle.Models;
|
||||
using StellaOps.Concelier.Core.Raw;
|
||||
using StellaOps.Concelier.RawModels;
|
||||
using StellaOps.Determinism;
|
||||
|
||||
namespace StellaOps.AirGap.Bundle.Services;
|
||||
|
||||
@@ -134,12 +135,22 @@ public sealed class InMemoryAdvisoryRawRepository : IAdvisoryRawRepository
|
||||
{
|
||||
private readonly Dictionary<string, AdvisoryRawRecord> _records = new();
|
||||
private readonly object _lock = new();
|
||||
private readonly TimeProvider _timeProvider;
|
||||
private readonly IGuidProvider _guidProvider;
|
||||
|
||||
public InMemoryAdvisoryRawRepository(
|
||||
TimeProvider? timeProvider = null,
|
||||
IGuidProvider? guidProvider = null)
|
||||
{
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
_guidProvider = guidProvider ?? SystemGuidProvider.Instance;
|
||||
}
|
||||
|
||||
public Task<AdvisoryRawUpsertResult> UpsertAsync(AdvisoryRawDocument document, CancellationToken cancellationToken)
|
||||
{
|
||||
var contentHash = ComputeHash(document);
|
||||
var key = $"{document.Tenant}:{contentHash}";
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
var now = _timeProvider.GetUtcNow();
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
@@ -149,7 +160,7 @@ public sealed class InMemoryAdvisoryRawRepository : IAdvisoryRawRepository
|
||||
}
|
||||
|
||||
var record = new AdvisoryRawRecord(
|
||||
Id: Guid.NewGuid().ToString(),
|
||||
Id: _guidProvider.NewGuid().ToString(),
|
||||
Document: document,
|
||||
IngestedAt: now,
|
||||
CreatedAt: now);
|
||||
|
||||
@@ -10,6 +10,7 @@ using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using StellaOps.AirGap.Bundle.Models;
|
||||
using StellaOps.Determinism;
|
||||
using StellaOps.Excititor.Core;
|
||||
using StellaOps.Excititor.Core.Storage;
|
||||
|
||||
@@ -161,10 +162,14 @@ public sealed class InMemoryVexRawDocumentSink : IVexRawDocumentSink, IVexRawSto
|
||||
private readonly Dictionary<string, VexRawRecord> _records = new();
|
||||
private readonly string _tenant;
|
||||
private readonly object _lock = new();
|
||||
private readonly TimeProvider _timeProvider;
|
||||
|
||||
public InMemoryVexRawDocumentSink(string tenant = "default")
|
||||
public InMemoryVexRawDocumentSink(
|
||||
string tenant = "default",
|
||||
TimeProvider? timeProvider = null)
|
||||
{
|
||||
_tenant = tenant;
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
}
|
||||
|
||||
public ValueTask StoreAsync(VexRawDocument document, CancellationToken cancellationToken)
|
||||
@@ -183,7 +188,7 @@ public sealed class InMemoryVexRawDocumentSink : IVexRawDocumentSink, IVexRawSto
|
||||
Metadata: document.Metadata,
|
||||
Content: document.Content,
|
||||
InlineContent: true,
|
||||
RecordedAt: DateTimeOffset.UtcNow);
|
||||
RecordedAt: _timeProvider.GetUtcNow());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ using System.IO.Compression;
|
||||
using System.Formats.Tar;
|
||||
using System.Text.Json;
|
||||
using StellaOps.AirGap.Bundle.Models;
|
||||
using StellaOps.Determinism;
|
||||
|
||||
namespace StellaOps.AirGap.Bundle.Services;
|
||||
|
||||
@@ -25,15 +26,21 @@ public sealed class KnowledgeSnapshotImporter : IKnowledgeSnapshotImporter
|
||||
private readonly IAdvisoryImportTarget? _advisoryTarget;
|
||||
private readonly IVexImportTarget? _vexTarget;
|
||||
private readonly IPolicyImportTarget? _policyTarget;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
private readonly IGuidProvider _guidProvider;
|
||||
|
||||
public KnowledgeSnapshotImporter(
|
||||
IAdvisoryImportTarget? advisoryTarget = null,
|
||||
IVexImportTarget? vexTarget = null,
|
||||
IPolicyImportTarget? policyTarget = null)
|
||||
IPolicyImportTarget? policyTarget = null,
|
||||
TimeProvider? timeProvider = null,
|
||||
IGuidProvider? guidProvider = null)
|
||||
{
|
||||
_advisoryTarget = advisoryTarget;
|
||||
_vexTarget = vexTarget;
|
||||
_policyTarget = policyTarget;
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
_guidProvider = guidProvider ?? SystemGuidProvider.Instance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -48,10 +55,10 @@ public sealed class KnowledgeSnapshotImporter : IKnowledgeSnapshotImporter
|
||||
|
||||
if (!File.Exists(request.BundlePath))
|
||||
{
|
||||
return SnapshotImportResult.Failed("Bundle file not found");
|
||||
return SnapshotImportResult.Failed("Bundle file not found", _timeProvider);
|
||||
}
|
||||
|
||||
var tempDir = Path.Combine(Path.GetTempPath(), $"import-{Guid.NewGuid():N}");
|
||||
var tempDir = Path.Combine(Path.GetTempPath(), $"import-{_guidProvider.NewGuid():N}");
|
||||
Directory.CreateDirectory(tempDir);
|
||||
|
||||
try
|
||||
@@ -63,21 +70,21 @@ public sealed class KnowledgeSnapshotImporter : IKnowledgeSnapshotImporter
|
||||
var manifestPath = Path.Combine(tempDir, "manifest.json");
|
||||
if (!File.Exists(manifestPath))
|
||||
{
|
||||
return SnapshotImportResult.Failed("Manifest not found in bundle");
|
||||
return SnapshotImportResult.Failed("Manifest not found in bundle", _timeProvider);
|
||||
}
|
||||
|
||||
var manifestBytes = await File.ReadAllBytesAsync(manifestPath, cancellationToken);
|
||||
var manifest = JsonSerializer.Deserialize<KnowledgeSnapshotManifest>(manifestBytes, JsonOptions);
|
||||
if (manifest is null)
|
||||
{
|
||||
return SnapshotImportResult.Failed("Failed to parse manifest");
|
||||
return SnapshotImportResult.Failed("Failed to parse manifest", _timeProvider);
|
||||
}
|
||||
|
||||
var result = new SnapshotImportResult
|
||||
{
|
||||
Success = true,
|
||||
BundleId = manifest.BundleId,
|
||||
StartedAt = DateTimeOffset.UtcNow
|
||||
StartedAt = _timeProvider.GetUtcNow()
|
||||
};
|
||||
|
||||
var errors = new List<string>();
|
||||
@@ -148,7 +155,7 @@ public sealed class KnowledgeSnapshotImporter : IKnowledgeSnapshotImporter
|
||||
|
||||
result = result with
|
||||
{
|
||||
CompletedAt = DateTimeOffset.UtcNow,
|
||||
CompletedAt = _timeProvider.GetUtcNow(),
|
||||
Statistics = stats,
|
||||
Errors = errors.Count > 0 ? [.. errors] : null,
|
||||
Success = errors.Count == 0 || !request.FailOnAnyError
|
||||
@@ -158,7 +165,7 @@ public sealed class KnowledgeSnapshotImporter : IKnowledgeSnapshotImporter
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return SnapshotImportResult.Failed($"Import failed: {ex.Message}");
|
||||
return SnapshotImportResult.Failed($"Import failed: {ex.Message}", _timeProvider);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -422,13 +429,17 @@ public sealed record SnapshotImportResult
|
||||
public IReadOnlyList<string>? Errors { get; init; }
|
||||
public string? Error { get; init; }
|
||||
|
||||
public static SnapshotImportResult Failed(string error) => new()
|
||||
public static SnapshotImportResult Failed(string error, TimeProvider? timeProvider = null)
|
||||
{
|
||||
Success = false,
|
||||
Error = error,
|
||||
StartedAt = DateTimeOffset.UtcNow,
|
||||
CompletedAt = DateTimeOffset.UtcNow
|
||||
};
|
||||
var now = (timeProvider ?? TimeProvider.System).GetUtcNow();
|
||||
return new()
|
||||
{
|
||||
Success = false,
|
||||
Error = error,
|
||||
StartedAt = now,
|
||||
CompletedAt = now
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public sealed record ImportStatistics
|
||||
|
||||
@@ -9,6 +9,7 @@ using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using StellaOps.AirGap.Bundle.Models;
|
||||
using StellaOps.Determinism;
|
||||
|
||||
namespace StellaOps.AirGap.Bundle.Services;
|
||||
|
||||
@@ -26,13 +27,16 @@ public sealed class PolicyRegistryImportTarget : IPolicyImportTarget
|
||||
|
||||
private readonly IPolicyPackImportStore _store;
|
||||
private readonly string _tenantId;
|
||||
private readonly TimeProvider _timeProvider;
|
||||
|
||||
public PolicyRegistryImportTarget(
|
||||
IPolicyPackImportStore store,
|
||||
string tenantId = "default")
|
||||
string tenantId = "default",
|
||||
TimeProvider? timeProvider = null)
|
||||
{
|
||||
_store = store ?? throw new ArgumentNullException(nameof(store));
|
||||
_tenantId = tenantId;
|
||||
_timeProvider = timeProvider ?? TimeProvider.System;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -83,7 +87,7 @@ public sealed class PolicyRegistryImportTarget : IPolicyImportTarget
|
||||
Version: data.Version ?? "1.0.0",
|
||||
Content: data.Content,
|
||||
Metadata: bundle.Metadata,
|
||||
ImportedAt: DateTimeOffset.UtcNow);
|
||||
ImportedAt: _timeProvider.GetUtcNow());
|
||||
|
||||
await _store.SaveAsync(pack, cancellationToken);
|
||||
created++;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Canonical.Json\StellaOps.Canonical.Json.csproj" />
|
||||
<ProjectReference Include="..\..\..\__Libraries\StellaOps.Determinism.Abstractions\StellaOps.Determinism.Abstractions.csproj" />
|
||||
<ProjectReference Include="..\..\..\Concelier\__Libraries\StellaOps.Concelier.Core\StellaOps.Concelier.Core.csproj" />
|
||||
<ProjectReference Include="..\..\..\Concelier\__Libraries\StellaOps.Concelier.RawModels\StellaOps.Concelier.RawModels.csproj" />
|
||||
<ProjectReference Include="..\..\..\Excititor\__Libraries\StellaOps.Excititor.Core\StellaOps.Excititor.Core.csproj" />
|
||||
|
||||
Reference in New Issue
Block a user