doctor enhancements, setup, enhancements, ui functionality and design consolidation and , test projects fixes , product advisory attestation/rekor and delta verfications enhancements

This commit is contained in:
master
2026-01-19 09:02:59 +02:00
parent 8c4bf54aed
commit 17419ba7c4
809 changed files with 170738 additions and 12244 deletions

View File

@@ -0,0 +1,176 @@
using FluentAssertions;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Time.Testing;
using StellaOps.Scanner.Cache.Abstractions;
using StellaOps.Scanner.Cache.LayerCache;
using StellaOps.TestKit;
using Xunit;
namespace StellaOps.Scanner.Cache.Tests.LayerCache;
/// <summary>
/// Unit tests for <see cref="LayerCacheStore"/> with FakeTimeProvider for deterministic TTL testing.
/// </summary>
[Trait("Category", TestCategories.Unit)]
public sealed class LayerCacheStoreTimeProviderTests : IDisposable
{
private readonly FakeTimeProvider _timeProvider;
private readonly LayerCacheStore _store;
private readonly string _testCacheDir;
public LayerCacheStoreTimeProviderTests()
{
_timeProvider = new FakeTimeProvider(new DateTimeOffset(2026, 1, 18, 12, 0, 0, TimeSpan.Zero));
_testCacheDir = Path.Combine(Path.GetTempPath(), $"layer-cache-test-{Guid.NewGuid():N}");
Directory.CreateDirectory(_testCacheDir);
var options = Options.Create(new ScannerCacheOptions
{
RootPath = _testCacheDir,
LayerTtl = TimeSpan.FromHours(24)
});
_store = new LayerCacheStore(
options,
NullLogger<LayerCacheStore>.Instance,
_timeProvider);
}
public void Dispose()
{
if (Directory.Exists(_testCacheDir))
{
try
{
Directory.Delete(_testCacheDir, recursive: true);
}
catch
{
// Ignore cleanup errors in tests
}
}
}
private static LayerCachePutRequest CreatePutRequest(string layerDigest) =>
new(
layerDigest: layerDigest,
architecture: "amd64",
mediaType: "application/vnd.oci.image.layer.v1.tar+gzip",
metadata: new Dictionary<string, string>(),
artifacts: new List<LayerCacheArtifactContent>
{
new("sbom.json", new MemoryStream(new byte[] { 1, 2, 3, 4, 5 }), "application/json")
});
[Fact]
public async Task TryGetAsync_NewEntry_ReturnsEntry()
{
// Arrange
var layerDigest = "sha256:" + Guid.NewGuid().ToString("N");
var request = CreatePutRequest(layerDigest);
await _store.PutAsync(request);
// Act
var entry = await _store.TryGetAsync(layerDigest);
// Assert
entry.Should().NotBeNull();
entry!.LayerDigest.Should().Be(layerDigest);
}
[Fact]
public async Task TryGetAsync_AfterTtlExpires_ReturnsNull()
{
// Arrange
var layerDigest = "sha256:" + Guid.NewGuid().ToString("N");
var request = CreatePutRequest(layerDigest);
await _store.PutAsync(request);
// Verify entry exists
var entryBefore = await _store.TryGetAsync(layerDigest);
entryBefore.Should().NotBeNull();
// Act - advance time past TTL (24 hours + buffer)
_timeProvider.Advance(TimeSpan.FromHours(25));
var entryAfter = await _store.TryGetAsync(layerDigest);
// Assert
entryAfter.Should().BeNull();
}
[Fact]
public async Task TryGetAsync_BeforeTtlExpires_ReturnsEntry()
{
// Arrange
var layerDigest = "sha256:" + Guid.NewGuid().ToString("N");
var request = CreatePutRequest(layerDigest);
await _store.PutAsync(request);
// Act - advance time but not past TTL
_timeProvider.Advance(TimeSpan.FromHours(12));
var entry = await _store.TryGetAsync(layerDigest);
// Assert
entry.Should().NotBeNull();
entry!.LayerDigest.Should().Be(layerDigest);
}
[Fact]
public async Task TryGetAsync_AtExactTtl_ReturnsNull()
{
// Arrange
var layerDigest = "sha256:" + Guid.NewGuid().ToString("N");
var request = CreatePutRequest(layerDigest);
await _store.PutAsync(request);
// Act - advance time to exactly TTL + 1 second
_timeProvider.Advance(TimeSpan.FromHours(24).Add(TimeSpan.FromSeconds(1)));
var entry = await _store.TryGetAsync(layerDigest);
// Assert
entry.Should().BeNull();
}
[Fact]
public async Task TryGetAsync_UpdatesLastAccessed()
{
// Arrange
var layerDigest = "sha256:" + Guid.NewGuid().ToString("N");
var request = CreatePutRequest(layerDigest);
await _store.PutAsync(request);
// First access
await _store.TryGetAsync(layerDigest);
var firstAccessTime = _timeProvider.GetUtcNow();
// Advance time
_timeProvider.Advance(TimeSpan.FromHours(1));
// Second access
var entry = await _store.TryGetAsync(layerDigest);
// Assert
entry.Should().NotBeNull();
entry!.LastAccessed.Should().BeAfter(firstAccessTime);
}
[Fact]
public async Task PutAsync_SetsCorrectCachedAt()
{
// Arrange
var layerDigest = "sha256:" + Guid.NewGuid().ToString("N");
var request = CreatePutRequest(layerDigest);
var expectedTime = _timeProvider.GetUtcNow();
// Act
var entry = await _store.PutAsync(request);
// Assert
entry.CachedAt.Should().Be(expectedTime);
}
}

View File

@@ -9,6 +9,8 @@
<ItemGroup>
<PackageReference Include="FluentAssertions" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
<PackageReference Include="Microsoft.Extensions.TimeProvider.Testing" />
<PackageReference Include="Moq" />
</ItemGroup>
<ItemGroup>
<Compile Remove="..\StellaOps.Concelier.Tests.Shared\AssemblyInfo.cs" />