FUll implementation plan (first draft)
This commit is contained in:
		| @@ -24,6 +24,7 @@ internal static class CommandFactory | ||||
|         root.Add(BuildScannerCommand(services, verboseOption, cancellationToken)); | ||||
|         root.Add(BuildScanCommand(services, options, verboseOption, cancellationToken)); | ||||
|         root.Add(BuildDatabaseCommand(services, verboseOption, cancellationToken)); | ||||
|         root.Add(BuildExcititorCommand(services, verboseOption, cancellationToken)); | ||||
|         root.Add(BuildAuthCommand(services, options, verboseOption, cancellationToken)); | ||||
|         root.Add(BuildConfigCommand(options)); | ||||
|  | ||||
| @@ -220,10 +221,191 @@ internal static class CommandFactory | ||||
|  | ||||
|         db.Add(fetch); | ||||
|         db.Add(merge); | ||||
|         db.Add(export); | ||||
|         db.Add(export); | ||||
|         return db; | ||||
|     } | ||||
|  | ||||
|     private static Command BuildExcititorCommand(IServiceProvider services, Option<bool> verboseOption, CancellationToken cancellationToken) | ||||
|     { | ||||
|         var excititor = new Command("excititor", "Manage Excititor ingest, exports, and reconciliation workflows."); | ||||
|  | ||||
|         var init = new Command("init", "Initialize Excititor ingest state."); | ||||
|         var initProviders = new Option<string[]>("--provider", new[] { "-p" }) | ||||
|         { | ||||
|             Description = "Optional provider identifier(s) to initialize.", | ||||
|             Arity = ArgumentArity.ZeroOrMore | ||||
|         }; | ||||
|         var resumeOption = new Option<bool>("--resume") | ||||
|         { | ||||
|             Description = "Resume ingest from the last persisted checkpoint instead of starting fresh." | ||||
|         }; | ||||
|         init.Add(initProviders); | ||||
|         init.Add(resumeOption); | ||||
|         init.SetAction((parseResult, _) => | ||||
|         { | ||||
|             var providers = parseResult.GetValue(initProviders) ?? Array.Empty<string>(); | ||||
|             var resume = parseResult.GetValue(resumeOption); | ||||
|             var verbose = parseResult.GetValue(verboseOption); | ||||
|             return CommandHandlers.HandleExcititorInitAsync(services, providers, resume, verbose, cancellationToken); | ||||
|         }); | ||||
|  | ||||
|         var pull = new Command("pull", "Trigger Excititor ingest for configured providers."); | ||||
|         var pullProviders = new Option<string[]>("--provider", new[] { "-p" }) | ||||
|         { | ||||
|             Description = "Optional provider identifier(s) to ingest.", | ||||
|             Arity = ArgumentArity.ZeroOrMore | ||||
|         }; | ||||
|         var sinceOption = new Option<DateTimeOffset?>("--since") | ||||
|         { | ||||
|             Description = "Optional ISO-8601 timestamp to begin the ingest window." | ||||
|         }; | ||||
|         var windowOption = new Option<TimeSpan?>("--window") | ||||
|         { | ||||
|             Description = "Optional window duration (e.g. 24:00:00)." | ||||
|         }; | ||||
|         var forceOption = new Option<bool>("--force") | ||||
|         { | ||||
|             Description = "Force ingestion even if the backend reports no pending work." | ||||
|         }; | ||||
|         pull.Add(pullProviders); | ||||
|         pull.Add(sinceOption); | ||||
|         pull.Add(windowOption); | ||||
|         pull.Add(forceOption); | ||||
|         pull.SetAction((parseResult, _) => | ||||
|         { | ||||
|             var providers = parseResult.GetValue(pullProviders) ?? Array.Empty<string>(); | ||||
|             var since = parseResult.GetValue(sinceOption); | ||||
|             var window = parseResult.GetValue(windowOption); | ||||
|             var force = parseResult.GetValue(forceOption); | ||||
|             var verbose = parseResult.GetValue(verboseOption); | ||||
|             return CommandHandlers.HandleExcititorPullAsync(services, providers, since, window, force, verbose, cancellationToken); | ||||
|         }); | ||||
|  | ||||
|         var resume = new Command("resume", "Resume Excititor ingest using a checkpoint token."); | ||||
|         var resumeProviders = new Option<string[]>("--provider", new[] { "-p" }) | ||||
|         { | ||||
|             Description = "Optional provider identifier(s) to resume.", | ||||
|             Arity = ArgumentArity.ZeroOrMore | ||||
|         }; | ||||
|         var checkpointOption = new Option<string?>("--checkpoint") | ||||
|         { | ||||
|             Description = "Optional checkpoint identifier to resume from." | ||||
|         }; | ||||
|         resume.Add(resumeProviders); | ||||
|         resume.Add(checkpointOption); | ||||
|         resume.SetAction((parseResult, _) => | ||||
|         { | ||||
|             var providers = parseResult.GetValue(resumeProviders) ?? Array.Empty<string>(); | ||||
|             var checkpoint = parseResult.GetValue(checkpointOption); | ||||
|             var verbose = parseResult.GetValue(verboseOption); | ||||
|             return CommandHandlers.HandleExcititorResumeAsync(services, providers, checkpoint, verbose, cancellationToken); | ||||
|         }); | ||||
|  | ||||
|         var list = new Command("list-providers", "List Excititor providers and their ingest status."); | ||||
|         var includeDisabledOption = new Option<bool>("--include-disabled") | ||||
|         { | ||||
|             Description = "Include disabled providers in the listing." | ||||
|         }; | ||||
|         list.Add(includeDisabledOption); | ||||
|         list.SetAction((parseResult, _) => | ||||
|         { | ||||
|             var includeDisabled = parseResult.GetValue(includeDisabledOption); | ||||
|             var verbose = parseResult.GetValue(verboseOption); | ||||
|             return CommandHandlers.HandleExcititorListProvidersAsync(services, includeDisabled, verbose, cancellationToken); | ||||
|         }); | ||||
|  | ||||
|         var export = new Command("export", "Trigger Excititor export generation."); | ||||
|         var formatOption = new Option<string>("--format") | ||||
|         { | ||||
|             Description = "Export format (e.g. openvex, json)." | ||||
|         }; | ||||
|         var exportDeltaOption = new Option<bool>("--delta") | ||||
|         { | ||||
|             Description = "Request a delta export when supported." | ||||
|         }; | ||||
|         var exportScopeOption = new Option<string?>("--scope") | ||||
|         { | ||||
|             Description = "Optional policy scope or tenant identifier." | ||||
|         }; | ||||
|         var exportSinceOption = new Option<DateTimeOffset?>("--since") | ||||
|         { | ||||
|             Description = "Optional ISO-8601 timestamp to restrict export contents." | ||||
|         }; | ||||
|         var exportProviderOption = new Option<string?>("--provider") | ||||
|         { | ||||
|             Description = "Optional provider identifier when requesting targeted exports." | ||||
|         }; | ||||
|         export.Add(formatOption); | ||||
|         export.Add(exportDeltaOption); | ||||
|         export.Add(exportScopeOption); | ||||
|         export.Add(exportSinceOption); | ||||
|         export.Add(exportProviderOption); | ||||
|         export.SetAction((parseResult, _) => | ||||
|         { | ||||
|             var format = parseResult.GetValue(formatOption) ?? "openvex"; | ||||
|             var delta = parseResult.GetValue(exportDeltaOption); | ||||
|             var scope = parseResult.GetValue(exportScopeOption); | ||||
|             var since = parseResult.GetValue(exportSinceOption); | ||||
|             var provider = parseResult.GetValue(exportProviderOption); | ||||
|             var verbose = parseResult.GetValue(verboseOption); | ||||
|             return CommandHandlers.HandleExcititorExportAsync(services, format, delta, scope, since, provider, verbose, cancellationToken); | ||||
|         }); | ||||
|  | ||||
|         var verify = new Command("verify", "Verify Excititor exports or attestations."); | ||||
|         var exportIdOption = new Option<string?>("--export-id") | ||||
|         { | ||||
|             Description = "Export identifier to verify." | ||||
|         }; | ||||
|         var digestOption = new Option<string?>("--digest") | ||||
|         { | ||||
|             Description = "Expected digest for the export or attestation." | ||||
|         }; | ||||
|         var attestationOption = new Option<string?>("--attestation") | ||||
|         { | ||||
|             Description = "Path to a local attestation file to verify (base64 content will be uploaded)." | ||||
|         }; | ||||
|         verify.Add(exportIdOption); | ||||
|         verify.Add(digestOption); | ||||
|         verify.Add(attestationOption); | ||||
|         verify.SetAction((parseResult, _) => | ||||
|         { | ||||
|             var exportId = parseResult.GetValue(exportIdOption); | ||||
|             var digest = parseResult.GetValue(digestOption); | ||||
|             var attestation = parseResult.GetValue(attestationOption); | ||||
|             var verbose = parseResult.GetValue(verboseOption); | ||||
|             return CommandHandlers.HandleExcititorVerifyAsync(services, exportId, digest, attestation, verbose, cancellationToken); | ||||
|         }); | ||||
|  | ||||
|         var reconcile = new Command("reconcile", "Trigger Excititor reconciliation against canonical advisories."); | ||||
|         var reconcileProviders = new Option<string[]>("--provider", new[] { "-p" }) | ||||
|         { | ||||
|             Description = "Optional provider identifier(s) to reconcile.", | ||||
|             Arity = ArgumentArity.ZeroOrMore | ||||
|         }; | ||||
|         var maxAgeOption = new Option<TimeSpan?>("--max-age") | ||||
|         { | ||||
|             Description = "Optional maximum age window (e.g. 7.00:00:00)." | ||||
|         }; | ||||
|         reconcile.Add(reconcileProviders); | ||||
|         reconcile.Add(maxAgeOption); | ||||
|         reconcile.SetAction((parseResult, _) => | ||||
|         { | ||||
|             var providers = parseResult.GetValue(reconcileProviders) ?? Array.Empty<string>(); | ||||
|             var maxAge = parseResult.GetValue(maxAgeOption); | ||||
|             var verbose = parseResult.GetValue(verboseOption); | ||||
|             return CommandHandlers.HandleExcititorReconcileAsync(services, providers, maxAge, verbose, cancellationToken); | ||||
|         }); | ||||
|  | ||||
|         excititor.Add(init); | ||||
|         excititor.Add(pull); | ||||
|         excititor.Add(resume); | ||||
|         excititor.Add(list); | ||||
|         excititor.Add(export); | ||||
|         excititor.Add(verify); | ||||
|         excititor.Add(reconcile); | ||||
|         return excititor; | ||||
|     } | ||||
|  | ||||
|     private static Command BuildAuthCommand(IServiceProvider services, StellaOpsCliOptions options, Option<bool> verboseOption, CancellationToken cancellationToken) | ||||
|     { | ||||
|         var auth = new Command("auth", "Manage authentication with StellaOps Authority."); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user