Files
git.stella-ops.org/src/Cli/__Tests/StellaOps.Cli.Tests/Commands/VexVerifyCommandTests.cs
2026-01-16 23:30:47 +02:00

157 lines
5.1 KiB
C#

// -----------------------------------------------------------------------------
// VexVerifyCommandTests.cs
// Sprint: SPRINT_20260117_009_CLI_vex_processing (VPR-001)
// Task: VPR-001 - Add stella vex verify command
// Description: Unit tests for VEX verify command
// -----------------------------------------------------------------------------
using System.CommandLine;
using System.Text.Json;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging.Abstractions;
using StellaOps.Cli.Configuration;
using StellaOps.Cli.Plugins.Vex;
using StellaOps.TestKit;
using Xunit;
namespace StellaOps.Cli.Tests.Commands;
public sealed class VexVerifyCommandTests
{
private readonly IServiceProvider _services;
private readonly StellaOpsCliOptions _options;
private readonly Option<bool> _verboseOption;
public VexVerifyCommandTests()
{
var services = new ServiceCollection();
services.AddSingleton(NullLoggerFactory.Instance);
_services = services.BuildServiceProvider();
_options = new StellaOpsCliOptions();
_verboseOption = new Option<bool>("--verbose");
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public void VexCommand_RegistersVerifySubcommand()
{
// Arrange
var root = new RootCommand();
var module = new VexCliCommandModule();
// Act
module.RegisterCommands(root, _services, _options, _verboseOption, CancellationToken.None);
var vexCommand = root.Children.OfType<Command>().FirstOrDefault(c => c.Name == "vex");
var verifyCommand = vexCommand?.Subcommands.FirstOrDefault(c => c.Name == "verify");
// Assert
Assert.NotNull(vexCommand);
Assert.NotNull(verifyCommand);
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task VexVerify_ValidOpenVex_ReturnsSuccessJson()
{
// Arrange
var root = new RootCommand();
var module = new VexCliCommandModule();
module.RegisterCommands(root, _services, _options, _verboseOption, CancellationToken.None);
var tempDir = Path.Combine(Path.GetTempPath(), "stellaops-vex-tests", Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(tempDir);
var vexPath = Path.Combine(tempDir, "valid.openvex.json");
var vexJson = """
{
"@context": "https://openvex.dev/ns",
"@id": "https://stellaops.dev/vex/example-1",
"author": "stellaops",
"timestamp": "2026-01-16T00:00:00Z",
"statements": [
{
"vulnerability": { "name": "CVE-2025-0001" },
"status": "not_affected",
"products": ["pkg:oci/example@sha256:abc"]
}
]
}
""";
await File.WriteAllTextAsync(vexPath, vexJson);
var writer = new StringWriter();
var originalOut = Console.Out;
int exitCode;
try
{
Console.SetOut(writer);
exitCode = await root.Parse($"vex verify \"{vexPath}\" --format json").InvokeAsync();
}
finally
{
Console.SetOut(originalOut);
}
// Assert
Assert.Equal(0, exitCode);
using var doc = JsonDocument.Parse(writer.ToString());
var rootElement = doc.RootElement;
Assert.True(rootElement.GetProperty("valid").GetBoolean());
Assert.Equal("OpenVEX", rootElement.GetProperty("detectedFormat").GetString());
}
[Trait("Category", TestCategories.Unit)]
[Fact]
public async Task VexVerify_StrictModeWithoutSignature_Fails()
{
// Arrange
var root = new RootCommand();
var module = new VexCliCommandModule();
module.RegisterCommands(root, _services, _options, _verboseOption, CancellationToken.None);
var tempDir = Path.Combine(Path.GetTempPath(), "stellaops-vex-tests", Guid.NewGuid().ToString("N"));
Directory.CreateDirectory(tempDir);
var vexPath = Path.Combine(tempDir, "valid.openvex.json");
var vexJson = """
{
"@context": "https://openvex.dev/ns",
"@id": "https://stellaops.dev/vex/example-2",
"author": "stellaops",
"timestamp": "2026-01-16T00:00:00Z",
"statements": [
{
"vulnerability": { "name": "CVE-2025-0002" },
"status": "not_affected",
"products": ["pkg:oci/example@sha256:def"]
}
]
}
""";
await File.WriteAllTextAsync(vexPath, vexJson);
var writer = new StringWriter();
var originalOut = Console.Out;
int exitCode;
try
{
Console.SetOut(writer);
exitCode = await root.Parse($"vex verify \"{vexPath}\" --strict --format json").InvokeAsync();
}
finally
{
Console.SetOut(originalOut);
}
// Assert
Assert.Equal(1, exitCode);
using var doc = JsonDocument.Parse(writer.ToString());
var rootElement = doc.RootElement;
Assert.False(rootElement.GetProperty("valid").GetBoolean());
}
}