up
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Concelier Attestation Tests / attestation-tests (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled

This commit is contained in:
StellaOps Bot
2025-11-28 09:40:40 +02:00
parent 1c6730a1d2
commit 05da719048
206 changed files with 34741 additions and 1751 deletions

View File

@@ -35,3 +35,60 @@ internal sealed record TenantProfile
[JsonPropertyName("lastUpdated")]
public DateTimeOffset? LastUpdated { get; init; }
}
// CLI-TEN-49-001: Token minting and delegation models
/// <summary>
/// Request to mint a service account token.
/// </summary>
internal sealed record TokenMintRequest(
[property: JsonPropertyName("serviceAccountId")] string ServiceAccountId,
[property: JsonPropertyName("scopes")] IReadOnlyList<string> Scopes,
[property: JsonPropertyName("expiresInSeconds")] int? ExpiresInSeconds = null,
[property: JsonPropertyName("tenant")] string? Tenant = null,
[property: JsonPropertyName("reason")] string? Reason = null);
/// <summary>
/// Response from token minting.
/// </summary>
internal sealed record TokenMintResponse(
[property: JsonPropertyName("accessToken")] string AccessToken,
[property: JsonPropertyName("tokenType")] string TokenType,
[property: JsonPropertyName("expiresAt")] DateTimeOffset ExpiresAt,
[property: JsonPropertyName("scopes")] IReadOnlyList<string> Scopes,
[property: JsonPropertyName("tokenId")] string? TokenId = null);
/// <summary>
/// Request to delegate a token to another principal.
/// </summary>
internal sealed record TokenDelegateRequest(
[property: JsonPropertyName("delegateTo")] string DelegateTo,
[property: JsonPropertyName("scopes")] IReadOnlyList<string> Scopes,
[property: JsonPropertyName("expiresInSeconds")] int? ExpiresInSeconds = null,
[property: JsonPropertyName("tenant")] string? Tenant = null,
[property: JsonPropertyName("reason")] string? Reason = null);
/// <summary>
/// Response from token delegation.
/// </summary>
internal sealed record TokenDelegateResponse(
[property: JsonPropertyName("accessToken")] string AccessToken,
[property: JsonPropertyName("tokenType")] string TokenType,
[property: JsonPropertyName("expiresAt")] DateTimeOffset ExpiresAt,
[property: JsonPropertyName("delegationId")] string DelegationId,
[property: JsonPropertyName("originalSubject")] string OriginalSubject,
[property: JsonPropertyName("delegatedSubject")] string DelegatedSubject,
[property: JsonPropertyName("scopes")] IReadOnlyList<string> Scopes);
/// <summary>
/// Token introspection response for impersonation banner.
/// </summary>
internal sealed record TokenIntrospectionResponse(
[property: JsonPropertyName("active")] bool Active,
[property: JsonPropertyName("sub")] string? Subject = null,
[property: JsonPropertyName("clientId")] string? ClientId = null,
[property: JsonPropertyName("scope")] string? Scope = null,
[property: JsonPropertyName("exp")] long? ExpiresAt = null,
[property: JsonPropertyName("iat")] long? IssuedAt = null,
[property: JsonPropertyName("delegatedBy")] string? DelegatedBy = null,
[property: JsonPropertyName("delegationReason")] string? DelegationReason = null);

View File

