// ----------------------------------------------------------------------------- // Program.cs // Sprint: SPRINT_20260121_036_BinaryIndex_golden_corpus_bundle_verification // Task: GCB-003 - Implement standalone offline verifier // Description: Entry point for standalone bundle verifier CLI // ----------------------------------------------------------------------------- // Exit codes: // 0: All verifications passed // 1: One or more verifications failed // 2: Invalid input or configuration error using StellaOps.Verifier; using System.CommandLine; using System.CommandLine.Builder; using System.CommandLine.Parsing; var bundleOption = new Option("--bundle", ["-b"]) { Description = "Path to the evidence bundle to verify", IsRequired = true }; var trustedKeysOption = new Option("--trusted-keys", ["-k"]) { Description = "Path to trusted public keys file" }; var trustProfileOption = new Option("--trust-profile", ["-p"]) { Description = "Path to trust profile JSON file" }; var outputOption = new Option("--output", ["-o"]) { Description = "Path to write verification report" }; var formatOption = new Option("--format", ["-f"]) { Description = "Report output format" }; formatOption.SetDefaultValue(ReportFormat.Markdown); var verifySignaturesOption = new Option("--verify-signatures") { Description = "Verify bundle manifest signatures" }; verifySignaturesOption.SetDefaultValue(true); var verifyTimestampsOption = new Option("--verify-timestamps") { Description = "Verify RFC 3161 timestamps" }; verifyTimestampsOption.SetDefaultValue(true); var verifyDigestsOption = new Option("--verify-digests") { Description = "Verify blob digests" }; verifyDigestsOption.SetDefaultValue(true); var verifyPairsOption = new Option("--verify-pairs") { Description = "Verify pair artifacts (SBOM, delta-sig)" }; verifyPairsOption.SetDefaultValue(true); var quietOption = new Option("--quiet", ["-q"]) { Description = "Suppress output except for errors" }; var verboseOption = new Option("--verbose", ["-v"]) { Description = "Show detailed verification output" }; var verifyCommand = new Command("verify", "Verify an evidence bundle") { bundleOption, trustedKeysOption, trustProfileOption, outputOption, formatOption, verifySignaturesOption, verifyTimestampsOption, verifyDigestsOption, verifyPairsOption, quietOption, verboseOption }; verifyCommand.SetHandler(async (context) => { var bundle = context.ParseResult.GetValueForOption(bundleOption)!; var trustedKeys = context.ParseResult.GetValueForOption(trustedKeysOption); var trustProfile = context.ParseResult.GetValueForOption(trustProfileOption); var output = context.ParseResult.GetValueForOption(outputOption); var format = context.ParseResult.GetValueForOption(formatOption); var verifySignatures = context.ParseResult.GetValueForOption(verifySignaturesOption); var verifyTimestamps = context.ParseResult.GetValueForOption(verifyTimestampsOption); var verifyDigests = context.ParseResult.GetValueForOption(verifyDigestsOption); var verifyPairs = context.ParseResult.GetValueForOption(verifyPairsOption); var quiet = context.ParseResult.GetValueForOption(quietOption); var verbose = context.ParseResult.GetValueForOption(verboseOption); var options = new VerifierOptions { BundlePath = bundle.FullName, TrustedKeysPath = trustedKeys?.FullName, TrustProfilePath = trustProfile?.FullName, OutputPath = output?.FullName, OutputFormat = format, VerifySignatures = verifySignatures, VerifyTimestamps = verifyTimestamps, VerifyDigests = verifyDigests, VerifyPairs = verifyPairs, Quiet = quiet, Verbose = verbose }; var verifier = new BundleVerifier(); var exitCode = await verifier.VerifyAsync(options, context.GetCancellationToken()); context.ExitCode = exitCode; }); var infoCommand = new Command("info", "Display bundle information without verification") { bundleOption, formatOption, quietOption }; infoCommand.SetHandler(async (context) => { var bundle = context.ParseResult.GetValueForOption(bundleOption)!; var format = context.ParseResult.GetValueForOption(formatOption); var quiet = context.ParseResult.GetValueForOption(quietOption); var verifier = new BundleVerifier(); var exitCode = await verifier.ShowInfoAsync( bundle.FullName, format, quiet, context.GetCancellationToken()); context.ExitCode = exitCode; }); var rootCommand = new RootCommand("Stella Ops Bundle Verifier - Offline evidence bundle verification") { verifyCommand, infoCommand }; // Add version option rootCommand.AddOption(new Option("--version", "Show version information")); var parser = new CommandLineBuilder(rootCommand) .UseDefaults() .UseExceptionHandler((ex, context) => { Console.Error.WriteLine($"Error: {ex.Message}"); context.ExitCode = 2; }) .Build(); return await parser.InvokeAsync(args);