component_architecture_cli.md — Stella Ops CLI (2025Q4)

Consolidates requirements captured in the Policy Engine, Policy Studio, Vulnerability Explorer, Export Center, and Notifications implementation plans and module guides.

Scope. Implementation‑ready architecture for Stella Ops CLI: command surface, process model, auth (Authority/DPoP), integration with Scanner/Excititor/Concelier/Signer/Attestor, Buildx plug‑in management, offline kit behavior, packaging, observability, security posture, and CI ergonomics.


0) Mission & boundaries

Mission. Provide a fast, deterministic, CI‑friendly command‑line interface to drive Stella Ops workflows:

  • Build‑time SBOM generation via Buildx generator orchestration.
  • Post‑build scan/compose/diff/export against Scanner.WebService.
  • Policy operations and VEX/Vuln data pulls (operator tasks).
  • Verification (attestation, referrers, signatures) for audits.
  • Air‑gapped/offline kit administration.

Boundaries.

  • CLI never signs; it only calls Signer/Attestor via backend APIs when needed (e.g., report --attest).
  • CLI does not store long‑lived credentials beyond OS keychain; tokens are short (Authority OpToks).
  • Heavy work (scanning, merging, policy) is executed server‑side (Scanner/Excititor/Concelier).

1) Solution layout & runtime form

src/
 ├─ StellaOps.Cli/                         # net10.0 (Native AOT) single binary
 ├─ StellaOps.Cli.Core/                    # verb plumbing, config, HTTP, auth
 ├─ StellaOps.Cli.Plugins/                 # optional verbs packaged as plugins
 ├─ StellaOps.Cli.Tests/                   # unit + golden-output tests
 └─ packaging/
     ├─ msix / msi / deb / rpm / brew formula
     └─ scoop manifest / winget manifest

Language/runtime: .NET 10 Native AOT for speed/startup; Linux builds use musl static when possible.

