namespace StellaOps.PolicyDsl; /// /// Provides signal values for policy evaluation. /// public sealed class SignalContext { private readonly Dictionary _signals; /// /// Creates an empty signal context. /// public SignalContext() { _signals = new Dictionary(StringComparer.Ordinal); } /// /// Creates a signal context with initial values. /// /// Initial signal values. public SignalContext(IDictionary signals) { _signals = new Dictionary(signals, StringComparer.Ordinal); } /// /// Gets whether a signal exists. /// /// The signal name. /// True if the signal exists. public bool HasSignal(string name) => _signals.ContainsKey(name); /// /// Gets a signal value. /// /// The signal name. /// The signal value, or null if not found. public object? GetSignal(string name) => _signals.TryGetValue(name, out var value) ? value : null; /// /// Gets a signal value as a specific type. /// /// The expected type. /// The signal name. /// The signal value, or default if not found or wrong type. public T? GetSignal(string name) => _signals.TryGetValue(name, out var value) && value is T t ? t : default; /// /// Sets a signal value. /// /// The signal name. /// The signal value. /// This context for chaining. public SignalContext SetSignal(string name, object? value) { _signals[name] = value; return this; } /// /// Removes a signal. /// /// The signal name. /// This context for chaining. public SignalContext RemoveSignal(string name) { _signals.Remove(name); return this; } /// /// Gets all signal names. /// public IEnumerable SignalNames => _signals.Keys; /// /// Gets all signals as a read-only dictionary. /// public IReadOnlyDictionary Signals => _signals; /// /// Creates a copy of this context. /// /// A new context with the same signals. public SignalContext Clone() => new(_signals); /// /// Creates a signal context builder for fluent construction. /// /// A new builder. public static SignalContextBuilder Builder() => new(); } /// /// Builder for creating signal contexts with fluent API. /// public sealed class SignalContextBuilder { private readonly Dictionary _signals = new(StringComparer.Ordinal); /// /// Adds a signal to the context. /// /// The signal name. /// The signal value. /// This builder for chaining. public SignalContextBuilder WithSignal(string name, object? value) { _signals[name] = value; return this; } /// /// Adds a boolean signal to the context. /// /// The signal name. /// The boolean value. /// This builder for chaining. public SignalContextBuilder WithFlag(string name, bool value = true) { _signals[name] = value; return this; } /// /// Adds a numeric signal to the context. /// /// The signal name. /// The numeric value. /// This builder for chaining. public SignalContextBuilder WithNumber(string name, decimal value) { _signals[name] = value; return this; } /// /// Adds a string signal to the context. /// /// The signal name. /// The string value. /// This builder for chaining. public SignalContextBuilder WithString(string name, string value) { _signals[name] = value; return this; } /// /// Adds a nested object signal to the context. /// /// The signal name. /// The nested properties. /// This builder for chaining. public SignalContextBuilder WithObject(string name, IDictionary properties) { _signals[name] = new Dictionary(properties, StringComparer.Ordinal); return this; } /// /// Adds common finding signals. /// /// The finding severity (e.g., "critical", "high", "medium", "low"). /// The confidence score (0.0 to 1.0). /// Optional CVE identifier. /// This builder for chaining. public SignalContextBuilder WithFinding(string severity, decimal confidence, string? cveId = null) { _signals["finding"] = new Dictionary(StringComparer.Ordinal) { ["severity"] = severity, ["confidence"] = confidence, ["cve_id"] = cveId, }; return this; } /// /// Adds common reachability signals. /// /// The reachability state (e.g., "reachable", "unreachable", "unknown"). /// The confidence score (0.0 to 1.0). /// Whether there is runtime evidence. /// This builder for chaining. public SignalContextBuilder WithReachability(string state, decimal confidence, bool hasRuntimeEvidence = false) { _signals["reachability"] = new Dictionary(StringComparer.Ordinal) { ["state"] = state, ["confidence"] = confidence, ["has_runtime_evidence"] = hasRuntimeEvidence, }; return this; } /// /// Adds common trust score signals. /// /// The trust score (0.0 to 1.0). /// Whether the source is verified. /// This builder for chaining. public SignalContextBuilder WithTrustScore(decimal score, bool verified = false) { _signals["trust_score"] = score; _signals["trust_verified"] = verified; return this; } /// /// Builds the signal context. /// /// A new signal context with the configured signals. public SignalContext Build() => new(_signals); }