feat: Implement vulnerability token signing and verification utilities
Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled

- Added VulnTokenSigner for signing JWT tokens with specified algorithms and keys.
- Introduced VulnTokenUtilities for resolving tenant and subject claims, and sanitizing context dictionaries.
- Created VulnTokenVerificationUtilities for parsing tokens, verifying signatures, and deserializing payloads.
- Developed VulnWorkflowAntiForgeryTokenIssuer for issuing anti-forgery tokens with configurable options.
- Implemented VulnWorkflowAntiForgeryTokenVerifier for verifying anti-forgery tokens and validating payloads.
- Added AuthorityVulnerabilityExplorerOptions to manage configuration for vulnerability explorer features.
- Included tests for FilesystemPackRunDispatcher to ensure proper job handling under egress policy restrictions.
This commit is contained in:
master
2025-11-03 10:02:29 +02:00
parent bf2bf4b395
commit b1e78fe412
215 changed files with 19441 additions and 12185 deletions

View File

@@ -1,18 +1,18 @@
namespace StellaOps.Scheduler.WebService.Options;
/// <summary>
/// Scheduler WebService event options (outbound + inbound).
/// </summary>
namespace StellaOps.Scheduler.WebService.Options;
/// <summary>
/// Scheduler WebService event options (outbound + inbound).
/// </summary>
using System;
using System.Collections.Generic;
public sealed class SchedulerEventsOptions
{
public GraphJobEventsOptions GraphJobs { get; set; } = new();
public SchedulerInboundWebhooksOptions Webhooks { get; set; } = new();
}
public sealed class SchedulerEventsOptions
{
public GraphJobEventsOptions GraphJobs { get; set; } = new();
public SchedulerInboundWebhooksOptions Webhooks { get; set; } = new();
}
public sealed class GraphJobEventsOptions
{
/// <summary>
@@ -50,91 +50,91 @@ public sealed class GraphJobEventsOptions
/// </summary>
public IDictionary<string, string> DriverSettings { get; set; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
}
public sealed class SchedulerInboundWebhooksOptions
{
public SchedulerWebhookOptions Feedser { get; set; } = SchedulerWebhookOptions.CreateDefault("feedser");
public SchedulerWebhookOptions Vexer { get; set; } = SchedulerWebhookOptions.CreateDefault("vexer");
}
public sealed class SchedulerWebhookOptions
{
private const string DefaultSignatureHeader = "X-Scheduler-Signature";
public SchedulerWebhookOptions()
{
SignatureHeader = DefaultSignatureHeader;
}
public bool Enabled { get; set; } = true;
/// <summary>
/// Require a client certificate to be presented (mTLS). Optional when HMAC is configured.
/// </summary>
public bool RequireClientCertificate { get; set; }
/// <summary>
/// Shared secret (Base64 or raw text) for HMAC-SHA256 signatures. Required if <see cref="RequireClientCertificate"/> is false.
/// </summary>
public string? HmacSecret { get; set; }
/// <summary>
/// Header name carrying the webhook signature (defaults to <c>X-Scheduler-Signature</c>).
/// </summary>
public string SignatureHeader { get; set; }
/// <summary>
/// Maximum number of accepted requests per sliding window.
/// </summary>
public int RateLimitRequests { get; set; } = 60;
/// <summary>
/// Sliding window duration in seconds for the rate limiter.
/// </summary>
public int RateLimitWindowSeconds { get; set; } = 60;
/// <summary>
/// Optional label used for logging/diagnostics; populated via <see cref="CreateDefault"/>.
/// </summary>
public string Name { get; set; } = string.Empty;
public static SchedulerWebhookOptions CreateDefault(string name)
=> new()
{
Name = name,
SignatureHeader = DefaultSignatureHeader,
RateLimitRequests = 120,
RateLimitWindowSeconds = 60
};
public void Validate()
{
if (!Enabled)
{
return;
}
if (string.IsNullOrWhiteSpace(SignatureHeader))
{
throw new InvalidOperationException($"Scheduler webhook '{Name}' must specify a signature header when enabled.");
}
if (!RequireClientCertificate && string.IsNullOrWhiteSpace(HmacSecret))
{
throw new InvalidOperationException($"Scheduler webhook '{Name}' must configure either HMAC secret or mTLS enforcement.");
}
if (RateLimitRequests <= 0)
{
throw new InvalidOperationException($"Scheduler webhook '{Name}' must configure a positive rate limit.");
}
if (RateLimitWindowSeconds <= 0)
{
throw new InvalidOperationException($"Scheduler webhook '{Name}' must configure a rate limit window greater than zero seconds.");
}
}
public TimeSpan GetRateLimitWindow() => TimeSpan.FromSeconds(RateLimitWindowSeconds <= 0 ? 60 : RateLimitWindowSeconds);
}
public sealed class SchedulerInboundWebhooksOptions
{
public SchedulerWebhookOptions Conselier { get; set; } = SchedulerWebhookOptions.CreateDefault("conselier");
public SchedulerWebhookOptions Excitor { get; set; } = SchedulerWebhookOptions.CreateDefault("excitor");
}
public sealed class SchedulerWebhookOptions
{
private const string DefaultSignatureHeader = "X-Scheduler-Signature";
public SchedulerWebhookOptions()
{
SignatureHeader = DefaultSignatureHeader;
}
public bool Enabled { get; set; } = true;
/// <summary>
/// Require a client certificate to be presented (mTLS). Optional when HMAC is configured.
/// </summary>
public bool RequireClientCertificate { get; set; }
/// <summary>
/// Shared secret (Base64 or raw text) for HMAC-SHA256 signatures. Required if <see cref="RequireClientCertificate"/> is false.
/// </summary>
public string? HmacSecret { get; set; }
/// <summary>
/// Header name carrying the webhook signature (defaults to <c>X-Scheduler-Signature</c>).
/// </summary>
public string SignatureHeader { get; set; }
/// <summary>
/// Maximum number of accepted requests per sliding window.
/// </summary>
public int RateLimitRequests { get; set; } = 60;
/// <summary>
/// Sliding window duration in seconds for the rate limiter.
/// </summary>
public int RateLimitWindowSeconds { get; set; } = 60;
/// <summary>
/// Optional label used for logging/diagnostics; populated via <see cref="CreateDefault"/>.
/// </summary>
public string Name { get; set; } = string.Empty;
public static SchedulerWebhookOptions CreateDefault(string name)
=> new()
{
Name = name,
SignatureHeader = DefaultSignatureHeader,
RateLimitRequests = 120,
RateLimitWindowSeconds = 60
};
public void Validate()
{
if (!Enabled)
{
return;
}
if (string.IsNullOrWhiteSpace(SignatureHeader))
{
throw new InvalidOperationException($"Scheduler webhook '{Name}' must specify a signature header when enabled.");
}
if (!RequireClientCertificate && string.IsNullOrWhiteSpace(HmacSecret))
{
throw new InvalidOperationException($"Scheduler webhook '{Name}' must configure either HMAC secret or mTLS enforcement.");
}
if (RateLimitRequests <= 0)
{
throw new InvalidOperationException($"Scheduler webhook '{Name}' must configure a positive rate limit.");
}
if (RateLimitWindowSeconds <= 0)
{
throw new InvalidOperationException($"Scheduler webhook '{Name}' must configure a rate limit window greater than zero seconds.");
}
}
public TimeSpan GetRateLimitWindow() => TimeSpan.FromSeconds(RateLimitWindowSeconds <= 0 ? 60 : RateLimitWindowSeconds);
}