using ControlPlane.Core.Interfaces; using ControlPlane.Core.Models; using System.Text.Json; namespace ControlPlane.Worker.Steps; public class VaultStep(ILogger logger, IConfiguration config) : ISagaStep { public string StepName => "Cryptographic Pre-Flight (Vault)"; public Task ExecuteAsync(SagaContext context, CancellationToken cancellationToken) { // TODO: VaultSharp // 1. Assert Transit engine is active and healthy // 2. Derive/validate TenantContextId (e.g. FL_COM_001) // 3. Register TenantContextId in a KV entry or TenantRegistry table // so Clarity.Server can resolve the derivation path later // // Root token is read at runtime from the persisted init.json on the Vault volume: // var token = ReadRootToken(); logger.LogInformation("[{JobId}] Vault step is a stub - VaultSharp not yet wired.", context.Job.Id); context.Job.CompletedSteps |= CompletedSteps.VaultVerified; return Task.CompletedTask; } public Task CompensateAsync(SagaContext context, CancellationToken cancellationToken) { logger.LogInformation("[{JobId}] Vault step: no compensation needed.", context.Job.Id); return Task.CompletedTask; } /// /// Reads the root token from the init.json written by the Vault entrypoint on first boot. /// Path is injected via Vault__KeysFile config. /// internal string ReadRootToken() { var path = config["Vault__KeysFile"] ?? throw new InvalidOperationException("Vault__KeysFile is not configured."); using var doc = JsonDocument.Parse(File.ReadAllText(path)); return doc.RootElement.GetProperty("root_token").GetString() ?? throw new InvalidOperationException("root_token not found in Vault init.json."); } }