feat: Implement air-gap functionality with timeline impact and evidence snapshot services
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
devportal-offline / build-offline (push) Has been cancelled
Mirror Thin Bundle Sign & Verify / mirror-sign (push) Has been cancelled

- Added AirgapTimelineImpact, AirgapTimelineImpactInput, and AirgapTimelineImpactResult records for managing air-gap bundle import impacts.
- Introduced EvidenceSnapshotRecord, EvidenceSnapshotLinkInput, and EvidenceSnapshotLinkResult records for linking findings to evidence snapshots.
- Created IEvidenceSnapshotRepository interface for managing evidence snapshot records.
- Developed StalenessValidationService to validate staleness and enforce freshness thresholds.
- Implemented AirgapTimelineService for emitting timeline events related to bundle imports.
- Added EvidenceSnapshotService for linking findings to evidence snapshots and verifying their validity.
- Introduced AirGapOptions for configuring air-gap staleness enforcement and thresholds.
- Added minimal jsPDF stub for offline/testing builds in the web application.
- Created TypeScript definitions for jsPDF to enhance type safety in the web application.
This commit is contained in:
StellaOps Bot
2025-12-06 01:30:08 +02:00
parent 6c1177a6ce
commit 2eaf0f699b
144 changed files with 7578 additions and 2581 deletions

View File

@@ -15,6 +15,8 @@ internal static class LedgerTimeline
private static readonly EventId ProjectionUpdated = new(6201, "ledger.projection.updated");
private static readonly EventId OrchestratorExport = new(6301, "ledger.export.recorded");
private static readonly EventId AirgapImport = new(6401, "ledger.airgap.imported");
private static readonly EventId EvidenceSnapshotLinkedEvent = new(6501, "ledger.evidence.snapshot_linked");
private static readonly EventId AirgapTimelineImpactEvent = new(6601, "ledger.airgap.timeline_impact");
public static void EmitLedgerAppended(ILogger logger, LedgerEventRecord record, string? evidenceBundleRef = null)
{
@@ -99,4 +101,47 @@ internal static class LedgerTimeline
merkleRoot,
ledgerEventId?.ToString() ?? string.Empty);
}
public static void EmitEvidenceSnapshotLinked(ILogger logger, string tenantId, string findingId, string bundleUri, string dsseDigest)
{
if (logger is null)
{
return;
}
logger.LogInformation(
EvidenceSnapshotLinkedEvent,
"timeline ledger.evidence.snapshot_linked tenant={Tenant} finding={FindingId} bundle_uri={BundleUri} dsse_digest={DsseDigest}",
tenantId,
findingId,
bundleUri,
dsseDigest);
}
public static void EmitAirgapTimelineImpact(
ILogger logger,
string tenantId,
string bundleId,
int newFindings,
int resolvedFindings,
int criticalDelta,
DateTimeOffset timeAnchor,
bool sealedMode)
{
if (logger is null)
{
return;
}
logger.LogInformation(
AirgapTimelineImpactEvent,
"timeline ledger.airgap.timeline_impact tenant={Tenant} bundle={BundleId} new_findings={NewFindings} resolved_findings={ResolvedFindings} critical_delta={CriticalDelta} time_anchor={TimeAnchor} sealed_mode={SealedMode}",
tenantId,
bundleId,
newFindings,
resolvedFindings,
criticalDelta,
timeAnchor.ToString("O"),
sealedMode);
}
}