using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace StellaOps.Cli.Services.Models;
// CLI-LNM-22-002: VEX observation models for CLI commands
///
/// Query options for VEX observations.
///
internal sealed class VexObservationQuery
{
[JsonPropertyName("tenant")]
public string Tenant { get; init; } = string.Empty;
[JsonPropertyName("vulnerabilityIds")]
public IReadOnlyList VulnerabilityIds { get; init; } = Array.Empty();
[JsonPropertyName("productKeys")]
public IReadOnlyList ProductKeys { get; init; } = Array.Empty();
[JsonPropertyName("purls")]
public IReadOnlyList Purls { get; init; } = Array.Empty();
[JsonPropertyName("cpes")]
public IReadOnlyList Cpes { get; init; } = Array.Empty();
[JsonPropertyName("statuses")]
public IReadOnlyList Statuses { get; init; } = Array.Empty();
[JsonPropertyName("providerIds")]
public IReadOnlyList ProviderIds { get; init; } = Array.Empty();
[JsonPropertyName("limit")]
public int? Limit { get; init; }
[JsonPropertyName("cursor")]
public string? Cursor { get; init; }
}
///
/// Response from VEX observation query.
///
internal sealed class VexObservationResponse
{
[JsonPropertyName("observations")]
public IReadOnlyList Observations { get; init; } = Array.Empty();
[JsonPropertyName("aggregate")]
public VexObservationAggregate? Aggregate { get; init; }
[JsonPropertyName("nextCursor")]
public string? NextCursor { get; init; }
[JsonPropertyName("hasMore")]
public bool HasMore { get; init; }
}
///
/// VEX observation document.
///
internal sealed class VexObservation
{
[JsonPropertyName("observationId")]
public string ObservationId { get; init; } = string.Empty;
[JsonPropertyName("tenant")]
public string Tenant { get; init; } = string.Empty;
[JsonPropertyName("vulnerabilityId")]
public string VulnerabilityId { get; init; } = string.Empty;
[JsonPropertyName("providerId")]
public string ProviderId { get; init; } = string.Empty;
[JsonPropertyName("product")]
public VexObservationProduct? Product { get; init; }
[JsonPropertyName("status")]
public string Status { get; init; } = string.Empty;
[JsonPropertyName("justification")]
public string? Justification { get; init; }
[JsonPropertyName("detail")]
public string? Detail { get; init; }
[JsonPropertyName("document")]
public VexObservationDocument? Document { get; init; }
[JsonPropertyName("firstSeen")]
public DateTimeOffset FirstSeen { get; init; }
[JsonPropertyName("lastSeen")]
public DateTimeOffset LastSeen { get; init; }
[JsonPropertyName("confidence")]
public VexObservationConfidence? Confidence { get; init; }
[JsonPropertyName("createdAt")]
public DateTimeOffset CreatedAt { get; init; }
[JsonPropertyName("updatedAt")]
public DateTimeOffset? UpdatedAt { get; init; }
}
///
/// Product information in VEX observation.
///
internal sealed class VexObservationProduct
{
[JsonPropertyName("key")]
public string Key { get; init; } = string.Empty;
[JsonPropertyName("name")]
public string? Name { get; init; }
[JsonPropertyName("version")]
public string? Version { get; init; }
[JsonPropertyName("purl")]
public string? Purl { get; init; }
[JsonPropertyName("cpe")]
public string? Cpe { get; init; }
[JsonPropertyName("componentIdentifiers")]
public IReadOnlyList ComponentIdentifiers { get; init; } = Array.Empty();
}
///
/// Document reference in VEX observation.
///
internal sealed class VexObservationDocument
{
[JsonPropertyName("format")]
public string Format { get; init; } = string.Empty;
[JsonPropertyName("digest")]
public string Digest { get; init; } = string.Empty;
[JsonPropertyName("sourceUri")]
public string SourceUri { get; init; } = string.Empty;
[JsonPropertyName("revision")]
public string? Revision { get; init; }
[JsonPropertyName("signature")]
public VexObservationSignature? Signature { get; init; }
}
///
/// Signature metadata for VEX document.
///
internal sealed class VexObservationSignature
{
[JsonPropertyName("type")]
public string Type { get; init; } = string.Empty;
[JsonPropertyName("subject")]
public string? Subject { get; init; }
[JsonPropertyName("issuer")]
public string? Issuer { get; init; }
[JsonPropertyName("keyId")]
public string? KeyId { get; init; }
[JsonPropertyName("verifiedAt")]
public DateTimeOffset? VerifiedAt { get; init; }
[JsonPropertyName("transparencyLogReference")]
public string? TransparencyLogReference { get; init; }
}
///
/// Confidence level in VEX observation.
///
internal sealed class VexObservationConfidence
{
[JsonPropertyName("level")]
public string Level { get; init; } = string.Empty;
[JsonPropertyName("score")]
public double? Score { get; init; }
[JsonPropertyName("method")]
public string? Method { get; init; }
}
///
/// Aggregate data from VEX observation query.
///
internal sealed class VexObservationAggregate
{
[JsonPropertyName("vulnerabilityIds")]
public IReadOnlyList VulnerabilityIds { get; init; } = Array.Empty();
[JsonPropertyName("productKeys")]
public IReadOnlyList ProductKeys { get; init; } = Array.Empty();
[JsonPropertyName("purls")]
public IReadOnlyList Purls { get; init; } = Array.Empty();
[JsonPropertyName("cpes")]
public IReadOnlyList Cpes { get; init; } = Array.Empty();
[JsonPropertyName("providerIds")]
public IReadOnlyList ProviderIds { get; init; } = Array.Empty();
[JsonPropertyName("statusCounts")]
public IReadOnlyDictionary StatusCounts { get; init; } = new Dictionary();
}
///
/// VEX linkset query options.
///
internal sealed class VexLinksetQuery
{
[JsonPropertyName("tenant")]
public string Tenant { get; init; } = string.Empty;
[JsonPropertyName("vulnerabilityId")]
public string VulnerabilityId { get; init; } = string.Empty;
[JsonPropertyName("productKeys")]
public IReadOnlyList ProductKeys { get; init; } = Array.Empty();
[JsonPropertyName("purls")]
public IReadOnlyList Purls { get; init; } = Array.Empty();
[JsonPropertyName("statuses")]
public IReadOnlyList Statuses { get; init; } = Array.Empty();
}
///
/// VEX linkset response showing linked observations.
///
internal sealed class VexLinksetResponse
{
[JsonPropertyName("vulnerabilityId")]
public string VulnerabilityId { get; init; } = string.Empty;
[JsonPropertyName("observations")]
public IReadOnlyList Observations { get; init; } = Array.Empty();
[JsonPropertyName("summary")]
public VexLinksetSummary? Summary { get; init; }
[JsonPropertyName("conflicts")]
public IReadOnlyList Conflicts { get; init; } = Array.Empty();
}
///
/// Summary of VEX linkset.
///
internal sealed class VexLinksetSummary
{
[JsonPropertyName("totalObservations")]
public int TotalObservations { get; init; }
[JsonPropertyName("providers")]
public IReadOnlyList Providers { get; init; } = Array.Empty();
[JsonPropertyName("products")]
public IReadOnlyList Products { get; init; } = Array.Empty();
[JsonPropertyName("statusCounts")]
public IReadOnlyDictionary StatusCounts { get; init; } = new Dictionary();
[JsonPropertyName("hasConflicts")]
public bool HasConflicts { get; init; }
}
///
/// Conflict between VEX observations.
///
internal sealed class VexLinksetConflict
{
[JsonPropertyName("productKey")]
public string ProductKey { get; init; } = string.Empty;
[JsonPropertyName("conflictingStatuses")]
public IReadOnlyList ConflictingStatuses { get; init; } = Array.Empty();
[JsonPropertyName("observations")]
public IReadOnlyList ObservationIds { get; init; } = Array.Empty();
[JsonPropertyName("description")]
public string Description { get; init; } = string.Empty;
}