@@ -0,0 +1,258 @@
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace StellaOps.Cli.Services.Models;
// CLI-VEX-30-001: VEX consensus models for CLI
/// <summary>
/// VEX consensus list request parameters.
/// </summary>
internal sealed record VexConsensusListRequest(
[property: JsonPropertyName("vulnerabilityId")] string? VulnerabilityId = null,
[property: JsonPropertyName("productKey")] string? ProductKey = null,
[property: JsonPropertyName("purl")] string? Purl = null,
[property: JsonPropertyName("status")] string? Status = null,
[property: JsonPropertyName("policyVersion")] string? PolicyVersion = null,
[property: JsonPropertyName("limit")] int? Limit = null,
[property: JsonPropertyName("offset")] int? Offset = null);
/// <summary>
/// Paginated VEX consensus list response.
/// </summary>
internal sealed record VexConsensusListResponse(
[property: JsonPropertyName("items")] IReadOnlyList<VexConsensusItem> Items,
[property: JsonPropertyName("total")] int Total,
[property: JsonPropertyName("limit")] int Limit,
[property: JsonPropertyName("offset")] int Offset,
[property: JsonPropertyName("hasMore")] bool HasMore);
/// <summary>
/// VEX consensus item from the API.
/// </summary>
internal sealed record VexConsensusItem(
[property: JsonPropertyName("vulnerabilityId")] string VulnerabilityId,
[property: JsonPropertyName("product")] VexProductInfo Product,
[property: JsonPropertyName("status")] string Status,
[property: JsonPropertyName("calculatedAt")] DateTimeOffset CalculatedAt,
[property: JsonPropertyName("sources")] IReadOnlyList<VexConsensusSourceInfo> Sources,
[property: JsonPropertyName("conflicts")] IReadOnlyList<VexConsensusConflictInfo>? Conflicts = null,
[property: JsonPropertyName("policyVersion")] string? PolicyVersion = null,
[property: JsonPropertyName("policyDigest")] string? PolicyDigest = null,
[property: JsonPropertyName("summary")] string? Summary = null);
/// <summary>
/// VEX product information.
/// </summary>
internal sealed record VexProductInfo(
[property: JsonPropertyName("key")] string Key,
[property: JsonPropertyName("name")] string? Name = null,
[property: JsonPropertyName("version")] string? Version = null,
[property: JsonPropertyName("purl")] string? Purl = null,
[property: JsonPropertyName("cpe")] string? Cpe = null);
/// <summary>
/// VEX consensus source (accepted claim).
/// </summary>
internal sealed record VexConsensusSourceInfo(
[property: JsonPropertyName("providerId")] string ProviderId,
[property: JsonPropertyName("status")] string Status,
[property: JsonPropertyName("documentDigest")] string? DocumentDigest = null,
[property: JsonPropertyName("weight")] double Weight = 1.0,
[property: JsonPropertyName("justification")] string? Justification = null,
[property: JsonPropertyName("detail")] string? Detail = null,
[property: JsonPropertyName("confidence")] VexConfidenceInfo? Confidence = null);
/// <summary>
/// VEX consensus conflict (rejected claim).
/// </summary>
internal sealed record VexConsensusConflictInfo(
[property: JsonPropertyName("providerId")] string ProviderId,
[property: JsonPropertyName("status")] string Status,
[property: JsonPropertyName("documentDigest")] string? DocumentDigest = null,
[property: JsonPropertyName("justification")] string? Justification = null,
[property: JsonPropertyName("detail")] string? Detail = null,
[property: JsonPropertyName("reason")] string? Reason = null);
/// <summary>
/// VEX confidence information.
/// </summary>
internal sealed record VexConfidenceInfo(
[property: JsonPropertyName("level")] string? Level = null,
[property: JsonPropertyName("score")] double? Score = null,
[property: JsonPropertyName("method")] string? Method = null);
// CLI-VEX-30-002: VEX consensus detail models
/// <summary>
/// Detailed VEX consensus response including quorum, evidence, rationale, and signature status.
/// </summary>
internal sealed record VexConsensusDetailResponse(
[property: JsonPropertyName("vulnerabilityId")] string VulnerabilityId,
[property: JsonPropertyName("product")] VexProductInfo Product,
[property: JsonPropertyName("status")] string Status,
[property: JsonPropertyName("calculatedAt")] DateTimeOffset CalculatedAt,
[property: JsonPropertyName("sources")] IReadOnlyList<VexConsensusSourceInfo> Sources,
[property: JsonPropertyName("conflicts")] IReadOnlyList<VexConsensusConflictInfo>? Conflicts = null,
[property: JsonPropertyName("policyVersion")] string? PolicyVersion = null,
[property: JsonPropertyName("policyDigest")] string? PolicyDigest = null,
[property: JsonPropertyName("summary")] string? Summary = null,
[property: JsonPropertyName("quorum")] VexQuorumInfo? Quorum = null,
[property: JsonPropertyName("rationale")] VexRationaleInfo? Rationale = null,
[property: JsonPropertyName("signature")] VexSignatureInfo? Signature = null,
[property: JsonPropertyName("evidence")] IReadOnlyList<VexEvidenceInfo>? Evidence = null);
/// <summary>
/// VEX quorum information showing how consensus was reached.
/// </summary>
internal sealed record VexQuorumInfo(
[property: JsonPropertyName("required")] int Required,
[property: JsonPropertyName("achieved")] int Achieved,
[property: JsonPropertyName("threshold")] double Threshold,
[property: JsonPropertyName("totalWeight")] double TotalWeight,
[property: JsonPropertyName("weightAchieved")] double WeightAchieved,
[property: JsonPropertyName("participatingProviders")] IReadOnlyList<string>? ParticipatingProviders = null);
/// <summary>
/// VEX rationale explaining the consensus decision.
/// </summary>
internal sealed record VexRationaleInfo(
[property: JsonPropertyName("text")] string? Text = null,
[property: JsonPropertyName("justifications")] IReadOnlyList<string>? Justifications = null,
[property: JsonPropertyName("policyRules")] IReadOnlyList<string>? PolicyRules = null);
/// <summary>
/// VEX signature status information.
/// </summary>
internal sealed record VexSignatureInfo(
[property: JsonPropertyName("signed")] bool Signed,
[property: JsonPropertyName("algorithm")] string? Algorithm = null,
[property: JsonPropertyName("keyId")] string? KeyId = null,
[property: JsonPropertyName("signedAt")] DateTimeOffset? SignedAt = null,
[property: JsonPropertyName("verificationStatus")] string? VerificationStatus = null,
[property: JsonPropertyName("certificateChain")] IReadOnlyList<string>? CertificateChain = null);
/// <summary>
/// VEX evidence supporting the consensus decision.
/// </summary>
internal sealed record VexEvidenceInfo(
[property: JsonPropertyName("type")] string Type,
[property: JsonPropertyName("providerId")] string ProviderId,
[property: JsonPropertyName("documentId")] string? DocumentId = null,
[property: JsonPropertyName("documentDigest")] string? DocumentDigest = null,
[property: JsonPropertyName("timestamp")] DateTimeOffset? Timestamp = null,
[property: JsonPropertyName("content")] string? Content = null);
// CLI-VEX-30-003: VEX simulation models
/// <summary>
/// VEX simulation request with trust/threshold overrides.
/// </summary>
internal sealed record VexSimulationRequest(
[property: JsonPropertyName("vulnerabilityId")] string? VulnerabilityId = null,
[property: JsonPropertyName("productKey")] string? ProductKey = null,
[property: JsonPropertyName("purl")] string? Purl = null,
[property: JsonPropertyName("trustOverrides")] IReadOnlyDictionary<string, double>? TrustOverrides = null,
[property: JsonPropertyName("thresholdOverride")] double? ThresholdOverride = null,
[property: JsonPropertyName("quorumOverride")] int? QuorumOverride = null,
[property: JsonPropertyName("excludeProviders")] IReadOnlyList<string>? ExcludeProviders = null,
[property: JsonPropertyName("includeOnly")] IReadOnlyList<string>? IncludeOnly = null);
/// <summary>
/// VEX simulation response showing before/after comparison.
/// </summary>
internal sealed record VexSimulationResponse(
[property: JsonPropertyName("items")] IReadOnlyList<VexSimulationResultItem> Items,
[property: JsonPropertyName("parameters")] VexSimulationParameters Parameters,
[property: JsonPropertyName("summary")] VexSimulationSummary Summary);
/// <summary>
/// Individual VEX simulation result showing the delta.
/// </summary>
internal sealed record VexSimulationResultItem(
[property: JsonPropertyName("vulnerabilityId")] string VulnerabilityId,
[property: JsonPropertyName("product")] VexProductInfo Product,
[property: JsonPropertyName("before")] VexSimulationState Before,
[property: JsonPropertyName("after")] VexSimulationState After,
[property: JsonPropertyName("changed")] bool Changed,
[property: JsonPropertyName("changeType")] string? ChangeType = null);
/// <summary>
/// VEX state for simulation comparison.
/// </summary>
internal sealed record VexSimulationState(
[property: JsonPropertyName("status")] string Status,
[property: JsonPropertyName("quorumAchieved")] int QuorumAchieved,
[property: JsonPropertyName("weightAchieved")] double WeightAchieved,
[property: JsonPropertyName("sources")] IReadOnlyList<string>? Sources = null);
/// <summary>
/// Parameters used in the simulation.
/// </summary>
internal sealed record VexSimulationParameters(
[property: JsonPropertyName("threshold")] double Threshold,
[property: JsonPropertyName("quorum")] int Quorum,
[property: JsonPropertyName("trustWeights")] IReadOnlyDictionary<string, double>? TrustWeights = null,
[property: JsonPropertyName("excludedProviders")] IReadOnlyList<string>? ExcludedProviders = null);
/// <summary>
/// Summary of simulation results.
/// </summary>
internal sealed record VexSimulationSummary(
[property: JsonPropertyName("totalEvaluated")] int TotalEvaluated,
[property: JsonPropertyName("totalChanged")] int TotalChanged,
[property: JsonPropertyName("statusUpgrades")] int StatusUpgrades,
[property: JsonPropertyName("statusDowngrades")] int StatusDowngrades,
[property: JsonPropertyName("noChange")] int NoChange);
// CLI-VEX-30-004: VEX export models
/// <summary>
/// VEX export request parameters.
/// </summary>
internal sealed record VexExportRequest(
[property: JsonPropertyName("vulnerabilityIds")] IReadOnlyList<string>? VulnerabilityIds = null,
[property: JsonPropertyName("productKeys")] IReadOnlyList<string>? ProductKeys = null,
[property: JsonPropertyName("purls")] IReadOnlyList<string>? Purls = null,
[property: JsonPropertyName("statuses")] IReadOnlyList<string>? Statuses = null,
[property: JsonPropertyName("policyVersion")] string? PolicyVersion = null,
[property: JsonPropertyName("signed")] bool Signed = true,
[property: JsonPropertyName("format")] string Format = "ndjson");
/// <summary>
/// VEX export response with download information.
/// </summary>
internal sealed record VexExportResponse(
[property: JsonPropertyName("exportId")] string ExportId,
[property: JsonPropertyName("downloadUrl")] string? DownloadUrl = null,
[property: JsonPropertyName("format")] string Format = "ndjson",
[property: JsonPropertyName("itemCount")] int ItemCount = 0,
[property: JsonPropertyName("signed")] bool Signed = false,
[property: JsonPropertyName("signatureAlgorithm")] string? SignatureAlgorithm = null,
[property: JsonPropertyName("signatureKeyId")] string? SignatureKeyId = null,
[property: JsonPropertyName("digest")] string? Digest = null,
[property: JsonPropertyName("digestAlgorithm")] string? DigestAlgorithm = null,
[property: JsonPropertyName("expiresAt")] DateTimeOffset? ExpiresAt = null);
/// <summary>
/// VEX export signature verification request.
/// </summary>
internal sealed record VexExportVerifyRequest(
[property: JsonPropertyName("filePath")] string FilePath,
[property: JsonPropertyName("signaturePath")] string? SignaturePath = null,
[property: JsonPropertyName("expectedDigest")] string? ExpectedDigest = null,
[property: JsonPropertyName("publicKeyPath")] string? PublicKeyPath = null);
/// <summary>
/// VEX export signature verification result.
/// </summary>
internal sealed record VexExportVerifyResult(
[property: JsonPropertyName("valid")] bool Valid,
[property: JsonPropertyName("signatureStatus")] string SignatureStatus,
[property: JsonPropertyName("digestMatch")] bool? DigestMatch = null,
[property: JsonPropertyName("actualDigest")] string? ActualDigest = null,
[property: JsonPropertyName("expectedDigest")] string? ExpectedDigest = null,
[property: JsonPropertyName("keyId")] string? KeyId = null,
[property: JsonPropertyName("signedAt")] DateTimeOffset? SignedAt = null,
[property: JsonPropertyName("errors")] IReadOnlyList<string>? Errors = null);

