save checkpoint

This commit is contained in:
master
2026-02-11 01:32:14 +02:00
parent 5593212b41
commit cf5b72974f
2316 changed files with 68799 additions and 3808 deletions

View File

@@ -46,14 +46,9 @@ public sealed class LineageStreamControllerTests
{
// Arrange
var digest = "sha256:abc123";
_graphService.SetupGraph(digest, new LineageGraphResponse(
new LineageGraphDto(
Nodes: ImmutableArray.Create(
new LineageNodeDto(digest, "app", "1.0.0", 10),
new LineageNodeDto("sha256:child", "lib", "1.0.0", 5)),
Edges: ImmutableArray.Create(
new LineageEdgeDto(digest, "sha256:child"))),
Enrichment: null));
_graphService.SetupGraph(digest, CreateGraphResponse(
new[] { CreateNode(digest), CreateNode("sha256:child") },
new[] { CreateEdge(digest, "sha256:child") }));
// Act
var result = await _controller.GetOptimizedLineage(digest, maxDepth: 3, pageSize: 50, pageNumber: 0);
@@ -103,12 +98,9 @@ public sealed class LineageStreamControllerTests
{
// Arrange
var digest = "sha256:meta123";
_graphService.SetupGraph(digest, new LineageGraphResponse(
new LineageGraphDto(
Nodes: ImmutableArray.Create(
new LineageNodeDto(digest, "app", "1.0.0", 10)),
Edges: ImmutableArray<LineageEdgeDto>.Empty),
Enrichment: null));
_graphService.SetupGraph(digest, CreateGraphResponse(
new[] { CreateNode(digest) },
Array.Empty<LineageEdge>()));
// Act
var result = await _controller.GetMetadata(digest);
@@ -145,16 +137,18 @@ public sealed class LineageStreamControllerTests
{
// Arrange
var digest = "sha256:center";
_graphService.SetupGraph(digest, new LineageGraphResponse(
new LineageGraphDto(
Nodes: ImmutableArray.Create(
new LineageNodeDto(digest, "center-app", "1.0.0", 10),
new LineageNodeDto("sha256:logging", "logging-lib", "1.0.0", 5),
new LineageNodeDto("sha256:database", "database-lib", "1.0.0", 8)),
Edges: ImmutableArray.Create(
new LineageEdgeDto(digest, "sha256:logging"),
new LineageEdgeDto(digest, "sha256:database"))),
Enrichment: null));
_graphService.SetupGraph(digest, CreateGraphResponse(
new[]
{
CreateNode(digest),
CreateNode("sha256:logging"),
CreateNode("sha256:database")
},
new[]
{
CreateEdge(digest, "sha256:logging"),
CreateEdge(digest, "sha256:database")
}));
// Act
var result = await _controller.GetOptimizedLineage(digest, searchTerm: "log");
@@ -172,24 +166,17 @@ public sealed class LineageStreamControllerTests
{
// Arrange
var digest = "sha256:center";
var nodes = new List<LineageNodeDto>
{
new(digest, "center", "1.0.0", 10)
};
var edges = new List<LineageEdgeDto>();
var nodes = new List<LineageNode> { CreateNode(digest) };
var edges = new List<LineageEdge>();
for (int i = 0; i < 20; i++)
{
var childDigest = $"sha256:child{i:D2}";
nodes.Add(new LineageNodeDto(childDigest, $"child-{i}", "1.0.0", i + 1));
edges.Add(new LineageEdgeDto(digest, childDigest));
nodes.Add(CreateNode(childDigest));
edges.Add(CreateEdge(digest, childDigest));
}
_graphService.SetupGraph(digest, new LineageGraphResponse(
new LineageGraphDto(
Nodes: nodes.ToImmutableArray(),
Edges: edges.ToImmutableArray()),
Enrichment: null));
_graphService.SetupGraph(digest, CreateGraphResponse(nodes, edges));
// Act
var result = await _controller.GetOptimizedLineage(digest, pageSize: 5, pageNumber: 0);
@@ -201,6 +188,19 @@ public sealed class LineageStreamControllerTests
graph.PageNumber.Should().Be(0);
}
// Helper methods
private static LineageNode CreateNode(string artifactDigest) =>
new(artifactDigest, Guid.NewGuid(), 1, DateTimeOffset.UtcNow, null);
private static LineageEdge CreateEdge(string parent, string child) =>
new(Guid.NewGuid(), parent, child, LineageRelationship.Parent, Guid.Empty, DateTimeOffset.UtcNow);
private static LineageGraphResponse CreateGraphResponse(
IEnumerable<LineageNode> nodes,
IEnumerable<LineageEdge> edges) =>
new(new LineageGraph(nodes.ToList(), edges.ToList()),
new Dictionary<string, NodeEnrichment>());
// Test helper implementations
private sealed class InMemoryLineageStreamService : ILineageStreamService
{
@@ -216,76 +216,80 @@ public sealed class LineageStreamControllerTests
public async IAsyncEnumerable<LineageUpdateEvent> SubscribeAsync(
Guid tenantId,
IReadOnlyList<string>? watchDigests = null,
CancellationToken ct = default)
[System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken ct = default)
{
await Task.CompletedTask;
yield break;
}
public Task PublishAsync(Guid tenantId, LineageUpdateEvent evt, CancellationToken ct = default)
=> Task.CompletedTask;
public ValueTask PublishAsync(LineageUpdateEvent updateEvent, CancellationToken ct = default)
=> ValueTask.CompletedTask;
public Task NotifySbomAddedAsync(Guid tenantId, string artifactDigest, string? parentDigest,
public ValueTask NotifySbomAddedAsync(Guid tenantId, string artifactDigest, string? parentDigest,
SbomVersionSummary summary, CancellationToken ct = default)
=> Task.CompletedTask;
=> ValueTask.CompletedTask;
public Task NotifyVexChangedAsync(Guid tenantId, string artifactDigest, VexChangeData change,
public ValueTask NotifyVexChangedAsync(Guid tenantId, string artifactDigest, VexChangeData change,
CancellationToken ct = default)
=> Task.CompletedTask;
=> ValueTask.CompletedTask;
public Task NotifyReachabilityUpdatedAsync(Guid tenantId, string artifactDigest, ReachabilityUpdateData update,
public ValueTask NotifyReachabilityUpdatedAsync(Guid tenantId, string artifactDigest, ReachabilityUpdateData update,
CancellationToken ct = default)
=> Task.CompletedTask;
=> ValueTask.CompletedTask;
public Task NotifyEdgeChangedAsync(Guid tenantId, string fromDigest, string toDigest,
public ValueTask NotifyEdgeChangedAsync(Guid tenantId, string fromDigest, string toDigest,
LineageEdgeChangeType changeType, CancellationToken ct = default)
=> Task.CompletedTask;
=> ValueTask.CompletedTask;
}
private sealed class InMemoryLineageGraphOptimizer : ILineageGraphOptimizer
{
public LineageOptimizationRequest? LastRequest { get; private set; }
public OptimizedLineageGraph Optimize(LineageOptimizationRequest request)
public OptimizedLineageGraph Optimize(
LineageGraph fullGraph,
LineageOptimizationRequest request)
{
LastRequest = request;
return new OptimizedLineageGraph
{
Nodes = request.AllNodes,
Edges = request.AllEdges,
Nodes = fullGraph.Nodes,
Edges = fullGraph.Edges,
BoundaryNodes = ImmutableArray<BoundaryNodeInfo>.Empty,
TotalNodes = request.AllNodes.Length,
HasMorePages = false
TotalNodeCount = fullGraph.Nodes.Count,
HasMore = false,
Offset = request.Offset,
Limit = request.Limit,
OptimizationTimeMs = 0
};
}
public async IAsyncEnumerable<LineageLevel> TraverseLevelsAsync(
string centerDigest,
ImmutableArray<LineageNode> nodes,
ImmutableArray<LineageEdge> edges,
TraversalDirection direction,
int maxDepth = 10,
CancellationToken ct = default)
Func<string, CancellationToken, Task<IReadOnlyList<LineageNode>>> getChildrenAsync,
Func<string, CancellationToken, Task<IReadOnlyList<LineageNode>>> getParentsAsync,
int maxDepth = 5,
[System.Runtime.CompilerServices.EnumeratorCancellation] CancellationToken ct = default)
{
await Task.CompletedTask;
yield return new LineageLevel(0, nodes, true);
yield return new LineageLevel
{
Level = 0,
Direction = TraversalDirection.Center,
NodeDigests = ImmutableArray.Create(centerDigest)
};
}
public Task<LineageGraphMetadata> GetOrComputeMetadataAsync(
string artifactDigest,
Guid tenantId,
string centerDigest,
ImmutableArray<LineageNode> nodes,
ImmutableArray<LineageEdge> edges,
Func<CancellationToken, Task<LineageGraphMetadata>> computeAsync,
CancellationToken ct = default)
{
return Task.FromResult(new LineageGraphMetadata(
TotalNodes: nodes.Length,
TotalEdges: edges.Length,
MaxDepth: 1,
ComputedAt: DateTimeOffset.UtcNow));
return computeAsync(ct);
}
public Task InvalidateCacheAsync(Guid tenantId, string centerDigest, CancellationToken ct = default)
public Task InvalidateCacheAsync(string artifactDigest, Guid tenantId, CancellationToken ct = default)
=> Task.CompletedTask;
}
@@ -308,8 +312,10 @@ public sealed class LineageStreamControllerTests
return ValueTask.FromResult(response);
return ValueTask.FromResult(new LineageGraphResponse(
new LineageGraphDto(ImmutableArray<LineageNodeDto>.Empty, ImmutableArray<LineageEdgeDto>.Empty),
null));
new LineageGraph(
ImmutableArray<LineageNode>.Empty,
ImmutableArray<LineageEdge>.Empty),
new Dictionary<string, NodeEnrichment>()));
}
public ValueTask<LineageDiffResponse> GetDiffAsync(
@@ -319,9 +325,15 @@ public sealed class LineageStreamControllerTests
CancellationToken ct = default)
{
return ValueTask.FromResult(new LineageDiffResponse(
ImmutableArray<LineageChangeSummary>.Empty,
ImmutableArray<LineageChangeSummary>.Empty,
ImmutableArray<LineageChangeSummary>.Empty));
fromDigest,
toDigest,
new SbomDiff(
ImmutableArray<ComponentChange>.Empty,
ImmutableArray<ComponentChange>.Empty,
ImmutableArray<ComponentChange>.Empty),
new VexDiff(
ImmutableArray<VexDelta>.Empty, 0, 0, 0, 0),
null));
}
public ValueTask<ExportResult> ExportEvidencePackAsync(
@@ -329,21 +341,11 @@ public sealed class LineageStreamControllerTests
Guid tenantId,
CancellationToken ct = default)
{
return ValueTask.FromResult(new ExportResult("https://example.com/pack.zip", 1024));
return ValueTask.FromResult(new ExportResult(
"https://example.com/pack.zip",
DateTimeOffset.UtcNow.AddHours(1),
1024,
null));
}
}
}
// Placeholder types to match interface expectations
file record LineageNodeDto(string Digest, string Name, string Version, int ComponentCount);
file record LineageEdgeDto(string FromDigest, string ToDigest);
file record LineageGraphDto(ImmutableArray<LineageNodeDto> Nodes, ImmutableArray<LineageEdgeDto> Edges);
file record LineageGraphResponse(LineageGraphDto Graph, object? Enrichment);
file record LineageDiffResponse(
ImmutableArray<LineageChangeSummary> Added,
ImmutableArray<LineageChangeSummary> Removed,
ImmutableArray<LineageChangeSummary> Modified);
file record LineageChangeSummary(string Digest, string Name);
file record ExportRequest(string ArtifactDigest, int MaxDepth);
file record ExportResult(string DownloadUrl, long SizeBytes);
file record LineageQueryOptions(int MaxDepth, bool IncludeVerdicts, bool IncludeBadges);