feat: add Attestation Chain and Triage Evidence API clients and models

- Implemented Attestation Chain API client with methods for verifying, fetching, and managing attestation chains.
- Created models for Attestation Chain, including DSSE envelope structures and verification results.
- Developed Triage Evidence API client for fetching finding evidence, including methods for evidence retrieval by CVE and component.
- Added models for Triage Evidence, encapsulating evidence responses, entry points, boundary proofs, and VEX evidence.
- Introduced mock implementations for both API clients to facilitate testing and development.
This commit is contained in:
master
2025-12-18 13:15:13 +02:00
parent 7d5250238c
commit 00d2c99af9
118 changed files with 13463 additions and 151 deletions

View File

@@ -0,0 +1,216 @@
// -----------------------------------------------------------------------------
// BoundaryProof.cs
// Sprint: SPRINT_3800_0001_0001_evidence_api_models
// Description: Boundary proof model for surface exposure and security controls.
// -----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace StellaOps.Scanner.SmartDiff.Detection;
/// <summary>
/// Boundary proof describing surface exposure, authentication, and security controls.
/// Used to determine the attack surface and protective measures for a finding.
/// </summary>
public sealed record BoundaryProof
{
/// <summary>
/// Kind of boundary (network, file, ipc, process).
/// </summary>
[JsonPropertyName("kind")]
public string Kind { get; init; } = string.Empty;
/// <summary>
/// Surface descriptor (what is exposed).
/// </summary>
[JsonPropertyName("surface")]
public BoundarySurface? Surface { get; init; }
/// <summary>
/// Exposure descriptor (how it's exposed).
/// </summary>
[JsonPropertyName("exposure")]
public BoundaryExposure? Exposure { get; init; }
/// <summary>
/// Authentication requirements.
/// </summary>
[JsonPropertyName("auth")]
public BoundaryAuth? Auth { get; init; }
/// <summary>
/// Security controls protecting the boundary.
/// </summary>
[JsonPropertyName("controls")]
public IReadOnlyList<BoundaryControl>? Controls { get; init; }
/// <summary>
/// When the boundary was last verified.
/// </summary>
[JsonPropertyName("last_seen")]
public DateTimeOffset LastSeen { get; init; }
/// <summary>
/// Confidence score for this boundary proof (0.0 to 1.0).
/// </summary>
[JsonPropertyName("confidence")]
public double Confidence { get; init; }
/// <summary>
/// Source of this boundary proof (static_analysis, runtime_observation, config).
/// </summary>
[JsonPropertyName("source")]
public string? Source { get; init; }
/// <summary>
/// Reference to the evidence source (graph hash, scan ID, etc.).
/// </summary>
[JsonPropertyName("evidence_ref")]
public string? EvidenceRef { get; init; }
}
/// <summary>
/// Describes what attack surface is exposed.
/// </summary>
public sealed record BoundarySurface
{
/// <summary>
/// Type of surface (api, web, cli, library, file, socket).
/// </summary>
[JsonPropertyName("type")]
public string Type { get; init; } = string.Empty;
/// <summary>
/// Protocol (http, https, grpc, tcp, udp, unix).
/// </summary>
[JsonPropertyName("protocol")]
public string? Protocol { get; init; }
/// <summary>
/// Port number if network-exposed.
/// </summary>
[JsonPropertyName("port")]
public int? Port { get; init; }
/// <summary>
/// Host or interface binding.
/// </summary>
[JsonPropertyName("host")]
public string? Host { get; init; }
/// <summary>
/// Path or route pattern.
/// </summary>
[JsonPropertyName("path")]
public string? Path { get; init; }
}
/// <summary>
/// Describes how the surface is exposed.
/// </summary>
public sealed record BoundaryExposure
{
/// <summary>
/// Exposure level (public, internal, private, localhost).
/// </summary>
[JsonPropertyName("level")]
public string Level { get; init; } = string.Empty;
/// <summary>
/// Whether the exposure is internet-facing.
/// </summary>
[JsonPropertyName("internet_facing")]
public bool InternetFacing { get; init; }
/// <summary>
/// Network zone (dmz, internal, trusted, untrusted).
/// </summary>
[JsonPropertyName("zone")]
public string? Zone { get; init; }
/// <summary>
/// Whether behind a load balancer or proxy.
/// </summary>
[JsonPropertyName("behind_proxy")]
public bool? BehindProxy { get; init; }
/// <summary>
/// Expected client types (browser, api_client, service, any).
/// </summary>
[JsonPropertyName("client_types")]
public IReadOnlyList<string>? ClientTypes { get; init; }
}
/// <summary>
/// Describes authentication requirements at the boundary.
/// </summary>
public sealed record BoundaryAuth
{
/// <summary>
/// Whether authentication is required.
/// </summary>
[JsonPropertyName("required")]
public bool Required { get; init; }
/// <summary>
/// Authentication type (jwt, oauth2, basic, api_key, mtls, session).
/// </summary>
[JsonPropertyName("type")]
public string? Type { get; init; }
/// <summary>
/// Required roles or scopes.
/// </summary>
[JsonPropertyName("roles")]
public IReadOnlyList<string>? Roles { get; init; }
/// <summary>
/// Authentication provider or issuer.
/// </summary>
[JsonPropertyName("provider")]
public string? Provider { get; init; }
/// <summary>
/// Whether MFA is required.
/// </summary>
[JsonPropertyName("mfa_required")]
public bool? MfaRequired { get; init; }
}
/// <summary>
/// Describes a security control at the boundary.
/// </summary>
public sealed record BoundaryControl
{
/// <summary>
/// Type of control (rate_limit, waf, input_validation, output_encoding, etc.).
/// </summary>
[JsonPropertyName("type")]
public string Type { get; init; } = string.Empty;
/// <summary>
/// Whether the control is currently active.
/// </summary>
[JsonPropertyName("active")]
public bool Active { get; init; }
/// <summary>
/// Control configuration or policy reference.
/// </summary>
[JsonPropertyName("config")]
public string? Config { get; init; }
/// <summary>
/// Effectiveness rating (high, medium, low).
/// </summary>
[JsonPropertyName("effectiveness")]
public string? Effectiveness { get; init; }
/// <summary>
/// When the control was last verified.
/// </summary>
[JsonPropertyName("verified_at")]
public DateTimeOffset? VerifiedAt { get; init; }
}

