# 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. 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. 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: ```bash # 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 ```bash 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 ```bash # 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): ```bash 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) ```bash 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 ```bash 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 ```bash 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. ```csharp 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 ```bash # Run determinism-tagged fixtures dotnet test --filter Category=Determinism ``` Update golden snapshots deliberately: ```bash dotnet test --filter Category=Determinism -- \ TestRunParameters.Parameter(name="UpdateSnapshots", value="true") ``` ### 10.2 Quick API Smoke ```bash 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 ```bash 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.