Files
git.stella-ops.org/tests/architecture/StellaOps.Architecture.Tests/ForbiddenPackageRulesTests.cs
master 491e883653 Add tests for SBOM generation determinism across multiple formats
- Created `StellaOps.TestKit.Tests` project for unit tests related to determinism.
- Implemented `DeterminismManifestTests` to validate deterministic output for canonical bytes and strings, file read/write operations, and error handling for invalid schema versions.
- Added `SbomDeterminismTests` to ensure identical inputs produce consistent SBOMs across SPDX 3.0.1 and CycloneDX 1.6/1.7 formats, including parallel execution tests.
- Updated project references in `StellaOps.Integration.Determinism` to include the new determinism testing library.
2025-12-24 00:36:14 +02:00

167 lines
5.2 KiB
C#

using System.Reflection;
using NetArchTest.Rules;
using Xunit;
using FluentAssertions;
namespace StellaOps.Architecture.Tests;
/// <summary>
/// Architecture tests for forbidden package rules.
/// Enforces compliance constraints on library usage.
/// </summary>
[Trait("Category", "Architecture")]
public sealed class ForbiddenPackageRulesTests
{
/// <summary>
/// No direct Redis library usage - only Valkey-compatible clients allowed.
/// </summary>
[Fact]
public void Assemblies_MustNot_Use_Direct_Redis_Clients()
{
var stellaOpsAssemblies = GetStellaOpsAssemblies();
if (!stellaOpsAssemblies.Any())
{
return;
}
// ServiceStack.Redis and similar direct Redis clients are forbidden
// StackExchange.Redis is allowed as it's Valkey-compatible
var forbiddenRedisPackages = new[]
{
"ServiceStack.Redis",
"CSRedis",
"FreeRedis"
};
var result = Types.InAssemblies(stellaOpsAssemblies)
.ShouldNot()
.HaveDependencyOnAny(forbiddenRedisPackages)
.GetResult();
result.IsSuccessful.Should().BeTrue(
$"StellaOps assemblies must not use non-Valkey-compatible Redis clients. " +
$"Use StackExchange.Redis (Valkey-compatible). " +
$"Violations: {string.Join(", ", result.FailingTypeNames ?? Enumerable.Empty<string>())}");
}
/// <summary>
/// No MongoDB usage - deprecated per Sprint 4400.
/// </summary>
[Fact]
public void Assemblies_MustNot_Use_MongoDB()
{
var stellaOpsAssemblies = GetStellaOpsAssemblies();
if (!stellaOpsAssemblies.Any())
{
return;
}
var result = Types.InAssemblies(stellaOpsAssemblies)
.ShouldNot()
.HaveDependencyOnAny(
"MongoDB.Driver",
"MongoDB.Bson",
"MongoDb.*")
.GetResult();
result.IsSuccessful.Should().BeTrue(
$"MongoDB is deprecated (Sprint 4400). Use PostgreSQL. " +
$"Violations: {string.Join(", ", result.FailingTypeNames ?? Enumerable.Empty<string>())}");
}
/// <summary>
/// Crypto libraries must be plugin-based - no direct BouncyCastle references in core.
/// </summary>
[Fact]
public void CoreAssemblies_MustNot_Reference_BouncyCastle_Directly()
{
var coreAssemblies = GetCoreAssemblies();
if (!coreAssemblies.Any())
{
return;
}
// Core assemblies should use crypto through plugin abstraction
var result = Types.InAssemblies(coreAssemblies)
.ShouldNot()
.HaveDependencyOnAny(
"Org.BouncyCastle.*",
"BouncyCastle.*")
.GetResult();
result.IsSuccessful.Should().BeTrue(
$"Core assemblies must not reference BouncyCastle directly. " +
$"Use crypto plugins instead. " +
$"Violations: {string.Join(", ", result.FailingTypeNames ?? Enumerable.Empty<string>())}");
}
/// <summary>
/// No Newtonsoft.Json in new code - use System.Text.Json or StellaOps.Canonical.Json.
/// </summary>
[Fact]
public void Assemblies_Should_Prefer_SystemTextJson()
{
var stellaOpsAssemblies = GetStellaOpsAssemblies()
.Where(a => !a.GetName().Name?.Contains("Test") ?? false);
if (!stellaOpsAssemblies.Any())
{
return;
}
// This is a warning-level check, not a hard requirement
// Some interop scenarios may require Newtonsoft
var result = Types.InAssemblies(stellaOpsAssemblies)
.That()
.HaveDependencyOn("Newtonsoft.Json")
.GetTypes();
// Log but don't fail - this is advisory
if (result.Any())
{
// Advisory: consider migrating to System.Text.Json
}
}
/// <summary>
/// No Entity Framework - use Dapper or raw Npgsql.
/// </summary>
[Fact]
public void Assemblies_MustNot_Use_EntityFramework()
{
var stellaOpsAssemblies = GetStellaOpsAssemblies();
if (!stellaOpsAssemblies.Any())
{
return;
}
var result = Types.InAssemblies(stellaOpsAssemblies)
.ShouldNot()
.HaveDependencyOnAny(
"Microsoft.EntityFrameworkCore",
"Microsoft.EntityFrameworkCore.*")
.GetResult();
result.IsSuccessful.Should().BeTrue(
$"Entity Framework is not used in StellaOps. Use Dapper or Npgsql. " +
$"Violations: {string.Join(", ", result.FailingTypeNames ?? Enumerable.Empty<string>())}");
}
private static IEnumerable<Assembly> GetStellaOpsAssemblies()
{
return AppDomain.CurrentDomain.GetAssemblies()
.Where(a => a.GetName().Name?.StartsWith("StellaOps") == true);
}
private static IEnumerable<Assembly> GetCoreAssemblies()
{
return AppDomain.CurrentDomain.GetAssemblies()
.Where(a => a.GetName().Name?.Contains("Core") == true &&
a.GetName().Name?.StartsWith("StellaOps") == true);
}
}