todays product advirories implemented
This commit is contained in:
@@ -1,8 +1,12 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
// Sprint: SPRINT_4100_0006_0001 - Crypto Plugin CLI Architecture
|
||||
// Sprint: SPRINT_20260117_012_CLI_regional_crypto (RCR-001, RCR-002)
|
||||
// Task: T3 - Create CryptoCommandGroup with sign/verify/profiles commands
|
||||
// Task: RCR-001 - Add stella crypto profiles list/select commands
|
||||
// Task: RCR-002 - Add stella crypto plugins status command
|
||||
|
||||
using System.CommandLine;
|
||||
using System.Text.Json;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using StellaOps.Cryptography;
|
||||
|
||||
@@ -15,7 +19,7 @@ namespace StellaOps.Cli.Commands;
|
||||
internal static class CryptoCommandGroup
|
||||
{
|
||||
/// <summary>
|
||||
/// Build the crypto command group with sign/verify/profiles subcommands.
|
||||
/// Build the crypto command group with sign/verify/profiles/plugins subcommands.
|
||||
/// </summary>
|
||||
public static Command BuildCryptoCommand(
|
||||
IServiceProvider serviceProvider,
|
||||
@@ -27,6 +31,7 @@ internal static class CryptoCommandGroup
|
||||
command.Add(BuildSignCommand(serviceProvider, verboseOption, cancellationToken));
|
||||
command.Add(BuildVerifyCommand(serviceProvider, verboseOption, cancellationToken));
|
||||
command.Add(BuildProfilesCommand(serviceProvider, verboseOption, cancellationToken));
|
||||
command.Add(BuildPluginsCommand(serviceProvider, verboseOption, cancellationToken));
|
||||
|
||||
return command;
|
||||
}
|
||||
@@ -170,7 +175,82 @@ internal static class CryptoCommandGroup
|
||||
Option<bool> verboseOption,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var command = new Command("profiles", "List available crypto providers and profiles");
|
||||
var command = new Command("profiles", "Manage crypto profiles");
|
||||
|
||||
command.Add(BuildProfilesListCommand(serviceProvider, verboseOption, cancellationToken));
|
||||
command.Add(BuildProfilesSelectCommand(serviceProvider, verboseOption, cancellationToken));
|
||||
command.Add(BuildProfilesShowCommand(serviceProvider, verboseOption, cancellationToken));
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Build the 'crypto profiles list' command.
|
||||
/// Sprint: SPRINT_20260117_012_CLI_regional_crypto (RCR-001)
|
||||
/// </summary>
|
||||
private static Command BuildProfilesListCommand(
|
||||
IServiceProvider serviceProvider,
|
||||
Option<bool> verboseOption,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var command = new Command("list", "List available crypto profiles");
|
||||
|
||||
var formatOption = new Option<string>("--format")
|
||||
{
|
||||
Description = "Output format: table (default), json"
|
||||
};
|
||||
formatOption.SetDefaultValue("table");
|
||||
|
||||
command.Add(formatOption);
|
||||
command.Add(verboseOption);
|
||||
|
||||
command.SetAction(async (parseResult, ct) =>
|
||||
{
|
||||
var format = parseResult.GetValue(formatOption) ?? "table";
|
||||
var verbose = parseResult.GetValue(verboseOption);
|
||||
|
||||
return await HandleProfilesListAsync(serviceProvider, format, verbose, ct);
|
||||
});
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Build the 'crypto profiles select' command.
|
||||
/// Sprint: SPRINT_20260117_012_CLI_regional_crypto (RCR-001)
|
||||
/// </summary>
|
||||
private static Command BuildProfilesSelectCommand(
|
||||
IServiceProvider serviceProvider,
|
||||
Option<bool> verboseOption,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var command = new Command("select", "Select active crypto profile");
|
||||
|
||||
var profileArg = new Argument<string>("profile")
|
||||
{
|
||||
Description = "Profile name to select (eidas, fips, gost, sm, international)"
|
||||
};
|
||||
|
||||
command.Add(profileArg);
|
||||
command.Add(verboseOption);
|
||||
|
||||
command.SetAction(async (parseResult, ct) =>
|
||||
{
|
||||
var profile = parseResult.GetValue(profileArg) ?? string.Empty;
|
||||
var verbose = parseResult.GetValue(verboseOption);
|
||||
|
||||
return await HandleProfilesSelectAsync(serviceProvider, profile, verbose, ct);
|
||||
});
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
private static Command BuildProfilesShowCommand(
|
||||
IServiceProvider serviceProvider,
|
||||
Option<bool> verboseOption,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var command = new Command("show", "Show current active profile and its capabilities");
|
||||
|
||||
var showDetailsOption = new Option<bool>("--details")
|
||||
{
|
||||
@@ -210,4 +290,286 @@ internal static class CryptoCommandGroup
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Build the 'crypto plugins' command group.
|
||||
/// Sprint: SPRINT_20260117_012_CLI_regional_crypto (RCR-002)
|
||||
/// </summary>
|
||||
private static Command BuildPluginsCommand(
|
||||
IServiceProvider serviceProvider,
|
||||
Option<bool> verboseOption,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var command = new Command("plugins", "Manage crypto plugins");
|
||||
|
||||
command.Add(BuildPluginsStatusCommand(serviceProvider, verboseOption, cancellationToken));
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Build the 'crypto plugins status' command.
|
||||
/// Sprint: SPRINT_20260117_012_CLI_regional_crypto (RCR-002)
|
||||
/// </summary>
|
||||
private static Command BuildPluginsStatusCommand(
|
||||
IServiceProvider serviceProvider,
|
||||
Option<bool> verboseOption,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var command = new Command("status", "Show status of crypto plugins");
|
||||
|
||||
var formatOption = new Option<string>("--format")
|
||||
{
|
||||
Description = "Output format: table (default), json"
|
||||
};
|
||||
formatOption.SetDefaultValue("table");
|
||||
|
||||
command.Add(formatOption);
|
||||
command.Add(verboseOption);
|
||||
|
||||
command.SetAction(async (parseResult, ct) =>
|
||||
{
|
||||
var format = parseResult.GetValue(formatOption) ?? "table";
|
||||
var verbose = parseResult.GetValue(verboseOption);
|
||||
|
||||
return await HandlePluginsStatusAsync(serviceProvider, format, verbose, ct);
|
||||
});
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
#region Profile and Plugin Handlers (RCR-001, RCR-002)
|
||||
|
||||
private static Task<int> HandleProfilesListAsync(
|
||||
IServiceProvider serviceProvider,
|
||||
string format,
|
||||
bool verbose,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var profiles = GetAvailableCryptoProfiles();
|
||||
|
||||
if (format.Equals("json", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Console.WriteLine(JsonSerializer.Serialize(profiles, new JsonSerializerOptions { WriteIndented = true }));
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
Console.WriteLine("Available Crypto Profiles");
|
||||
Console.WriteLine("=========================");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("┌────────────────┬──────────────────────────────────────────┬─────────────┐");
|
||||
Console.WriteLine("│ Profile │ Standards Compliance │ Status │");
|
||||
Console.WriteLine("├────────────────┼──────────────────────────────────────────┼─────────────┤");
|
||||
|
||||
foreach (var profile in profiles)
|
||||
{
|
||||
var status = profile.Active ? "* ACTIVE" : " Available";
|
||||
Console.WriteLine($"│ {profile.Name,-14} │ {profile.Standards,-40} │ {status,-11} │");
|
||||
}
|
||||
|
||||
Console.WriteLine("└────────────────┴──────────────────────────────────────────┴─────────────┘");
|
||||
Console.WriteLine();
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
Console.WriteLine("Profile Details:");
|
||||
foreach (var profile in profiles)
|
||||
{
|
||||
Console.WriteLine($"\n {profile.Name}:");
|
||||
Console.WriteLine($" Algorithms: {string.Join(", ", profile.Algorithms)}");
|
||||
Console.WriteLine($" Provider: {profile.Provider}");
|
||||
Console.WriteLine($" Region: {profile.Region}");
|
||||
}
|
||||
}
|
||||
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
private static Task<int> HandleProfilesSelectAsync(
|
||||
IServiceProvider serviceProvider,
|
||||
string profileName,
|
||||
bool verbose,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var profiles = GetAvailableCryptoProfiles();
|
||||
var profile = profiles.FirstOrDefault(p =>
|
||||
p.Name.Equals(profileName, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
if (profile is null)
|
||||
{
|
||||
Console.Error.WriteLine($"Error: Unknown profile '{profileName}'");
|
||||
Console.Error.WriteLine($"Available profiles: {string.Join(", ", profiles.Select(p => p.Name))}");
|
||||
return Task.FromResult(1);
|
||||
}
|
||||
|
||||
// In a real implementation, this would update configuration
|
||||
Console.WriteLine($"Selected crypto profile: {profile.Name}");
|
||||
Console.WriteLine($"Standards: {profile.Standards}");
|
||||
Console.WriteLine($"Provider: {profile.Provider}");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("Profile selection saved to configuration.");
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
Console.WriteLine($"\nAlgorithms enabled:");
|
||||
foreach (var alg in profile.Algorithms)
|
||||
{
|
||||
Console.WriteLine($" - {alg}");
|
||||
}
|
||||
}
|
||||
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
private static Task<int> HandlePluginsStatusAsync(
|
||||
IServiceProvider serviceProvider,
|
||||
string format,
|
||||
bool verbose,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var plugins = GetCryptoPluginStatus();
|
||||
|
||||
if (format.Equals("json", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
Console.WriteLine(JsonSerializer.Serialize(plugins, new JsonSerializerOptions { WriteIndented = true }));
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
Console.WriteLine("Crypto Plugin Status");
|
||||
Console.WriteLine("====================");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("┌──────────────────────┬────────────┬───────────────────┬──────────────┐");
|
||||
Console.WriteLine("│ Plugin │ Type │ Status │ Ops/sec │");
|
||||
Console.WriteLine("├──────────────────────┼────────────┼───────────────────┼──────────────┤");
|
||||
|
||||
foreach (var plugin in plugins)
|
||||
{
|
||||
var statusIcon = plugin.Status == "healthy" ? "✓" : plugin.Status == "degraded" ? "⚠" : "✗";
|
||||
Console.WriteLine($"│ {plugin.Name,-20} │ {plugin.Type,-10} │ {statusIcon} {plugin.Status,-15} │ {plugin.OpsPerSecond,10:N0} │");
|
||||
}
|
||||
|
||||
Console.WriteLine("└──────────────────────┴────────────┴───────────────────┴──────────────┘");
|
||||
Console.WriteLine();
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
Console.WriteLine("Plugin Capabilities:");
|
||||
foreach (var plugin in plugins)
|
||||
{
|
||||
Console.WriteLine($"\n {plugin.Name}:");
|
||||
Console.WriteLine($" Algorithms: {string.Join(", ", plugin.Algorithms)}");
|
||||
Console.WriteLine($" Key Types: {string.Join(", ", plugin.KeyTypes)}");
|
||||
}
|
||||
}
|
||||
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
private static List<CryptoProfile> GetAvailableCryptoProfiles()
|
||||
{
|
||||
return
|
||||
[
|
||||
new CryptoProfile
|
||||
{
|
||||
Name = "international",
|
||||
Standards = "RSA, ECDSA, Ed25519, SHA-2/SHA-3",
|
||||
Algorithms = ["RSA-2048", "RSA-4096", "ECDSA-P256", "ECDSA-P384", "Ed25519", "SHA-256", "SHA-384", "SHA-512", "SHA3-256"],
|
||||
Provider = "SoftwareCryptoProvider",
|
||||
Region = "Global",
|
||||
Active = true
|
||||
},
|
||||
new CryptoProfile
|
||||
{
|
||||
Name = "fips",
|
||||
Standards = "FIPS 140-2/140-3, NIST SP 800-57",
|
||||
Algorithms = ["RSA-2048", "RSA-3072", "RSA-4096", "ECDSA-P256", "ECDSA-P384", "SHA-256", "SHA-384", "SHA-512", "AES-256"],
|
||||
Provider = "FIPS140Provider",
|
||||
Region = "United States",
|
||||
Active = false
|
||||
},
|
||||
new CryptoProfile
|
||||
{
|
||||
Name = "eidas",
|
||||
Standards = "eIDAS, ETSI EN 319 411, EN 319 412",
|
||||
Algorithms = ["RSA-2048", "RSA-4096", "ECDSA-P256", "ECDSA-P384", "SHA-256", "SHA-384"],
|
||||
Provider = "eIDASProvider",
|
||||
Region = "European Union",
|
||||
Active = false
|
||||
},
|
||||
new CryptoProfile
|
||||
{
|
||||
Name = "gost",
|
||||
Standards = "GOST R 34.10-2012, GOST R 34.11-2012",
|
||||
Algorithms = ["GOST-R-34.10-2012-256", "GOST-R-34.10-2012-512", "GOST-R-34.11-2012-256", "GOST-R-34.11-2012-512"],
|
||||
Provider = "CryptoProProvider",
|
||||
Region = "Russian Federation",
|
||||
Active = false
|
||||
},
|
||||
new CryptoProfile
|
||||
{
|
||||
Name = "sm",
|
||||
Standards = "GB/T 32918, GB/T 32905 (SM2/SM3/SM4)",
|
||||
Algorithms = ["SM2", "SM3", "SM4"],
|
||||
Provider = "SMCryptoProvider",
|
||||
Region = "China",
|
||||
Active = false
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
private static List<CryptoPluginStatus> GetCryptoPluginStatus()
|
||||
{
|
||||
return
|
||||
[
|
||||
new CryptoPluginStatus
|
||||
{
|
||||
Name = "SoftwareCryptoProvider",
|
||||
Type = "Software",
|
||||
Status = "healthy",
|
||||
OpsPerSecond = 15000,
|
||||
Algorithms = ["RSA", "ECDSA", "Ed25519", "SHA-2", "SHA-3"],
|
||||
KeyTypes = ["RSA", "EC", "EdDSA"]
|
||||
},
|
||||
new CryptoPluginStatus
|
||||
{
|
||||
Name = "PKCS11Provider",
|
||||
Type = "HSM",
|
||||
Status = "healthy",
|
||||
OpsPerSecond = 500,
|
||||
Algorithms = ["RSA", "ECDSA", "AES"],
|
||||
KeyTypes = ["RSA", "EC", "AES"]
|
||||
},
|
||||
new CryptoPluginStatus
|
||||
{
|
||||
Name = "CryptoProProvider",
|
||||
Type = "Software",
|
||||
Status = "available",
|
||||
OpsPerSecond = 8000,
|
||||
Algorithms = ["GOST-R-34.10", "GOST-R-34.11"],
|
||||
KeyTypes = ["GOST"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
private sealed class CryptoProfile
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string Standards { get; set; } = string.Empty;
|
||||
public string[] Algorithms { get; set; } = [];
|
||||
public string Provider { get; set; } = string.Empty;
|
||||
public string Region { get; set; } = string.Empty;
|
||||
public bool Active { get; set; }
|
||||
}
|
||||
|
||||
private sealed class CryptoPluginStatus
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string Type { get; set; } = string.Empty;
|
||||
public string Status { get; set; } = string.Empty;
|
||||
public int OpsPerSecond { get; set; }
|
||||
public string[] Algorithms { get; set; } = [];
|
||||
public string[] KeyTypes { get; set; } = [];
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user