410 lines
12 KiB
C#
410 lines
12 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel.DataAnnotations;
|
|
using System.Text.Json;
|
|
using System.Text.Json.Serialization;
|
|
|
|
namespace StellaOps.SbomService.Models;
|
|
|
|
public sealed record SbomUploadRequest
|
|
{
|
|
[JsonPropertyName("artifactRef")]
|
|
public string ArtifactRef { get; init; } = string.Empty;
|
|
|
|
[JsonPropertyName("sbom")]
|
|
public JsonElement? Sbom { get; init; }
|
|
|
|
[JsonPropertyName("sbomBase64")]
|
|
public string? SbomBase64 { get; init; }
|
|
|
|
[JsonPropertyName("format")]
|
|
public string? Format { get; init; }
|
|
|
|
[JsonPropertyName("source")]
|
|
public SbomUploadSource? Source { get; init; }
|
|
|
|
// LIN-BE-003: Lineage ancestry fields
|
|
[JsonPropertyName("parentArtifactDigest")]
|
|
public string? ParentArtifactDigest { get; init; }
|
|
|
|
[JsonPropertyName("baseImageRef")]
|
|
public string? BaseImageRef { get; init; }
|
|
|
|
[JsonPropertyName("baseImageDigest")]
|
|
public string? BaseImageDigest { get; init; }
|
|
}
|
|
|
|
public sealed record SbomUploadSource
|
|
{
|
|
[JsonPropertyName("tool")]
|
|
public string? Tool { get; init; }
|
|
|
|
[JsonPropertyName("version")]
|
|
public string? Version { get; init; }
|
|
|
|
[JsonPropertyName("ciContext")]
|
|
public SbomUploadCiContext? CiContext { get; init; }
|
|
}
|
|
|
|
public sealed record SbomUploadCiContext
|
|
{
|
|
[JsonPropertyName("buildId")]
|
|
public string? BuildId { get; init; }
|
|
|
|
[JsonPropertyName("repository")]
|
|
public string? Repository { get; init; }
|
|
}
|
|
|
|
public sealed record SbomUploadResponse
|
|
{
|
|
[JsonPropertyName("sbomId")]
|
|
public string SbomId { get; init; } = string.Empty;
|
|
|
|
[JsonPropertyName("artifactRef")]
|
|
public string ArtifactRef { get; init; } = string.Empty;
|
|
|
|
[JsonPropertyName("digest")]
|
|
public string Digest { get; init; } = string.Empty;
|
|
|
|
[JsonPropertyName("format")]
|
|
public string Format { get; init; } = string.Empty;
|
|
|
|
[JsonPropertyName("formatVersion")]
|
|
public string FormatVersion { get; init; } = string.Empty;
|
|
|
|
[JsonPropertyName("validationResult")]
|
|
public SbomValidationSummary ValidationResult { get; init; } = new();
|
|
|
|
[JsonPropertyName("analysisJobId")]
|
|
public string AnalysisJobId { get; init; } = string.Empty;
|
|
}
|
|
|
|
public sealed record SbomValidationSummary
|
|
{
|
|
[JsonPropertyName("valid")]
|
|
public bool Valid { get; init; }
|
|
|
|
[JsonPropertyName("qualityScore")]
|
|
public double QualityScore { get; init; }
|
|
|
|
[JsonPropertyName("warnings")]
|
|
public IReadOnlyList<string> Warnings { get; init; } = Array.Empty<string>();
|
|
|
|
[JsonPropertyName("errors")]
|
|
public IReadOnlyList<string> Errors { get; init; } = Array.Empty<string>();
|
|
|
|
[JsonPropertyName("componentCount")]
|
|
public int ComponentCount { get; init; }
|
|
}
|
|
|
|
public sealed record SbomNormalizedComponent(
|
|
string Key,
|
|
string Name,
|
|
string? Version,
|
|
string? Purl,
|
|
string? License);
|
|
|
|
public sealed record SbomLedgerSubmission(
|
|
string ArtifactRef,
|
|
string Digest,
|
|
string Format,
|
|
string FormatVersion,
|
|
string Source,
|
|
SbomUploadSource? Provenance,
|
|
IReadOnlyList<SbomNormalizedComponent> Components,
|
|
Guid? ParentVersionId,
|
|
// LIN-BE-003: Lineage ancestry fields
|
|
string? ParentArtifactDigest = null,
|
|
string? BaseImageRef = null,
|
|
string? BaseImageDigest = null,
|
|
string? BuildId = null);
|
|
|
|
public sealed record SbomLedgerVersion
|
|
{
|
|
public required Guid VersionId { get; init; }
|
|
public required Guid ChainId { get; init; }
|
|
public required string ArtifactRef { get; init; }
|
|
public required int SequenceNumber { get; init; }
|
|
public required string Digest { get; init; }
|
|
public required string Format { get; init; }
|
|
public required string FormatVersion { get; init; }
|
|
public required string Source { get; init; }
|
|
public required DateTimeOffset CreatedAtUtc { get; init; }
|
|
public SbomUploadSource? Provenance { get; init; }
|
|
public Guid? ParentVersionId { get; init; }
|
|
public string? ParentDigest { get; init; }
|
|
// LIN-BE-003: Lineage ancestry fields
|
|
public string? ParentArtifactDigest { get; init; }
|
|
public string? BaseImageRef { get; init; }
|
|
public string? BaseImageDigest { get; init; }
|
|
public string? BuildId { get; init; }
|
|
public IReadOnlyList<SbomNormalizedComponent> Components { get; init; } = Array.Empty<SbomNormalizedComponent>();
|
|
// LIN-BE-023: Replay hash for reproducibility verification
|
|
public string? ReplayHash { get; init; }
|
|
public ReplayHashInputSnapshot? ReplayHashInputs { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Snapshot of inputs used to compute a replay hash.
|
|
/// Stored alongside the version for audit and reproducibility.
|
|
/// Sprint: LIN-BE-023
|
|
/// </summary>
|
|
public sealed record ReplayHashInputSnapshot
|
|
{
|
|
public required string SbomDigest { get; init; }
|
|
public required string FeedsSnapshotDigest { get; init; }
|
|
public required string PolicyVersion { get; init; }
|
|
public required string VexVerdictsDigest { get; init; }
|
|
public required DateTimeOffset ComputedAt { get; init; }
|
|
}
|
|
|
|
public sealed record SbomVersionHistoryItem(
|
|
Guid VersionId,
|
|
int SequenceNumber,
|
|
string Digest,
|
|
string Format,
|
|
string FormatVersion,
|
|
string Source,
|
|
DateTimeOffset CreatedAtUtc,
|
|
Guid? ParentVersionId,
|
|
string? ParentDigest,
|
|
int ComponentCount);
|
|
|
|
public sealed record SbomVersionHistoryResult(
|
|
string ArtifactRef,
|
|
Guid ChainId,
|
|
IReadOnlyList<SbomVersionHistoryItem> Versions,
|
|
string? NextCursor);
|
|
|
|
public sealed record SbomTemporalQueryResult(
|
|
string ArtifactRef,
|
|
SbomVersionHistoryItem? Version);
|
|
|
|
public sealed record SbomDiffComponent(
|
|
string Key,
|
|
string Name,
|
|
string? Purl,
|
|
string? Version,
|
|
string? License);
|
|
|
|
public sealed record SbomVersionChange(
|
|
string Key,
|
|
string Name,
|
|
string? Purl,
|
|
string? FromVersion,
|
|
string? ToVersion);
|
|
|
|
public sealed record SbomLicenseChange(
|
|
string Key,
|
|
string Name,
|
|
string? Purl,
|
|
string? FromLicense,
|
|
string? ToLicense);
|
|
|
|
public sealed record SbomDiffSummary(
|
|
int AddedCount,
|
|
int RemovedCount,
|
|
int VersionChangedCount,
|
|
int LicenseChangedCount);
|
|
|
|
public sealed record SbomDiffResult
|
|
{
|
|
public required Guid BeforeVersionId { get; init; }
|
|
public required Guid AfterVersionId { get; init; }
|
|
public IReadOnlyList<SbomDiffComponent> Added { get; init; } = Array.Empty<SbomDiffComponent>();
|
|
public IReadOnlyList<SbomDiffComponent> Removed { get; init; } = Array.Empty<SbomDiffComponent>();
|
|
public IReadOnlyList<SbomVersionChange> VersionChanged { get; init; } = Array.Empty<SbomVersionChange>();
|
|
public IReadOnlyList<SbomLicenseChange> LicenseChanged { get; init; } = Array.Empty<SbomLicenseChange>();
|
|
public SbomDiffSummary Summary { get; init; } = new(0, 0, 0, 0);
|
|
}
|
|
|
|
public sealed record SbomLineageNode(
|
|
Guid VersionId,
|
|
int SequenceNumber,
|
|
string Digest,
|
|
string Source,
|
|
DateTimeOffset CreatedAtUtc);
|
|
|
|
public sealed record SbomLineageEdge(
|
|
Guid FromVersionId,
|
|
Guid ToVersionId,
|
|
string Relationship);
|
|
|
|
public static class SbomLineageRelationships
|
|
{
|
|
public const string Parent = "parent";
|
|
public const string Build = "build";
|
|
public const string Base = "base";
|
|
}
|
|
|
|
public sealed record SbomLineageResult(
|
|
string ArtifactRef,
|
|
Guid ChainId,
|
|
IReadOnlyList<SbomLineageNode> Nodes,
|
|
IReadOnlyList<SbomLineageEdge> Edges);
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// Extended Lineage Models for SBOM Lineage Graph
|
|
// Sprint: SPRINT_20251228_005_BE_sbom_lineage_graph_i (LIN-BE-004/005)
|
|
// -----------------------------------------------------------------------------
|
|
|
|
/// <summary>
|
|
/// Persistent lineage edge stored in database.
|
|
/// Uses artifact digests as stable identifiers across systems.
|
|
/// </summary>
|
|
public sealed record SbomLineageEdgeEntity
|
|
{
|
|
public required Guid Id { get; init; }
|
|
public required string ParentDigest { get; init; }
|
|
public required string ChildDigest { get; init; }
|
|
public required LineageRelationship Relationship { get; init; }
|
|
public required Guid TenantId { get; init; }
|
|
public required DateTimeOffset CreatedAt { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Lineage relationship type.
|
|
/// </summary>
|
|
public enum LineageRelationship
|
|
{
|
|
/// <summary>
|
|
/// Direct version succession (v1.0 → v1.1).
|
|
/// </summary>
|
|
Parent,
|
|
|
|
/// <summary>
|
|
/// Same CI build produced multiple artifacts (multi-arch).
|
|
/// </summary>
|
|
Build,
|
|
|
|
/// <summary>
|
|
/// Derived from base image (FROM instruction).
|
|
/// </summary>
|
|
Base
|
|
}
|
|
|
|
/// <summary>
|
|
/// Extended lineage node with badge information for UI.
|
|
/// </summary>
|
|
public sealed record SbomLineageNodeExtended
|
|
{
|
|
public required Guid Id { get; init; }
|
|
public required string Digest { get; init; }
|
|
public required string ArtifactRef { get; init; }
|
|
public required int SequenceNumber { get; init; }
|
|
public required DateTimeOffset CreatedAt { get; init; }
|
|
public required string Source { get; init; }
|
|
public SbomLineageBadges? Badges { get; init; }
|
|
public string? ReplayHash { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Badge information for lineage node.
|
|
/// </summary>
|
|
public sealed record SbomLineageBadges
|
|
{
|
|
public int NewVulns { get; init; }
|
|
public int ResolvedVulns { get; init; }
|
|
public string SignatureStatus { get; init; } = "unknown";
|
|
public int ComponentCount { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Extended lineage edge with digest-based endpoints.
|
|
/// </summary>
|
|
public sealed record SbomLineageEdgeExtended
|
|
{
|
|
public required string From { get; init; }
|
|
public required string To { get; init; }
|
|
public required string Relationship { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Complete lineage graph response.
|
|
/// </summary>
|
|
public sealed record SbomLineageGraphResponse
|
|
{
|
|
public required string Artifact { get; init; }
|
|
public required IReadOnlyList<SbomLineageNodeExtended> Nodes { get; init; }
|
|
public required IReadOnlyList<SbomLineageEdgeExtended> Edges { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Lineage diff response with component and VEX deltas.
|
|
/// </summary>
|
|
public sealed record SbomLineageDiffResponse
|
|
{
|
|
public required SbomDiffResult SbomDiff { get; init; }
|
|
public required IReadOnlyList<VexDeltaSummary> VexDiff { get; init; }
|
|
public IReadOnlyList<ReachabilityDeltaSummary>? ReachabilityDiff { get; init; }
|
|
public required string ReplayHash { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// VEX status change between versions.
|
|
/// </summary>
|
|
public sealed record VexDeltaSummary
|
|
{
|
|
public required string Cve { get; init; }
|
|
public required string FromStatus { get; init; }
|
|
public required string ToStatus { get; init; }
|
|
public string? Reason { get; init; }
|
|
public string? EvidenceLink { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reachability change between versions.
|
|
/// </summary>
|
|
public sealed record ReachabilityDeltaSummary
|
|
{
|
|
public required string Cve { get; init; }
|
|
public required string FromStatus { get; init; }
|
|
public required string ToStatus { get; init; }
|
|
public int PathsAdded { get; init; }
|
|
public int PathsRemoved { get; init; }
|
|
public IReadOnlyList<string>? GatesAdded { get; init; }
|
|
public IReadOnlyList<string>? GatesRemoved { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Query options for lineage graph.
|
|
/// </summary>
|
|
public sealed record SbomLineageQueryOptions
|
|
{
|
|
public int MaxDepth { get; init; } = 10;
|
|
public bool IncludeVerdicts { get; init; } = true;
|
|
public bool IncludeBadges { get; init; } = true;
|
|
public bool IncludeReplayHash { get; init; }
|
|
}
|
|
|
|
public sealed record SbomRetentionResult(
|
|
int VersionsPruned,
|
|
int ChainsTouched,
|
|
IReadOnlyList<string> Messages);
|
|
|
|
public sealed class SbomLedgerOptions
|
|
{
|
|
[Range(1, 10000)]
|
|
public int MaxVersionsPerArtifact { get; init; } = 50;
|
|
|
|
[Range(0, 36500)]
|
|
public int MaxAgeDays { get; init; }
|
|
|
|
[Range(1, 10000)]
|
|
public int MinVersionsToKeep { get; init; } = 1;
|
|
}
|
|
|
|
public sealed record SbomLedgerAuditEntry(
|
|
string ArtifactRef,
|
|
Guid VersionId,
|
|
string Action,
|
|
DateTimeOffset TimestampUtc,
|
|
string? Details);
|
|
|
|
public sealed record SbomAnalysisJob(
|
|
string JobId,
|
|
string ArtifactRef,
|
|
Guid VersionId,
|
|
DateTimeOffset CreatedAtUtc,
|
|
string Status);
|