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:
@@ -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; }
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
Reference in New Issue
Block a user