Files
git.stella-ops.org/docs/architecture/enforcement-rules.md
master 5590a99a1a 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-23 23:51:58 +02:00

120 lines
6.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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*