using Spectre.Console; using ZB.MOM.WW.Secrets.Abstractions; namespace ZB.MOM.WW.Secrets.Cli.Interactive.Flows; /// /// Creates or rotates a secret: prompts for a validated name, confirms before overwriting an existing /// live row, reads the value through a masked prompt, and seals it under a fresh per-secret DEK via the /// session cipher. The value is never echoed and the confirmation line carries the name only. Requires a /// KEK-capable session (the shell upgrades a degraded session before dispatch). /// public sealed class SetSecretFlow : IInteractiveFlow { /// public string Title => "Set / rotate a secret"; /// public bool RequiresKek => true; /// public async Task RunAsync(IAnsiConsole console, SecretsSession session, CancellationToken ct) { ArgumentNullException.ThrowIfNull(console); ArgumentNullException.ThrowIfNull(session); ISecretCipher cipher = session.Cipher ?? throw new InvalidOperationException("flow requires an unlocked KEK session"); var name = new SecretName(console.Prompt( new TextPrompt("Secret [green]name[/]:").Validate(FlowPrompts.ValidateSecretName))); StoredSecret? existing = await session.Store.GetAsync(name, ct).ConfigureAwait(false); if (existing is { IsDeleted: false } && !console.Prompt(new ConfirmationPrompt($"'{name.Value}' exists — overwrite in place?") { DefaultValue = false })) { console.MarkupLine("[yellow]Left unchanged.[/]"); return; } string value = console.Prompt(new TextPrompt("Secret [green]value[/]:").Secret()); SecretContentType contentType = console.Prompt( new SelectionPrompt().Title("Content type").AddChoices(Enum.GetValues())); string description = console.Prompt( new TextPrompt("Description [grey](optional)[/]:").AllowEmpty()); string actor = FlowPrompts.Actor; StoredSecret row = cipher.Encrypt(name, value, contentType) with { Description = string.IsNullOrWhiteSpace(description) ? null : description, CreatedBy = actor, UpdatedBy = actor, }; await session.Store.UpsertAsync(row, ct).ConfigureAwait(false); console.MarkupLineInterpolated($"[green]Sealed '{name.Value}'.[/]"); } }