Files
git.stella-ops.org/docs/18_CODING_STANDARDS.md
StellaOps Bot b058dbe031 up
2025-12-14 23:20:14 +02:00

8.4 KiB
Executable File
Raw Blame History

18 · Coding Standards & Contributor Guide — StellaOps

(v2.0 — 12Jul2025 · supersedes v1.0)

Audience — Anyone sending a pullrequest to the opensource Core.
Goal — Keep the codebase smallfiled, pluginfriendly, DIconsistent, and instantly readable.


0Why read this?

  • Cuts review time → quicker merges.
  • Guarantees code is hotloadsafe for runtime plugins.
  • Prevents style churn and merge conflicts.

1Highlevel principles

  1. SOLID first especially Interface & Dependency Inversion.
  2. 100line rule any file >100 physical lines must be split or refactored.
  3. Contractlevel ownership public abstractions live in lightweight Contracts libraries; impl classes live in runtime projects.
  4. Single Composition Root all DI wiring happens in StellaOps.Web/Program.cs and in each plugins IoCConfigurator; nothing else calls IServiceCollection.BuildServiceProvider.
  5. No Service Locator constructor injection only; static ServiceProvider is banned.
  6. Failfast startup configuration validated before the webhost listens.
  7. Hotload compatible no static singletons that survive plugin unload; avoid Assembly.LoadFrom outside the builtin plugin loader.

2Repository layout (flat, July2025)**

src/
├─ backend/
│   ├─ StellaOps.Web/                # ASP.NET host + composition root
│   ├─ StellaOps.Common/             # Serilog, Result<T>, helpers
│   ├─ StellaOps.Contracts/          # DTO + interface contracts (no impl)
│   ├─ StellaOps.Configuration/      # Options + validation
│   ├─ StellaOps.Localization/
│   ├─ StellaOps.PluginLoader/       # Cosign verify, hotload
│   ├─ StellaOps.Scanners.Trivy/     # Firstparty scanner
│   ├─ StellaOps.TlsProviders.OpenSsl/
│   └─ … (additional runtime projects)
├─ plugins-sdk/                      # Templated contracts & abstractions
└─ frontend/                         # Angular workspace
tests/                               # Mirrors src structure 1to1

There are no folders named “Module” and no nested solutions.

3Naming & style conventions

Element Rule Example
Namespaces Filescoped, StellaOps. namespace StellaOps.Scanners;
Interfaces I prefix, PascalCase IScannerRunner
Classes / records PascalCase ScanRequest, TrivyRunner
Private fields _camelCase (with leading underscore) _redisCache, _httpClient
Constants PascalCase (standard C#) const int MaxRetries = 3;
Async methods End with Async Task ScanAsync()
File length 100 lines incl. using & braces enforced by dotnet format check
Using directives Outside namespace, sorted, no wildcards

Static analyzers (.editorconfig, StyleCop.Analyzers package) enforce the above.

4Dependencyinjection policy

Composition root exactly one per process:

builder.Services
       .AddStellaCore()          // extension methods from each runtime project
       .AddPluginLoader("/Plugins", cfg);   // hotload signed DLLs

Plugins register additional services via the IoCConfigurator convention described in the Plugin SDK Guide, §5. Never resolve services manually (provider.GetService()) outside the composition root; tests may use WebApplicationFactory or ServiceProvider.New() helpers. Scoped lifetime is default; singletons only for stateless, threadsafe helpers.

5Project organisation rules

Contracts vs. Runtime public DTO & interfaces live in .Contracts; implementation lives in sibling project. Feature folders inside each runtime project group classes by usecase, e.g.

├─ Scan/
│   ├─ ScanService.cs
│   └─ ScanController.cs
├─ Feed/
└─ Tls/

Tests mirror the structure under tests/ onetoone; no test code inside production projects.

6C# language features

Nullable reference types enabled. record for immutable DTOs. Pattern matching encouraged; avoid long switchcascades. Span & Memory OK when perfcritical, but measure first. Use await foreach over manual paginator loops.

7Errorhandling template

public async Task<IActionResult> PostScan([FromBody] ScanRequest req)
{
    if (!ModelState.IsValid) return BadRequest(ModelState);

    try
    {
        ScanResult result = await scanService.ScanAsync(req);
        if (result.Quota != null) 
        {
            Response.Headers.TryAdd("X-Stella-Quota-Remaining", result.Quota.Remaining.ToString());
            Response.Headers.TryAdd("X-Stella-Reset", result.Quota.ResetUtc.ToString("o"));
        }
        return Ok(result);
    }
}

RFC7807 ProblemDetails for all non200s. Capture structured logs with Serilogs messagetemplate syntax.

8Async & threading

  • All I/O is async; no .Result / .Wait().
  • Library code: ConfigureAwait(false).
  • Limit concurrency via Channel or Parallel.ForEachAsync, never raw Task.Run loops.

9Testing rules

Layer Framework Coverage gate
Unit xUnit + FluentAssertions 80% line, ≥60% branch
Integration Testcontainers PostgreSQL, real services
Mutation (critical libs) Stryker.NET 60% score

One test project per runtime/contract project; naming .Tests.

10Static analysis & formatting

  • dotnet format must exit clean (CI gate).
  • StyleCop.Analyzers + RoslynSecurityGuard run on every PR.
  • CodeQL workflow runs nightly on main.

11Commit & PR checklist

  • Conventional Commit prefix (feat:, fix:, etc.).
  • dotnet format & dotnet test both green.
  • Added or updated XMLdoc comments for public APIs.
  • File count & length comply with 100line rule.
  • If new public contract → update relevant markdown doc & JSONSchema.

12Common pitfalls

Symptom Root cause Fix
InvalidOperationException: Cannot consume scoped service... Mismatched DI lifetimes Use scoped everywhere unless truly stateless
Hotreload plugin crash Static singleton caching plugin types Store nothing static; rely on DI scopes

100line style violation |Large handlers or utils |Split into private helpers or new class

13Change log

Version Date Notes
v2.1 2025-12-14 Corrected field naming to _camelCase, constants to PascalCase, integration tests to PostgreSQL.
v2.0 2025-07-12 Updated DI policy, 100-line rule, new repo layout, removed "Module" terminology.
v1.0 2025-07-09 Original standards.