469 lines
11 KiB
C#
469 lines
11 KiB
C#
// <copyright file="WitnessModels.cs" company="StellaOps">
|
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
// Sprint: SPRINT_20260112_014_CLI_witness_commands (CLI-WIT-001)
|
|
// </copyright>
|
|
|
|
using System.Text.Json.Serialization;
|
|
|
|
namespace StellaOps.Cli.Services.Models;
|
|
|
|
/// <summary>
|
|
/// Request for listing witnesses.
|
|
/// </summary>
|
|
public sealed record WitnessListRequest
|
|
{
|
|
/// <summary>
|
|
/// Filter by scan ID.
|
|
/// </summary>
|
|
public string? ScanId { get; init; }
|
|
|
|
/// <summary>
|
|
/// Filter by vulnerability ID (e.g., CVE-2024-1234).
|
|
/// </summary>
|
|
public string? VulnerabilityId { get; init; }
|
|
|
|
/// <summary>
|
|
/// Filter by component PURL.
|
|
/// </summary>
|
|
public string? ComponentPurl { get; init; }
|
|
|
|
/// <summary>
|
|
/// Filter by predicate type.
|
|
/// </summary>
|
|
public string? PredicateType { get; init; }
|
|
|
|
/// <summary>
|
|
/// Maximum number of results.
|
|
/// </summary>
|
|
public int? Limit { get; init; }
|
|
|
|
/// <summary>
|
|
/// Continuation token for pagination.
|
|
/// </summary>
|
|
public string? ContinuationToken { get; init; }
|
|
|
|
/// <summary>
|
|
/// Tenant ID.
|
|
/// </summary>
|
|
public string? TenantId { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Response for listing witnesses.
|
|
/// </summary>
|
|
public sealed record WitnessListResponse
|
|
{
|
|
/// <summary>
|
|
/// List of witness summaries.
|
|
/// </summary>
|
|
[JsonPropertyName("witnesses")]
|
|
public IReadOnlyList<WitnessSummary> Witnesses { get; init; } = [];
|
|
|
|
/// <summary>
|
|
/// Continuation token for next page.
|
|
/// </summary>
|
|
[JsonPropertyName("continuation_token")]
|
|
public string? ContinuationToken { get; init; }
|
|
|
|
/// <summary>
|
|
/// Total count of matching witnesses.
|
|
/// </summary>
|
|
[JsonPropertyName("total_count")]
|
|
public int TotalCount { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Summary of a witness for list views.
|
|
/// </summary>
|
|
public sealed record WitnessSummary
|
|
{
|
|
/// <summary>
|
|
/// Content-addressed witness ID.
|
|
/// </summary>
|
|
[JsonPropertyName("witness_id")]
|
|
public required string WitnessId { get; init; }
|
|
|
|
/// <summary>
|
|
/// Vulnerability ID.
|
|
/// </summary>
|
|
[JsonPropertyName("vulnerability_id")]
|
|
public string? VulnerabilityId { get; init; }
|
|
|
|
/// <summary>
|
|
/// Component PURL.
|
|
/// </summary>
|
|
[JsonPropertyName("component_purl")]
|
|
public string? ComponentPurl { get; init; }
|
|
|
|
/// <summary>
|
|
/// Entrypoint name.
|
|
/// </summary>
|
|
[JsonPropertyName("entrypoint")]
|
|
public string? Entrypoint { get; init; }
|
|
|
|
/// <summary>
|
|
/// Sink symbol.
|
|
/// </summary>
|
|
[JsonPropertyName("sink")]
|
|
public string? Sink { get; init; }
|
|
|
|
/// <summary>
|
|
/// Path length.
|
|
/// </summary>
|
|
[JsonPropertyName("path_length")]
|
|
public int PathLength { get; init; }
|
|
|
|
/// <summary>
|
|
/// Predicate type URI.
|
|
/// </summary>
|
|
[JsonPropertyName("predicate_type")]
|
|
public string? PredicateType { get; init; }
|
|
|
|
/// <summary>
|
|
/// Whether the witness has a valid DSSE signature.
|
|
/// </summary>
|
|
[JsonPropertyName("is_signed")]
|
|
public bool IsSigned { get; init; }
|
|
|
|
/// <summary>
|
|
/// When the witness was created.
|
|
/// </summary>
|
|
[JsonPropertyName("created_at")]
|
|
public DateTimeOffset CreatedAt { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Detailed witness response.
|
|
/// </summary>
|
|
public sealed record WitnessDetailResponse
|
|
{
|
|
/// <summary>
|
|
/// Schema version.
|
|
/// </summary>
|
|
[JsonPropertyName("witness_schema")]
|
|
public string? WitnessSchema { get; init; }
|
|
|
|
/// <summary>
|
|
/// Content-addressed witness ID.
|
|
/// </summary>
|
|
[JsonPropertyName("witness_id")]
|
|
public required string WitnessId { get; init; }
|
|
|
|
/// <summary>
|
|
/// Artifact information.
|
|
/// </summary>
|
|
[JsonPropertyName("artifact")]
|
|
public WitnessArtifactInfo? Artifact { get; init; }
|
|
|
|
/// <summary>
|
|
/// Vulnerability information.
|
|
/// </summary>
|
|
[JsonPropertyName("vuln")]
|
|
public WitnessVulnInfo? Vuln { get; init; }
|
|
|
|
/// <summary>
|
|
/// Entrypoint information.
|
|
/// </summary>
|
|
[JsonPropertyName("entrypoint")]
|
|
public WitnessEntrypointInfo? Entrypoint { get; init; }
|
|
|
|
/// <summary>
|
|
/// Call path from entrypoint to sink.
|
|
/// </summary>
|
|
[JsonPropertyName("path")]
|
|
public IReadOnlyList<WitnessPathStep>? Path { get; init; }
|
|
|
|
/// <summary>
|
|
/// Sink information.
|
|
/// </summary>
|
|
[JsonPropertyName("sink")]
|
|
public WitnessSinkInfo? Sink { get; init; }
|
|
|
|
/// <summary>
|
|
/// Detected gates along the path.
|
|
/// </summary>
|
|
[JsonPropertyName("gates")]
|
|
public IReadOnlyList<WitnessGateInfo>? Gates { get; init; }
|
|
|
|
/// <summary>
|
|
/// Evidence digests.
|
|
/// </summary>
|
|
[JsonPropertyName("evidence")]
|
|
public WitnessEvidenceInfo? Evidence { get; init; }
|
|
|
|
/// <summary>
|
|
/// When the witness was observed.
|
|
/// </summary>
|
|
[JsonPropertyName("observed_at")]
|
|
public DateTimeOffset ObservedAt { get; init; }
|
|
|
|
/// <summary>
|
|
/// Path hash for deterministic joining.
|
|
/// Sprint: SPRINT_20260112_004_SCANNER_path_witness_nodehash
|
|
/// </summary>
|
|
[JsonPropertyName("path_hash")]
|
|
public string? PathHash { get; init; }
|
|
|
|
/// <summary>
|
|
/// Top-K node hashes along the path.
|
|
/// Sprint: SPRINT_20260112_004_SCANNER_path_witness_nodehash
|
|
/// </summary>
|
|
[JsonPropertyName("node_hashes")]
|
|
public IReadOnlyList<string>? NodeHashes { get; init; }
|
|
|
|
/// <summary>
|
|
/// Evidence URIs for traceability.
|
|
/// </summary>
|
|
[JsonPropertyName("evidence_uris")]
|
|
public IReadOnlyList<string>? EvidenceUris { get; init; }
|
|
|
|
/// <summary>
|
|
/// Predicate type URI.
|
|
/// </summary>
|
|
[JsonPropertyName("predicate_type")]
|
|
public string? PredicateType { get; init; }
|
|
|
|
/// <summary>
|
|
/// DSSE envelope if signed.
|
|
/// </summary>
|
|
[JsonPropertyName("dsse_envelope")]
|
|
public WitnessDsseEnvelope? DsseEnvelope { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Artifact information in a witness.
|
|
/// </summary>
|
|
public sealed record WitnessArtifactInfo
|
|
{
|
|
[JsonPropertyName("sbom_digest")]
|
|
public string? SbomDigest { get; init; }
|
|
|
|
[JsonPropertyName("component_purl")]
|
|
public string? ComponentPurl { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Vulnerability information in a witness.
|
|
/// </summary>
|
|
public sealed record WitnessVulnInfo
|
|
{
|
|
[JsonPropertyName("id")]
|
|
public string? Id { get; init; }
|
|
|
|
[JsonPropertyName("source")]
|
|
public string? Source { get; init; }
|
|
|
|
[JsonPropertyName("affected_range")]
|
|
public string? AffectedRange { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Entrypoint information in a witness.
|
|
/// </summary>
|
|
public sealed record WitnessEntrypointInfo
|
|
{
|
|
[JsonPropertyName("kind")]
|
|
public string? Kind { get; init; }
|
|
|
|
[JsonPropertyName("name")]
|
|
public string? Name { get; init; }
|
|
|
|
[JsonPropertyName("symbol_id")]
|
|
public string? SymbolId { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// A step in the call path.
|
|
/// </summary>
|
|
public sealed record WitnessPathStep
|
|
{
|
|
[JsonPropertyName("symbol")]
|
|
public string? Symbol { get; init; }
|
|
|
|
[JsonPropertyName("symbol_id")]
|
|
public string? SymbolId { get; init; }
|
|
|
|
[JsonPropertyName("file")]
|
|
public string? File { get; init; }
|
|
|
|
[JsonPropertyName("line")]
|
|
public int? Line { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sink information in a witness.
|
|
/// </summary>
|
|
public sealed record WitnessSinkInfo
|
|
{
|
|
[JsonPropertyName("symbol")]
|
|
public string? Symbol { get; init; }
|
|
|
|
[JsonPropertyName("symbol_id")]
|
|
public string? SymbolId { get; init; }
|
|
|
|
[JsonPropertyName("sink_type")]
|
|
public string? SinkType { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gate (guard/control) information in a witness.
|
|
/// </summary>
|
|
public sealed record WitnessGateInfo
|
|
{
|
|
[JsonPropertyName("type")]
|
|
public string? Type { get; init; }
|
|
|
|
[JsonPropertyName("guard_symbol")]
|
|
public string? GuardSymbol { get; init; }
|
|
|
|
[JsonPropertyName("confidence")]
|
|
public double Confidence { get; init; }
|
|
|
|
[JsonPropertyName("detail")]
|
|
public string? Detail { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Evidence information in a witness.
|
|
/// </summary>
|
|
public sealed record WitnessEvidenceInfo
|
|
{
|
|
[JsonPropertyName("callgraph_digest")]
|
|
public string? CallgraphDigest { get; init; }
|
|
|
|
[JsonPropertyName("surface_digest")]
|
|
public string? SurfaceDigest { get; init; }
|
|
|
|
[JsonPropertyName("analysis_config_digest")]
|
|
public string? AnalysisConfigDigest { get; init; }
|
|
|
|
[JsonPropertyName("build_id")]
|
|
public string? BuildId { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// DSSE envelope information.
|
|
/// </summary>
|
|
public sealed record WitnessDsseEnvelope
|
|
{
|
|
[JsonPropertyName("payload_type")]
|
|
public string? PayloadType { get; init; }
|
|
|
|
[JsonPropertyName("payload")]
|
|
public string? Payload { get; init; }
|
|
|
|
[JsonPropertyName("signatures")]
|
|
public IReadOnlyList<WitnessDsseSignature>? Signatures { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// DSSE signature information.
|
|
/// </summary>
|
|
public sealed record WitnessDsseSignature
|
|
{
|
|
[JsonPropertyName("keyid")]
|
|
public string? KeyId { get; init; }
|
|
|
|
[JsonPropertyName("sig")]
|
|
public string? Signature { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Response for witness verification.
|
|
/// </summary>
|
|
public sealed record WitnessVerifyResponse
|
|
{
|
|
/// <summary>
|
|
/// Whether verification succeeded.
|
|
/// </summary>
|
|
[JsonPropertyName("verified")]
|
|
public bool Verified { get; init; }
|
|
|
|
/// <summary>
|
|
/// Verification status code.
|
|
/// </summary>
|
|
[JsonPropertyName("status")]
|
|
public string? Status { get; init; }
|
|
|
|
/// <summary>
|
|
/// Detailed verification message.
|
|
/// </summary>
|
|
[JsonPropertyName("message")]
|
|
public string? Message { get; init; }
|
|
|
|
/// <summary>
|
|
/// DSSE verification details.
|
|
/// </summary>
|
|
[JsonPropertyName("dsse")]
|
|
public WitnessDsseVerifyInfo? Dsse { get; init; }
|
|
|
|
/// <summary>
|
|
/// Content hash verification.
|
|
/// </summary>
|
|
[JsonPropertyName("content_hash")]
|
|
public WitnessContentHashInfo? ContentHash { get; init; }
|
|
|
|
/// <summary>
|
|
/// Verification timestamp.
|
|
/// </summary>
|
|
[JsonPropertyName("verified_at")]
|
|
public DateTimeOffset VerifiedAt { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// DSSE verification details.
|
|
/// </summary>
|
|
public sealed record WitnessDsseVerifyInfo
|
|
{
|
|
[JsonPropertyName("envelope_valid")]
|
|
public bool EnvelopeValid { get; init; }
|
|
|
|
[JsonPropertyName("signature_count")]
|
|
public int SignatureCount { get; init; }
|
|
|
|
[JsonPropertyName("valid_signatures")]
|
|
public int ValidSignatures { get; init; }
|
|
|
|
[JsonPropertyName("signer_identities")]
|
|
public IReadOnlyList<string>? SignerIdentities { get; init; }
|
|
|
|
[JsonPropertyName("predicate_type")]
|
|
public string? PredicateType { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Content hash verification details.
|
|
/// </summary>
|
|
public sealed record WitnessContentHashInfo
|
|
{
|
|
[JsonPropertyName("expected")]
|
|
public string? Expected { get; init; }
|
|
|
|
[JsonPropertyName("actual")]
|
|
public string? Actual { get; init; }
|
|
|
|
[JsonPropertyName("match")]
|
|
public bool Match { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Export format for witnesses.
|
|
/// </summary>
|
|
public enum WitnessExportFormat
|
|
{
|
|
/// <summary>
|
|
/// Raw JSON witness payload.
|
|
/// </summary>
|
|
Json,
|
|
|
|
/// <summary>
|
|
/// DSSE-signed envelope.
|
|
/// </summary>
|
|
Dsse,
|
|
|
|
/// <summary>
|
|
/// SARIF format.
|
|
/// </summary>
|
|
Sarif
|
|
}
|