Sprint: SPRINT_4100_0006_0001 Status: COMPLETED Implemented plugin-based crypto command architecture for regional compliance with build-time distribution selection (GOST/eIDAS/SM) and runtime validation. ## New Commands - `stella crypto sign` - Sign artifacts with regional crypto providers - `stella crypto verify` - Verify signatures with trust policy support - `stella crypto profiles` - List available crypto providers & capabilities ## Build-Time Distribution Selection ```bash # International (default - BouncyCastle) dotnet build src/Cli/StellaOps.Cli/StellaOps.Cli.csproj # Russia distribution (GOST R 34.10-2012) dotnet build -p:StellaOpsEnableGOST=true # EU distribution (eIDAS Regulation 910/2014) dotnet build -p:StellaOpsEnableEIDAS=true # China distribution (SM2/SM3/SM4) dotnet build -p:StellaOpsEnableSM=true ``` ## Key Features - Build-time conditional compilation prevents export control violations - Runtime crypto profile validation on CLI startup - 8 predefined profiles (international, russia-prod/dev, eu-prod/dev, china-prod/dev) - Comprehensive configuration with environment variable substitution - Integration tests with distribution-specific assertions - Full migration path from deprecated `cryptoru` CLI ## Files Added - src/Cli/StellaOps.Cli/Commands/CryptoCommandGroup.cs - src/Cli/StellaOps.Cli/Commands/CommandHandlers.Crypto.cs - src/Cli/StellaOps.Cli/Services/CryptoProfileValidator.cs - src/Cli/StellaOps.Cli/appsettings.crypto.yaml.example - src/Cli/__Tests/StellaOps.Cli.Tests/CryptoCommandTests.cs - docs/cli/crypto-commands.md - docs/implplan/SPRINT_4100_0006_0001_COMPLETION_SUMMARY.md ## Files Modified - src/Cli/StellaOps.Cli/StellaOps.Cli.csproj (conditional plugin refs) - src/Cli/StellaOps.Cli/Program.cs (plugin registration + validation) - src/Cli/StellaOps.Cli/Commands/CommandFactory.cs (command wiring) - src/Scanner/__Libraries/StellaOps.Scanner.Core/Configuration/PoEConfiguration.cs (fix) ## Compliance - GOST (Russia): GOST R 34.10-2012, FSB certified - eIDAS (EU): Regulation (EU) No 910/2014, QES/AES/AdES - SM (China): GM/T 0003-2012 (SM2), OSCCA certified ## Migration `cryptoru` CLI deprecated → sunset date: 2025-07-01 - `cryptoru providers` → `stella crypto profiles` - `cryptoru sign` → `stella crypto sign` ## Testing ✅ All crypto code compiles successfully ✅ Integration tests pass ✅ Build verification for all distributions (international/GOST/eIDAS/SM) Next: SPRINT_4100_0006_0002 (eIDAS plugin implementation) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
214 lines
7.0 KiB
C#
214 lines
7.0 KiB
C#
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
// Sprint: SPRINT_4100_0006_0001 - Crypto Plugin CLI Architecture
|
|
// Task: T3 - Create CryptoCommandGroup with sign/verify/profiles commands
|
|
|
|
using System.CommandLine;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using StellaOps.Cryptography;
|
|
|
|
namespace StellaOps.Cli.Commands;
|
|
|
|
/// <summary>
|
|
/// CLI commands for cryptographic operations with regional compliance support.
|
|
/// Supports GOST (Russia), eIDAS (EU), SM (China), and international crypto.
|
|
/// </summary>
|
|
internal static class CryptoCommandGroup
|
|
{
|
|
/// <summary>
|
|
/// Build the crypto command group with sign/verify/profiles subcommands.
|
|
/// </summary>
|
|
public static Command BuildCryptoCommand(
|
|
IServiceProvider serviceProvider,
|
|
Option<bool> verboseOption,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
var command = new Command("crypto", "Cryptographic operations (sign, verify, profiles)");
|
|
|
|
command.Add(BuildSignCommand(serviceProvider, verboseOption, cancellationToken));
|
|
command.Add(BuildVerifyCommand(serviceProvider, verboseOption, cancellationToken));
|
|
command.Add(BuildProfilesCommand(serviceProvider, verboseOption, cancellationToken));
|
|
|
|
return command;
|
|
}
|
|
|
|
private static Command BuildSignCommand(
|
|
IServiceProvider serviceProvider,
|
|
Option<bool> verboseOption,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
var command = new Command("sign", "Sign artifacts using configured crypto provider");
|
|
|
|
var inputOption = new Option<string>("--input")
|
|
{
|
|
Description = "Path to file or artifact to sign",
|
|
Required = true
|
|
};
|
|
command.Add(inputOption);
|
|
|
|
var outputOption = new Option<string?>("--output")
|
|
{
|
|
Description = "Output path for signature (defaults to <input>.sig)"
|
|
};
|
|
command.Add(outputOption);
|
|
|
|
var providerOption = new Option<string?>("--provider")
|
|
{
|
|
Description = "Override crypto provider (e.g., gost-cryptopro, eidas-tsp, sm-remote)"
|
|
};
|
|
command.Add(providerOption);
|
|
|
|
var keyIdOption = new Option<string?>("--key-id")
|
|
{
|
|
Description = "Key identifier for signing operation"
|
|
};
|
|
command.Add(keyIdOption);
|
|
|
|
var formatOption = new Option<string?>("--format")
|
|
{
|
|
Description = "Signature format: dsse, jws, raw (default: dsse)"
|
|
};
|
|
command.Add(formatOption);
|
|
|
|
var detachedOption = new Option<bool>("--detached")
|
|
{
|
|
Description = "Create detached signature (default: true)"
|
|
};
|
|
command.Add(detachedOption);
|
|
|
|
command.Add(verboseOption);
|
|
|
|
command.SetAction(async (parseResult, ct) =>
|
|
{
|
|
var input = parseResult.GetValue(inputOption) ?? string.Empty;
|
|
var output = parseResult.GetValue(outputOption);
|
|
var provider = parseResult.GetValue(providerOption);
|
|
var keyId = parseResult.GetValue(keyIdOption);
|
|
var format = parseResult.GetValue(formatOption) ?? "dsse";
|
|
var detached = parseResult.GetValue(detachedOption);
|
|
var verbose = parseResult.GetValue(verboseOption);
|
|
|
|
return await CommandHandlers.HandleCryptoSignAsync(
|
|
serviceProvider,
|
|
input,
|
|
output,
|
|
provider,
|
|
keyId,
|
|
format,
|
|
detached,
|
|
verbose,
|
|
ct);
|
|
});
|
|
|
|
return command;
|
|
}
|
|
|
|
private static Command BuildVerifyCommand(
|
|
IServiceProvider serviceProvider,
|
|
Option<bool> verboseOption,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
var command = new Command("verify", "Verify signatures using configured crypto provider");
|
|
|
|
var inputOption = new Option<string>("--input")
|
|
{
|
|
Description = "Path to file or artifact to verify",
|
|
Required = true
|
|
};
|
|
command.Add(inputOption);
|
|
|
|
var signatureOption = new Option<string?>("--signature")
|
|
{
|
|
Description = "Path to signature file (defaults to <input>.sig)"
|
|
};
|
|
command.Add(signatureOption);
|
|
|
|
var providerOption = new Option<string?>("--provider")
|
|
{
|
|
Description = "Override crypto provider for verification"
|
|
};
|
|
command.Add(providerOption);
|
|
|
|
var trustPolicyOption = new Option<string?>("--trust-policy")
|
|
{
|
|
Description = "Path to trust policy YAML file"
|
|
};
|
|
command.Add(trustPolicyOption);
|
|
|
|
var formatOption = new Option<string?>("--format")
|
|
{
|
|
Description = "Signature format: dsse, jws, raw (default: auto-detect)"
|
|
};
|
|
command.Add(formatOption);
|
|
|
|
command.Add(verboseOption);
|
|
|
|
command.SetAction(async (parseResult, ct) =>
|
|
{
|
|
var input = parseResult.GetValue(inputOption) ?? string.Empty;
|
|
var signature = parseResult.GetValue(signatureOption);
|
|
var provider = parseResult.GetValue(providerOption);
|
|
var trustPolicy = parseResult.GetValue(trustPolicyOption);
|
|
var format = parseResult.GetValue(formatOption);
|
|
var verbose = parseResult.GetValue(verboseOption);
|
|
|
|
return await CommandHandlers.HandleCryptoVerifyAsync(
|
|
serviceProvider,
|
|
input,
|
|
signature,
|
|
provider,
|
|
trustPolicy,
|
|
format,
|
|
verbose,
|
|
ct);
|
|
});
|
|
|
|
return command;
|
|
}
|
|
|
|
private static Command BuildProfilesCommand(
|
|
IServiceProvider serviceProvider,
|
|
Option<bool> verboseOption,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
var command = new Command("profiles", "List available crypto providers and profiles");
|
|
|
|
var showDetailsOption = new Option<bool>("--details")
|
|
{
|
|
Description = "Show detailed provider capabilities"
|
|
};
|
|
command.Add(showDetailsOption);
|
|
|
|
var providerFilterOption = new Option<string?>("--provider")
|
|
{
|
|
Description = "Filter by provider name"
|
|
};
|
|
command.Add(providerFilterOption);
|
|
|
|
var testOption = new Option<bool>("--test")
|
|
{
|
|
Description = "Run provider diagnostics and connectivity tests"
|
|
};
|
|
command.Add(testOption);
|
|
|
|
command.Add(verboseOption);
|
|
|
|
command.SetAction(async (parseResult, ct) =>
|
|
{
|
|
var showDetails = parseResult.GetValue(showDetailsOption);
|
|
var providerFilter = parseResult.GetValue(providerFilterOption);
|
|
var test = parseResult.GetValue(testOption);
|
|
var verbose = parseResult.GetValue(verboseOption);
|
|
|
|
return await CommandHandlers.HandleCryptoProfilesAsync(
|
|
serviceProvider,
|
|
showDetails,
|
|
providerFilter,
|
|
test,
|
|
verbose,
|
|
ct);
|
|
});
|
|
|
|
return command;
|
|
}
|
|
}
|