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.7), 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.2.1) Resolver Version Tracking
| Rule |
Guidance |
| Include resolver/engine version in snapshots |
For strict reproducibility verification, include the resolver or engine version digest in KnowledgeSnapshot and similar input manifests. This ensures that identical inputs processed by different engine versions can be detected and flagged. |
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)