sprints and audit work
This commit is contained in:
@@ -18,148 +18,217 @@ internal static class Program
|
||||
|
||||
// Harvest command
|
||||
var harvestCommand = new Command("harvest", "Harvest and store a fixture with metadata");
|
||||
var harvestTypeOption = new Option<string>(
|
||||
"--type",
|
||||
description: "Fixture type: sbom, feed, vex") { IsRequired = true };
|
||||
var harvestIdOption = new Option<string>(
|
||||
"--id",
|
||||
description: "Unique fixture identifier") { IsRequired = true };
|
||||
var harvestSourceOption = new Option<string>(
|
||||
"--source",
|
||||
description: "Source URL or path");
|
||||
var harvestOutputOption = new Option<string>(
|
||||
"--output",
|
||||
description: "Output directory",
|
||||
getDefaultValue: () => "src/__Tests/fixtures");
|
||||
var harvestTypeOption = new Option<string>("--type")
|
||||
{
|
||||
Description = "Fixture type: sbom, feed, vex",
|
||||
Required = true
|
||||
};
|
||||
var harvestIdOption = new Option<string>("--id")
|
||||
{
|
||||
Description = "Unique fixture identifier",
|
||||
Required = true
|
||||
};
|
||||
var harvestSourceOption = new Option<string>("--source")
|
||||
{
|
||||
Description = "Source URL or path"
|
||||
};
|
||||
var harvestOutputOption = new Option<string>("--output")
|
||||
{
|
||||
Description = "Output directory",
|
||||
DefaultValueFactory = _ => "src/__Tests/fixtures"
|
||||
};
|
||||
|
||||
harvestCommand.AddOption(harvestTypeOption);
|
||||
harvestCommand.AddOption(harvestIdOption);
|
||||
harvestCommand.AddOption(harvestSourceOption);
|
||||
harvestCommand.AddOption(harvestOutputOption);
|
||||
harvestCommand.SetHandler(HarvestCommand.ExecuteAsync, harvestTypeOption, harvestIdOption, harvestSourceOption, harvestOutputOption);
|
||||
harvestCommand.Add(harvestTypeOption);
|
||||
harvestCommand.Add(harvestIdOption);
|
||||
harvestCommand.Add(harvestSourceOption);
|
||||
harvestCommand.Add(harvestOutputOption);
|
||||
harvestCommand.SetAction((parseResult, _) =>
|
||||
{
|
||||
var type = parseResult.GetValue(harvestTypeOption) ?? string.Empty;
|
||||
var id = parseResult.GetValue(harvestIdOption) ?? string.Empty;
|
||||
var source = parseResult.GetValue(harvestSourceOption);
|
||||
var output = parseResult.GetValue(harvestOutputOption) ?? "src/__Tests/fixtures";
|
||||
return HarvestCommand.ExecuteAsync(type, id, source, output);
|
||||
});
|
||||
|
||||
// Validate command
|
||||
var validateCommand = new Command("validate", "Validate fixtures against manifest");
|
||||
var validatePathOption = new Option<string>(
|
||||
"--path",
|
||||
description: "Fixtures directory path",
|
||||
getDefaultValue: () => "src/__Tests/fixtures");
|
||||
var validatePathOption = new Option<string>("--path")
|
||||
{
|
||||
Description = "Fixtures directory path",
|
||||
DefaultValueFactory = _ => "src/__Tests/fixtures"
|
||||
};
|
||||
|
||||
validateCommand.AddOption(validatePathOption);
|
||||
validateCommand.SetHandler(ValidateCommand.ExecuteAsync, validatePathOption);
|
||||
validateCommand.Add(validatePathOption);
|
||||
validateCommand.SetAction((parseResult, _) =>
|
||||
{
|
||||
var path = parseResult.GetValue(validatePathOption) ?? "src/__Tests/fixtures";
|
||||
return ValidateCommand.ExecuteAsync(path);
|
||||
});
|
||||
|
||||
// Regen command
|
||||
var regenCommand = new Command("regen", "Regenerate expected outputs (manual, use with caution)");
|
||||
var regenFixtureOption = new Option<string>(
|
||||
"--fixture",
|
||||
description: "Fixture ID to regenerate");
|
||||
var regenAllOption = new Option<bool>(
|
||||
"--all",
|
||||
description: "Regenerate all fixtures",
|
||||
getDefaultValue: () => false);
|
||||
var regenConfirmOption = new Option<bool>(
|
||||
"--confirm",
|
||||
description: "Confirm regeneration",
|
||||
getDefaultValue: () => false);
|
||||
var regenFixtureOption = new Option<string>("--fixture")
|
||||
{
|
||||
Description = "Fixture ID to regenerate"
|
||||
};
|
||||
var regenAllOption = new Option<bool>("--all")
|
||||
{
|
||||
Description = "Regenerate all fixtures",
|
||||
DefaultValueFactory = _ => false
|
||||
};
|
||||
var regenConfirmOption = new Option<bool>("--confirm")
|
||||
{
|
||||
Description = "Confirm regeneration",
|
||||
DefaultValueFactory = _ => false
|
||||
};
|
||||
|
||||
regenCommand.AddOption(regenFixtureOption);
|
||||
regenCommand.AddOption(regenAllOption);
|
||||
regenCommand.AddOption(regenConfirmOption);
|
||||
regenCommand.SetHandler(RegenCommand.ExecuteAsync, regenFixtureOption, regenAllOption, regenConfirmOption);
|
||||
regenCommand.Add(regenFixtureOption);
|
||||
regenCommand.Add(regenAllOption);
|
||||
regenCommand.Add(regenConfirmOption);
|
||||
regenCommand.SetAction((parseResult, _) =>
|
||||
{
|
||||
var fixture = parseResult.GetValue(regenFixtureOption);
|
||||
var all = parseResult.GetValue(regenAllOption);
|
||||
var confirm = parseResult.GetValue(regenConfirmOption);
|
||||
return RegenCommand.ExecuteAsync(fixture, all, confirm);
|
||||
});
|
||||
|
||||
// OCI Pin command (FH-004)
|
||||
var ociPinCommand = new Command("oci-pin", "Pin OCI image digests for deterministic testing");
|
||||
var ociImageOption = new Option<string>(
|
||||
"--image",
|
||||
description: "Image reference (e.g., alpine:3.19, myregistry.io/app:v1)") { IsRequired = true };
|
||||
var ociOutputOption = new Option<string>(
|
||||
"--output",
|
||||
description: "Output directory",
|
||||
getDefaultValue: () => "src/__Tests/fixtures/oci");
|
||||
var ociVerifyOption = new Option<bool>(
|
||||
"--verify",
|
||||
description: "Verify digest by re-fetching manifest",
|
||||
getDefaultValue: () => true);
|
||||
var ociImageOption = new Option<string>("--image")
|
||||
{
|
||||
Description = "Image reference (e.g., alpine:3.19, myregistry.io/app:v1)",
|
||||
Required = true
|
||||
};
|
||||
var ociOutputOption = new Option<string>("--output")
|
||||
{
|
||||
Description = "Output directory",
|
||||
DefaultValueFactory = _ => "src/__Tests/fixtures/oci"
|
||||
};
|
||||
var ociVerifyOption = new Option<bool>("--verify")
|
||||
{
|
||||
Description = "Verify digest by re-fetching manifest",
|
||||
DefaultValueFactory = _ => true
|
||||
};
|
||||
|
||||
ociPinCommand.AddOption(ociImageOption);
|
||||
ociPinCommand.AddOption(ociOutputOption);
|
||||
ociPinCommand.AddOption(ociVerifyOption);
|
||||
ociPinCommand.SetHandler(OciPinCommand.ExecuteAsync, ociImageOption, ociOutputOption, ociVerifyOption);
|
||||
ociPinCommand.Add(ociImageOption);
|
||||
ociPinCommand.Add(ociOutputOption);
|
||||
ociPinCommand.Add(ociVerifyOption);
|
||||
ociPinCommand.SetAction((parseResult, _) =>
|
||||
{
|
||||
var image = parseResult.GetValue(ociImageOption) ?? string.Empty;
|
||||
var output = parseResult.GetValue(ociOutputOption) ?? "src/__Tests/fixtures/oci";
|
||||
var verify = parseResult.GetValue(ociVerifyOption);
|
||||
return OciPinCommand.ExecuteAsync(image, output, verify);
|
||||
});
|
||||
|
||||
// Feed Snapshot command (FH-005)
|
||||
var feedSnapshotCommand = new Command("feed-snapshot", "Capture vulnerability feed snapshots");
|
||||
var feedTypeOption = new Option<string>(
|
||||
"--feed",
|
||||
description: "Feed type: osv, ghsa, nvd, epss, kev, oval") { IsRequired = true };
|
||||
var feedUrlOption = new Option<string>(
|
||||
"--url",
|
||||
description: "Concelier base URL",
|
||||
getDefaultValue: () => "http://localhost:5010");
|
||||
var feedCountOption = new Option<int>(
|
||||
"--count",
|
||||
description: "Number of advisories to capture",
|
||||
getDefaultValue: () => 30);
|
||||
var feedOutputOption = new Option<string>(
|
||||
"--output",
|
||||
description: "Output directory",
|
||||
getDefaultValue: () => "src/__Tests/fixtures/feeds");
|
||||
var feedTypeOption = new Option<string>("--feed")
|
||||
{
|
||||
Description = "Feed type: osv, ghsa, nvd, epss, kev, oval",
|
||||
Required = true
|
||||
};
|
||||
var feedUrlOption = new Option<string>("--url")
|
||||
{
|
||||
Description = "Concelier base URL",
|
||||
DefaultValueFactory = _ => "http://localhost:5010"
|
||||
};
|
||||
var feedCountOption = new Option<int>("--count")
|
||||
{
|
||||
Description = "Number of advisories to capture",
|
||||
DefaultValueFactory = _ => 30
|
||||
};
|
||||
var feedOutputOption = new Option<string>("--output")
|
||||
{
|
||||
Description = "Output directory",
|
||||
DefaultValueFactory = _ => "src/__Tests/fixtures/feeds"
|
||||
};
|
||||
|
||||
feedSnapshotCommand.AddOption(feedTypeOption);
|
||||
feedSnapshotCommand.AddOption(feedUrlOption);
|
||||
feedSnapshotCommand.AddOption(feedCountOption);
|
||||
feedSnapshotCommand.AddOption(feedOutputOption);
|
||||
feedSnapshotCommand.SetHandler(FeedSnapshotCommand.ExecuteAsync, feedTypeOption, feedUrlOption, feedCountOption, feedOutputOption);
|
||||
feedSnapshotCommand.Add(feedTypeOption);
|
||||
feedSnapshotCommand.Add(feedUrlOption);
|
||||
feedSnapshotCommand.Add(feedCountOption);
|
||||
feedSnapshotCommand.Add(feedOutputOption);
|
||||
feedSnapshotCommand.SetAction((parseResult, _) =>
|
||||
{
|
||||
var feed = parseResult.GetValue(feedTypeOption) ?? string.Empty;
|
||||
var url = parseResult.GetValue(feedUrlOption) ?? "http://localhost:5010";
|
||||
var count = parseResult.GetValue(feedCountOption);
|
||||
var output = parseResult.GetValue(feedOutputOption) ?? "src/__Tests/fixtures/feeds";
|
||||
return FeedSnapshotCommand.ExecuteAsync(feed, url, count, output);
|
||||
});
|
||||
|
||||
// VEX Source command (FH-006)
|
||||
var vexSourceCommand = new Command("vex", "Acquire OpenVEX and CSAF samples");
|
||||
var vexSourceArg = new Argument<string>(
|
||||
"source",
|
||||
description: "Source name (list, all, openvex-examples, csaf-redhat, alpine-secdb) or 'list' to see all");
|
||||
var vexCustomUrlOption = new Option<string>(
|
||||
"--url",
|
||||
description: "Custom VEX document URL");
|
||||
var vexOutputOption = new Option<string>(
|
||||
"--output",
|
||||
description: "Output directory",
|
||||
getDefaultValue: () => "src/__Tests/fixtures/vex");
|
||||
var vexSourceArg = new Argument<string>("source")
|
||||
{
|
||||
Description = "Source name (list, all, openvex-examples, csaf-redhat, alpine-secdb) or 'list' to see all"
|
||||
};
|
||||
var vexCustomUrlOption = new Option<string>("--url")
|
||||
{
|
||||
Description = "Custom VEX document URL"
|
||||
};
|
||||
var vexOutputOption = new Option<string>("--output")
|
||||
{
|
||||
Description = "Output directory",
|
||||
DefaultValueFactory = _ => "src/__Tests/fixtures/vex"
|
||||
};
|
||||
|
||||
vexSourceCommand.AddArgument(vexSourceArg);
|
||||
vexSourceCommand.AddOption(vexCustomUrlOption);
|
||||
vexSourceCommand.AddOption(vexOutputOption);
|
||||
vexSourceCommand.SetHandler(VexSourceCommand.ExecuteAsync, vexSourceArg, vexCustomUrlOption, vexOutputOption);
|
||||
vexSourceCommand.Add(vexSourceArg);
|
||||
vexSourceCommand.Add(vexCustomUrlOption);
|
||||
vexSourceCommand.Add(vexOutputOption);
|
||||
vexSourceCommand.SetAction((parseResult, _) =>
|
||||
{
|
||||
var source = parseResult.GetValue(vexSourceArg) ?? string.Empty;
|
||||
var url = parseResult.GetValue(vexCustomUrlOption);
|
||||
var output = parseResult.GetValue(vexOutputOption) ?? "src/__Tests/fixtures/vex";
|
||||
return VexSourceCommand.ExecuteAsync(source, url, output);
|
||||
});
|
||||
|
||||
// SBOM Golden command (FH-007)
|
||||
var sbomGoldenCommand = new Command("sbom-golden", "Generate SBOM golden fixtures from container images");
|
||||
var sbomImageArg = new Argument<string>(
|
||||
"image",
|
||||
description: "Image key (list, all, alpine-minimal, debian-slim, distroless-static) or custom image ref");
|
||||
var sbomFormatOption = new Option<string>(
|
||||
"--format",
|
||||
description: "SBOM format: cyclonedx, spdx",
|
||||
getDefaultValue: () => "cyclonedx");
|
||||
var sbomScannerOption = new Option<string>(
|
||||
"--scanner",
|
||||
description: "Scanner tool: syft, trivy",
|
||||
getDefaultValue: () => "syft");
|
||||
var sbomOutputOption = new Option<string>(
|
||||
"--output",
|
||||
description: "Output directory",
|
||||
getDefaultValue: () => "src/__Tests/fixtures/sbom");
|
||||
var sbomImageArg = new Argument<string>("image")
|
||||
{
|
||||
Description = "Image key (list, all, alpine-minimal, debian-slim, distroless-static) or custom image ref"
|
||||
};
|
||||
var sbomFormatOption = new Option<string>("--format")
|
||||
{
|
||||
Description = "SBOM format: cyclonedx, spdx",
|
||||
DefaultValueFactory = _ => "cyclonedx"
|
||||
};
|
||||
var sbomScannerOption = new Option<string>("--scanner")
|
||||
{
|
||||
Description = "Scanner tool: syft, trivy",
|
||||
DefaultValueFactory = _ => "syft"
|
||||
};
|
||||
var sbomOutputOption = new Option<string>("--output")
|
||||
{
|
||||
Description = "Output directory",
|
||||
DefaultValueFactory = _ => "src/__Tests/fixtures/sbom"
|
||||
};
|
||||
|
||||
sbomGoldenCommand.AddArgument(sbomImageArg);
|
||||
sbomGoldenCommand.AddOption(sbomFormatOption);
|
||||
sbomGoldenCommand.AddOption(sbomScannerOption);
|
||||
sbomGoldenCommand.AddOption(sbomOutputOption);
|
||||
sbomGoldenCommand.SetHandler(SbomGoldenCommand.ExecuteAsync, sbomImageArg, sbomFormatOption, sbomScannerOption, sbomOutputOption);
|
||||
sbomGoldenCommand.Add(sbomImageArg);
|
||||
sbomGoldenCommand.Add(sbomFormatOption);
|
||||
sbomGoldenCommand.Add(sbomScannerOption);
|
||||
sbomGoldenCommand.Add(sbomOutputOption);
|
||||
sbomGoldenCommand.SetAction((parseResult, _) =>
|
||||
{
|
||||
var image = parseResult.GetValue(sbomImageArg) ?? string.Empty;
|
||||
var format = parseResult.GetValue(sbomFormatOption) ?? "cyclonedx";
|
||||
var scanner = parseResult.GetValue(sbomScannerOption) ?? "syft";
|
||||
var output = parseResult.GetValue(sbomOutputOption) ?? "src/__Tests/fixtures/sbom";
|
||||
return SbomGoldenCommand.ExecuteAsync(image, format, scanner, output);
|
||||
});
|
||||
|
||||
rootCommand.AddCommand(harvestCommand);
|
||||
rootCommand.AddCommand(validateCommand);
|
||||
rootCommand.AddCommand(regenCommand);
|
||||
rootCommand.AddCommand(ociPinCommand);
|
||||
rootCommand.AddCommand(feedSnapshotCommand);
|
||||
rootCommand.AddCommand(vexSourceCommand);
|
||||
rootCommand.AddCommand(sbomGoldenCommand);
|
||||
rootCommand.Add(harvestCommand);
|
||||
rootCommand.Add(validateCommand);
|
||||
rootCommand.Add(regenCommand);
|
||||
rootCommand.Add(ociPinCommand);
|
||||
rootCommand.Add(feedSnapshotCommand);
|
||||
rootCommand.Add(vexSourceCommand);
|
||||
rootCommand.Add(sbomGoldenCommand);
|
||||
|
||||
return await rootCommand.InvokeAsync(args);
|
||||
return await rootCommand.Parse(args).InvokeAsync();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user