tests fixes and sprints work
This commit is contained in:
@@ -12,6 +12,7 @@ using System.Globalization;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using StellaOps.Cli.Configuration;
|
||||
using StellaOps.Cli.Extensions;
|
||||
using StellaOps.Cli.Plugins;
|
||||
|
||||
namespace StellaOps.Cli.Plugins.Vex;
|
||||
@@ -108,9 +109,10 @@ public sealed class VexCliCommandModule : ICliCommandModule
|
||||
|
||||
var formatOption = new Option<OutputFormat>("--format")
|
||||
{
|
||||
Description = "Output format",
|
||||
DefaultValueFactory = _ => OutputFormat.Table
|
||||
Description = "Output format"
|
||||
};
|
||||
formatOption.AddAlias("-f");
|
||||
formatOption.SetDefaultValue(OutputFormat.Table);
|
||||
|
||||
var cmd = new Command("auto-downgrade", "Auto-downgrade VEX based on runtime observations.")
|
||||
{
|
||||
@@ -256,10 +258,11 @@ public sealed class VexCliCommandModule : ICliCommandModule
|
||||
DefaultValueFactory = _ => OutputFormat.Table
|
||||
};
|
||||
|
||||
var schemaOption = new Option<string?>("--schema")
|
||||
{
|
||||
Description = "Schema version to validate against (e.g., openvex-0.2, csaf-2.0)"
|
||||
};
|
||||
var schemaOption = new Option<string?>("--schema")
|
||||
{
|
||||
Description = "Schema version to validate against (e.g., openvex-0.2, csaf-2.0)"
|
||||
};
|
||||
schemaOption.AddAlias("-s");
|
||||
|
||||
var strictOption = new Option<bool>("--strict")
|
||||
{
|
||||
@@ -310,16 +313,18 @@ public sealed class VexCliCommandModule : ICliCommandModule
|
||||
Description = "Digest or component identifier (e.g., sha256:..., pkg:npm/...)"
|
||||
};
|
||||
|
||||
var formatOption = new Option<string>("--format", new[] { "-f" })
|
||||
var formatOption = new Option<string>("--format")
|
||||
{
|
||||
Description = "Output format: json (default), openvex"
|
||||
};
|
||||
formatOption.AddAlias("-f");
|
||||
formatOption.SetDefaultValue("json");
|
||||
|
||||
var outputOption = new Option<string?>("--output", new[] { "-o" })
|
||||
var outputOption = new Option<string?>("--output")
|
||||
{
|
||||
Description = "Write output to the specified file"
|
||||
};
|
||||
outputOption.AddAlias("-o");
|
||||
|
||||
var export = new Command("export", "Export VEX evidence for a digest or component")
|
||||
{
|
||||
@@ -446,135 +451,6 @@ public sealed class VexCliCommandModule : ICliCommandModule
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Build the 'vex webhooks' command group.
|
||||
/// Sprint: SPRINT_20260117_009_CLI_vex_processing (VPR-003)
|
||||
/// </summary>
|
||||
private static Command BuildWebhooksCommand(Option<bool> verboseOption)
|
||||
{
|
||||
var webhooks = new Command("webhooks", "Manage VEX webhook subscriptions.");
|
||||
|
||||
var formatOption = new Option<string>("--format", new[] { "-f" })
|
||||
{
|
||||
Description = "Output format: json (default)"
|
||||
};
|
||||
formatOption.SetDefaultValue("json");
|
||||
|
||||
var list = new Command("list", "List configured VEX webhooks")
|
||||
{
|
||||
formatOption,
|
||||
verboseOption
|
||||
};
|
||||
|
||||
list.SetAction((parseResult, ct) =>
|
||||
{
|
||||
var format = parseResult.GetValue(formatOption) ?? "json";
|
||||
var payload = new[]
|
||||
{
|
||||
new { id = "wh-001", url = "https://hooks.stellaops.dev/vex", events = new[] { "vex.created", "vex.updated" }, status = "active" },
|
||||
new { id = "wh-002", url = "https://hooks.example.com/vex", events = new[] { "vex.created" }, status = "paused" }
|
||||
};
|
||||
|
||||
if (format.Equals("json", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Console.WriteLine(System.Text.Json.JsonSerializer.Serialize(payload, new System.Text.Json.JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true,
|
||||
PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.CamelCase
|
||||
}));
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
Console.WriteLine("Only json output is supported.");
|
||||
return Task.FromResult(0);
|
||||
});
|
||||
|
||||
var urlOption = new Option<string>("--url")
|
||||
{
|
||||
Description = "Webhook URL",
|
||||
IsRequired = true
|
||||
};
|
||||
var eventsOption = new Option<string[]>("--events")
|
||||
{
|
||||
Description = "Event types (repeatable)",
|
||||
Arity = ArgumentArity.ZeroOrMore
|
||||
};
|
||||
eventsOption.AllowMultipleArgumentsPerToken = true;
|
||||
|
||||
var add = new Command("add", "Register a VEX webhook")
|
||||
{
|
||||
urlOption,
|
||||
eventsOption,
|
||||
formatOption,
|
||||
verboseOption
|
||||
};
|
||||
|
||||
add.SetAction((parseResult, ct) =>
|
||||
{
|
||||
var url = parseResult.GetValue(urlOption) ?? string.Empty;
|
||||
var events = parseResult.GetValue(eventsOption) ?? Array.Empty<string>();
|
||||
var format = parseResult.GetValue(formatOption) ?? "json";
|
||||
|
||||
var payload = new
|
||||
{
|
||||
id = "wh-003",
|
||||
url,
|
||||
events = events.Length > 0 ? events : new[] { "vex.created" },
|
||||
status = "active"
|
||||
};
|
||||
|
||||
if (format.Equals("json", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Console.WriteLine(System.Text.Json.JsonSerializer.Serialize(payload, new System.Text.Json.JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true,
|
||||
PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.CamelCase
|
||||
}));
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
Console.WriteLine("Only json output is supported.");
|
||||
return Task.FromResult(0);
|
||||
});
|
||||
|
||||
var idArg = new Argument<string>("id")
|
||||
{
|
||||
Description = "Webhook identifier"
|
||||
};
|
||||
var remove = new Command("remove", "Unregister a VEX webhook")
|
||||
{
|
||||
idArg,
|
||||
formatOption,
|
||||
verboseOption
|
||||
};
|
||||
|
||||
remove.SetAction((parseResult, ct) =>
|
||||
{
|
||||
var id = parseResult.GetValue(idArg) ?? string.Empty;
|
||||
var format = parseResult.GetValue(formatOption) ?? "json";
|
||||
|
||||
var payload = new { id, status = "removed" };
|
||||
|
||||
if (format.Equals("json", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Console.WriteLine(System.Text.Json.JsonSerializer.Serialize(payload, new System.Text.Json.JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true,
|
||||
PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.CamelCase
|
||||
}));
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
Console.WriteLine("Only json output is supported.");
|
||||
return Task.FromResult(0);
|
||||
});
|
||||
|
||||
webhooks.Add(list);
|
||||
webhooks.Add(add);
|
||||
webhooks.Add(remove);
|
||||
return webhooks;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute VEX document verification.
|
||||
/// Sprint: SPRINT_20260117_009_CLI_vex_processing (VPR-001)
|
||||
|
||||
@@ -10,6 +10,7 @@ using System.Globalization;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using StellaOps.Cli.Configuration;
|
||||
using StellaOps.Cli.Extensions;
|
||||
|
||||
namespace StellaOps.Cli.Plugins.Vex;
|
||||
|
||||
@@ -60,10 +61,12 @@ public static class VexRekorCommandGroup
|
||||
Description = "Include Rekor linkage details in output."
|
||||
};
|
||||
|
||||
var formatOption = new Option<string>("--format", new[] { "-f" })
|
||||
var formatOption = new Option<string>("--format")
|
||||
{
|
||||
Description = "Output format: text (default), json, yaml."
|
||||
}.SetDefaultValue("text").FromAmong("text", "json", "yaml");
|
||||
};
|
||||
formatOption.AddAlias("-f");
|
||||
formatOption.SetDefaultValue("text").FromAmong("text", "json", "yaml");
|
||||
|
||||
var command = new Command("show", "Display observation details including Rekor linkage.")
|
||||
{
|
||||
@@ -104,20 +107,22 @@ public static class VexRekorCommandGroup
|
||||
Description = "Rekor server URL (default: https://rekor.sigstore.dev)."
|
||||
};
|
||||
|
||||
var keyOption = new Option<string?>("--key", new[] { "-k" })
|
||||
var keyOption = new Option<string?>("--key")
|
||||
{
|
||||
Description = "Signing key identifier."
|
||||
};
|
||||
keyOption.AddAlias("-k");
|
||||
|
||||
var dryRunOption = new Option<bool>("--dry-run")
|
||||
{
|
||||
Description = "Create DSSE envelope without submitting to Rekor."
|
||||
};
|
||||
|
||||
var outputOption = new Option<string?>("--output", new[] { "-o" })
|
||||
var outputOption = new Option<string?>("--output")
|
||||
{
|
||||
Description = "Output file for DSSE envelope."
|
||||
};
|
||||
outputOption.AddAlias("-o");
|
||||
|
||||
var command = new Command("attest", "Attest a VEX observation to Rekor transparency log.")
|
||||
{
|
||||
@@ -167,10 +172,12 @@ public static class VexRekorCommandGroup
|
||||
Description = "Rekor server URL for online verification."
|
||||
};
|
||||
|
||||
var formatOption = new Option<string>("--format", new[] { "-f" })
|
||||
var formatOption = new Option<string>("--format")
|
||||
{
|
||||
Description = "Output format: text (default), json."
|
||||
}.SetDefaultValue("text").FromAmong("text", "json");
|
||||
};
|
||||
formatOption.AddAlias("-f");
|
||||
formatOption.SetDefaultValue("text").FromAmong("text", "json");
|
||||
|
||||
var command = new Command("verify-rekor", "Verify an observation's Rekor transparency log linkage.")
|
||||
{
|
||||
@@ -203,15 +210,19 @@ public static class VexRekorCommandGroup
|
||||
StellaOpsCliOptions options,
|
||||
Option<bool> verboseOption)
|
||||
{
|
||||
var limitOption = new Option<int>("--limit", new[] { "-n" })
|
||||
var limitOption = new Option<int>("--limit")
|
||||
{
|
||||
Description = "Maximum number of results to return."
|
||||
}.SetDefaultValue(50);
|
||||
};
|
||||
limitOption.AddAlias("-n");
|
||||
limitOption.SetDefaultValue(50);
|
||||
|
||||
var formatOption = new Option<string>("--format", new[] { "-f" })
|
||||
var formatOption = new Option<string>("--format")
|
||||
{
|
||||
Description = "Output format: text (default), json."
|
||||
}.SetDefaultValue("text").FromAmong("text", "json");
|
||||
};
|
||||
formatOption.AddAlias("-f");
|
||||
formatOption.SetDefaultValue("text").FromAmong("text", "json");
|
||||
|
||||
var command = new Command("list-pending", "List VEX observations pending Rekor attestation.")
|
||||
{
|
||||
@@ -248,7 +259,7 @@ public static class VexRekorCommandGroup
|
||||
var httpClientFactory = services.GetRequiredService<IHttpClientFactory>();
|
||||
var httpClient = httpClientFactory.CreateClient("StellaOpsApi");
|
||||
|
||||
var baseUrl = options.ApiBaseUrl?.TrimEnd('/') ?? "http://localhost:5000";
|
||||
var baseUrl = options.BackendUrl?.TrimEnd('/') ?? "http://localhost:5000";
|
||||
var url = $"{baseUrl}/api/v1/vex/observations/{observationId}";
|
||||
|
||||
if (showRekor)
|
||||
@@ -351,7 +362,7 @@ public static class VexRekorCommandGroup
|
||||
var httpClientFactory = services.GetRequiredService<IHttpClientFactory>();
|
||||
var httpClient = httpClientFactory.CreateClient("StellaOpsApi");
|
||||
|
||||
var baseUrl = options.ApiBaseUrl?.TrimEnd('/') ?? "http://localhost:5000";
|
||||
var baseUrl = options.BackendUrl?.TrimEnd('/') ?? "http://localhost:5000";
|
||||
|
||||
if (dryRun)
|
||||
{
|
||||
@@ -430,7 +441,7 @@ public static class VexRekorCommandGroup
|
||||
var httpClientFactory = services.GetRequiredService<IHttpClientFactory>();
|
||||
var httpClient = httpClientFactory.CreateClient("StellaOpsApi");
|
||||
|
||||
var baseUrl = options.ApiBaseUrl?.TrimEnd('/') ?? "http://localhost:5000";
|
||||
var baseUrl = options.BackendUrl?.TrimEnd('/') ?? "http://localhost:5000";
|
||||
var url = $"{baseUrl}/attestations/rekor/observations/{observationId}/verify";
|
||||
|
||||
if (offline)
|
||||
@@ -515,7 +526,7 @@ public static class VexRekorCommandGroup
|
||||
var httpClientFactory = services.GetRequiredService<IHttpClientFactory>();
|
||||
var httpClient = httpClientFactory.CreateClient("StellaOpsApi");
|
||||
|
||||
var baseUrl = options.ApiBaseUrl?.TrimEnd('/') ?? "http://localhost:5000";
|
||||
var baseUrl = options.BackendUrl?.TrimEnd('/') ?? "http://localhost:5000";
|
||||
var url = $"{baseUrl}/attestations/rekor/pending?limit={limit}";
|
||||
|
||||
try
|
||||
|
||||
Reference in New Issue
Block a user