// ----------------------------------------------------------------------------- // TimestampCommandTests.cs // Sprint: SPRINT_20260119_010 Attestor TST Integration // Description: Unit tests for timestamp CLI commands. // ----------------------------------------------------------------------------- using System.CommandLine; using System.Security.Cryptography; using System.Text; using StellaOps.Cli.Commands; using StellaOps.Cli.Tests.Testing; using StellaOps.TestKit; using Xunit; namespace StellaOps.Cli.Tests.Commands; public sealed class TimestampCommandTests { private readonly Option _verboseOption = new("--verbose"); private readonly CancellationToken _ct = CancellationToken.None; [Trait("Category", TestCategories.Unit)] [Fact] public void TimestampCommandGroup_ExposesSubcommands() { var command = TimestampCommandGroup.BuildTimestampCommand(_verboseOption, _ct); Assert.Contains(command.Children, child => child.Name == "rfc3161"); Assert.Contains(command.Children, child => child.Name == "verify"); Assert.Contains(command.Children, child => child.Name == "info"); } [Trait("Category", TestCategories.Unit)] [Fact] public async Task TimestampCommandGroup_Rfc3161ThenVerify_Succeeds() { using var temp = new TempDirectory(); var artifactPath = Path.Combine(temp.Path, "artifact.bin"); var tokenPath = Path.Combine(temp.Path, "artifact.tst"); var bytes = Encoding.UTF8.GetBytes("timestamp-test"); await File.WriteAllBytesAsync(artifactPath, bytes, _ct); var digest = "sha256:" + Convert.ToHexString(SHA256.HashData(bytes)).ToLowerInvariant(); var root = new RootCommand { TimestampCommandGroup.BuildTimestampCommand(_verboseOption, _ct) }; var originalOut = Console.Out; var writer = new StringWriter(); int exitCode; try { Console.SetOut(writer); exitCode = await root.Parse($"ts rfc3161 --hash {digest} --tsa https://tsa.example --out \"{tokenPath}\"").InvokeAsync(); } finally { Console.SetOut(originalOut); } Assert.Equal(0, exitCode); Assert.True(File.Exists(tokenPath)); var verifyWriter = new StringWriter(); try { Console.SetOut(verifyWriter); exitCode = await root.Parse($"ts verify --tst \"{tokenPath}\" --artifact \"{artifactPath}\"").InvokeAsync(); } finally { Console.SetOut(originalOut); } Assert.Equal(0, exitCode); Assert.Contains("PASSED", verifyWriter.ToString()); } }