Plug-in verbs. Non-core verbs (Excititor, runtime helpers, future integrations) ship as restart-time plug-ins under plugins/cli/** with manifest descriptors. The launcher loads plug-ins on startup; hot reloading is intentionally unsupported. The inaugural bundle, StellaOps.Cli.Plugins.NonCore, packages the Excititor, runtime, and offline-kit command groups and publishes its manifest at plugins/cli/StellaOps.Cli.Plugins.NonCore/.

OS targets: linux‑x64/arm64, windows‑x64/arm64, macOS‑x64/arm64.


2) Command surface (verbs)

All verbs default to JSON output when --json is set (CI mode). Human output is concise, deterministic.

2.1 Auth & profile

  • auth login

    • Modes: device‑code (default), client‑credentials (service principal).
    • Produces Authority access token (OpTok) + stores DPoP keypair in OS keychain.
  • auth status — show current issuer, subject, audiences, expiry.

  • auth logout — wipe cached tokens/keys.

2.2 Build‑time SBOM (Buildx)

  • buildx install — install/update the StellaOps.Scanner.Sbomer.BuildXPlugin on the host.

  • buildx verify — ensure generator is usable.

  • buildx build — thin wrapper around docker buildx build --attest=type=sbom,generator=stellaops/sbom-indexer with convenience flags:

    • --attest (request Signer/Attestor via backend post‑push)
    • --provenance pass‑through (optional)

2.3 Scanning & artifacts

  • scan image <ref|digest>

    • Options: --force, --wait, --view=inventory|usage|both, --format=cdx-json|cdx-pb|spdx-json, --attest (ask backend to sign/log).
    • Streams progress; exits early unless --wait.
  • diff image --old <digest> --new <digest> [--view ...] — show layer‑attributed changes.

  • export sbom <digest> [--view ... --format ... --out file] — download artifact.

  • report final <digest> [--policy-revision ... --attest] — request PASS/FAIL report from backend (policy+vex) and optional attestation.

2.4 Policy & data

  • policy get/set/apply — fetch active policy, apply staged policy, compute digest.
  • concelier export — trigger/export canonical JSON or Trivy DB (admin).
  • excititor export — trigger/export consensus/raw claims (admin).

2.5 Verification

  • verify attestation --uuid <rekor-uuid> | --artifact <sha256> | --bundle <path> — call Attestor /verify and print proof summary.
  • verify referrers <digest> — ask Signer /verify/referrers (is image Stella‑signed?).
  • verify image-signature <ref|digest> — standalone cosign verification (optional, local).

2.6 Runtime (Zastava helper)

  • runtime policy test --image/-i <digest> [--file <path> --ns <name> --label key=value --json] — ask backend /policy/runtime like the webhook would (accepts multiple --image, comma/space lists, or stdin pipelines).

2.7 Offline kit

  • offline kit pull — fetch latest Concelier JSON + Trivy DB + Excititor exports as a tarball from a mirror.
  • offline kit import <tar> — upload the kit to on‑prem services (Concelier/Excititor).
  • offline kit status — list current seed versions.

2.8 Utilities

  • config set/get — endpoint & defaults.
  • whoami — short auth display.
  • version — CLI + protocol versions; release channel.

2.9 Aggregation-only guard helpers

  • sources ingest --dry-run --source <id> --input <path|uri> [--tenant ... --format table|json --output file]

    • Normalises documents (handles gzip/base64), posts them to the backend aoc/ingest/dry-run route, and exits non-zero when guard violations are detected.
    • Defaults to table output with ANSI colour; --json/--output produce deterministic JSON for CI pipelines.
  • aoc verify [--since <ISO8601|duration>] [--limit <count>] [--sources list] [--codes list] [--format table|json] [--export file] [--tenant id] [--no-color]

    • Replays guard checks against stored raw documents. Maps backend ERR_AOC_00x codes onto deterministic exit codes so CI can block regressions.
    • Supports pagination hints (--limit, --since), tenant scoping via --tenant or STELLA_TENANT, and JSON exports for evidence lockers.

2.10 Key management (file KMS support)

  • kms export --key-id <logicalId> --output <file> [--version <id>] [--force]

    • Decrypts the file-backed KMS store (passphrase supplied via --passphrase, STELLAOPS_KMS_PASSPHRASE, or interactive prompt) and writes a portable JSON bundle (KmsKeyMaterial) with key metadata and coordinates for offline escrow or replication.
  • kms import --key-id <logicalId> --input <file> [--version <override>]

    • Imports a previously exported bundle into the local KMS root (kms/ by default), promotes the imported version to Active, and preserves existing versions by marking them PendingRotation. Prompts for the passphrase when not provided to keep automation password-safe.

Both subcommands honour offline-first expectations (no network access) and normalise relative roots via --root when operators mirror the credential store.

2.11 Advisory AI (RAG summaries)

  • advise run <summary|conflict|remediation> --advisory-key <id> [--artifact-id id] [--artifact-purl purl] [--policy-version v] [--profile profile] [--section name] [--force-refresh] [--timeout seconds]

    • Calls the Advisory AI service (/v1/advisory-ai/pipeline/{task} + /outputs/{cacheKey}) to materialise a deterministic plan, queue execution, and poll for the generated brief.
    • Renders plan metadata (cache key, prompt template, token budgets), guardrail results, provenance hashes/signatures, and citation list. Exit code is non-zero if guardrails block or the command times out.
    • Uses STELLAOPS_ADVISORYAI_URL when configured; otherwise it reuses the backend base address and adds X-StellaOps-Scopes (advisory:run + task scope) per request.
    • --timeout 0 performs a single cache lookup (for CI flows that only want cached artefacts).

2.12 Decision evidence (new)

  • decision export

    • Parameters: --cve, --product <purl or digest>, --scan-id <optional>, --output-dir.
    • Pulls decision.openvex.json, decision.dsse.json, rekor.txt, and evidence metadata from Policy Engine and writes them into the bench/findings/<CVE>/ layout defined in docs/benchmarks/vex-evidence-playbook.md.
    • When --sync is set, uploads the bundle to Git (bench repo) with deterministic commit messages.
  • decision verify

    • Offline verifier that wraps tools/verify.sh/verify.py from the bench repo. Checks DSSE signature, optional Rekor inclusion, and recomputes digests for reachability/SBOM artifacts.
    • Supports --from bench (local path) and --remote (fetch via API). Exit codes align with verify.sh (0 success, 3 signature failure, 18 truncated evidence).
  • decision compare

    • Executes the benchmark harness against baseline scanners (Trivy/Syft/Grype/Snyk/Xray), capturing false-positive reduction, mean-time-to-decision, and reproducibility metrics into results/summary.csv.
    • Flags regressions when Stella Ops produces more false positives or slower MTTD than the configured target.

All verbs require scopes policy.findings:read, signer.verify, and (for Rekor lookups) attestor.read. They honour sealed-mode rules by falling back to offline verification only when Rekor/Signer endpoints are unreachable.

2.13 Air-gap guard

  • CLI outbound HTTP flows (Authority auth, backend APIs, advisory downloads) route through StellaOps.AirGap.Policy. When sealed mode is active the CLI refuses commands that would require external egress and surfaces the shared AIRGAP_EGRESS_BLOCKED remediation guidance instead of attempting the request.

3) AuthN: Authority + DPoP

3.1 Token acquisition

  • Device‑code: the CLI opens an OIDC device code flow against Authority; the browser login is optional for service principals.
  • Client‑credentials: service principals use private_key_jwt or mTLS to get tokens.

3.2 DPoP key management

  • On first login, the CLI generates an ephemeral JWK (Ed25519) and stores it in the OS keychain (Keychain/DPAPI/KWallet/Gnome Keyring).
  • Every request to backend services includes a DPoP proof; CLI refreshes tokens as needed.

3.3 Multi‑audience & scopes

  • CLI requests audiences as needed per verb:

    • scanner for scan/export/report/diff
    • signer (indirect; usually backend calls Signer)
    • attestor for verify (requires attestor.verify scope; read-only verbs fall back to attestor.read)
    • concelier/excititor for admin verbs

CLI rejects verbs if required scopes are missing.


4) Process model & reliability

4.1 HTTP client

  • Single http2 client with connection pooling, DNS pinning, retry/backoff (idempotent GET/POST marked safe).
  • DPoP nonce handling: on 401 with nonce challenge, CLI replays once.

4.2 Streaming

  • scan and report support server‑sent JSON lines (progress events).
  • --json prints machine events; human mode shows compact spinners and crucial updates only.

4.3 Exit codes (CI‑safe)

CodeMeaning
0Success
2Policy fail (final report verdict=fail)
3Verification failed (attestation/signature)
4Auth error (invalid/missing token/DPoP)
5Resource not found (image/SBOM)
6Rate limited / quota exceeded
7Backend unavailable (retryable)
9Invalid arguments
11–17Aggregation-only guard violation (ERR_AOC_00x)
18Verification truncated (increase --limit)
70Transport/authentication failure
71CLI usage error (missing tenant, invalid cursor)

5) Configuration model

Precedence: CLI flags → env vars → config file → defaults.

Config file: ${XDG_CONFIG_HOME}/stellaops/config.yaml (Windows: %APPDATA%\StellaOps\config.yaml)

cli:
  authority: "https://authority.internal"
  backend:
    scanner: "https://scanner-web.internal"
    attestor: "https://attestor.internal"
    concelier: "https://concelier-web.internal"
    excititor: "https://excititor-web.internal"
  auth:
    audienceDefault: "scanner"
    deviceCode: true
  output:
    json: false
    color: auto
  tls:
    caBundle: "/etc/ssl/certs/ca-bundle.crt"
  offline:
    kitMirror: "s3://mirror/stellaops-kit"

Environment variables: STELLAOPS_AUTHORITY, STELLAOPS_SCANNER_URL, etc.


6) Buildx generator orchestration

  • buildx install locates the Docker root directory, writes the generator plugin manifest, and pulls stellaops/sbom-indexer image (pinned digest).

  • buildx build wrapper injects:

    • --attest=type=sbom,generator=stellaops/sbom-indexer
    • --label org.stellaops.request=sbom
  • Post‑build: CLI optionally calls Scanner.WebService to verify referrers, compose image SBOMs, and attest via Signer/Attestor.

Detection: If Buildx or generator unavailable, CLI falls back to post‑build scan with a warning.


7) Artifact handling

  • Downloads (export sbom, report final): stream to file; compute sha256 on the fly; write sidecar .sha256 and optional verification bundle (if --bundle).
  • Uploads (offline kit import): chunked upload; retry on transient errors; show progress bar (unless --json).

8) Security posture

  • DPoP private keys stored in OS keychain; metadata cached in config.
  • No plaintext tokens on disk; short‑lived OpToks held in memory.
  • TLS: verify backend certificates; allow custom CA bundle for on‑prem.
  • Redaction: CLI logs remove Authorization, DPoP headers, PoE tokens.
  • Supply chain: CLI distribution binaries are cosign‑signed; stellaops version --verify checks its own signature.

9) Observability

  • --verbose adds request IDs, timings, and retry traces.
  • Metrics (optional, disabled by default): Prometheus text file exporter for local monitoring in long‑running agents.
  • Structured logs (--json): per‑event JSON lines with ts, verb, status, latencyMs.

10) Performance targets

  • Startup ≤ 20 ms (AOT).
  • scan image request/response overhead ≤ 5 ms (excluding server work).
  • Buildx wrapper overhead negligible (<1 ms).
  • Large artifact download (100 MB) sustained ≥ 80 MB/s on local networks.

11) Tests & golden outputs

  • Unit tests: argument parsing, config precedence, URL resolution, DPoP proof creation.
  • Integration tests (Testcontainers): mock Authority/Scanner/Attestor; CI pipeline with fake registry.
  • Golden outputs: verb snapshots for --json across OSes; kept in tests/golden/….
  • Contract tests: ensure API shapes match service OpenAPI; fail build if incompatible.

12) Error envelopes (human + JSON)

Human:

✖ Policy FAIL: 3 high, 1 critical (VEX suppressed 12)
  - pkg:rpm/openssl (CVE-2025-12345) — affected (vendor) — fixed in 3.0.14
  - pkg:npm/lodash (GHSA-xxxx) — affected — no fix
  See: https://ui.internal/scans/sha256:...
Exit code: 2

JSON (--json):

{ "event":"report", "status":"fail", "critical":1, "high":3, "url":"https://ui..." }

13) Admin & advanced flags

  • --authority, --scanner, --attestor, --concelier, --excititor override config URLs.
  • --no-color, --quiet, --json.
  • --timeout, --retries, --retry-backoff-ms.
  • --ca-bundle, --insecure (dev only; prints warning).
  • --trace (dump HTTP traces to file; scrubbed).

14) Interop with other tools

  • Emits CycloneDX Protobuf directly to stdout when export sbom --format cdx-pb --out -.
  • Pipes to jq/yq cleanly in JSON mode.
  • Can act as a credential helper for scripts: stellaops auth token --aud scanner prints a one‑shot token for curl.

15) Packaging & distribution

  • Installers: deb/rpm (postinst registers completions), Homebrew, Scoop, Winget, MSI/MSIX.
  • Shell completions: bash/zsh/fish/pwsh.
  • Update channel: stellaops self-update (optional) fetches cosign‑signed release manifest; corporate environments can disable.

16) Security hard lines

  • Refuse to print token values; redact Authorization headers in verbose output.
  • Disallow --insecure unless STELLAOPS_CLI_ALLOW_INSECURE=1 set (double opt‑in).
  • Enforce short token TTL; refresh proactively when <30 s left.
  • Device‑code cache binding to machine and user (protect against copy to other machines).

17) Wire sequences

A) Scan & wait with attestation

sequenceDiagram
  autonumber
  participant CLI
  participant Auth as Authority
  participant SW as Scanner.WebService
  participant SG as Signer
  participant AT as Attestor

  CLI->>Auth: device code flow (DPoP)
  Auth-->>CLI: OpTok (aud=scanner)

  CLI->>SW: POST /scans { imageRef, attest:true }
  SW-->>CLI: { scanId }
  CLI->>SW: GET /scans/{id} (poll)
  SW-->>CLI: { status: completed, artifacts, rekor? }  # if attested

  alt attestation pending
    SW->>SG: POST /sign/dsse (server-side)
    SG-->>SW: DSSE
    SW->>AT: POST /rekor/entries
    AT-->>SW: { uuid, proof }
  end

  CLI->>SW: GET /sboms/?format=cdx-pb&view=usage
  SW-->>CLI: bytes

B) Verify attestation by artifact

sequenceDiagram
  autonumber
  participant CLI
  participant AT as Attestor

  CLI->>AT: POST /rekor/verify { artifactSha256 }
  AT-->>CLI: { ok:true, uuid, index, logURL }

18) Roadmap (CLI)

  • scan fs <path> (local filesystem tree) → upload to backend for analysis.
  • policy test --sbom <file> (simulate policy results offline using local policy bundle).
  • runtime capture (developer mode) — capture small /proc/<pid>/maps for troubleshooting.
  • Pluggable output renderers for SARIF/HTML (admin‑controlled).

19) Example CI snippets

GitHub Actions (post‑build)

- name: Login (device code w/ OIDC broker)
  run: stellaops auth login --json --authority ${{ secrets.AUTHORITY_URL }}

- name: Scan
  run: stellaops scan image ${{ steps.build.outputs.digest }} --wait --json

- name: Export (usage view, protobuf)
  run: stellaops export sbom ${{ steps.build.outputs.digest }} --view usage --format cdx-pb --out sbom.pb

- name: Verify attestation
  run: stellaops verify attestation --artifact $(sha256sum sbom.pb | cut -d' ' -f1) --json

GitLab (buildx generator)

script:
  - stellaops buildx install
  - docker buildx build --attest=type=sbom,generator=stellaops/sbom-indexer -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
  - stellaops scan image $CI_REGISTRY_IMAGE@$IMAGE_DIGEST --wait --json

20) Test matrix (OS/arch)

  • Linux: ubuntu‑20.04/22.04/24.04 (x64, arm64), alpine (musl).
  • macOS: 13–15 (x64, arm64).
  • Windows: 10/11, Server 2019/2022 (x64, arm64).
  • Docker engines: Docker Desktop, containerd‑based runners.