feat: Implement Wine CSP HTTP provider for GOST cryptographic operations
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled

- Added WineCspHttpProvider class to interface with Wine-hosted CryptoPro CSP.
- Implemented ICryptoProvider, ICryptoProviderDiagnostics, and IDisposable interfaces.
- Introduced WineCspHttpSigner and WineCspHttpHasher for signing and hashing operations.
- Created WineCspProviderOptions for configuration settings including service URL and key options.
- Developed CryptoProGostSigningService to handle GOST signing operations and key management.
- Implemented HTTP service for the Wine CSP with endpoints for signing, verification, and hashing.
- Added Swagger documentation for API endpoints.
- Included health checks and error handling for service availability.
- Established DTOs for request and response models in the service.
This commit is contained in:
StellaOps Bot
2025-12-07 14:02:42 +02:00
parent 965cbf9574
commit bd2529502e
56 changed files with 9438 additions and 699 deletions

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
namespace StellaOps.Signals.Options;
@@ -9,18 +10,144 @@ namespace StellaOps.Signals.Options;
public sealed class SignalsArtifactStorageOptions
{
/// <summary>
/// Root directory used to persist raw callgraph artifacts.
/// Storage driver: "filesystem" (default) or "rustfs".
/// </summary>
public string Driver { get; set; } = SignalsStorageDrivers.FileSystem;
/// <summary>
/// Root directory used to persist raw callgraph artifacts (filesystem driver).
/// </summary>
public string RootPath { get; set; } = Path.Combine(AppContext.BaseDirectory, "callgraph-artifacts");
/// <summary>
/// Bucket name for CAS storage (RustFS driver).
/// Per CAS contract, signals uses "signals-data" bucket.
/// </summary>
public string BucketName { get; set; } = "signals-data";
/// <summary>
/// Root prefix within the bucket for callgraph artifacts.
/// </summary>
public string RootPrefix { get; set; } = "callgraphs";
/// <summary>
/// RustFS-specific options.
/// </summary>
public SignalsRustFsOptions RustFs { get; set; } = new();
/// <summary>
/// Additional headers to include in storage requests.
/// </summary>
public IDictionary<string, string> Headers { get; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
/// <summary>
/// Returns true if the filesystem driver is configured.
/// </summary>
public bool IsFileSystemDriver()
=> string.Equals(Driver, SignalsStorageDrivers.FileSystem, StringComparison.OrdinalIgnoreCase);
/// <summary>
/// Returns true if the RustFS driver is configured.
/// </summary>
public bool IsRustFsDriver()
=> string.Equals(Driver, SignalsStorageDrivers.RustFs, StringComparison.OrdinalIgnoreCase);
/// <summary>
/// Validates the configured values.
/// </summary>
public void Validate()
{
if (string.IsNullOrWhiteSpace(RootPath))
if (!IsFileSystemDriver() && !IsRustFsDriver())
{
throw new InvalidOperationException("Signals artifact storage path must be configured.");
throw new InvalidOperationException($"Signals storage driver '{Driver}' is not supported. Use '{SignalsStorageDrivers.FileSystem}' or '{SignalsStorageDrivers.RustFs}'.");
}
if (IsFileSystemDriver() && string.IsNullOrWhiteSpace(RootPath))
{
throw new InvalidOperationException("Signals artifact storage path must be configured for filesystem driver.");
}
if (IsRustFsDriver())
{
RustFs ??= new SignalsRustFsOptions();
RustFs.Validate();
if (string.IsNullOrWhiteSpace(BucketName))
{
throw new InvalidOperationException("Signals storage bucket name must be configured for RustFS driver.");
}
}
}
}
/// <summary>
/// RustFS-specific configuration options.
/// </summary>
public sealed class SignalsRustFsOptions
{
/// <summary>
/// Base URL for the RustFS service (e.g., http://localhost:8180/api/v1).
/// </summary>
public string BaseUrl { get; set; } = string.Empty;
/// <summary>
/// Allow insecure TLS connections (development only).
/// </summary>
public bool AllowInsecureTls { get; set; }
/// <summary>
/// API key for authentication.
/// </summary>
public string? ApiKey { get; set; }
/// <summary>
/// Header name for the API key (e.g., "X-API-Key").
/// </summary>
public string ApiKeyHeader { get; set; } = "X-API-Key";
/// <summary>
/// HTTP request timeout.
/// </summary>
public TimeSpan Timeout { get; set; } = TimeSpan.FromSeconds(60);
/// <summary>
/// Validates the configured values.
/// </summary>
public void Validate()
{
if (string.IsNullOrWhiteSpace(BaseUrl))
{
throw new InvalidOperationException("RustFS baseUrl must be configured.");
}
if (!Uri.TryCreate(BaseUrl, UriKind.Absolute, out var uri))
{
throw new InvalidOperationException("RustFS baseUrl must be an absolute URI.");
}
if (!string.Equals(uri.Scheme, Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase)
&& !string.Equals(uri.Scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException("RustFS baseUrl must use HTTP or HTTPS.");
}
if (Timeout <= TimeSpan.Zero)
{
throw new InvalidOperationException("RustFS timeout must be greater than zero.");
}
if (!string.IsNullOrWhiteSpace(ApiKeyHeader) && string.IsNullOrWhiteSpace(ApiKey))
{
throw new InvalidOperationException("RustFS API key header name requires a non-empty API key.");
}
}
}
/// <summary>
/// Supported storage driver names.
/// </summary>
public static class SignalsStorageDrivers
{
public const string FileSystem = "filesystem";
public const string RustFs = "rustfs";
}