Refactor code structure for improved readability and maintainability; optimize performance in key functions.
This commit is contained in:
44
src/Scanner/__Libraries/StellaOps.Scanner.Triage/AGENTS.md
Normal file
44
src/Scanner/__Libraries/StellaOps.Scanner.Triage/AGENTS.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# StellaOps.Scanner.Triage — Agent Charter
|
||||
|
||||
## Mission
|
||||
Provide triage workflow infrastructure for the Scanner module:
|
||||
- Define and maintain Triage database schema (findings, decisions, evidence, snapshots) with EF Core migrations.
|
||||
- Support evidence-first workflow with signed decisions (DSSE envelopes) and audit trails.
|
||||
- Enable Smart-Diff through triage snapshots that capture finding state at points in time.
|
||||
- Provide models for VEX merge results, reachability analysis, and risk/lattice evaluations.
|
||||
|
||||
## Expectations
|
||||
- Coordinate with Scanner.WebService for REST API exposure, Policy for verdict evaluation, and Attestor for decision signing.
|
||||
- Maintain deterministic serialization for reproducible triage outcomes.
|
||||
- Keep database schema aligned with triage workflow requirements (lanes, verdicts, evidence types).
|
||||
- Update migrations and seed data when schema changes.
|
||||
|
||||
## Required Reading
|
||||
- `docs/modules/scanner/architecture.md`
|
||||
- `docs/product-advisories/21-Dec-2025 - How Top Scanners Shape Evidence‑First UX.md`
|
||||
- `docs/product-advisories/21-Dec-2025 - Designing Explainable Triage Workflows.md`
|
||||
- `docs/modules/platform/architecture-overview.md`
|
||||
|
||||
## Working Agreement
|
||||
- 1. Update task status to `DOING`/`DONE` in both corresponding sprint file `/docs/implplan/SPRINT_*.md` and the local `TASKS.md` when you start or finish work.
|
||||
- 2. Review this charter and the Required Reading documents before coding; confirm prerequisites are met.
|
||||
- 3. Keep changes deterministic (stable ordering, timestamps, hashes) and align with offline/air-gap expectations.
|
||||
- 4. Coordinate doc updates, tests, and cross-guild communication whenever contracts or workflows change.
|
||||
- 5. Revert to `TODO` if you pause the task without shipping changes; leave notes in commit/PR descriptions for context.
|
||||
|
||||
## Triage Schema Overview
|
||||
- **TriageFinding**: Core finding entity linking vulnerability to component, with computed lane and verdict
|
||||
- **TriageDecision**: Signed human decisions (mute-reach, mute-vex, exception, ack) with DSSE envelopes
|
||||
- **TriageEvidenceArtifact**: Content-addressable evidence store (VEX docs, witness paths, SBOM refs)
|
||||
- **TriageSnapshot**: Point-in-time captures for Smart-Diff baseline comparison
|
||||
- **TriageEffectiveVex**: Merged VEX status per finding with lattice provenance
|
||||
- **TriageReachabilityResult**: Static analysis outcomes (reachable, unreachable, unknown)
|
||||
- **TriageRiskResult**: Policy/lattice evaluation results
|
||||
|
||||
## Guardrails
|
||||
- All decisions must be DSSE-signed for non-repudiation.
|
||||
- Lane transitions must be deterministic and auditable.
|
||||
- Evidence artifacts must be content-addressable (stored by hash).
|
||||
- Snapshots must capture complete finding state for reproducible diffs.
|
||||
- Preserve determinism: sort outputs, normalize timestamps (UTC ISO-8601).
|
||||
- Keep Offline Kit parity in mind—document air-gapped workflows for any new feature.
|
||||
@@ -0,0 +1,144 @@
|
||||
using System.Collections.Immutable;
|
||||
|
||||
namespace StellaOps.Scanner.Triage.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a complete exploit path from artifact entry point to vulnerable symbol.
|
||||
/// Groups related findings that share the same attack chain.
|
||||
/// </summary>
|
||||
public sealed record ExploitPath
|
||||
{
|
||||
/// <summary>
|
||||
/// Stable deterministic ID for this path: hash(artifact + package + symbol + entryPoint).
|
||||
/// </summary>
|
||||
public required string PathId { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Artifact containing the vulnerable code.
|
||||
/// </summary>
|
||||
public required string ArtifactDigest { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Package containing the vulnerability.
|
||||
/// </summary>
|
||||
public required PackageRef Package { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The vulnerable symbol (function, method, class).
|
||||
/// </summary>
|
||||
public required VulnerableSymbol Symbol { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Entry point from which this path is reachable.
|
||||
/// </summary>
|
||||
public required EntryPoint EntryPoint { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// All CVEs affecting this path.
|
||||
/// </summary>
|
||||
public required ImmutableArray<string> CveIds { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Reachability status from lattice.
|
||||
/// </summary>
|
||||
public required ReachabilityStatus Reachability { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Aggregated CVSS/EPSS scores for this path.
|
||||
/// </summary>
|
||||
public required PathRiskScore RiskScore { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Evidence supporting this path.
|
||||
/// </summary>
|
||||
public required PathEvidence Evidence { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Active exceptions applying to this path.
|
||||
/// </summary>
|
||||
public ImmutableArray<ExceptionRef> ActiveExceptions { get; init; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Whether this path is "quiet" (all findings suppressed by exceptions/VEX).
|
||||
/// </summary>
|
||||
public bool IsQuiet => ActiveExceptions.Length > 0 || Evidence.VexStatus == VexStatus.NotAffected;
|
||||
|
||||
/// <summary>
|
||||
/// When this path was first detected.
|
||||
/// </summary>
|
||||
public required DateTimeOffset FirstSeenAt { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// When this path was last updated.
|
||||
/// </summary>
|
||||
public required DateTimeOffset LastUpdatedAt { get; init; }
|
||||
}
|
||||
|
||||
public sealed record PackageRef(
|
||||
string Purl,
|
||||
string Name,
|
||||
string Version,
|
||||
string? Ecosystem);
|
||||
|
||||
public sealed record VulnerableSymbol(
|
||||
string FullyQualifiedName,
|
||||
string? SourceFile,
|
||||
int? LineNumber,
|
||||
string? Language);
|
||||
|
||||
public sealed record EntryPoint(
|
||||
string Name,
|
||||
string Type,
|
||||
string? Path);
|
||||
|
||||
public sealed record PathRiskScore(
|
||||
decimal AggregatedCvss,
|
||||
decimal MaxEpss,
|
||||
int CriticalCount,
|
||||
int HighCount,
|
||||
int MediumCount,
|
||||
int LowCount);
|
||||
|
||||
public sealed record PathEvidence(
|
||||
ReachabilityLatticeState LatticeState,
|
||||
VexStatus VexStatus,
|
||||
decimal Confidence,
|
||||
ImmutableArray<EvidenceItem> Items);
|
||||
|
||||
public sealed record EvidenceItem(
|
||||
string Type,
|
||||
string Source,
|
||||
string Description,
|
||||
decimal Weight);
|
||||
|
||||
public sealed record ExceptionRef(
|
||||
string ExceptionId,
|
||||
string Reason,
|
||||
DateTimeOffset ExpiresAt);
|
||||
|
||||
public enum ReachabilityStatus
|
||||
{
|
||||
Unknown,
|
||||
StaticallyReachable,
|
||||
RuntimeConfirmed,
|
||||
Unreachable,
|
||||
Contested
|
||||
}
|
||||
|
||||
public enum ReachabilityLatticeState
|
||||
{
|
||||
Unknown,
|
||||
StaticallyReachable,
|
||||
RuntimeObserved,
|
||||
Unreachable,
|
||||
Contested
|
||||
}
|
||||
|
||||
public enum VexStatus
|
||||
{
|
||||
Unknown,
|
||||
NotAffected,
|
||||
Affected,
|
||||
Fixed,
|
||||
UnderInvestigation
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using StellaOps.Scanner.Triage.Models;
|
||||
|
||||
namespace StellaOps.Scanner.Triage.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Groups findings into exploit paths by correlating reachability data.
|
||||
/// </summary>
|
||||
public interface IExploitPathGroupingService
|
||||
{
|
||||
/// <summary>
|
||||
/// Groups findings for an artifact into exploit paths.
|
||||
/// </summary>
|
||||
Task<IReadOnlyList<ExploitPath>> GroupFindingsAsync(
|
||||
string artifactDigest,
|
||||
IReadOnlyList<Finding> findings,
|
||||
CancellationToken ct = default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a vulnerability finding.
|
||||
/// </summary>
|
||||
public sealed record Finding(
|
||||
string FindingId,
|
||||
string PackagePurl,
|
||||
string PackageName,
|
||||
string PackageVersion,
|
||||
IReadOnlyList<string> CveIds,
|
||||
decimal CvssScore,
|
||||
decimal EpssScore,
|
||||
Severity Severity,
|
||||
string ArtifactDigest,
|
||||
DateTimeOffset FirstSeenAt);
|
||||
|
||||
public enum Severity
|
||||
{
|
||||
Critical,
|
||||
High,
|
||||
Medium,
|
||||
Low,
|
||||
Info
|
||||
}
|
||||
@@ -1,16 +1,14 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
<RootNamespace>StellaOps.Scanner.Triage</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.0-*" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.0-*" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="10.0.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
Reference in New Issue
Block a user