StellaOps Developer Quickstart

Audience: Mid-level .NET developers
Goal: Get you productive on StellaOps in 1–2 days, with special focus on determinism, cryptographic attestations, and the canonical data model.


This quickstart mirrors the 29-Nov-2025 Developer Onboarding advisory (docs/product-advisories/29-Nov-2025 - StellaOps – Mid-Level .NET Onboarding (Quick Start).md) and keeps the determinism-first guidance in sync with that release note.

1. What You’re Building (Context)

StellaOps is a sovereign, air-gap-friendly platform that turns SBOMs → VEX with a fully replayable, deterministic trust graph.

Core concepts:

  • Deterministic scans: Same inputs → same graph, hashes, and verdicts.
  • Cryptographic attestations: DSSE/in-toto envelopes, optional PQC.
  • Trust lattice: Merges vendor VEX, runtime signals, configs, etc. into a single deterministic verdict.
  • Audit trail: Every decision is reproducible from stored inputs and proofs.

Offline/determinism essentials (read first):

  • Install from the curated offline kit (no network); pin SDK + tool versions in inputs.lock.
  • Use DSSE-signed configs and keep signing keys in offline ~/.stellaops/keys with short-lived tokens.
  • Run dotnet format / dotnet test with --blame-crash --blame-hang using fixed seeds (Random(1337)) to avoid flakiness.
  • Capture DB/queue matrix upfront: MongoDB (pinned version), optional Postgres slices, and local cache paths; set TZ=UTC for all runs.

If you think “content-addressed trust pipeline for SBOMs + VEX,” you’re in the right mental model.


2. Repository & Docs Map

Start by opening these projects in order:

  1. src/StellaOps.Scanner.WebService/
    Scanning endpoints, rule plumbing, and calls into the trust lattice.
  2. src/StellaOps.Vexer/ (a.k.a. Excititor)
    VEX verdict engine and trust-merge logic.
  3. src/StellaOps.Sbomer/
    SBOM ingest / normalize (CycloneDX, SPDX).
  4. src/StellaOps.Authority/
    Key management, DSSE/in-toto attestations, license tokens, Rekor integration.
  5. src/StellaOps.Scheduler/
    Batch processing, replay orchestration.
  6. src/StellaOps.Shared/CanonicalModel/
    Canonical entities & graph IDs. Read this carefully – it underpins determinism.

Starter issues to grab on day 1 (all offline-friendly):

  • Add DSSE verification to a small CLI path (stella verify --local-only).
  • Extend inputs.lock examples with a pinned scanner/DB matrix.
  • Write a deterministic unit test for canonical ID ordering.
  • Improve docs/ cross-links (Developer Quickstart ↔ platform architecture) and ensure docs: trailer appears in commits.

UI note: Console remains in flux; focus on backend determinism first, then follow UI sprints 0209/0215 for micro-interactions and proof-linked VEX updates.

3. Environment & DB matrix

  • MongoDB: 6.0.12 (pin in inputs.lock).
  • Optional Postgres slices: see sprint 340x series; keep read-only in dev until instructed.
  • Offline feeds: offline-cache-2025-11-30 (scanner, advisories, VEX).
  • Timezone: TZ=UTC for all tests and tooling.

4. Secrets & signing

  • Store short-lived signing keys in ~/.stellaops/keys (gitignored); never commit secrets.
  • Use DSSE for pack manifests and fixtures; include signer IDs.
  • For Rekor: use mirrored bundle (no live log writes); verify receipts offline.

5. Contribution checklist

See docs/onboarding/contribution-checklist.md for the minimal gates (docs trailer, seeds, inputs.lock, DSSE, secrets).