View File

@@ -0,0 +1,291 @@
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace StellaOps.Cli.Services.Models;
// CLI-VULN-29-001: Vulnerability Explorer models for CLI
/// <summary>
/// Vulnerability list request parameters.
/// </summary>
internal sealed record VulnListRequest(
[property: JsonPropertyName("vulnerabilityId")] string? VulnerabilityId = null,
[property: JsonPropertyName("severity")] string? Severity = null,
[property: JsonPropertyName("status")] string? Status = null,
[property: JsonPropertyName("purl")] string? Purl = null,
[property: JsonPropertyName("cpe")] string? Cpe = null,
[property: JsonPropertyName("sbomId")] string? SbomId = null,
[property: JsonPropertyName("policyId")] string? PolicyId = null,
[property: JsonPropertyName("policyVersion")] int? PolicyVersion = null,
[property: JsonPropertyName("groupBy")] string? GroupBy = null,
[property: JsonPropertyName("limit")] int? Limit = null,
[property: JsonPropertyName("offset")] int? Offset = null,
[property: JsonPropertyName("cursor")] string? Cursor = null);
/// <summary>
/// Paginated vulnerability list response.
/// </summary>
internal sealed record VulnListResponse(
[property: JsonPropertyName("items")] IReadOnlyList<VulnItem> Items,
[property: JsonPropertyName("total")] int Total,
[property: JsonPropertyName("limit")] int Limit,
[property: JsonPropertyName("offset")] int Offset,
[property: JsonPropertyName("hasMore")] bool HasMore,
[property: JsonPropertyName("nextCursor")] string? NextCursor = null,
[property: JsonPropertyName("grouping")] VulnGroupingInfo? Grouping = null);
/// <summary>
/// Individual vulnerability item from the explorer.
/// </summary>
internal sealed record VulnItem(
[property: JsonPropertyName("vulnerabilityId")] string VulnerabilityId,
[property: JsonPropertyName("status")] string Status,
[property: JsonPropertyName("severity")] VulnSeverityInfo Severity,
[property: JsonPropertyName("affectedPackages")] IReadOnlyList<VulnAffectedPackage> AffectedPackages,
[property: JsonPropertyName("vexStatus")] string? VexStatus = null,
[property: JsonPropertyName("policyFindingId")] string? PolicyFindingId = null,
[property: JsonPropertyName("aliases")] IReadOnlyList<string>? Aliases = null,
[property: JsonPropertyName("summary")] string? Summary = null,
[property: JsonPropertyName("publishedAt")] DateTimeOffset? PublishedAt = null,
[property: JsonPropertyName("updatedAt")] DateTimeOffset? UpdatedAt = null,
[property: JsonPropertyName("assignee")] string? Assignee = null,
[property: JsonPropertyName("dueDate")] DateTimeOffset? DueDate = null,
[property: JsonPropertyName("tags")] IReadOnlyList<string>? Tags = null);
/// <summary>
/// Vulnerability severity information.
/// </summary>
internal sealed record VulnSeverityInfo(
[property: JsonPropertyName("level")] string Level,
[property: JsonPropertyName("score")] double? Score = null,
[property: JsonPropertyName("vector")] string? Vector = null,
[property: JsonPropertyName("source")] string? Source = null);
/// <summary>
/// Affected package information.
/// </summary>
internal sealed record VulnAffectedPackage(
[property: JsonPropertyName("purl")] string? Purl = null,
[property: JsonPropertyName("cpe")] string? Cpe = null,
[property: JsonPropertyName("name")] string? Name = null,
[property: JsonPropertyName("version")] string? Version = null,
[property: JsonPropertyName("fixedIn")] string? FixedIn = null,
[property: JsonPropertyName("sbomId")] string? SbomId = null,
[property: JsonPropertyName("pathCount")] int? PathCount = null);
/// <summary>
/// Grouping information for aggregated results.
/// </summary>
internal sealed record VulnGroupingInfo(
[property: JsonPropertyName("field")] string Field,
[property: JsonPropertyName("groups")] IReadOnlyList<VulnGroup> Groups);
/// <summary>
/// A group in aggregated results.
/// </summary>
internal sealed record VulnGroup(
[property: JsonPropertyName("key")] string Key,
[property: JsonPropertyName("count")] int Count,
[property: JsonPropertyName("criticalCount")] int? CriticalCount = null,
[property: JsonPropertyName("highCount")] int? HighCount = null,
[property: JsonPropertyName("mediumCount")] int? MediumCount = null,
[property: JsonPropertyName("lowCount")] int? LowCount = null);
// CLI-VULN-29-002: Vulnerability detail models
/// <summary>
/// Detailed vulnerability response including evidence, rationale, paths, and ledger.
/// </summary>
internal sealed record VulnDetailResponse(
[property: JsonPropertyName("vulnerabilityId")] string VulnerabilityId,
[property: JsonPropertyName("status")] string Status,
[property: JsonPropertyName("severity")] VulnSeverityInfo Severity,
[property: JsonPropertyName("affectedPackages")] IReadOnlyList<VulnAffectedPackage> AffectedPackages,
[property: JsonPropertyName("vexStatus")] string? VexStatus = null,
[property: JsonPropertyName("policyFindingId")] string? PolicyFindingId = null,
[property: JsonPropertyName("aliases")] IReadOnlyList<string>? Aliases = null,
[property: JsonPropertyName("summary")] string? Summary = null,
[property: JsonPropertyName("description")] string? Description = null,
[property: JsonPropertyName("publishedAt")] DateTimeOffset? PublishedAt = null,
[property: JsonPropertyName("updatedAt")] DateTimeOffset? UpdatedAt = null,
[property: JsonPropertyName("assignee")] string? Assignee = null,
[property: JsonPropertyName("dueDate")] DateTimeOffset? DueDate = null,
[property: JsonPropertyName("tags")] IReadOnlyList<string>? Tags = null,
[property: JsonPropertyName("evidence")] IReadOnlyList<VulnEvidenceInfo>? Evidence = null,
[property: JsonPropertyName("policyRationale")] VulnPolicyRationale? PolicyRationale = null,
[property: JsonPropertyName("dependencyPaths")] IReadOnlyList<VulnDependencyPath>? DependencyPaths = null,
[property: JsonPropertyName("ledger")] IReadOnlyList<VulnLedgerEntry>? Ledger = null,
[property: JsonPropertyName("references")] IReadOnlyList<VulnReference>? References = null);
/// <summary>
/// Evidence supporting the vulnerability assessment.
/// </summary>
internal sealed record VulnEvidenceInfo(
[property: JsonPropertyName("type")] string Type,
[property: JsonPropertyName("source")] string Source,
[property: JsonPropertyName("documentId")] string? DocumentId = null,
[property: JsonPropertyName("documentDigest")] string? DocumentDigest = null,
[property: JsonPropertyName("timestamp")] DateTimeOffset? Timestamp = null,
[property: JsonPropertyName("content")] string? Content = null);
/// <summary>
/// Policy rationale explaining the status decision.
/// </summary>
internal sealed record VulnPolicyRationale(
[property: JsonPropertyName("policyId")] string PolicyId,
[property: JsonPropertyName("policyVersion")] int PolicyVersion,
[property: JsonPropertyName("rules")] IReadOnlyList<VulnPolicyRuleResult>? Rules = null,
[property: JsonPropertyName("summary")] string? Summary = null);
/// <summary>
/// Result of a policy rule evaluation.
/// </summary>
internal sealed record VulnPolicyRuleResult(
[property: JsonPropertyName("rule")] string Rule,
[property: JsonPropertyName("result")] string Result,
[property: JsonPropertyName("weight")] double? Weight = null,
[property: JsonPropertyName("reason")] string? Reason = null);
/// <summary>
/// Dependency path showing how the vulnerable package is included.
/// </summary>
internal sealed record VulnDependencyPath(
[property: JsonPropertyName("path")] IReadOnlyList<string> Path,
[property: JsonPropertyName("sbomId")] string? SbomId = null,
[property: JsonPropertyName("depth")] int? Depth = null);
/// <summary>
/// Ledger entry tracking vulnerability workflow history.
/// </summary>
internal sealed record VulnLedgerEntry(
[property: JsonPropertyName("timestamp")] DateTimeOffset Timestamp,
[property: JsonPropertyName("action")] string Action,
[property: JsonPropertyName("actor")] string? Actor = null,
[property: JsonPropertyName("fromStatus")] string? FromStatus = null,
[property: JsonPropertyName("toStatus")] string? ToStatus = null,
[property: JsonPropertyName("comment")] string? Comment = null,
[property: JsonPropertyName("metadata")] IReadOnlyDictionary<string, string>? Metadata = null);
/// <summary>
/// Reference link for the vulnerability.
/// </summary>
internal sealed record VulnReference(
[property: JsonPropertyName("type")] string Type,
[property: JsonPropertyName("url")] string Url,
[property: JsonPropertyName("title")] string? Title = null);
// CLI-VULN-29-003: Vulnerability workflow models
/// <summary>
/// Workflow action request for vulnerability operations.
/// </summary>
internal sealed record VulnWorkflowRequest(
[property: JsonPropertyName("action")] string Action,
[property: JsonPropertyName("vulnerabilityIds")] IReadOnlyList<string>? VulnerabilityIds = null,
[property: JsonPropertyName("filter")] VulnFilterSpec? Filter = null,
[property: JsonPropertyName("assignee")] string? Assignee = null,
[property: JsonPropertyName("comment")] string? Comment = null,
[property: JsonPropertyName("dueDate")] DateTimeOffset? DueDate = null,
[property: JsonPropertyName("justification")] string? Justification = null,
[property: JsonPropertyName("fixVersion")] string? FixVersion = null,
[property: JsonPropertyName("idempotencyKey")] string? IdempotencyKey = null);
/// <summary>
/// Filter specification for bulk workflow operations.
/// </summary>
internal sealed record VulnFilterSpec(
[property: JsonPropertyName("severity")] string? Severity = null,
[property: JsonPropertyName("status")] string? Status = null,
[property: JsonPropertyName("purl")] string? Purl = null,
[property: JsonPropertyName("sbomId")] string? SbomId = null,
[property: JsonPropertyName("policyId")] string? PolicyId = null);
/// <summary>
/// Workflow action response with affected items.
/// </summary>
internal sealed record VulnWorkflowResponse(
[property: JsonPropertyName("success")] bool Success,
[property: JsonPropertyName("action")] string Action,
[property: JsonPropertyName("affectedCount")] int AffectedCount,
[property: JsonPropertyName("affectedIds")] IReadOnlyList<string>? AffectedIds = null,
[property: JsonPropertyName("errors")] IReadOnlyList<VulnWorkflowError>? Errors = null,
[property: JsonPropertyName("idempotencyKey")] string? IdempotencyKey = null);
/// <summary>
/// Error detail for workflow operations.
/// </summary>
internal sealed record VulnWorkflowError(
[property: JsonPropertyName("vulnerabilityId")] string VulnerabilityId,
[property: JsonPropertyName("code")] string Code,
[property: JsonPropertyName("message")] string Message);
// CLI-VULN-29-004: Vulnerability simulation models
/// <summary>
/// Simulation request for policy/VEX changes.
/// </summary>
internal sealed record VulnSimulationRequest(
[property: JsonPropertyName("policyId")] string? PolicyId = null,
[property: JsonPropertyName("policyVersion")] int? PolicyVersion = null,
[property: JsonPropertyName("vexOverrides")] IReadOnlyDictionary<string, string>? VexOverrides = null,
[property: JsonPropertyName("severityThreshold")] string? SeverityThreshold = null,
[property: JsonPropertyName("sbomIds")] IReadOnlyList<string>? SbomIds = null,
[property: JsonPropertyName("outputMarkdown")] bool OutputMarkdown = false);
/// <summary>
/// Simulation response showing deltas.
/// </summary>
internal sealed record VulnSimulationResponse(
[property: JsonPropertyName("items")] IReadOnlyList<VulnSimulationDelta> Items,
[property: JsonPropertyName("summary")] VulnSimulationSummary Summary,
[property: JsonPropertyName("markdownReport")] string? MarkdownReport = null);
/// <summary>
/// Individual delta in simulation results.
/// </summary>
internal sealed record VulnSimulationDelta(
[property: JsonPropertyName("vulnerabilityId")] string VulnerabilityId,
[property: JsonPropertyName("beforeStatus")] string BeforeStatus,
[property: JsonPropertyName("afterStatus")] string AfterStatus,
[property: JsonPropertyName("changed")] bool Changed,
[property: JsonPropertyName("changeReason")] string? ChangeReason = null);
/// <summary>
/// Summary of simulation results.
/// </summary>
internal sealed record VulnSimulationSummary(
[property: JsonPropertyName("totalEvaluated")] int TotalEvaluated,
[property: JsonPropertyName("totalChanged")] int TotalChanged,
[property: JsonPropertyName("statusUpgrades")] int StatusUpgrades,
[property: JsonPropertyName("statusDowngrades")] int StatusDowngrades,
[property: JsonPropertyName("noChange")] int NoChange);
// CLI-VULN-29-005: Vulnerability export models
/// <summary>
/// Export request for vulnerability evidence bundles.
/// </summary>
internal sealed record VulnExportRequest(
[property: JsonPropertyName("vulnerabilityIds")] IReadOnlyList<string>? VulnerabilityIds = null,
[property: JsonPropertyName("sbomIds")] IReadOnlyList<string>? SbomIds = null,
[property: JsonPropertyName("policyId")] string? PolicyId = null,
[property: JsonPropertyName("format")] string Format = "ndjson",
[property: JsonPropertyName("includeEvidence")] bool IncludeEvidence = true,
[property: JsonPropertyName("includeLedger")] bool IncludeLedger = true,
[property: JsonPropertyName("signed")] bool Signed = true);
/// <summary>
/// Export response with download information.
/// </summary>
internal sealed record VulnExportResponse(
[property: JsonPropertyName("exportId")] string ExportId,
[property: JsonPropertyName("downloadUrl")] string? DownloadUrl = null,
[property: JsonPropertyName("format")] string Format = "ndjson",
[property: JsonPropertyName("itemCount")] int ItemCount = 0,
[property: JsonPropertyName("signed")] bool Signed = false,
[property: JsonPropertyName("signatureAlgorithm")] string? SignatureAlgorithm = null,
[property: JsonPropertyName("signatureKeyId")] string? SignatureKeyId = null,
[property: JsonPropertyName("digest")] string? Digest = null,
[property: JsonPropertyName("digestAlgorithm")] string? DigestAlgorithm = null,
[property: JsonPropertyName("expiresAt")] DateTimeOffset? ExpiresAt = null);