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.
This commit is contained in:
119
docs/architecture/enforcement-rules.md
Normal file
119
docs/architecture/enforcement-rules.md
Normal file
@@ -0,0 +1,119 @@
|
||||
# Architecture Enforcement Rules
|
||||
|
||||
This document describes the automated architecture rules enforced by `tests/architecture/StellaOps.Architecture.Tests`. These rules run on every PR and gate merges, ensuring consistent adherence to StellaOps architectural boundaries.
|
||||
|
||||
## Overview
|
||||
|
||||
Architecture tests use [NetArchTest.Rules](https://github.com/BenMorris/NetArchTest) to enforce structural constraints at compile time. Rules are categorized into four areas:
|
||||
|
||||
1. **Lattice Engine Placement** – Ensures lattice/scoring logic stays in Scanner
|
||||
2. **Module Dependencies** – Enforces proper layering between Core, Storage, WebServices, and Workers
|
||||
3. **Forbidden Packages** – Blocks deprecated or non-compliant dependencies
|
||||
4. **Naming Conventions** – Ensures consistent project/assembly naming
|
||||
|
||||
---
|
||||
|
||||
## 1. Lattice Engine Placement Rules
|
||||
|
||||
**Purpose**: The lattice engine computes vulnerability scoring, VEX decisions, and reachability proofs. These computations must remain in Scanner to preserve "prune at source" semantics—no other module should re-derive decisions.
|
||||
|
||||
| Rule ID | Description | Assemblies Affected | Enforcement |
|
||||
|---------|-------------|---------------------|-------------|
|
||||
| `Lattice_Concelier_NoReference` | Concelier assemblies must NOT reference Scanner lattice engine | `StellaOps.Concelier.*` | Fail if any reference to `StellaOps.Scanner.Lattice` |
|
||||
| `Lattice_Excititor_NoReference` | Excititor assemblies must NOT reference Scanner lattice engine | `StellaOps.Excititor.*` | Fail if any reference to `StellaOps.Scanner.Lattice` |
|
||||
| `Lattice_Scanner_MayReference` | Scanner.WebService MAY reference Scanner lattice engine | `StellaOps.Scanner.WebService` | Allowed (no constraint) |
|
||||
| `Lattice_PreservePruneSource` | Excititor does not compute lattice decisions (verified via type search) | `StellaOps.Excititor.*` | Fail if types named `*LatticeEngine*`, `*VexDecision*`, or `*ScoreCalculator*` exist |
|
||||
|
||||
**Rationale**: If Excititor or Concelier computed their own lattice decisions, findings could drift from Scanner's authoritative scoring. Downstream consumers must accept pre-computed verdicts.
|
||||
|
||||
---
|
||||
|
||||
## 2. Module Dependency Rules
|
||||
|
||||
**Purpose**: Enforce clean architecture layering. Core business logic must not depend on infrastructure; services must not cross-call each other.
|
||||
|
||||
| Rule ID | Description | Source | Forbidden Target |
|
||||
|---------|-------------|--------|------------------|
|
||||
| `Dependency_Core_NoInfrastructure` | Core libraries must not depend on infrastructure | `*.Core` | `*.Storage.*`, `*.Postgres`, `*.WebService` |
|
||||
| `Dependency_WebService_NoWebService` | WebServices may not depend on other WebServices | `*.WebService` | Other `*.WebService` assemblies |
|
||||
| `Dependency_Worker_NoWebService` | Workers must not depend directly on WebServices | `*.Worker` | `*.WebService` |
|
||||
|
||||
**Rationale**:
|
||||
- Core libraries define contracts and business rules; they must remain portable.
|
||||
- WebServices should communicate via HTTP/gRPC, not direct assembly references.
|
||||
- Workers may share Core and Storage, but reaching into another service's WebService layer violates service boundaries.
|
||||
|
||||
---
|
||||
|
||||
## 3. Forbidden Package Rules
|
||||
|
||||
**Purpose**: Block usage of deprecated, non-compliant, or strategically-replaced dependencies.
|
||||
|
||||
| Rule ID | Description | Forbidden Namespace/Type | Rationale |
|
||||
|---------|-------------|-------------------------|-----------|
|
||||
| `Forbidden_Redis` | No direct Redis library usage | `StackExchange.Redis`, `ServiceStack.Redis` | StellaOps uses Valkey; Redis clients may introduce incompatible commands |
|
||||
| `Forbidden_MongoDB` | No MongoDB usage | `MongoDB.Driver`, `MongoDB.Bson` | MongoDB storage was deprecated in Sprint 4400; all persistence is PostgreSQL |
|
||||
| `Forbidden_BouncyCastle_Core` | No direct BouncyCastle in core assemblies | `Org.BouncyCastle.*` | Cryptography must be plugin-based (`StellaOps.Cryptography.Plugin.*`); core assemblies reference only `StellaOps.Cryptography.Abstractions` |
|
||||
|
||||
**Exception**: `StellaOps.Cryptography.Plugin.BouncyCastle` is the designated wrapper and may reference BouncyCastle directly.
|
||||
|
||||
---
|
||||
|
||||
## 4. Naming Convention Rules
|
||||
|
||||
**Purpose**: Ensure consistent assembly naming for discoverability and tooling.
|
||||
|
||||
| Rule ID | Pattern | Enforcement |
|
||||
|---------|---------|-------------|
|
||||
| `Naming_TestProjects` | Test projects must end with `.Tests` | Assemblies matching `StellaOps.*Tests*` must end with `.Tests` |
|
||||
| `Naming_Plugins` | Plugins must follow `StellaOps.<Module>.Plugin.*` or `StellaOps.<Module>.Connector.*` | Assemblies with "Plugin" or "Connector" in name must match pattern |
|
||||
|
||||
**Rationale**: Consistent naming enables CI glob patterns (`**/*.Tests.csproj`) and plugin discovery (`Assembly.Load("StellaOps.*.Plugin.*")`).
|
||||
|
||||
---
|
||||
|
||||
## Running Architecture Tests
|
||||
|
||||
```bash
|
||||
# From repository root
|
||||
dotnet test tests/architecture/StellaOps.Architecture.Tests --logger "console;verbosity=detailed"
|
||||
```
|
||||
|
||||
**CI Integration**: Architecture tests run in the Unit test lane on every PR. They are PR-gating—failures block merge.
|
||||
|
||||
---
|
||||
|
||||
## Adding New Rules
|
||||
|
||||
1. Open `tests/architecture/StellaOps.Architecture.Tests/`
|
||||
2. Add test method to the appropriate `*RulesTests.cs` file
|
||||
3. Use NetArchTest fluent API:
|
||||
```csharp
|
||||
[Fact]
|
||||
public void NewRule_Description()
|
||||
{
|
||||
var result = Types.InAssembly(typeof(SomeType).Assembly)
|
||||
.That()
|
||||
.HaveDependencyOn("Forbidden.Namespace")
|
||||
.Should()
|
||||
.NotExist()
|
||||
.GetResult();
|
||||
|
||||
result.IsSuccessful.Should().BeTrue(
|
||||
"Assemblies should not reference Forbidden.Namespace");
|
||||
}
|
||||
```
|
||||
4. Document the rule in this file
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- [docs/07_HIGH_LEVEL_ARCHITECTURE.md](../07_HIGH_LEVEL_ARCHITECTURE.md) – High-level architecture overview
|
||||
- [docs/modules/scanner/architecture.md](../modules/scanner/architecture.md) – Scanner module architecture (lattice engine details)
|
||||
- [AGENTS.md](../../AGENTS.md) – Project-wide agent guidelines and module boundaries
|
||||
- [NetArchTest Documentation](https://github.com/BenMorris/NetArchTest)
|
||||
|
||||
---
|
||||
|
||||
*Last updated: 2025-06-30 · Sprint 5100.0007.0007*
|
||||
Reference in New Issue
Block a user