725 lines
27 KiB
Markdown
725 lines
27 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## Project Overview
|
|
|
|
StellaOps is a self-hostable, sovereign container-security platform released under AGPL-3.0-or-later. It provides reproducible vulnerability scanning with VEX-first decisioning, SBOM generation (SPDX 3.0.1 and CycloneDX 1.6), in-toto/DSSE attestations, and optional Sigstore Rekor transparency. The platform is designed for offline/air-gapped operation with regional crypto support (eIDAS/FIPS/GOST/SM).
|
|
|
|
## Build Commands
|
|
|
|
```bash
|
|
# Build the entire solution
|
|
dotnet build src/StellaOps.sln
|
|
|
|
# Build a specific module (example: Concelier web service)
|
|
dotnet build src/Concelier/StellaOps.Concelier.WebService/StellaOps.Concelier.WebService.csproj
|
|
|
|
# Run the Concelier web service
|
|
dotnet run --project src/Concelier/StellaOps.Concelier.WebService
|
|
|
|
# Build CLI for current platform
|
|
dotnet publish src/Cli/StellaOps.Cli/StellaOps.Cli.csproj --configuration Release
|
|
|
|
# Build CLI for specific runtime (linux-x64, linux-arm64, osx-x64, osx-arm64, win-x64)
|
|
dotnet publish src/Cli/StellaOps.Cli/StellaOps.Cli.csproj --configuration Release --runtime linux-x64
|
|
```
|
|
|
|
## Test Commands
|
|
|
|
```bash
|
|
# Run all tests
|
|
dotnet test src/StellaOps.sln
|
|
|
|
# Run tests for a specific project
|
|
dotnet test src/Scanner/__Tests/StellaOps.Scanner.WebService.Tests/StellaOps.Scanner.WebService.Tests.csproj
|
|
|
|
# Run a single test by filter
|
|
dotnet test --filter "FullyQualifiedName~TestMethodName"
|
|
|
|
# Run tests with verbosity
|
|
dotnet test src/StellaOps.sln --verbosity normal
|
|
```
|
|
|
|
**Note:** Integration tests use Testcontainers for PostgreSQL. Ensure Docker is running before executing tests.
|
|
|
|
## Linting and Validation
|
|
|
|
```bash
|
|
# Lint OpenAPI specs
|
|
npm run api:lint
|
|
|
|
# Validate attestation schemas
|
|
npm run docs:attestor:validate
|
|
|
|
# Validate Helm chart
|
|
helm lint devops/helm/stellaops
|
|
|
|
# Validate Docker Compose profiles
|
|
./devops/scripts/validate-compose.sh
|
|
|
|
# Run local CI tests
|
|
./devops/scripts/test-local.sh
|
|
```
|
|
|
|
## Architecture
|
|
|
|
### Technology Stack
|
|
- **Runtime:** .NET 10 (`net10.0`) with latest C# preview features
|
|
- **Frontend:** Angular v17 (in `src/Web/StellaOps.Web`)
|
|
- **Database:** PostgreSQL (≥16) with per-module schema isolation; see `docs/db/` for specification
|
|
- **Testing:** xUnit with Testcontainers (PostgreSQL), Moq, Microsoft.AspNetCore.Mvc.Testing
|
|
- **Observability:** Structured logging, OpenTelemetry traces
|
|
- **NuGet:** Uses standard NuGet feeds configured in `nuget.config` (dotnet-public, nuget-mirror, nuget.org)
|
|
|
|
### Module Structure
|
|
|
|
The codebase follows a monorepo pattern with modules under `src/`:
|
|
|
|
| Module | Path | Purpose |
|
|
|--------|------|---------|
|
|
| **Core Platform** | | |
|
|
| Authority | `src/Authority/` | Authentication, authorization, OAuth/OIDC, DPoP |
|
|
| Gateway | `src/Gateway/` | API gateway with routing and transport abstraction |
|
|
| Router | `src/Router/` | Transport-agnostic messaging (TCP/TLS/UDP/RabbitMQ/Valkey) |
|
|
| **Data Ingestion** | | |
|
|
| Concelier | `src/Concelier/` | Vulnerability advisory ingestion and merge engine |
|
|
| Excititor | `src/Excititor/` | VEX document ingestion and export |
|
|
| VexLens | `src/VexLens/` | VEX consensus computation across issuers |
|
|
| VexHub | `src/VexHub/` | VEX distribution and exchange hub |
|
|
| IssuerDirectory | `src/IssuerDirectory/` | Issuer trust registry (CSAF publishers) |
|
|
| Feedser | `src/Feedser/` | Evidence collection library for backport detection |
|
|
| Mirror | `src/Mirror/` | Vulnerability feed mirror and distribution |
|
|
| **Scanning & Analysis** | | |
|
|
| Scanner | `src/Scanner/` | Container scanning with SBOM generation (11 language analyzers) |
|
|
| BinaryIndex | `src/BinaryIndex/` | Binary identity extraction and fingerprinting |
|
|
| AdvisoryAI | `src/AdvisoryAI/` | AI-assisted advisory analysis |
|
|
| ReachGraph | `src/ReachGraph/` | Reachability graph service |
|
|
| Symbols | `src/Symbols/` | Symbol resolution and debug information |
|
|
| **Artifacts & Evidence** | | |
|
|
| Attestor | `src/Attestor/` | in-toto/DSSE attestation generation |
|
|
| Signer | `src/Signer/` | Cryptographic signing operations |
|
|
| SbomService | `src/SbomService/` | SBOM storage, versioning, and lineage ledger |
|
|
| EvidenceLocker | `src/EvidenceLocker/` | Sealed evidence storage and export |
|
|
| ExportCenter | `src/ExportCenter/` | Batch export and report generation |
|
|
| Provenance | `src/Provenance/` | SLSA/DSSE attestation tooling |
|
|
| **Policy & Risk** | | |
|
|
| Policy | `src/Policy/` | Policy engine with K4 lattice logic |
|
|
| RiskEngine | `src/RiskEngine/` | Risk scoring runtime with pluggable providers |
|
|
| VulnExplorer | `src/VulnExplorer/` | Vulnerability exploration and triage UI backend |
|
|
| Unknowns | `src/Unknowns/` | Unknown component and symbol tracking |
|
|
| **Operations** | | |
|
|
| Scheduler | `src/Scheduler/` | Job scheduling and queue management |
|
|
| Orchestrator | `src/Orchestrator/` | Workflow orchestration and task coordination |
|
|
| TaskRunner | `src/TaskRunner/` | Task pack execution engine |
|
|
| Notify | `src/Notify/` | Notification toolkit (Email, Slack, Teams, Webhooks) |
|
|
| Notifier | `src/Notifier/` | Notifications Studio host |
|
|
| PacksRegistry | `src/PacksRegistry/` | Task packs registry and distribution |
|
|
| TimelineIndexer | `src/TimelineIndexer/` | Timeline event indexing |
|
|
| Replay | `src/Replay/` | Deterministic replay engine |
|
|
| **Integration** | | |
|
|
| CLI | `src/Cli/` | Command-line interface (Native AOT) |
|
|
| Zastava | `src/Zastava/` | Container registry webhook observer |
|
|
| Web | `src/Web/` | Angular 17 frontend SPA |
|
|
| API | `src/Api/` | OpenAPI contracts and governance |
|
|
| **Infrastructure** | | |
|
|
| Cryptography | `src/Cryptography/` | Crypto plugins (FIPS, eIDAS, GOST, SM, PQ) |
|
|
| Telemetry | `src/Telemetry/` | OpenTelemetry traces, metrics, logging |
|
|
| Graph | `src/Graph/` | Call graph and reachability data structures |
|
|
| Signals | `src/Signals/` | Runtime signal collection and correlation |
|
|
| AirGap | `src/AirGap/` | Air-gapped deployment support |
|
|
| AOC | `src/Aoc/` | Append-Only Contract enforcement (Roslyn analyzers) |
|
|
|
|
> **Note:** See `docs/modules/<module>/architecture.md` for detailed module dossiers.
|
|
|
|
### Code Organization Patterns
|
|
|
|
- **Libraries:** `src/<Module>/__Libraries/StellaOps.<Module>.*`
|
|
- **Tests:** `src/<Module>/__Tests/StellaOps.<Module>.*.Tests/`
|
|
- **Plugins:** Follow naming `StellaOps.<Module>.Connector.*` or `StellaOps.<Module>.Plugin.*`
|
|
- **Shared test infrastructure:** `StellaOps.Concelier.Testing` and `StellaOps.Infrastructure.Postgres.Testing` provide PostgreSQL fixtures
|
|
|
|
### Naming Conventions
|
|
|
|
- All modules are .NET 10 projects, except the UI (Angular)
|
|
- Module projects: `StellaOps.<ModuleName>`
|
|
- Libraries/plugins common to multiple modules: `StellaOps.<LibraryOrPlugin>`
|
|
- Each project lives in its own folder
|
|
|
|
### Key Glossary
|
|
|
|
- **OVAL** — Vendor/distro security definition format; authoritative for OS packages
|
|
- **NEVRA / EVR** — RPM and Debian version semantics for OS packages
|
|
- **PURL / SemVer** — Coordinates and version semantics for OSS ecosystems
|
|
- **KEV** — Known Exploited Vulnerabilities (flag only)
|
|
|
|
## Coding Rules
|
|
|
|
### Core Principles
|
|
|
|
1. **Determinism:** Outputs must be reproducible - stable ordering, UTC ISO-8601 timestamps, immutable NDJSON where applicable
|
|
2. **Offline-first:** Remote host allowlist, strict schema validation, avoid hard-coded external dependencies unless explicitly allowed
|
|
3. **Plugin architecture:** Concelier connectors, Authority plugins, Scanner analyzers are all plugin-based
|
|
4. **VEX-first decisioning:** Exploitability modeled in OpenVEX with lattice logic for stable outcomes
|
|
|
|
### Implementation Guidelines
|
|
|
|
- Follow .NET 10 and Angular v17 best practices
|
|
- Apply SOLID principles (SRP, OCP, LSP, ISP, DIP) when designing services, libraries, and tests
|
|
- Keep in mind the nuget versions are controlled centrally by src/Directory* files, not via csproj
|
|
- Maximise reuse and composability
|
|
- Never regress determinism, ordering, or precedence
|
|
- Every change must be accompanied by or covered by tests
|
|
- Gated LLM usage (only where explicitly configured)
|
|
|
|
### Test Layout
|
|
|
|
- **Module tests:** `src/<Module>/__Tests/StellaOps.<Module>.<Component>.Tests/`
|
|
- **Global tests:** `src/__Tests/{Category}/` (Integration, Acceptance, Load, Security, Chaos, E2E, etc.)
|
|
- **Shared testing libraries:** `src/__Tests/__Libraries/StellaOps.*.Testing/`
|
|
- **Benchmarks & golden corpus:** `src/__Tests/__Benchmarks/`
|
|
- **Ground truth datasets:** `src/__Tests/__Datasets/`
|
|
- Tests use xUnit, Testcontainers for PostgreSQL integration tests
|
|
- See `src/__Tests/AGENTS.md` for detailed test infrastructure guidance
|
|
|
|
## Code Quality & Determinism Rules
|
|
|
|
These rules were distilled from a comprehensive audit of 324+ projects. They address the most common recurring issues and must be followed by all implementers.
|
|
|
|
### 8.1) Compiler & Warning Discipline
|
|
|
|
| Rule | Guidance |
|
|
|------|----------|
|
|
| **Enable TreatWarningsAsErrors** | All projects must set `<TreatWarningsAsErrors>true</TreatWarningsAsErrors>` in the `.csproj` or via `Directory.Build.props`. Relaxed warnings mask regressions and code quality drift. |
|
|
|
|
```xml
|
|
<!-- In .csproj or Directory.Build.props -->
|
|
<PropertyGroup>
|
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
|
</PropertyGroup>
|
|
```
|
|
|
|
### 8.2) Deterministic Time & ID Generation
|
|
|
|
| Rule | Guidance |
|
|
|------|----------|
|
|
| **Inject TimeProvider / ID generators** | Never use `DateTime.UtcNow`, `DateTimeOffset.UtcNow`, `Guid.NewGuid()`, or `Random.Shared` directly in production code. Inject `TimeProvider` (or `ITimeProvider`) and `IGuidGenerator` abstractions. |
|
|
|
|
```csharp
|
|
// BAD - nondeterministic, hard to test
|
|
public class BadService
|
|
{
|
|
public Record CreateRecord() => new Record
|
|
{
|
|
Id = Guid.NewGuid(),
|
|
CreatedAt = DateTimeOffset.UtcNow
|
|
};
|
|
}
|
|
|
|
// GOOD - injectable, testable, deterministic
|
|
public class GoodService(TimeProvider timeProvider, IGuidGenerator guidGenerator)
|
|
{
|
|
public Record CreateRecord() => new Record
|
|
{
|
|
Id = guidGenerator.NewGuid(),
|
|
CreatedAt = timeProvider.GetUtcNow()
|
|
};
|
|
}
|
|
```
|
|
|
|
### 8.3) ASCII-Only Output
|
|
|
|
| Rule | Guidance |
|
|
|------|----------|
|
|
| **No mojibake or non-ASCII glyphs** | Use ASCII-only characters in comments, output strings, and log messages. No `ƒ?`, `バ`, `→`, `✓`, `✗`, or box-drawing characters. When Unicode is truly required, use explicit escapes (`\uXXXX`) and document the rationale. |
|
|
|
|
```csharp
|
|
// BAD - non-ASCII glyphs
|
|
Console.WriteLine("✓ Success → proceeding");
|
|
// or mojibake comments like: // ƒ+ validation passed
|
|
|
|
// GOOD - ASCII only
|
|
Console.WriteLine("[OK] Success - proceeding");
|
|
// Comment: validation passed
|
|
```
|
|
|
|
### 8.4) Test Project Requirements
|
|
|
|
| Rule | Guidance |
|
|
|------|----------|
|
|
| **Every library needs tests** | All production libraries/services must have a corresponding `*.Tests` project covering: (a) happy paths, (b) error/edge cases, (c) determinism, and (d) serialization round-trips. |
|
|
|
|
```
|
|
src/
|
|
Scanner/
|
|
__Libraries/
|
|
StellaOps.Scanner.Core/
|
|
__Tests/
|
|
StellaOps.Scanner.Core.Tests/ <-- Required
|
|
```
|
|
|
|
### 8.5) Culture-Invariant Parsing
|
|
|
|
| Rule | Guidance |
|
|
|------|----------|
|
|
| **Use InvariantCulture** | Always use `CultureInfo.InvariantCulture` for parsing and formatting dates, numbers, percentages, and any string that will be persisted, hashed, or compared. Current culture causes locale-dependent, nondeterministic behavior. |
|
|
|
|
```csharp
|
|
// BAD - culture-sensitive
|
|
var value = double.Parse(input);
|
|
var formatted = percentage.ToString("P2");
|
|
|
|
// GOOD - invariant culture
|
|
var value = double.Parse(input, CultureInfo.InvariantCulture);
|
|
var formatted = percentage.ToString("P2", CultureInfo.InvariantCulture);
|
|
```
|
|
|
|
### 8.6) DSSE PAE Consistency
|
|
|
|
| Rule | Guidance |
|
|
|------|----------|
|
|
| **Single DSSE PAE implementation** | Use one spec-compliant DSSE PAE helper (`StellaOps.Attestation.DsseHelper` or equivalent) across the codebase. DSSE v1 requires ASCII decimal lengths and space separators. Never reimplement PAE encoding. |
|
|
|
|
```csharp
|
|
// BAD - custom PAE implementation
|
|
var pae = $"DSSEv1 {payloadType.Length} {payloadType} {payload.Length} ";
|
|
|
|
// GOOD - use shared helper
|
|
var pae = DsseHelper.ComputePreAuthenticationEncoding(payloadType, payload);
|
|
```
|
|
|
|
### 8.7) RFC 8785 JSON Canonicalization
|
|
|
|
| Rule | Guidance |
|
|
|------|----------|
|
|
| **Use shared RFC 8785 canonicalizer** | For digest/signature inputs, use a shared RFC 8785-compliant JSON canonicalizer with: sorted keys, minimal escaping per spec, no exponent notation for numbers, no trailing/leading zeros. Do not use `UnsafeRelaxedJsonEscaping` or `CamelCase` naming for canonical outputs. |
|
|
|
|
```csharp
|
|
// BAD - non-canonical JSON
|
|
var json = JsonSerializer.Serialize(obj, new JsonSerializerOptions
|
|
{
|
|
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
|
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
|
});
|
|
|
|
// GOOD - use shared canonicalizer
|
|
var canonicalJson = CanonicalJsonSerializer.Serialize(obj);
|
|
var digest = ComputeDigest(canonicalJson);
|
|
```
|
|
|
|
### 8.8) CancellationToken Propagation
|
|
|
|
| Rule | Guidance |
|
|
|------|----------|
|
|
| **Propagate CancellationToken** | Always propagate `CancellationToken` through async call chains. Never use `CancellationToken.None` in production code except at entry points where no token is available. |
|
|
|
|
```csharp
|
|
// BAD - ignores cancellation
|
|
public async Task ProcessAsync(CancellationToken ct)
|
|
{
|
|
await _repository.SaveAsync(data, CancellationToken.None); // Wrong!
|
|
await Task.Delay(1000); // Missing ct
|
|
}
|
|
|
|
// GOOD - propagates cancellation
|
|
public async Task ProcessAsync(CancellationToken ct)
|
|
{
|
|
await _repository.SaveAsync(data, ct);
|
|
await Task.Delay(1000, ct);
|
|
}
|
|
```
|
|
|
|
### 8.9) HttpClient via Factory
|
|
|
|
| Rule | Guidance |
|
|
|------|----------|
|
|
| **Use IHttpClientFactory** | Never `new HttpClient()` directly. Use `IHttpClientFactory` with configured timeouts and retry policies via Polly or `Microsoft.Extensions.Http.Resilience`. Direct HttpClient creation risks socket exhaustion. |
|
|
|
|
```csharp
|
|
// BAD - direct instantiation
|
|
public class BadService
|
|
{
|
|
public async Task FetchAsync()
|
|
{
|
|
using var client = new HttpClient(); // Socket exhaustion risk
|
|
await client.GetAsync(url);
|
|
}
|
|
}
|
|
|
|
// GOOD - factory with resilience
|
|
public class GoodService(IHttpClientFactory httpClientFactory)
|
|
{
|
|
public async Task FetchAsync()
|
|
{
|
|
var client = httpClientFactory.CreateClient("MyApi");
|
|
await client.GetAsync(url);
|
|
}
|
|
}
|
|
|
|
// Registration with timeout/retry
|
|
services.AddHttpClient("MyApi")
|
|
.ConfigureHttpClient(c => c.Timeout = TimeSpan.FromSeconds(30))
|
|
.AddStandardResilienceHandler();
|
|
```
|
|
|
|
### 8.10) Path/Root Resolution
|
|
|
|
| Rule | Guidance |
|
|
|------|----------|
|
|
| **Explicit CLI options for paths** | Do not derive repository root from `AppContext.BaseDirectory` with parent directory walks. Use explicit CLI options (`--repo-root`) or environment variables. Provide sensible defaults with clear error messages. |
|
|
|
|
```csharp
|
|
// BAD - fragile parent walks
|
|
var repoRoot = Path.GetFullPath(Path.Combine(
|
|
AppContext.BaseDirectory, "..", "..", "..", ".."));
|
|
|
|
// GOOD - explicit option with fallback
|
|
[Option("--repo-root", Description = "Repository root path")]
|
|
public string? RepoRoot { get; set; }
|
|
|
|
public string GetRepoRoot() =>
|
|
RepoRoot ?? Environment.GetEnvironmentVariable("STELLAOPS_REPO_ROOT")
|
|
?? throw new InvalidOperationException("Repository root not specified. Use --repo-root or set STELLAOPS_REPO_ROOT.");
|
|
```
|
|
|
|
### 8.11) Test Categorization
|
|
|
|
| Rule | Guidance |
|
|
|------|----------|
|
|
| **Correct test categories** | Tag tests correctly: `[Trait("Category", "Unit")]` for pure unit tests, `[Trait("Category", "Integration")]` for tests requiring databases, containers, or network. Don't mix DB/network tests into unit suites. |
|
|
|
|
```csharp
|
|
// BAD - integration test marked as unit
|
|
public class UserRepositoryTests // Uses Testcontainers/Postgres
|
|
{
|
|
[Fact] // Missing category, runs with unit tests
|
|
public async Task Save_PersistsUser() { ... }
|
|
}
|
|
|
|
// GOOD - correctly categorized
|
|
[Trait("Category", "Integration")]
|
|
public class UserRepositoryTests
|
|
{
|
|
[Fact]
|
|
public async Task Save_PersistsUser() { ... }
|
|
}
|
|
|
|
[Trait("Category", "Unit")]
|
|
public class UserValidatorTests
|
|
{
|
|
[Fact]
|
|
public void Validate_EmptyEmail_ReturnsFalse() { ... }
|
|
}
|
|
```
|
|
|
|
### 8.12) No Silent Stubs
|
|
|
|
| Rule | Guidance |
|
|
|------|----------|
|
|
| **Unimplemented code must throw** | Placeholder code must throw `NotImplementedException` or return an explicit error/unsupported status. Never return success (`null`, empty results, or success codes) from unimplemented paths. |
|
|
|
|
```csharp
|
|
// BAD - silent stub masks missing implementation
|
|
public async Task<Result> ProcessAsync()
|
|
{
|
|
// TODO: implement later
|
|
return Result.Success(); // Ships broken feature!
|
|
}
|
|
|
|
// GOOD - explicit failure
|
|
public async Task<Result> ProcessAsync()
|
|
{
|
|
throw new NotImplementedException("ProcessAsync not yet implemented. See SPRINT_XYZ.");
|
|
}
|
|
```
|
|
|
|
### 8.13) Immutable Collection Returns
|
|
|
|
| Rule | Guidance |
|
|
|------|----------|
|
|
| **Return immutable collections** | Public APIs must return `IReadOnlyList<T>`, `ImmutableArray<T>`, or defensive copies. Never expose mutable backing stores that callers can mutate. |
|
|
|
|
```csharp
|
|
// BAD - exposes mutable backing store
|
|
public class BadRegistry
|
|
{
|
|
private readonly List<string> _scopes = new();
|
|
public List<string> Scopes => _scopes; // Callers can mutate!
|
|
}
|
|
|
|
// GOOD - immutable return
|
|
public class GoodRegistry
|
|
{
|
|
private readonly List<string> _scopes = new();
|
|
public IReadOnlyList<string> Scopes => _scopes.AsReadOnly();
|
|
// or: public ImmutableArray<string> Scopes => _scopes.ToImmutableArray();
|
|
}
|
|
```
|
|
|
|
### 8.14) Options Validation at Startup
|
|
|
|
| Rule | Guidance |
|
|
|------|----------|
|
|
| **ValidateOnStart for options** | Use `ValidateDataAnnotations()` and `ValidateOnStart()` for options. Implement `IValidateOptions<T>` for complex validation. All required config must be validated at startup, not at first use. |
|
|
|
|
```csharp
|
|
// BAD - no validation until runtime failure
|
|
services.Configure<MyOptions>(config.GetSection("My"));
|
|
|
|
// GOOD - validated at startup
|
|
services.AddOptions<MyOptions>()
|
|
.Bind(config.GetSection("My"))
|
|
.ValidateDataAnnotations()
|
|
.ValidateOnStart();
|
|
|
|
// With complex validation
|
|
public class MyOptionsValidator : IValidateOptions<MyOptions>
|
|
{
|
|
public ValidateOptionsResult Validate(string? name, MyOptions options)
|
|
{
|
|
if (options.Timeout <= TimeSpan.Zero)
|
|
return ValidateOptionsResult.Fail("Timeout must be positive");
|
|
return ValidateOptionsResult.Success;
|
|
}
|
|
}
|
|
```
|
|
|
|
### 8.15) No Backup Files in Source
|
|
|
|
| Rule | Guidance |
|
|
|------|----------|
|
|
| **Exclude backup/temp artifacts** | Add backup patterns (`*.Backup.tmp`, `*.bak`, `*.orig`) to `.gitignore`. Regularly audit for and remove stray artifacts. Consolidate duplicate tools/harnesses. |
|
|
|
|
```gitignore
|
|
# .gitignore additions
|
|
*.Backup.tmp
|
|
*.bak
|
|
*.orig
|
|
*~
|
|
```
|
|
|
|
### 8.16) Test Production Code, Not Reimplementations
|
|
|
|
| Rule | Guidance |
|
|
|------|----------|
|
|
| **Helpers call production code** | Test helpers must call production code, not reimplement algorithms (Merkle trees, DSSE PAE, parsers, canonicalizers). Only mock I/O and network boundaries. Reimplementations cause test/production drift. |
|
|
|
|
```csharp
|
|
// BAD - test reimplements production logic
|
|
[Fact]
|
|
public void Merkle_ComputesCorrectRoot()
|
|
{
|
|
// Custom Merkle implementation in test
|
|
var root = TestMerkleHelper.ComputeRoot(leaves); // Drift risk!
|
|
Assert.Equal(expected, root);
|
|
}
|
|
|
|
// GOOD - test exercises production code
|
|
[Fact]
|
|
public void Merkle_ComputesCorrectRoot()
|
|
{
|
|
// Uses production MerkleTreeBuilder
|
|
var root = MerkleTreeBuilder.ComputeRoot(leaves);
|
|
Assert.Equal(expected, root);
|
|
}
|
|
```
|
|
|
|
### 8.17) Bounded Caches with Eviction
|
|
|
|
| Rule | Guidance |
|
|
|------|----------|
|
|
| **No unbounded Dictionary caches** | Do not use `ConcurrentDictionary` or `Dictionary` for caching without eviction policies. Use bounded caches with TTL/LRU eviction (`MemoryCache` with size limits, or external cache like Valkey). Document expected cardinality and eviction behavior. |
|
|
|
|
```csharp
|
|
// BAD - unbounded growth
|
|
private readonly ConcurrentDictionary<string, CacheEntry> _cache = new();
|
|
|
|
public void Add(string key, CacheEntry entry)
|
|
{
|
|
_cache[key] = entry; // Never evicts, memory grows forever
|
|
}
|
|
|
|
// GOOD - bounded with eviction
|
|
private readonly MemoryCache _cache = new(new MemoryCacheOptions
|
|
{
|
|
SizeLimit = 10_000
|
|
});
|
|
|
|
public void Add(string key, CacheEntry entry)
|
|
{
|
|
_cache.Set(key, entry, new MemoryCacheEntryOptions
|
|
{
|
|
Size = 1,
|
|
SlidingExpiration = TimeSpan.FromMinutes(30)
|
|
});
|
|
}
|
|
```
|
|
|
|
### 8.18) DateTimeOffset for PostgreSQL timestamptz
|
|
|
|
| Rule | Guidance |
|
|
|------|----------|
|
|
| **Use GetFieldValue<DateTimeOffset>** | PostgreSQL `timestamptz` columns must be read via `reader.GetFieldValue<DateTimeOffset>()`, not `reader.GetDateTime()`. `GetDateTime()` loses offset information and causes UTC/local confusion. Store and retrieve all timestamps as UTC `DateTimeOffset`. |
|
|
|
|
```csharp
|
|
// BAD - loses offset information
|
|
var createdAt = reader.GetDateTime(reader.GetOrdinal("created_at"));
|
|
|
|
// GOOD - preserves offset
|
|
var createdAt = reader.GetFieldValue<DateTimeOffset>(reader.GetOrdinal("created_at"));
|
|
```
|
|
|
|
### Documentation Updates
|
|
|
|
When scope, contracts, or workflows change, update the relevant docs under:
|
|
- `docs/modules/**` - Module architecture dossiers
|
|
- `docs/api/` - API documentation
|
|
- `docs/risk/` - Risk documentation
|
|
- `docs/airgap/` - Air-gap operation docs
|
|
|
|
## Role-Based Behavior
|
|
|
|
When working in this repository, behavior changes based on the role specified:
|
|
|
|
### As Implementer (Default for coding tasks)
|
|
|
|
- Work only inside the module's directory defined by the sprint's "Working directory"
|
|
- Cross-module edits require explicit notes in commit/PR descriptions
|
|
- Do **not** ask clarification questions - if ambiguity exists:
|
|
- Mark the task as `BLOCKED` in the sprint `Delivery Tracker`
|
|
- Add a note in `Decisions & Risks` describing the issue
|
|
- Skip to the next unblocked task
|
|
- Maintain status tracking: `TODO → DOING → DONE/BLOCKED` in sprint files
|
|
- Read the module's `AGENTS.md` before coding in that module
|
|
|
|
### As Project Manager
|
|
|
|
Create implementation sprint files under `docs/implplan/` using the **mandatory** sprint filename format:
|
|
|
|
`SPRINT_<IMPLID>_<BATCHID>_<MODULEID>_<topic_in_few_words>.md`
|
|
|
|
- `<IMPLID>`: implementation epoch (e.g., `20251219`). Determine by scanning existing `docs/implplan/SPRINT_*.md` and using the highest epoch; if none exist, use today's epoch.
|
|
- `<BATCHID>`: `001`, `002`, etc. — grouping when more than one sprint is needed for a feature.
|
|
- `<MODULEID>`: `FE` (Frontend), `BE` (Backend), `AG` (Agent), `LB` (library), `BE` (Backend), `AG` (Agent), `LB` (library), 'SCANNER' (scanner), 'AUTH' (Authority), 'CONCEL' (Concelier), 'CONCEL-ASTRA' - (Concelier Astra source connecto) and etc.
|
|
- `<topic_in_few_words>`: short topic description.
|
|
- **If any existing sprint file name or internal format deviates from the standard, rename/normalize it** and record the change in its **Execution Log**.
|
|
- Normalize sprint files to standard template while preserving content
|
|
- Ensure module `AGENTS.md` files exist and are up to date
|
|
|
|
### As Product Manager
|
|
|
|
- Review advisories in `docs/product-advisories/`
|
|
- Check for overlaps with `docs/product-advisories/archived/`
|
|
- Validate against module docs and existing implementations
|
|
- Hand over to project manager role for sprint/task definition
|
|
|
|
## Task Workflow
|
|
|
|
### Status Discipline
|
|
|
|
Always update task status in `docs/implplan/SPRINT_*.md`:
|
|
- `TODO` - Not started
|
|
- `DOING` - In progress
|
|
- `DONE` - Completed
|
|
- `BLOCKED` - Waiting on decision/clarification
|
|
|
|
### Prerequisites
|
|
|
|
Before coding, confirm required docs are read:
|
|
- `docs/README.md`
|
|
- `docs/07_HIGH_LEVEL_ARCHITECTURE.md`
|
|
- `docs/modules/platform/architecture-overview.md`
|
|
- Relevant module dossier (e.g., `docs/modules/<module>/architecture.md`)
|
|
- Module-specific `AGENTS.md` file
|
|
|
|
### Git Rules
|
|
|
|
- Never use `git reset` unless explicitly told to do so
|
|
- Never skip hooks (--no-verify, --no-gpg-sign) unless explicitly requested
|
|
|
|
## Configuration
|
|
|
|
- **Sample configs:** `etc/concelier.yaml.sample`, `etc/authority.yaml.sample`
|
|
- **Plugin manifests:** `etc/authority.plugins/*.yaml`
|
|
- **NuGet sources:** Package cache in `.nuget/packages/`, public sources configured in `nuget.config`
|
|
|
|
## Documentation
|
|
|
|
- **Architecture overview:** `docs/07_HIGH_LEVEL_ARCHITECTURE.md`
|
|
- **Module dossiers:** `docs/modules/<module>/architecture.md`
|
|
- **Database specification:** `docs/db/SPECIFICATION.md`
|
|
- **PostgreSQL operations:** `docs/operations/postgresql-guide.md`
|
|
- **API/CLI reference:** `docs/09_API_CLI_REFERENCE.md`
|
|
- **Offline operation:** `docs/24_OFFLINE_KIT.md`
|
|
- **Quickstart:** `docs/10_CONCELIER_CLI_QUICKSTART.md`
|
|
- **Sprint planning:** `docs/implplan/SPRINT_*.md`
|
|
|
|
## CI/CD
|
|
|
|
### Folder Structure
|
|
|
|
The CI/CD infrastructure uses a two-tier organization:
|
|
|
|
| Folder | Purpose |
|
|
|--------|---------|
|
|
| `.gitea/workflows/` | Gitea Actions workflow YAML files (87+) |
|
|
| `.gitea/scripts/` | CI/CD scripts called by workflows |
|
|
| `devops/` | Deployment, tooling, and operational configs |
|
|
|
|
### CI/CD Scripts (`.gitea/scripts/`)
|
|
|
|
```
|
|
.gitea/scripts/
|
|
├── build/ # Build orchestration (build-cli.sh, build-multiarch.sh)
|
|
├── test/ # Test execution (test-lane.sh, determinism-run.sh)
|
|
├── validate/ # Validation (validate-sbom.sh, validate-helm.sh)
|
|
├── sign/ # Signing (sign-signals.sh, publish-attestation.sh)
|
|
├── release/ # Release automation (build_release.py, verify_release.py)
|
|
├── metrics/ # Performance metrics (compute-reachability-metrics.sh)
|
|
├── evidence/ # Evidence bundles (upload-all-evidence.sh)
|
|
└── util/ # Utilities (cleanup-runner-space.sh)
|
|
```
|
|
|
|
### DevOps Folder (`devops/`)
|
|
|
|
```
|
|
devops/
|
|
├── compose/ # Docker Compose profiles (dev, stage, prod, airgap)
|
|
├── helm/ # Helm charts (stellaops)
|
|
├── docker/ # Dockerfiles (platform, crypto-profile, ci)
|
|
├── telemetry/ # OpenTelemetry, Prometheus, Grafana configs
|
|
├── services/ # Service-specific configs (authority, crypto, signals)
|
|
├── offline/ # Air-gap and offline deployment
|
|
├── observability/ # Alerts, SLOs, incident management
|
|
├── database/ # PostgreSQL and MongoDB configs
|
|
├── ansible/ # Ansible playbooks
|
|
├── gitlab/ # GitLab CI templates
|
|
├── releases/ # Release manifests
|
|
├── tools/ # Development tools (callgraph, corpus, feeds)
|
|
└── scripts/ # DevOps scripts (test-local.sh, validate-compose.sh)
|
|
```
|
|
|
|
### Key Workflows
|
|
|
|
| Workflow | Purpose |
|
|
|----------|---------|
|
|
| `build-test-deploy.yml` | Main build, test, and deployment pipeline |
|
|
| `test-matrix.yml` | Unified test execution with TRX reporting |
|
|
| `module-publish.yml` | Per-module NuGet and container publishing |
|
|
| `release-suite.yml` | Full suite release (Ubuntu-style versioning) |
|
|
| `cli-build.yml` | CLI multi-platform builds |
|
|
| `scanner-determinism.yml` | Scanner output reproducibility tests |
|
|
| `policy-lint.yml` | Policy validation |
|
|
|
|
### Versioning
|
|
|
|
- **Suite releases**: Ubuntu-style `YYYY.MM` with codenames (e.g., "2026.04 Nova")
|
|
- **Module releases**: Semantic versioning `MAJOR.MINOR.PATCH`
|
|
- See `docs/releases/VERSIONING.md` for full documentation
|
|
|
|
## Environment Variables
|
|
|
|
- `STELLAOPS_BACKEND_URL` - Backend API URL for CLI
|
|
- `STELLAOPS_TEST_POSTGRES_CONNECTION` - PostgreSQL connection string for integration tests
|
|
- `StellaOpsEnableCryptoPro` - Enable GOST crypto support (set to `true` in build)
|