Helpful docs:

  • docs/modules/platform/* – protocols (DSSE envelopes, lattice terms, trust receipts).
  • docs/architecture/* – high-level diagrams and flows.

3. Local Dev Setup

3.1 Prerequisites

  • .NET 10 SDK (preview as specified in repo).
  • Docker (for DB, queues, object storage).
  • Node.js (for Angular UI, if you’re touching the frontend).
  • WSL2 (optional but convenient on Windows).

3.2 Bring Up Infra

From the repo root:

# Bring up core infra for offline / air-gap friendly dev
docker compose -f compose/offline-kit.yml up -d

This usually includes:

  • MongoDB or Postgres (configurable).
  • RabbitMQ (or equivalent queue).
  • MinIO / object storage (depending on profile).

3.3 Configure Environment

cp env/example.local.env .env

Key settings:

  • STELLAOPS_DB=Mongo or Postgres.
  • AUTHORITY_* – key material and config (see comments in example.local.env).
  • Optional: AUTHORITY_PQC=on to enable post-quantum keys (Dilithium).

3.4 Build & Run Backend

# Restore & build everything
dotnet restore
dotnet build -c Debug

# Run a focused slice for development
dotnet run --project src/StellaOps.Authority/StellaOps.Authority.csproj
dotnet run --project src/StellaOps.Scanner.WebService/StellaOps.Scanner.WebService.csproj

Health checks (adjust ports if needed):

curl -s http://localhost:5080/health          # Authority
curl -s http://localhost:5081/health          # Scanner

4. Deterministic Sanity Tests

These tests prove your local environment is configured correctly for determinism. If any of these fail due to snapshot mismatch, fix your environment before writing new features.

4.1 SBOM → VEX “Not Affected” (Reachability False)

dotnet test tests/Determinism/Det_SbomToVex_NotAffected.csproj

What it checks:

  • Two consecutive runs with the same SBOM produce identical GraphRevisionID and DSSE payload hashes.

If they differ, inspect:

  • JSON canonicalization.
  • Locale / culture.
  • Line endings.

4.2 In-toto Chain: Source → Build → Image Attestation

dotnet test tests/Attestations/Att_InToto_Chain.csproj

What it checks:

  • DSSE envelope canonicalization is stable.
  • Signature over CBOR-canonical JSON matches the stored hash.
  • Full in-toto chain can be replayed deterministically.

4.3 Lattice Merge: Vendor VEX + Runtime Signal

dotnet test tests/Lattice/Lattice_VendorPlusRuntime.csproj

What it checks:

  • Merge verdict is stable regardless of input set order.
  • Resulting TrustReceipt is byte-for-byte identical between runs.

If any “golden” snapshots differ, you likely have:

  • Non-canonical JSON.
  • Unstable enumeration (e.g., iterating Dictionary<> directly).
  • Locale or newline drift.

5. Coding Conventions (Determinism & Crypto)

These are non-negotiable in code that affects trust graphs, proofs, or attestations.

5.1 JSON & Canonicalization

  • Use the CanonicalJson helper whenever a payload is hashed, signed, or used for IDs.
  • Rules: UTF-8, sorted keys, no insignificant whitespace, \n line endings.

5.2 DSSE Envelopes

  • payloadType must always be application/vnd.stellaops.trust+json.
  • Sign over the canonicalized bytes.
var payload = CanonicalJson.Serialize(trustDoc);
var env = DsseEnvelope.Create("application/vnd.stellaops.trust+json", payload);
var signed = await keyRing.SignAsync(env.CanonicalizeBytes());
await rekor.SubmitAsync(signed, RekorMode.OfflineMirrorIfAirgapped);

5.3 Hashing

  • BLAKE3 for internal content addressing.
  • SHA-256 where interop demands it.
  • Never mix algorithms within the same ID type.

5.4 Keys & Algorithms

  • Default signatures: Ed25519 via Authority.KeyRing.
  • Optional PQC: Dilithium when AUTHORITY_PQC=on.
  • Always go through the keyring abstraction; never manage raw keys manually.

5.5 Time & Clocks

  • Use Instant/DateTimeOffset (UTC), truncated to milliseconds.
  • Never use DateTime.Now or local clocks in canonical data.

5.6 IDs & Graph Nodes

  • Canonical/public IDs derive from hashes of canonical bytes.
  • DB primary keys are implementation details.
  • Do not depend on DB auto-increment or implicit sort order when hashing.

5.7 VEX Verdicts

Every VEX verdict must:

  • Carry proofs[] (reachability, config guards, runtime paths).
  • Emit a receipt signed by Authority, covering verdict, proof hashes, and context.

6. Daily Workflow

  1. Pick a focused issue (see starter tasks below).
  2. Write tests first, especially determinism scenarios.
  3. Implement changes with canonicalization boundaries explicit and signing centralized.
  4. Run dotnet test --filter Category=Determinism.
  5. Commit with the appropriate prefix (feat(scanner):, feat(vexer):, feat(authority):) and mention the affected GraphRevisionID if your change alters the trust graph.

7. Suggested Starter Tasks

These introduce the canonical data model and determinism mindset.

7.1 Normalize CycloneDX Components → Canonical Packages

Area: StellaOps.Sbomer

Tests: tests/Determinism/Det_SbomMapping

Definition of done:

  • Equivalent SBOMs (even if fields shuffle) yield identical package sets and canonical IDs.
  • CanonicalPackageSet.hash is stable.
  • Edge cases covered: missing purl, duplicate components, case variation.

7.2 Implement “Not-Affected by Configuration” Proof

Area: StellaOps.Vexer/Proofs/ConfigSwitchProof.cs

Definition of done:

  • With FeatureX=false, CVE-1234 reports status = not_affected and the proof records configPath + observed=false.
  • Proof hash is deterministic and included in the DSSE receipt.
  • Lattice merge flips the verdict to not_affected when the runtime/config proof weight crosses the threshold, even if the vendor says affected.

7.3 Authority Offline Rekor Mirror Submitter

Area: StellaOps.Authority/Rekor/RekorMirrorClient.cs

Definition of done:

  • RekorMode.OfflineMirrorIfAirgapped records canonical entries (JSON + hash path) locally.
  • rekor sync replays entries in order, preserving entry IDs.
  • Golden test ensures the same input sequence → same mirror tree hash.

8. Database Notes (Mongo ↔ Postgres)

  • Use StellaOps.Shared.Persistence repository interfaces.
  • Canonical/public IDs are hash-derived; DB keys are internal details.
  • Never rely on DB sort order for anything that affects hashes or verdicts; re-canonicalize before hashing and apply deterministic ordering afterwards.

9. Common Pitfalls

  1. Non-canonical JSON (unsorted keys, extra whitespace, mixed \r\n).
  2. Local time creeping into proofs (DateTime.Now).
  3. Unstable GUIDs in tests or canonical entities.
  4. Unordered collections (Dictionary<> iterations, LINQ without OrderBy) while hashing or serializing.
  5. Platform drift (Windows vs Linux newline/culture differences) – always use invariant culture and \n in canonical data.

10. Useful Commands

10.1 Determinism Pack

# Run determinism-tagged fixtures
dotnet test --filter Category=Determinism

Update golden snapshots deliberately:

dotnet test --filter Category=Determinism -- \ 
  TestRunParameters.Parameter(name="UpdateSnapshots", value="true")

10.2 Quick API Smoke

curl -s http://localhost:5080/health

curl -s -X POST \
  http://localhost:5081/scan \
  -H "Content-Type: application/json" \
  -d @samples/nginx.sbom.json

10.3 Verify DSSE Signature Locally

dotnet run --project tools/StellaOps.Tools.Verify -- file trust.receipt.json

11. Glossary (Ask-Once)

  • SBOM – Software Bill of Materials (CycloneDX/SPDX).
  • VEX – Vulnerability Exploitability eXchange: verdicts include affected, not_affected, under_investigation.
  • DSSE – Dead Simple Signing Envelope; we sign canonical bytes.
  • In-toto – Supply-chain attestation framework for source → build → artifact chains.
  • Lattice – Rule system merging multiple verdicts/proofs into deterministic outcomes.
  • GraphRevisionID – Hash of the canonical trust graph; acts like a build number for audits.

Welcome aboard. Your best “map” is:

  1. Read the CanonicalModel types.
  2. Run the determinism tests.
  3. Ship one of the starter tasks with deterministic, test-covered changes.

Keep everything canonical, hashable, and replayable and you’ll fit right in.