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
Test Commands
Note: Integration tests use Testcontainers for PostgreSQL. Ensure Docker is running before executing tests.
Linting and Validation
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
- Determinism: Outputs must be reproducible - stable ordering, UTC ISO-8601 timestamps, immutable NDJSON where applicable
- Offline-first: Remote host allowlist, strict schema validation, avoid hard-coded external dependencies unless explicitly allowed
- Plugin architecture: Concelier connectors, Authority plugins, Scanner analyzers are all plugin-based
- 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. |
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. |
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. |
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. |
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. |
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. |
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. |
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. |
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. |
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. |
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. |
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. |
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. |
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. |
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. |
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. |
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. |
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. |
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/)
DevOps Folder (devops/)
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)