//
// Copyright (c) StellaOps. Licensed under the BUSL-1.1.
//
using System.Collections.Immutable;
namespace StellaOps.Scanner.Emit.Pedigree;
///
/// Provider interface for retrieving component pedigree data from Feedser.
/// Sprint: SPRINT_20260107_005_002 Task PD-001
///
public interface IPedigreeDataProvider
{
///
/// Retrieves pedigree data for a component identified by its PURL.
///
/// Package URL identifying the component.
/// Cancellation token.
/// Pedigree data if available, null otherwise.
Task GetPedigreeAsync(
string purl,
CancellationToken cancellationToken = default);
///
/// Retrieves pedigree data for multiple components.
///
/// Package URLs identifying the components.
/// Cancellation token.
/// Dictionary of PURL to pedigree data (missing components not included).
Task> GetPedigreesBatchAsync(
IEnumerable purls,
CancellationToken cancellationToken = default);
}
///
/// Aggregate of pedigree information for a component.
///
public sealed record PedigreeData
{
///
/// Gets the ancestor components (upstream sources).
///
public ImmutableArray Ancestors { get; init; } = ImmutableArray.Empty;
///
/// Gets the variant components (distro-specific packages derived from same source).
///
public ImmutableArray Variants { get; init; } = ImmutableArray.Empty;
///
/// Gets the relevant commits (security fixes, backports).
///
public ImmutableArray Commits { get; init; } = ImmutableArray.Empty;
///
/// Gets the patches applied to the component.
///
public ImmutableArray Patches { get; init; } = ImmutableArray.Empty;
///
/// Gets optional notes about the pedigree (e.g., backport explanation).
///
public string? Notes { get; init; }
///
/// Gets whether any pedigree data is present.
///
public bool HasData =>
!Ancestors.IsDefaultOrEmpty ||
!Variants.IsDefaultOrEmpty ||
!Commits.IsDefaultOrEmpty ||
!Patches.IsDefaultOrEmpty ||
Notes is not null;
}
///
/// Represents an upstream ancestor component.
///
public sealed record AncestorComponent
{
///
/// Gets the component type (e.g., "library", "application").
///
public string Type { get; init; } = "library";
///
/// Gets the component name.
///
public required string Name { get; init; }
///
/// Gets the upstream version.
///
public required string Version { get; init; }
///
/// Gets the Package URL for the ancestor.
///
public string? Purl { get; init; }
///
/// Gets the URL to the upstream project.
///
public string? ProjectUrl { get; init; }
///
/// Gets the relationship level (1 = direct parent, 2 = grandparent, etc.).
///
public int Level { get; init; } = 1;
}
///
/// Represents a variant component (distro-specific package).
///
public sealed record VariantComponent
{
///
/// Gets the component type.
///
public string Type { get; init; } = "library";
///
/// Gets the package name in the distribution.
///
public required string Name { get; init; }
///
/// Gets the distribution-specific version.
///
public required string Version { get; init; }
///
/// Gets the Package URL for the variant.
///
public required string Purl { get; init; }
///
/// Gets the distribution name (e.g., "debian", "rhel", "alpine").
///
public string? Distribution { get; init; }
///
/// Gets the distribution release (e.g., "bookworm", "9.3").
///
public string? Release { get; init; }
}
///
/// Represents commit information for a security fix or backport.
///
public sealed record CommitInfo
{
///
/// Gets the commit SHA (full or abbreviated).
///
public required string Uid { get; init; }
///
/// Gets the URL to view the commit.
///
public string? Url { get; init; }
///
/// Gets the commit message (may be truncated).
///
public string? Message { get; init; }
///
/// Gets the author information.
///
public CommitActor? Author { get; init; }
///
/// Gets the committer information.
///
public CommitActor? Committer { get; init; }
///
/// Gets the CVE IDs resolved by this commit, if known.
///
public ImmutableArray ResolvesCves { get; init; } = ImmutableArray.Empty;
}
///
/// Represents an actor (author or committer) in a commit.
///
public sealed record CommitActor
{
///
/// Gets the actor's name.
///
public string? Name { get; init; }
///
/// Gets the actor's email.
///
public string? Email { get; init; }
///
/// Gets the timestamp of the action.
///
public DateTimeOffset? Timestamp { get; init; }
}
///
/// Represents a patch applied to the component.
///
public sealed record PatchInfo
{
///
/// Gets the patch type.
///
public PatchType Type { get; init; } = PatchType.Backport;
///
/// Gets the URL to the patch file.
///
public string? DiffUrl { get; init; }
///
/// Gets the patch diff content (optional, may be truncated).
///
public string? DiffText { get; init; }
///
/// Gets the CVE IDs resolved by this patch.
///
public ImmutableArray Resolves { get; init; } = ImmutableArray.Empty;
///
/// Gets the functions affected by this patch.
///
public ImmutableArray AffectedFunctions { get; init; } = ImmutableArray.Empty;
///
/// Gets the source of the patch (e.g., "debian-security").
///
public string? Source { get; init; }
}
///
/// Patch type enumeration per CycloneDX 1.7 specification.
///
public enum PatchType
{
/// Informal patch not associated with upstream.
Unofficial,
/// A patch that is a bugfix or security fix that does not change feature.
Monkey,
/// A patch that is a backport of a fix from a later version.
Backport,
/// A cherry-picked commit from upstream.
CherryPick
}
///
/// Represents a vulnerability resolved by a patch.
///
public sealed record PatchResolution
{
///
/// Gets the vulnerability ID (e.g., "CVE-2024-1234").
///
public required string Id { get; init; }
///
/// Gets the source of the vulnerability reference.
///
public string? SourceName { get; init; }
///
/// Gets the URL to the vulnerability reference.
///
public string? SourceUrl { get; init; }
}