work work hard work

This commit is contained in:
StellaOps Bot
2025-12-18 00:47:24 +02:00
parent dee252940b
commit b4235c134c
189 changed files with 9627 additions and 3258 deletions

View File

@@ -0,0 +1,32 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<LangVersion>preview</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<UseConcelierTestInfra>false</UseConcelierTestInfra>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.collector" Version="6.0.4" />
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.0" />
<PackageReference Include="NSubstitute" Version="5.1.0" />
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.1" />
</ItemGroup>
<ItemGroup>
<Using Include="Xunit" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\__Libraries\StellaOps.Attestor.Persistence\StellaOps.Attestor.Persistence.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,185 @@
using FluentAssertions;
using Microsoft.Extensions.Logging.Abstractions;
using NSubstitute;
using StellaOps.Attestor.Persistence.Entities;
using StellaOps.Attestor.Persistence.Repositories;
using StellaOps.Attestor.Persistence.Services;
namespace StellaOps.Attestor.Persistence.Tests;
/// <summary>
/// Tests for trust anchor glob matching and allowlists.
/// Sprint: SPRINT_0501_0006_0001_proof_chain_database_schema
/// Task: PROOF-DB-0010
/// </summary>
public sealed class TrustAnchorMatcherTests
{
private readonly IProofChainRepository _repository;
private readonly TrustAnchorMatcher _matcher;
public TrustAnchorMatcherTests()
{
_repository = Substitute.For<IProofChainRepository>();
_matcher = new TrustAnchorMatcher(_repository, NullLogger<TrustAnchorMatcher>.Instance);
}
[Fact]
public async Task FindMatchAsync_ExactPattern_MatchesCorrectly()
{
var anchor = CreateAnchor("pkg:npm/lodash@4.17.21", ["key-1"]);
await SeedAnchors(anchor);
var result = await _matcher.FindMatchAsync("pkg:npm/lodash@4.17.21");
result.Should().NotBeNull();
result!.Anchor.AnchorId.Should().Be(anchor.AnchorId);
}
[Fact]
public async Task FindMatchAsync_WildcardPattern_MatchesPackages()
{
var anchor = CreateAnchor("pkg:npm/*", ["key-1"]);
await SeedAnchors(anchor);
var result = await _matcher.FindMatchAsync("pkg:npm/lodash@4.17.21");
result.Should().NotBeNull();
result!.MatchedPattern.Should().Be("pkg:npm/*");
}
[Fact]
public async Task FindMatchAsync_DoubleWildcard_MatchesNestedPaths()
{
var anchor = CreateAnchor("pkg:npm/@scope/**", ["key-1"]);
await SeedAnchors(anchor);
var result = await _matcher.FindMatchAsync("pkg:npm/@scope/sub/package@1.0.0");
result.Should().NotBeNull();
}
[Fact]
public async Task FindMatchAsync_MultipleMatches_ReturnsMoreSpecific()
{
var genericAnchor = CreateAnchor("pkg:npm/*", ["key-generic"], policyRef: "generic");
var specificAnchor = CreateAnchor("pkg:npm/lodash@*", ["key-specific"], policyRef: "specific");
await SeedAnchors(genericAnchor, specificAnchor);
var result = await _matcher.FindMatchAsync("pkg:npm/lodash@4.17.21");
result.Should().NotBeNull();
result!.Anchor.PolicyRef.Should().Be("specific");
}
[Fact]
public async Task FindMatchAsync_NoMatch_ReturnsNull()
{
var anchor = CreateAnchor("pkg:npm/*", ["key-1"]);
await SeedAnchors(anchor);
var result = await _matcher.FindMatchAsync("pkg:pypi/requests@2.28.0");
result.Should().BeNull();
}
[Fact]
public async Task IsKeyAllowedAsync_AllowedKey_ReturnsTrue()
{
var anchor = CreateAnchor("pkg:npm/*", ["key-1", "key-2"]);
await SeedAnchors(anchor);
var allowed = await _matcher.IsKeyAllowedAsync("pkg:npm/lodash@4.17.21", "key-1");
allowed.Should().BeTrue();
}
[Fact]
public async Task IsKeyAllowedAsync_DisallowedKey_ReturnsFalse()
{
var anchor = CreateAnchor("pkg:npm/*", ["key-1"]);
await SeedAnchors(anchor);
var allowed = await _matcher.IsKeyAllowedAsync("pkg:npm/lodash@4.17.21", "key-unknown");
allowed.Should().BeFalse();
}
[Fact]
public async Task IsKeyAllowedAsync_RevokedKey_ReturnsFalse()
{
var anchor = CreateAnchor("pkg:npm/*", ["key-1"], revokedKeys: ["key-1"]);
await SeedAnchors(anchor);
var allowed = await _matcher.IsKeyAllowedAsync("pkg:npm/lodash@4.17.21", "key-1");
allowed.Should().BeFalse();
}
[Fact]
public async Task IsPredicateAllowedAsync_NoRestrictions_AllowsAll()
{
var anchor = CreateAnchor("pkg:npm/*", ["key-1"]);
anchor.AllowedPredicateTypes = null;
await SeedAnchors(anchor);
var allowed = await _matcher.IsPredicateAllowedAsync(
"pkg:npm/lodash@4.17.21",
"https://in-toto.io/attestation/vulns/v0.1");
allowed.Should().BeTrue();
}
[Fact]
public async Task IsPredicateAllowedAsync_WithRestrictions_EnforcesAllowlist()
{
var anchor = CreateAnchor("pkg:npm/*", ["key-1"]);
anchor.AllowedPredicateTypes = ["evidence.stella/v1", "sbom.stella/v1"];
await SeedAnchors(anchor);
(await _matcher.IsPredicateAllowedAsync("pkg:npm/lodash@4.17.21", "evidence.stella/v1")).Should().BeTrue();
(await _matcher.IsPredicateAllowedAsync("pkg:npm/lodash@4.17.21", "random.predicate/v1")).Should().BeFalse();
}
[Theory]
[InlineData("pkg:npm/*", "pkg:npm/lodash@4.17.21", true)]
[InlineData("pkg:npm/lodash@*", "pkg:npm/lodash@4.17.21", true)]
[InlineData("pkg:npm/lodash@4.17.*", "pkg:npm/lodash@4.17.21", true)]
[InlineData("pkg:npm/lodash@4.17.21", "pkg:npm/lodash@4.17.21", true)]
[InlineData("pkg:npm/lodash@4.17.21", "pkg:npm/lodash@4.17.22", false)]
[InlineData("pkg:pypi/*", "pkg:npm/lodash@4.17.21", false)]
[InlineData("pkg:npm/@scope/*", "pkg:npm/@scope/package@1.0.0", true)]
[InlineData("pkg:npm/@scope/*", "pkg:npm/@other/package@1.0.0", false)]
public async Task FindMatchAsync_PatternVariations_MatchCorrectly(string pattern, string purl, bool shouldMatch)
{
var anchor = CreateAnchor(pattern, ["key-1"]);
await SeedAnchors(anchor);
var result = await _matcher.FindMatchAsync(purl);
(result != null).Should().Be(shouldMatch);
}
private Task SeedAnchors(params TrustAnchorEntity[] anchors)
{
_repository.GetActiveTrustAnchorsAsync(Arg.Any<CancellationToken>())
.Returns(Task.FromResult<IReadOnlyList<TrustAnchorEntity>>(anchors));
return Task.CompletedTask;
}
private static TrustAnchorEntity CreateAnchor(
string pattern,
string[] allowedKeys,
string? policyRef = null,
string[]? revokedKeys = null)
{
return new TrustAnchorEntity
{
AnchorId = Guid.NewGuid(),
PurlPattern = pattern,
AllowedKeyIds = allowedKeys,
PolicyRef = policyRef,
RevokedKeys = revokedKeys ?? []
};
}
}