Files
git.stella-ops.org/src/Scanner/StellaOps.Scanner.Worker/Options/ScannerWorkerOptions.cs
StellaOps Bot 37cba83708
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Export Center CI / export-ci (push) Has been cancelled
devportal-offline / build-offline (push) Has been cancelled
up
2025-12-03 00:10:19 +02:00

245 lines
7.9 KiB
C#

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using StellaOps.Configuration;
using StellaOps.Scanner.Core.Contracts;
namespace StellaOps.Scanner.Worker.Options;
public sealed class ScannerWorkerOptions
{
public const string SectionName = "Scanner:Worker";
public int MaxConcurrentJobs { get; set; } = 2;
public QueueOptions Queue { get; } = new();
public PollingOptions Polling { get; } = new();
public AuthorityOptions Authority { get; } = new();
public TelemetryOptions Telemetry { get; } = new();
public ShutdownOptions Shutdown { get; } = new();
public AnalyzerOptions Analyzers { get; } = new();
public StellaOpsCryptoOptions Crypto { get; } = new();
public SigningOptions Signing { get; } = new();
public DeterminismOptions Determinism { get; } = new();
public sealed class QueueOptions
{
public int MaxAttempts { get; set; } = 5;
public double HeartbeatSafetyFactor { get; set; } = 3.0;
public int MaxHeartbeatJitterMilliseconds { get; set; } = 750;
public IReadOnlyList<TimeSpan> HeartbeatRetryDelays => _heartbeatRetryDelays;
public TimeSpan MinHeartbeatInterval { get; set; } = TimeSpan.FromSeconds(10);
public TimeSpan MaxHeartbeatInterval { get; set; } = TimeSpan.FromSeconds(30);
public void SetHeartbeatRetryDelays(IEnumerable<TimeSpan> delays)
{
_heartbeatRetryDelays = NormalizeDelays(delays);
}
internal IReadOnlyList<TimeSpan> NormalizedHeartbeatRetryDelays => _heartbeatRetryDelays;
private static IReadOnlyList<TimeSpan> NormalizeDelays(IEnumerable<TimeSpan> delays)
{
var buffer = new List<TimeSpan>();
foreach (var delay in delays)
{
if (delay <= TimeSpan.Zero)
{
continue;
}
buffer.Add(delay);
}
buffer.Sort();
return new ReadOnlyCollection<TimeSpan>(buffer);
}
private IReadOnlyList<TimeSpan> _heartbeatRetryDelays = new ReadOnlyCollection<TimeSpan>(new TimeSpan[]
{
TimeSpan.FromSeconds(2),
TimeSpan.FromSeconds(5),
TimeSpan.FromSeconds(10),
});
}
public sealed class PollingOptions
{
public TimeSpan InitialDelay { get; set; } = TimeSpan.FromMilliseconds(200);
public TimeSpan MaxDelay { get; set; } = TimeSpan.FromSeconds(5);
public double JitterRatio { get; set; } = 0.2;
}
public sealed class AuthorityOptions
{
public bool Enabled { get; set; }
public string? Issuer { get; set; }
public string? ClientId { get; set; }
public string? ClientSecret { get; set; }
public bool RequireHttpsMetadata { get; set; } = true;
public string? MetadataAddress { get; set; }
public int BackchannelTimeoutSeconds { get; set; } = 20;
public int TokenClockSkewSeconds { get; set; } = 30;
public IList<string> Scopes { get; } = new List<string> { "scanner.scan" };
public ResilienceOptions Resilience { get; } = new();
}
public sealed class ResilienceOptions
{
public bool? EnableRetries { get; set; }
public IList<TimeSpan> RetryDelays { get; } = new List<TimeSpan>
{
TimeSpan.FromMilliseconds(250),
TimeSpan.FromMilliseconds(500),
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(5),
};
public bool? AllowOfflineCacheFallback { get; set; }
public TimeSpan? OfflineCacheTolerance { get; set; }
}
public sealed class TelemetryOptions
{
public bool EnableLogging { get; set; } = true;
public bool EnableTelemetry { get; set; } = true;
public bool EnableTracing { get; set; }
public bool EnableMetrics { get; set; } = true;
public string ServiceName { get; set; } = "stellaops-scanner-worker";
public string? OtlpEndpoint { get; set; }
public bool ExportConsole { get; set; }
public IDictionary<string, string?> ResourceAttributes { get; } = new ConcurrentDictionary<string, string?>(StringComparer.OrdinalIgnoreCase);
}
public sealed class ShutdownOptions
{
public TimeSpan Timeout { get; set; } = TimeSpan.FromSeconds(30);
}
public sealed class AnalyzerOptions
{
public AnalyzerOptions()
{
PluginDirectories = new List<string>
{
Path.Combine("plugins", "scanner", "analyzers", "os"),
};
LanguagePluginDirectories = new List<string>
{
Path.Combine("plugins", "scanner", "analyzers", "lang"),
};
}
public IList<string> PluginDirectories { get; }
public IList<string> LanguagePluginDirectories { get; }
public string RootFilesystemMetadataKey { get; set; } = ScanMetadataKeys.RootFilesystemPath;
public string WorkspaceMetadataKey { get; set; } = ScanMetadataKeys.WorkspacePath;
public string EntryTraceConfigMetadataKey { get; set; } = ScanMetadataKeys.ImageConfigPath;
public string EntryTraceLayerDirectoriesMetadataKey { get; set; } = ScanMetadataKeys.LayerDirectories;
public string EntryTraceLayerArchivesMetadataKey { get; set; } = ScanMetadataKeys.LayerArchives;
public string EntryTraceProcRootMetadataKey { get; set; } = ScanMetadataKeys.RuntimeProcRoot;
}
public sealed class DeterminismOptions
{
/// <summary>
/// If true, the worker uses a fixed clock to ensure deterministic timestamps.
/// </summary>
public bool FixedClock { get; set; }
/// <summary>
/// Fixed UTC timestamp to emit when FixedClock is enabled. Defaults to Unix epoch.
/// </summary>
public DateTimeOffset FixedInstantUtc { get; set; } = DateTimeOffset.UnixEpoch;
/// <summary>
/// Optional seed for RNG-based components when determinism is required.
/// </summary>
public int? RngSeed { get; set; }
/// <summary>
/// If true, trims noisy log fields (duration, PIDs) to stable placeholders.
/// </summary>
public bool FilterLogs { get; set; }
/// <summary>
/// Optional hard cap for in-flight jobs to keep replay runs hermetic.
/// When set, the worker will clamp MaxConcurrentJobs to this value.
/// </summary>
public int? ConcurrencyLimit { get; set; }
}
public sealed class SigningOptions
{
/// <summary>
/// Enable DSSE signing for surface artifacts (composition recipe, layer fragments).
/// When disabled, the worker will fall back to deterministic hash envelopes.
/// </summary>
public bool EnableDsseSigning { get; set; }
/// <summary>
/// Identifier recorded in DSSE signatures.
/// </summary>
public string KeyId { get; set; } = "scanner-hmac";
/// <summary>
/// Shared secret material for HMAC-based DSSE signatures (base64 or hex).
/// Prefer <see cref=\"SharedSecretFile\"/> for file-based loading.
/// </summary>
public string? SharedSecret { get; set; }
/// <summary>
/// Optional path to a file containing the shared secret (base64 or hex).
/// </summary>
public string? SharedSecretFile { get; set; }
/// <summary>
/// Allow deterministic fallback when signing is enabled but no secret is provided.
/// Keeps offline determinism while avoiding hard failures in sealed-mode runs.
/// </summary>
public bool AllowDeterministicFallback { get; set; } = true;
}
}