170 lines
5.1 KiB
C#
170 lines
5.1 KiB
C#
// -----------------------------------------------------------------------------
|
|
// 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<FileInfo>("--bundle", ["-b"])
|
|
{
|
|
Description = "Path to the evidence bundle to verify",
|
|
IsRequired = true
|
|
};
|
|
|
|
var trustedKeysOption = new Option<FileInfo?>("--trusted-keys", ["-k"])
|
|
{
|
|
Description = "Path to trusted public keys file"
|
|
};
|
|
|
|
var trustProfileOption = new Option<FileInfo?>("--trust-profile", ["-p"])
|
|
{
|
|
Description = "Path to trust profile JSON file"
|
|
};
|
|
|
|
var outputOption = new Option<FileInfo?>("--output", ["-o"])
|
|
{
|
|
Description = "Path to write verification report"
|
|
};
|
|
|
|
var formatOption = new Option<ReportFormat>("--format", ["-f"])
|
|
{
|
|
Description = "Report output format"
|
|
};
|
|
formatOption.SetDefaultValue(ReportFormat.Markdown);
|
|
|
|
var verifySignaturesOption = new Option<bool>("--verify-signatures")
|
|
{
|
|
Description = "Verify bundle manifest signatures"
|
|
};
|
|
verifySignaturesOption.SetDefaultValue(true);
|
|
|
|
var verifyTimestampsOption = new Option<bool>("--verify-timestamps")
|
|
{
|
|
Description = "Verify RFC 3161 timestamps"
|
|
};
|
|
verifyTimestampsOption.SetDefaultValue(true);
|
|
|
|
var verifyDigestsOption = new Option<bool>("--verify-digests")
|
|
{
|
|
Description = "Verify blob digests"
|
|
};
|
|
verifyDigestsOption.SetDefaultValue(true);
|
|
|
|
var verifyPairsOption = new Option<bool>("--verify-pairs")
|
|
{
|
|
Description = "Verify pair artifacts (SBOM, delta-sig)"
|
|
};
|
|
verifyPairsOption.SetDefaultValue(true);
|
|
|
|
var quietOption = new Option<bool>("--quiet", ["-q"])
|
|
{
|
|
Description = "Suppress output except for errors"
|
|
};
|
|
|
|
var verboseOption = new Option<bool>("--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<bool>("--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);
|