Files
git.stella-ops.org/src/Scanner/__Libraries/StellaOps.Scanner.Explainability/Assumptions/AssumptionSet.cs
StellaOps Bot 5146204f1b feat: add security sink detection patterns for JavaScript/TypeScript
- Introduced `sink-detect.js` with various security sink detection patterns categorized by type (e.g., command injection, SQL injection, file operations).
- Implemented functions to build a lookup map for fast sink detection and to match sink calls against known patterns.
- Added `package-lock.json` for dependency management.
2025-12-22 23:21:21 +02:00

120 lines
3.8 KiB
C#

// SPDX-License-Identifier: AGPL-3.0-or-later
// Copyright (c) StellaOps
using System.Collections.Immutable;
namespace StellaOps.Scanner.Explainability.Assumptions;
/// <summary>
/// A collection of assumptions associated with a finding or analysis context.
/// Provides methods for querying and validating assumptions.
/// </summary>
public sealed record AssumptionSet
{
/// <summary>
/// The unique identifier for this assumption set.
/// </summary>
public required string Id { get; init; }
/// <summary>
/// The assumptions in this set, keyed by category and key.
/// </summary>
public ImmutableArray<Assumption> Assumptions { get; init; } = [];
/// <summary>
/// When this assumption set was created.
/// </summary>
public required DateTimeOffset CreatedAt { get; init; }
/// <summary>
/// Optional context identifier (e.g., finding ID, image digest).
/// </summary>
public string? ContextId { get; init; }
/// <summary>
/// Gets all assumptions of a specific category.
/// </summary>
public IEnumerable<Assumption> GetByCategory(AssumptionCategory category) =>
Assumptions.Where(a => a.Category == category);
/// <summary>
/// Gets a specific assumption by category and key.
/// </summary>
public Assumption? Get(AssumptionCategory category, string key) =>
Assumptions.FirstOrDefault(a => a.Category == category &&
string.Equals(a.Key, key, StringComparison.OrdinalIgnoreCase));
/// <summary>
/// Returns the overall confidence level (minimum of all assumptions).
/// </summary>
public ConfidenceLevel OverallConfidence =>
Assumptions.Length == 0
? ConfidenceLevel.Low
: Assumptions.Min(a => a.Confidence);
/// <summary>
/// Returns the count of validated assumptions.
/// </summary>
public int ValidatedCount => Assumptions.Count(a => a.IsValidated);
/// <summary>
/// Returns the count of contradicted assumptions.
/// </summary>
public int ContradictedCount => Assumptions.Count(a => a.IsContradicted);
/// <summary>
/// Returns true if any assumption is contradicted by observed evidence.
/// </summary>
public bool HasContradictions => Assumptions.Any(a => a.IsContradicted);
/// <summary>
/// Returns the validation ratio (validated / total with observations).
/// </summary>
public double ValidationRatio
{
get
{
var withObservations = Assumptions.Count(a => a.ObservedValue is not null);
return withObservations == 0 ? 0.0 : (double)ValidatedCount / withObservations;
}
}
/// <summary>
/// Creates a new AssumptionSet with an additional assumption.
/// </summary>
public AssumptionSet WithAssumption(Assumption assumption) =>
this with { Assumptions = Assumptions.Add(assumption) };
/// <summary>
/// Creates a new AssumptionSet with updated observation for an assumption.
/// </summary>
public AssumptionSet WithObservation(AssumptionCategory category, string key, string observedValue)
{
var index = Assumptions.FindIndex(a =>
a.Category == category &&
string.Equals(a.Key, key, StringComparison.OrdinalIgnoreCase));
if (index < 0)
return this;
var updated = Assumptions[index] with { ObservedValue = observedValue };
return this with { Assumptions = Assumptions.SetItem(index, updated) };
}
}
/// <summary>
/// Extension methods for ImmutableArray to support FindIndex.
/// </summary>
internal static class ImmutableArrayExtensions
{
public static int FindIndex<T>(this ImmutableArray<T> array, Func<T, bool> predicate)
{
for (int i = 0; i < array.Length; i++)
{
if (predicate(array[i]))
return i;
}
return -1;
}
}