feat: Implement MongoDB orchestrator storage with registry, commands, and heartbeats
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled

- Added NullAdvisoryObservationEventTransport for handling advisory observation events.
- Created IOrchestratorRegistryStore interface for orchestrator registry operations.
- Implemented MongoOrchestratorRegistryStore for MongoDB interactions with orchestrator data.
- Defined OrchestratorCommandDocument and OrchestratorCommandRecord for command handling.
- Added OrchestratorHeartbeatDocument and OrchestratorHeartbeatRecord for heartbeat tracking.
- Created OrchestratorRegistryDocument and OrchestratorRegistryRecord for registry management.
- Developed tests for orchestrator collections migration and MongoOrchestratorRegistryStore functionality.
- Introduced AirgapImportRequest and AirgapImportValidator for air-gapped VEX bundle imports.
- Added incident mode rules sample JSON for notifier configuration.
This commit is contained in:
StellaOps Bot
2025-11-22 12:35:38 +02:00
parent cbdc05b24d
commit f43e828b4e
96 changed files with 3425 additions and 976 deletions

View File

@@ -21,6 +21,8 @@ public sealed class ConcelierOptions
public AdvisoryChunkOptions AdvisoryChunks { get; set; } = new();
public EvidenceBundleOptions Evidence { get; set; } = new();
public StellaOpsCryptoOptions Crypto { get; } = new();
public sealed class StorageOptions
@@ -172,4 +174,20 @@ public sealed class ConcelierOptions
public int CacheDurationSeconds { get; set; } = 30;
}
public sealed class EvidenceBundleOptions
{
public bool Enabled { get; set; } = true;
public string Root { get; set; } = System.IO.Path.Combine("out", "evidence", "bundles");
public string? DefaultManifestFileName { get; set; } = "manifest.json";
public string? DefaultTransparencyFileName { get; set; } = "transparency.json";
public string PipelineVersion { get; set; } = "git:unknown";
[JsonIgnore]
public string RootAbsolute { get; internal set; } = string.Empty;
}
}

View File

@@ -19,6 +19,7 @@ public static class ConcelierOptionsPostConfigure
options.Authority ??= new ConcelierOptions.AuthorityOptions();
options.Features ??= new ConcelierOptions.FeaturesOptions();
options.Evidence ??= new ConcelierOptions.EvidenceBundleOptions();
var authority = options.Authority;
if (string.IsNullOrWhiteSpace(authority.ClientSecret)
@@ -44,8 +45,8 @@ public static class ConcelierOptionsPostConfigure
authority.ClientSecret = secret;
}
options.Mirror ??= new ConcelierOptions.MirrorOptions();
var mirror = options.Mirror;
options.Mirror ??= new ConcelierOptions.MirrorOptions();
var mirror = options.Mirror;
if (string.IsNullOrWhiteSpace(mirror.ExportRoot))
{
@@ -65,9 +66,33 @@ public static class ConcelierOptionsPostConfigure
mirror.LatestDirectoryName = "latest";
}
if (string.IsNullOrWhiteSpace(mirror.MirrorDirectoryName))
{
mirror.MirrorDirectoryName = "mirror";
}
}
}
if (string.IsNullOrWhiteSpace(mirror.MirrorDirectoryName))
{
mirror.MirrorDirectoryName = "mirror";
}
var evidence = options.Evidence;
if (string.IsNullOrWhiteSpace(evidence.Root))
{
evidence.Root = Path.Combine("out", "evidence", "bundles");
}
var evidenceRoot = evidence.Root;
if (!Path.IsPathRooted(evidenceRoot))
{
evidenceRoot = Path.Combine(contentRootPath, evidenceRoot);
}
evidence.RootAbsolute = Path.GetFullPath(evidenceRoot);
if (string.IsNullOrWhiteSpace(evidence.DefaultManifestFileName))
{
evidence.DefaultManifestFileName = "manifest.json";
}
if (string.IsNullOrWhiteSpace(evidence.DefaultTransparencyFileName))
{
evidence.DefaultTransparencyFileName = "transparency.json";
}
}
}

View File

@@ -137,6 +137,9 @@ public static class ConcelierOptionsValidator
options.Mirror ??= new ConcelierOptions.MirrorOptions();
ValidateMirror(options.Mirror);
options.Evidence ??= new ConcelierOptions.EvidenceBundleOptions();
ValidateEvidence(options.Evidence);
options.AdvisoryChunks ??= new ConcelierOptions.AdvisoryChunkOptions();
ValidateAdvisoryChunks(options.AdvisoryChunks);
}
@@ -312,4 +315,22 @@ public static class ConcelierOptionsValidator
throw new InvalidOperationException("Advisory chunk cacheDurationSeconds must be greater than or equal to zero.");
}
}
private static void ValidateEvidence(ConcelierOptions.EvidenceBundleOptions evidence)
{
if (string.IsNullOrWhiteSpace(evidence.Root))
{
throw new InvalidOperationException("Evidence bundle root must be configured.");
}
if (string.IsNullOrWhiteSpace(evidence.RootAbsolute))
{
throw new InvalidOperationException("Evidence bundle root could not be resolved.");
}
if (string.IsNullOrWhiteSpace(evidence.PipelineVersion))
{
throw new InvalidOperationException("Evidence bundle pipelineVersion must be provided.");
}
}
}