View File

@@ -0,0 +1,179 @@
// -----------------------------------------------------------------------------
// VexEvidence.cs
// Sprint: SPRINT_3800_0001_0001_evidence_api_models
// Description: VEX (Vulnerability Exploitability eXchange) evidence model.
// -----------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace StellaOps.Scanner.SmartDiff.Detection;
/// <summary>
/// VEX (Vulnerability Exploitability eXchange) evidence for a vulnerability.
/// Captures vendor/first-party statements about whether a vulnerability is exploitable.
/// </summary>
public sealed record VexEvidence
{
/// <summary>
/// VEX status: not_affected, affected, fixed, under_investigation.
/// </summary>
[JsonPropertyName("status")]
public VexStatus Status { get; init; }
/// <summary>
/// Justification for the status (per OpenVEX specification).
/// </summary>
[JsonPropertyName("justification")]
public VexJustification? Justification { get; init; }
/// <summary>
/// Human-readable impact statement explaining why not affected.
/// </summary>
[JsonPropertyName("impact")]
public string? Impact { get; init; }
/// <summary>
/// Human-readable action statement (remediation steps).
/// </summary>
[JsonPropertyName("action")]
public string? Action { get; init; }
/// <summary>
/// Reference to the VEX document or DSSE attestation.
/// </summary>
[JsonPropertyName("attestation_ref")]
public string? AttestationRef { get; init; }
/// <summary>
/// VEX document ID.
/// </summary>
[JsonPropertyName("document_id")]
public string? DocumentId { get; init; }
/// <summary>
/// When the VEX statement was issued.
/// </summary>
[JsonPropertyName("issued_at")]
public DateTimeOffset? IssuedAt { get; init; }
/// <summary>
/// When the VEX statement was last updated.
/// </summary>
[JsonPropertyName("updated_at")]
public DateTimeOffset? UpdatedAt { get; init; }
/// <summary>
/// When the VEX statement expires.
/// </summary>
[JsonPropertyName("expires_at")]
public DateTimeOffset? ExpiresAt { get; init; }
/// <summary>
/// Source of the VEX statement (vendor, first_party, third_party, coordinator).
/// </summary>
[JsonPropertyName("source")]
public VexSource? Source { get; init; }
/// <summary>
/// Affected product or component reference (PURL).
/// </summary>
[JsonPropertyName("product_ref")]
public string? ProductRef { get; init; }
/// <summary>
/// Vulnerability ID (CVE, GHSA, etc.).
/// </summary>
[JsonPropertyName("vulnerability_id")]
public string? VulnerabilityId { get; init; }
/// <summary>
/// Confidence in the VEX statement (0.0 to 1.0).
/// Higher confidence for vendor statements, lower for third-party.
/// </summary>
[JsonPropertyName("confidence")]
public double Confidence { get; init; } = 1.0;
/// <summary>
/// Whether the VEX statement is still valid (not expired).
/// </summary>
[JsonIgnore]
public bool IsValid => ExpiresAt is null || ExpiresAt > DateTimeOffset.UtcNow;
/// <summary>
/// Whether this VEX statement indicates the vulnerability is not exploitable.
/// </summary>
[JsonIgnore]
public bool IsNotAffected => Status == VexStatus.NotAffected;
/// <summary>
/// Additional context or notes about the VEX statement.
/// </summary>
[JsonPropertyName("notes")]
public IReadOnlyList<string>? Notes { get; init; }
}
/// <summary>
/// VEX status values per OpenVEX specification.
/// </summary>
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum VexStatus
{
/// <summary>
/// The vulnerability is not exploitable in this context.
/// </summary>
[JsonPropertyName("not_affected")]
NotAffected,
/// <summary>
/// The vulnerability is exploitable.
/// </summary>
[JsonPropertyName("affected")]
Affected,
/// <summary>
/// The vulnerability has been fixed.
/// </summary>
[JsonPropertyName("fixed")]
Fixed,
/// <summary>
/// The vulnerability is under investigation.
/// </summary>
[JsonPropertyName("under_investigation")]
UnderInvestigation
}
// NOTE: VexJustification is defined in VexCandidateModels.cs to avoid duplication
/// <summary>
/// Source of a VEX statement.
/// </summary>
public sealed record VexSource
{
/// <summary>
/// Source type (vendor, first_party, third_party, coordinator, community).
/// </summary>
[JsonPropertyName("type")]
public string Type { get; init; } = string.Empty;
/// <summary>
/// Name of the source organization.
/// </summary>
[JsonPropertyName("name")]
public string? Name { get; init; }
/// <summary>
/// URL to the source's VEX feed or website.
/// </summary>
[JsonPropertyName("url")]
public string? Url { get; init; }
/// <summary>
/// Trust level (high, medium, low).
/// Vendor and first-party are typically high; third-party varies.
/// </summary>
[JsonPropertyName("trust_level")]
public string? TrustLevel { get; init; }
}