19 KiB
Here’s a compact, no‑fluff onboarding brief to get a mid‑level .NET dev productive on StellaOps in a couple of days.
StellaOps – Mid‑Level .NET Onboarding (Quick Start)
0) What you’re building (context in one minute)
StellaOps is a sovereign, air‑gap‑friendly SBOM→VEX platform written in .NET 10. Core ideas: deterministic scans, cryptographic attestations (DSSE/in‑toto; optional PQC), trust lattices for VEX decisions, and a replayable audit trail.
1) Repos to open first (read in this order)
src/StellaOps.Scanner.WebService/— scanning surfaces, rules plumbing, lattice calls.src/StellaOps.Vexer/(a.k.a. Excititor) — VEX verdict engine & trust‑merge logic.src/StellaOps.Sbomer/— SBOM ingest/normalize (CycloneDX/SPDX).src/StellaOps.Authority/— keys, attestations, license tokens, Rekor integration.src/StellaOps.Scheduler/— batch & replay orchestration.src/StellaOps.Shared/CanonicalModel/— canonical entities & graph IDs (read carefully).
Tip: keep docs/modules/platform/* open for protocol notes (DSSE envelopes, lattice terms).
2) Local dev up in ~10–15 min
- Prereqs: .NET 10 SDK (preview), Docker, Node (for Angular UI if needed), WSL2 optional.
- From repo root:
# infra
docker compose -f compose/offline-kit.yml up -d # Mongo/Postgres/Rabbit/MinIO per profile
# backend
dotnet restore
dotnet build -c Debug
# run a focused slice (scanner + authority)
dotnet run --project src/StellaOps.Authority/StellaOps.Authority.csproj
dotnet run --project src/StellaOps.Scanner.WebService/StellaOps.Scanner.WebService.csproj
- Environment: copy
env/example.local.env→.env, then setSTELLAOPS_DBprovider (MongoorPostgres) andAUTHORITY_*keys.
3) Deterministic testcases to run locally (prove your env is correct)
These are “golden” replays: same inputs → same graph & hashes.
- Hello‑SBOM → VEX Not‑Affected (Reachability‑false)
dotnet test tests/Determinism/Det_SbomToVex_NotAffected.csproj
Checks: identical GraphRevisionID and DSSE payload hash across two consecutive runs.
- In‑toto chain: source→build→image attestation
dotnet test tests/Attestations/Att_InToto_Chain.csproj
Checks: DSSE envelope canonicalization stable; signature over CBOR‑canonical JSON matches stored hash.
- Lattice merge: vendor VEX + runtime signal
dotnet test tests/Lattice/Lattice_VendorPlusRuntime.csproj
Checks: merge verdict is stable with the same input set order; produces identical TrustReceipt.
If any golden snapshot differs, your clock/locale/line‑endings or JSON canonicalizer is misconfigured.
4) Coding conventions (cryptographic attestations & determinism)
- JSON: serialize with our
CanonicalJson(UTF‑8, sorted keys, no insignificant whitespace,\nline endings). - DSSE: always embed
payloadType=application/vnd.stellaops.trust+json. - Hashing: BLAKE3 for internal content addressing, SHA‑256 where interop requires.
- Keys: use
Authority.KeyRingprovider (Ed25519 by default; PQC Dilithium optional flagAUTHORITY_PQC=on). - Timestamps: use
Instant(UTC) with truncation to milliseconds; neverDateTime.Now. - IDs: graph nodes use
HashStableIdderived from canonical bytes; never database autoinc for public IDs. - VEX: verdicts must include
proofs[](e.g., reachability, config‑guards, runtime path) and areceiptsigned by Authority. - Repro: any function that affects verdicts must be pure or behind a deterministic adapter.
Snippet (sign a DSSE envelope deterministically):
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) Minimal daily loop
- Pick one starter issue (below).
- Write unit tests first; ensure golden snapshots match.
- Run
dotnet test --filter Category=Determinism. - Commit with
feat(scanner|vexer|authority): …and include the GraphRevisionID delta in the body.
6) Three starter issues (teach the canonical data model)
A) Normalize CycloneDX components → Canonical Packages
Goal: map CycloneDX components to CanonicalPackage with stable IDs.
Where: StellaOps.Sbomer + tests in tests/Determinism/Det_SbomMapping.
Done when:
- Two equivalent SBOMs (field order shuffled) map to identical package set & IDs.
- Snapshot
CanonicalPackageSet.hashis stable. - Edge cases: missing
purl, duplicate components, case differences.
B) Implement “Not‑Affected by Configuration” proof
Goal: add proof generator that marks a CVE as not‑affected if a config gate is off.
Where: StellaOps.Vexer/Proofs/ConfigSwitchProof.cs.
Done when:
- Given
FeatureX=false, CVE‑1234 becomesnot_affectedwith proof payload includingconfigPath,observed=false. - Deterministic proof hash and DSSE receipt exist.
- Lattice merge keeps vendor “affected” but flips to
not_affectedwhen runtime/config proof weight > threshold.
C) Authority offline Rekor mirror submitter
Goal: if air‑gapped, write DSSE entries to local mirror; sync later.
Where: StellaOps.Authority/Rekor/RekorMirrorClient.cs.
Done when:
RekorMode.OfflineMirrorIfAirgappedstores canonical entry (JSON+hash path).rekor syncjob replays in order, preserving entry IDs.- Golden test ensures same input sequence → same mirror tree hash.
7) Database notes (Mongo ↔ Postgres switchability)
- Use repository interfaces in
StellaOps.Shared.Persistence. - Canonical/public IDs are hash‑derived; DB keys are implementation‑local.
- Never rely on DB sort order for any hash or verdict; always re‑canonicalize before hashing.
8) Debug checklist (most common slips)
- Non‑canonical JSON (unsorted keys, trailing spaces).
- Local time sneaking into proofs.
- Unstable GUIDs in tests.
- Non‑deterministic enumeration over
Dictionary<>. - Different newline conventions on Windows—enforce
\nin canonical paths.
9) Useful commands
# run determinism pack
dotnet test --filter Category=Determinism
# update golden snapshots (intentional change only)
dotnet test --filter Category=Determinism -- TestRunParameters.Parameter(name=\"UpdateSnapshots\", value=\"true\")
# quick API smoke
curl -s http://localhost:5080/health
curl -s -X POST http://localhost:5081/scan -d @samples/nginx.sbom.json
# verify DSSE signature locally
dotnet run --project tools/StellaOps.Tools.Verify -- file trust.receipt.json
10) Ask‑once glossary
- SBOM: software bill of materials (CycloneDX/SPDX).
- VEX: vulnerability exploitability exchange (verdicts: affected / not‑affected / under‑investigation).
- DSSE: signed payload wrapper; we canonicalize before signing.
- Lattice: rule system to merge proofs/verdicts from different sources deterministically.
- GraphRevisionID: hash of the canonical trust graph; your “build number” for audits.
Want me to turn this into docs/onboarding/dev-quickstart.md plus three ready‑to‑run GitHub issues and the test scaffolds?
# 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.
---
## 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 (if present).
---
## 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 makes life easier 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
Copy the example env and tweak:
cp env/example.local.env .env
Key settings:
STELLAOPS_DB=MongoorPostgresAUTHORITY_*– key material and config (see comments inexample.local.env)- Optional:
AUTHORITY_PQC=onto 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 - Identical DSSE payload hashes
- Identical
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
TrustReceiptis 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 when working on code that affects trust graphs, proofs, or attestations.
5.1 JSON & Canonicalization
-
Use our
CanonicalJsonhelper for anything that will be:- Hashed
- Signed
- Used as a canonical ID input
-
Rules:
- UTF‑8
- Sorted keys
- No insignificant whitespace
\nline endings (enforced for canonical paths)
5.2 DSSE Envelopes
-
payloadTypemust always be:application/vnd.stellaops.trust+json
-
Envelopes are signed over the canonicalized bytes of the payload.
Example:
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
- Internal content addressing: BLAKE3
- External / interop where required: SHA‑256
Never mix algorithms for the same ID type.
5.4 Keys & Algorithms
- Default signatures: Ed25519 via
Authority.KeyRing - Optional PQC: Dilithium when
AUTHORITY_PQC=on - Never manage keys directly – always use the keyring abstraction.
5.5 Time & Clocks
- Use
Instant(UTC) /DateTimeOffsetin UTC. - Truncate to milliseconds for anything that ends up in canonical data.
- Never use
DateTime.Nowor local time in trust‑critical code.
5.6 IDs & Graph Nodes
- Public / canonical IDs are derived from hashes of canonical bytes.
- DB primary keys are implementation details; do not leak them externally.
- Do not depend on DB auto‑increment or sort order for anything that affects hashing.
5.7 VEX Verdicts
Every VEX verdict must:
-
Be backed by
proofs[](e.g., reachability analysis, config guards, runtime path). -
Emit a
receiptsigned by Authority, wrapping:- Verdict
- Proof hashes
- Context (component, vulnerability, scope, etc.)
6. Daily Workflow
A minimal loop that keeps you aligned with the platform’s guarantees:
-
Pick a focused issue (see starter tasks below).
-
Write tests first, especially determinism tests where applicable.
-
Implement the change, keeping:
- Canonicalization boundaries explicit
- Hashing and signing centralized
-
Run:
dotnet test --filter Category=Determinism -
Commit using:
feat(scanner): ...feat(vexer): ...feat(authority): ...- etc.
Include the affected
GraphRevisionIDin the commit body when relevant to trust‑graph changes.
7. Suggested Starter Tasks
These are good first issues that teach the canonical model and determinism expectations.
7.1 Normalize CycloneDX Components → Canonical Packages
Goal: Map CycloneDX components to our CanonicalPackage model with stable IDs.
- Area:
StellaOps.Sbomer - Tests:
tests/Determinism/Det_SbomMapping
Definition of done:
-
Two equivalent SBOMs (only field order differs) produce:
- Identical package sets
- Identical canonical package IDs
-
CanonicalPackageSet.hashis stable. -
Edge cases handled:
- Missing
purl - Duplicate components
- Case differences in names or versions
- Missing
7.2 Implement “Not‑Affected by Configuration” Proof
Goal: Add proof generator that marks a CVE as not_affected when a config gate disables the vulnerable path.
- Area:
StellaOps.Vexer/Proofs/ConfigSwitchProof.cs
Definition of done:
-
Given
FeatureX=false, CVE‑1234 yields verdict:-
status = not_affected -
proofs[]includes aConfigSwitchProofwith:configPathobserved=false
-
-
Proof is hashed deterministically and included in the DSSE receipt.
-
Lattice merge behavior:
- Vendor verdict:
affected - Runtime/config proof weight > threshold → merged verdict becomes
not_affecteddeterministically.
- Vendor verdict:
7.3 Authority Offline Rekor Mirror Submitter
Goal: Support air‑gapped mode: DSSE entries are written to a local Rekor mirror and synced later.
- Area:
StellaOps.Authority/Rekor/RekorMirrorClient.cs
Definition of done:
-
RekorMode.OfflineMirrorIfAirgapped:- Stores canonical entries (JSON + hash‑based path) on disk / object store.
-
A
rekor syncbackground job (or CLI) replays entries in order to the real Rekor instance. -
Determinism test:
- Same input DSSE sequence → same mirror tree hash and Rekor entry order.
8. Database Notes (Mongo ↔ Postgres)
StellaOps is designed to be DB‑agnostic.
-
Use repository interfaces from
StellaOps.Shared.Persistence. -
Keep canonical/public IDs hash‑derived; DB keys are internal.
-
Do not depend on DB sort order for anything that:
- Affects hashes
- Affects verdicts
- Ends up in canonical data
If you need ordering, sort after canonicalization using deterministic criteria.
9. Common Pitfalls & Debug Checklist
When a determinism test fails, look for these first:
-
Non‑canonical JSON
- Unsorted keys
- Extra whitespace
- Mixed
\r\nvs\nline endings
-
Local Time Leaks
- Any
DateTime.Nowor local time in proofs or receipts.
- Any
-
Random / Unstable IDs
- New GUIDs in tests or canonical entities.
- Auto‑increment IDs leaking into hashes.
-
Unordered Collections
- Iterating over
Dictionary<>orHashSet<>without ordering. - Using LINQ without explicit
OrderBywhen hashing or serializing.
- Iterating over
-
Platform Differences
- Windows vs Linux newline differences.
- Locale differences (
,vs.for decimals, etc.) – always use invariant culture for canonical data.
10. Useful Commands
10.1 Determinism Pack
# Run only determinism‑tagged tests
dotnet test --filter Category=Determinism
Update golden snapshots when you intend to change canonical behavior:
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 like
affected,not_affected,under_investigation.
- Verdicts like
-
DSSE – Dead Simple Signing Envelope:
- Wrapper around payload + signature; we sign canonical bytes.
-
In‑toto – Supply‑chain attestation framework; we use it for source→build→artifact chains.
-
Lattice – Rule system that merges multiple verdicts/proofs into a single deterministic verdict.
-
GraphRevisionID – Hash of the canonical trust graph at a point in time; acts like a build number for audits.
Welcome aboard. Your best “map” into the system is:
- Read
CanonicalModeltypes. - Run the determinism tests.
- Pick one of the starter tasks and ship a small, well‑tested change.
If you keep everything canonical, hashable, and replayable, you’ll fit right in.