Stella Ops CLI architecture

Source ownership, 2026-10-03. PCD-253 withdrew the uncompiled StellaOps.Cli.Tests/Commands/WatchlistCommandGoldenTests.cs mock-formatting draft. It never called a CLI command; executable coverage stays in src/Cli/__Tests/. See the per-file source disposition.

Verified against commit 942a18727c (2026-09-26, DOC-2 of SPRINT_20260926_001). Re-verify by reading the evidence paths listed in the Evidence section.

Scope. The stella / stellaops command-line interface: solution layout, process model, configuration, Authority authentication, HTTP clients and egress policy, the command surface, restart-time plug-ins, exit codes, packaging, and the CI gates that keep documentation and code aligned. The authoritative command tree is CommandFactory.Create in src/Cli/StellaOps.Cli/Commands/CommandFactory.cs; when this page and the source disagree, the source wins.

CLI example gate. Living documentation is parsed against the released CommandFactory tree and the manifest-backed restart-time plug-ins under src/Cli/plugins/cli/ (CliDocumentationContractTests). Examples the parser rejects are explicitly classified as unshipped or stale in unshipped-command-examples.json; see the operator-readable policy. A baselined example is not runnable.


0) Mission and boundaries

The CLI drives Stella Ops workflows from a terminal or a CI job:

Boundaries:

attest build records caller-reported SLSA v1 provenance through the existing Evidence sign, submit and exact-envelope export APIs. It keeps CI lineage separate from the authenticated producer and signing key, and refuses online success when the backend or retained bytes are unavailable. See the build-provenance contract; this source path does not prove live CI execution or authorize identity enrollment.


1) Solution layout

src/Cli/
 |- StellaOps.Cli/                  # net10.0 console app; assembly StellaOps.Cli.dll (`stella` / `stellaops`)
 |  |- Program.cs                   # DI composition, HTTP clients, invocation and exit-code precedence
 |  |- Commands/CommandFactory.cs   # authoritative root command tree (CommandFactory.Create)
 |  |- Commands/*CommandGroup.cs    # per-domain command groups
 |  |- Commands/CommandHandlers*.cs # shared handlers (CommandHandlers.Auth.cs holds auth helpers)
 |  |- Configuration/               # CliBootstrapper, StellaOpsCliOptions, AuthorityTokenUtilities,
 |  |                               # PolicyGatewayEndpoint, profiles, secret protectors
 |  |- Plugins/                     # restart-only plug-in loader (CliCommandModuleLoader)
 |  |- Services/                    # typed HTTP clients and local services
 |  |- Output/                      # OutputFormat (table, json, yaml, sarif) and renderers
 |- __Libraries/StellaOps.Cli.Plugins.*/  # restart-time plug-in assemblies
 |- plugins/cli/<plug-in>/          # one *.manifest.json per shipped plug-in
 |- __Tests/                        # StellaOps.Cli.Tests plus focused test projects
                                    # (AdviseParity, Commands.Setup, CompareOverlay, PluginIntegration,
                                    #  QaSeed, ScannerPlugins, UnknownsExport)

There is no StellaOps.Cli.Core project; configuration, HTTP and auth wiring live in StellaOps.Cli. The project targets .NET 10; Native AOT, single-file and trimming are not enabled in StellaOps.Cli.csproj.

Retired CLI source is frozen under src/__Obsoleted/Cli/ (the GroundTruth plug-in and command group, the air-gap sync group, the BinaryIndex ops group, the Postgres compact-VulnDB corpus source, and a Symbols plug-in predecessor). Those files are not compiled.

The CLI references implementation libraries of several other modules (see the ProjectReference list in StellaOps.Cli.csproj). Signer custody is consumed only through StellaOps.Signer.Contracts and the neutral StellaOps.Cryptography.* signing libraries; the CLI does not compile StellaOps.Signer.Core, Infrastructure, KeyManagement or Keyless.


2) Process model

  1. Program.Main resets Environment.ExitCode, builds configuration and options through CliBootstrapper.Build(args), and records the global --tenant value for tenant resolution.
  2. It composes a ServiceCollection: air-gap egress policy (AddAirGapEgressPolicy), the crypto registry (AddStellaOpsCrypto, BouncyCastle Ed25519, and the regional providers compiled into the distribution through CliRegionalCryptoComposition), logging, the Authority token client, and the typed HTTP clients (section 5).
  3. CommandFactory.Create builds the root command. The root has two global options, --verbose/-v and --tenant/-t, and sets TreatUnmatchedTokensAsErrors = true.
  4. CliCommandModuleLoader loads the restart-time plug-ins (section 7) into the same root.
  5. CliInvocation.InvokeAsync runs the parse result. A parse error returns exit code 2 (CliExitCodes.MissingRequiredOption). The process exit code is Environment.ExitCode when a handler set it, otherwise the command’s return value.

Startup Authority and crypto diagnostics are emitted only for verbose human-readable invocations (CliStartupDiagnosticsPolicy); structured output (--json, --raw, --format json) stays clean.


3) Configuration

Sources and precedence. CliBootstrapper uses StellaOpsConfigurationBootstrapper with binding section StellaOps. Sources, lowest to highest precedence: appsettings.json, appsettings.local.json, appsettings.yaml, appsettings.local.yaml (all optional, resolved from the current directory), command-line configuration arguments, then environment variables (no prefix). After binding, each option is resolved from an ordered list of keys; the first non-empty value wins.

SettingKeys (first match wins)
Backend (gateway) URLSTELLAOPS_BACKEND_URL, StellaOps:BackendUrl
Personal access tokenAPI_KEY, StellaOps:ApiKey
Authority URLSTELLAOPS_AUTHORITY_URL, StellaOps:Authority:Url
Discovery documentSTELLAOPS_AUTHORITY_METADATA_ADDRESS, STELLAOPS_AUTHORITY_METADATA_URL, StellaOps:Authority:MetadataAddress
Token endpoint overrideSTELLAOPS_AUTHORITY_TOKEN_ENDPOINT, StellaOps:Authority:TokenEndpoint
ClientSTELLAOPS_AUTHORITY_CLIENT_ID (default stellaops-cli), STELLAOPS_AUTHORITY_CLIENT_SECRET
Operator loginSTELLAOPS_AUTHORITY_USERNAME, STELLAOPS_AUTHORITY_PASSWORD
Identity provider and tenant for token requestsSTELLAOPS_AUTHORITY_PROVIDER, STELLAOPS_AUTHORITY_TENANT
Default scopeSTELLAOPS_AUTHORITY_SCOPE (unset by default: the CLI requests no scope and Authority grants the client’s ordinary login scopes; operation-bound permissions require an explicit scope request)
Token cache directorySTELLAOPS_AUTHORITY_TOKEN_CACHE_DIR (default ~/.stellaops/tokens)
Authority retries and offline cacheSTELLAOPS_AUTHORITY_ENABLE_RETRIES, STELLAOPS_AUTHORITY_RETRY_DELAYS, STELLAOPS_AUTHORITY_ALLOW_OFFLINE_CACHE_FALLBACK, STELLAOPS_AUTHORITY_OFFLINE_CACHE_TOLERANCE
Service-specific URLsSTELLAOPS_ADVISORYAI_URL, STELLAOPS_VULNERABILITIES_URL, STELLAOPS_CONCELIER_URL, STELLAOPS_EVIDENCE_URL, STELLAOPS_POLICY_ENGINE_URL
Offline kitsSTELLAOPS_OFFLINE_KITS_DIRECTORY, STELLAOPS_OFFLINE_MIRROR_URL
Plug-insSTELLAOPS_CLI_PLUGIN_BASE_DIRECTORY, STELLAOPS_CLI_PLUGIN_DIRECTORY, STELLAOPS_CLI_PLUGIN_MANIFEST_PATTERN (default *.manifest.json)

Each key also has the StellaOps:* configuration form listed in CliBootstrapper.cs.

Profiles. CliProfileManager keeps profile metadata in ~/.stellaops/profiles.json and profile secrets in ~/.stellaops/profiles.<name>.secrets.bin through the host secret protector (section 4.4).

Tenant. Every tenant the CLI sends, in the token request and in the X-StellaOps-TenantId header, comes from one rule, TenantProfileStore.ResolveTenant (section 4.2).


4) Authentication

4.1 Credential modes

The token client (StellaOps.Auth.Client.StellaOpsTokenClient) implements only the password and client_credentials grants; device-code, PKCE and DPoP are not implemented in the CLI. The token endpoint comes from the Authority discovery document (cached by StellaOpsDiscoveryCache) unless STELLAOPS_AUTHORITY_TOKEN_ENDPOINT is set; then token requests go to that URL without fetching discovery. This lets a CLI outside the estate network work when discovery advertises an internal host.

4.2 Grant rule and tenant rule

AuthorityTokenUtilities is the single implementation used by every CLI client:

These rules are pinned by CliClientTenantResolutionConformanceTests (every registration resolves the tenant through the rule), CliTenantHeaderConformanceTests (every source that sets the tenant header is classified; each client that resolves its own tenant sends the token’s tenant against a recorded network; no CLI source reads a tenant source outside TenantProfileStore), CliClientGrantParityTests (every client that requests its own token follows the grant rule; the shrink-only register of exceptions is empty) and CliRequestedScopeCatalogueConformanceTests (every scope the CLI requests exists in StellaOpsScopes; a scope outside the catalogue is refused by Authority with invalid_scope).

The standard local/dev lab uses STELLAOPS_AUTHORITY_PROVIDER=standard and STELLAOPS_AUTHORITY_TENANT=default. These are lab values, not product defaults.

4.3 Scopes

Each client requests the catalogue scope for its owner API. Examples:

ClientScope(s)
SbomClientsbom:read, sbom:write
HubMirrorSeedClientread advisory:read vex:read aoc:verify; write advisory:ingest vex:ingest
CliLocalTransparencyRekorClientattest:read
AI code guard clientintegration:operate
Advisory AI chat clientadvisory-ai:operate
Evidence bundle exportexport.operator (create), export.viewer (status, download), evidence:read (portable release export)
Release gate (PolicyGate.Evaluate, PolicyGate.Bootstrap, PolicyGate.Decision)policy:run (gate evaluate), policy:run policy:write (gate evaluate --missing-baseline bootstrap: the gate refuses initial-baseline enrollment without write authority), policy:read (gate status), regardless of STELLAOPS_AUTHORITY_SCOPE
Risk budget (Budget.Read, Budget.Consume)policy:read (status, check, history, list), policy:operate (consume)
registry scanscanner:scan (submit, POST /api/v1/scans), scanner:read (status), minted for the command’s tenant
registry list, images, show, cache reads, upstream listregistry:read, minted for the command’s tenant
Registry cache policy writesregistry:cache:admin
Registry upstream writesregistry.admin
scan graph --uploadscanner.callgraph.ingest; stella.callgraph.v1 at POST /api/v1/scans/{scanId}/callgraphs

The canonical scope catalogue is src/Authority/StellaOps.Authority/StellaOps.Auth.Abstractions/StellaOpsScopes.cs.

4.4 Token and secret storage

Service-client cache boundary (PCD-291). A prompted auth login does not enable the named clients used by gate, exception and release commands. They use configured authentication through ConfigureApiAuthentication: an API key, configured operator username/password, or confidential client credentials. StellaOpsBearerTokenHandler has its own client/scope/mode/tenant/credential cache namespace, separate from AuthorityTokenUtilities.BuildCacheKey. It neither consumes the prompted login entry nor exchanges its refresh token. Configure service credentials explicitly; auth logout clears the login entry rather than those independently scoped caches. The auth command guide and auth login --help describe this requirement.


5) HTTP clients and egress policy

Program.cs registers typed and named HttpClients. Each is wrapped by AddEgressPolicyGuard("stellaops-cli", <intent>), which checks the request against StellaOps.AirGap.Policy: in sealed mode a blocked destination fails with the shared AIRGAP_EGRESS_BLOCKED guidance instead of contacting the host. Command sources must not construct raw HttpClient instances (CliHttpClientsTests.Command_sources_do_not_construct_raw_http_clients).

Base-address resolution:


6) Command surface

The former admin policy and admin system groups and general admin users management verbs were withdrawn under PCD-292 because their routes were unserved. Local Authority recovery remains under admin users password-set and admin break-glass; admin diagnostics health reads Platform readiness. See the administrative reference.

PCD-293 withdrew sample configuration inventories (config feeds, config registry), tenant and audit administration (admin tenants, admin audit), and diagnostics connectivity/logs. config sources list reads the Vulnerabilities owner. The sample scan image and evidence audit groups were also withdrawn by the timestamp census; image inspect is the functional OCI inspector. There are no aliases for the retired paths.

6.1 Top-level groups

CommandFactory.Create registers the following top-level groups (names from each builder’s new Command(...)). Use --help on the root and on each group for verbs and flags; the detailed guides are under guides/.

scan graph is attached to scan after the root is built (ScanGraphCommandGroup).

6.2 Auth and profile

6.3 Scanning and SBOM

Scanner management uses scanner download (--channel, --output, --overwrite, --no-install), scanner workers get|set and scanner secrets bundle import|verify|list|info. Worker set takes --count and optional --pool; both worker commands support --format. Bundle import, verify and info use --bundle <directory>; import/list use --store for the local bundle store. These paths perform their owner/local artifact operations. The simulated scan download, scan workers set and scan secrets group are withdrawn and rejected by the parser.

scan workers get remains a read-only view of the local worker configuration. Both worker-get paths require an existing configuration to contain an object with a positive integer count and string pool; malformed or unreadable inputs and directory paths fail without invented configuration output. A missing file is explicitly unconfigured and uses the default count/pool. Local configuration reads/writes do not establish the state of deployed workers. scan run uses the same reader when --workers is absent and rejects invalid fallback input before resolving the scanner executor or backend. An explicit positive --workers value bypasses that local file lookup. Scanning-management source verified against commit 9930a0528e2e7e8e5e36d5cfbf1e895c814bd73c (PCD-390). Re-verify with pwsh ./tools/scripts/test-targeted-xunit.ps1 -Project src/Cli/__Tests/StellaOps.Cli.Tests/StellaOps.Cli.Tests.csproj -Class '*ScanningManagementCommandTests' -BuildProjectReferences -MaxThreads 1.

scan sarif --scan-id <id> [--output <file>] [--pretty] reads Scanner’s SARIF export with scanner:read. The CLI preserves the owner’s document and metadata. The export has no hardening, reachability-inclusion or minimum-severity switches (PCD-297).

AI code guard. guard run <path> is a bounded source collector and typed client for the Integrations-owned POST /api/v1/integrations/ai-code-guard/run contract. It requests integration:operate and propagates the effective tenant. JSON is the canonical response; text, SARIF and GitLab are projections. Pass exits 0; warnings, failures, pending or error responses, invalid input and unavailable service paths are non-zero. Collection prunes generated and dependency directories, skips reparse points, keeps paths under the requested root, and fails closed on traversal, file, policy or aggregate-payload bounds. guard status reports contract ownership and does not claim a live health check. --sealed fails closed because no verified offline analyzer bundle is registered.

6.4 Policy, advisories and data

6.5 Verification

stella attest verify \
  --envelope ./scan-attestation.dsse.json \
  --root ./sm2-public.pem \
  --algorithm SM2 \
  --format json

Regional builds compose extra providers at startup: StellaOpsEnableGOST=true adds BouncyCastle, OpenSSL, PKCS#11 and CryptoPro GOST providers (configuration sections StellaOps:Crypto:OpenSsl, StellaOps:Crypto:Pkcs11, StellaOps:Crypto:CryptoPro); StellaOpsEnableSM=true adds the SM software provider and the cn.sm.remote.http remote provider bound from StellaOps:Crypto:SmRemote (the SmRemote plug-in also binds StellaOps:Crypto:Profiles:sm-remote).

Local-transparency owner verification. When StellaOps:Transparency:Local:Enabled=true, decision verify --rekor calls the Evidence owner at STELLAOPS_EVIDENCE_URL + /api/evidence/v1/rekor/entries/{uuid}?refresh=true with API_KEY or an Authority token for attest:read. The CLI verifies the payload-to-leaf binding and Merkle path locally and reports checkpoint-signature validity separately. A missing URL, missing credential, unavailable owner, malformed response or invalid proof fails closed; the CLI never opens a database and has no fallback route. See the EVD-9 data-move procedure.

Attestor transparency controls. attestor transparency targets list|show|upsert|enable|disable, attestor transparency sync run|report and controlled-media exchange call api/evidence/v1/transparency/* on the backend URL. Authority token requests use attest:read for the six GET operations and attest:create for the eight POST operations, independently of the configured base scope. Owner unavailability, refused requests and empty required responses remain failures; target/report/batch lookups preserve the owner’s resource-not-found result. Target creation accepts only secret references in --auth-ref. Live sync is refused in sealed mode and requires --confirm-egress-window. airgap exchange transparency ... (also under attestor transparency exchange) is the controlled-media exchange path; the CLI writes the package bytes and a stellaops-transparency-package.json descriptor and generates no keys. These external controls use the Evidence host’s served paths directly. attestor transparency receipts list|show uses GET /api/evidence/v1/attestations and GET /api/evidence/v1/attestations/{uuid} on the backend URL, with the explicit attest:read scope independently of the configured base scope. Both commands preserve local receipts, additive external mirror receipts and proof diagnostics in JSON. An empty list is successful; a missing detail returns exit 4. Refused or unavailable owner calls return exit 1. --refresh requests a best-effort proof refresh for an existing receipt and does not guarantee fresh proof or create an unknown receipt. See the receipt reference for filters and paging. PCD-465 verifies the caller contract against owner source and capture; the hermetic tests do not establish deployed routing, proof validity or owner tenant isolation.

Receipt caller verification: commit 6aff2f8ece7ccdfaeee4a237c9f17a24713df050 (2026-10-07). Re-verify with pwsh ./tools/scripts/test-targeted-xunit.ps1 -Project src/Cli/__Tests/StellaOps.Cli.Tests/StellaOps.Cli.Tests.csproj -Class '*Receipt*ContractTests' -BuildProjectReferences.

6.6 Truthfulness requirements for evidence commands

Local replay proof. prove --image <digest> --bundle <directory> requires a supplied local manifest and compares actual VerdictBuilder evidence-hash replay with its expected CGS hash. The complete SHA-256 or SHA-512 image digest must match the manifest’s normalized image identity; a different image fails before emitting a proof. The command reads one structurally checked manifest, confines declared paths to the selected bundle root, rejects child filesystem links, leaves bundle files unchanged and makes no provider request. Its unsigned proof does not evaluate policy or establish signature validity. See the local prove reference. PCD-430 withdrew timestamp/latest selection; PCD-431 withdrew --snapshot/-s and the bundle-store adapter after owner review found no compatible verdict snapshot/store contract. Timeline events, Replay advisory/feed snapshots and the AuditPack producer remain independent. Both unsupported adapters, the original shared command/contracts and its shape tests are preserved as whole files under src/__Obsoleted/Cli/; the registered command now lives in ProveLocalCommandGroup.cs.

Evidence-oriented commands fail closed when the verifier, trust store, transparency log or service interface needed to prove a claim is unavailable. They must not print success, create placeholder bundles, or emit unsigned or synthetic DSSE envelopes. Current behaviour:

6.7 Offline kit, mirror and air gap

6.8 vuln-db — compact offline vulnerability database

vuln-db export (Commands/VulnDb/VulnDbCommandGroup.cs) reads a retained, digest-addressed publication from the Vulnerabilities owner and writes the compact, offline-matchable database that sbom check consumes. It is the only verb; the group description reserves update and status.

Compact schema v8 preserves repository_url on affected rows. Component expansion retains the same decoded qualifier in both scoped and unscoped SBOM paths; matching compares it exactly, so a repository-qualified advisory cannot match a package with a different or unknown repository. Earlier compact exports lack that identity and are refused with a request to export a fresh v8 database. Repository identity participates in the projected content digest and is retained in JSON/SARIF findings and reconstructed PURLs used by VEX/reachability lookup.

The inclusive lastAffected bound travels from consensus-inputs v4 through compact affected-range expressions (<=) and mirror-seed applicability. It never enters the declared fixed-version list. Matcher-rows v5 and consensus-inputs v4 advance independently; unchanged exploit/reachability section formats retain their own window.

PCD-445 carries introducedExclusive into decision hashing, VEX explanation statements/ranges and mirror seeds. Compact schema 8 carries nullable comparison_scheme separately from the purl ecosystem. generic-range uses the shared neutral comparator; generic-exact is a complete literal, not an ordered singleton interval. Empty declared generic intervals are preserved. Mixed comparison schemes and conflicting endpoint/expression declarations refuse export. A database missing the current comparison column or current schema stamp requires a fresh export. Unsupported source comparison remains unknown without invented remediation, including beside a known-outside row. Declared generic operands bypass RPM NEVRA rewriting. Ordered endpoint atoms are validated before formatting, so embedded whitespace or operators cannot turn one source endpoint into two constraints. Retained OSV generic-exact also labels ECOSYSTEM ranges; those claims keep their existing ecosystem path and omit a newly inferred literal override pending the source producer’s separate correction.

PCD-445 source verified against 56357b8682799c029045a161491eabab422373e8 (2026-10-08 UTC). Re-verify: pwsh tools/scripts/test-targeted-xunit.ps1 -Project src/Cli/__Tests/StellaOps.Cli.Tests/StellaOps.Cli.Tests.csproj -All -BuildProjectReferences.

PCD-334 source verified against 6d3401cdc5 (2026-10-06). Re-verify: pwsh ./tools/scripts/test-targeted-xunit.ps1 -Project src/Cli/__Tests/StellaOps.Cli.Tests/StellaOps.Cli.Tests.csproj -Method "*LastAffected*" -BuildProjectReferences -MaxThreads 1.

PCD-332 source verified against 1e52c13050 (2026-10-06). Re-verify: pwsh ./tools/scripts/test-targeted-xunit.ps1 -Project src/Cli/__Tests/StellaOps.Cli.Tests/StellaOps.Cli.Tests.csproj -Method "*RepositoryIdentity*" -BuildProjectReferences -MaxThreads 1.

OptionDefaultMeaning
--output / -odevops/offline/vuln-db, or STELLA_VULN_DB_EXPORT_DIROutput root; a <db-version> subdirectory is created.
--db-versionUTC timestampVersion label and subdirectory name.
--sourcesall ecosystemsComma-separated ecosystem allow-list.
--max-memory-mbautoMemory envelope for the build.
--formatsqlitesqlite, bundle (adds a deterministic tar.zst) or corpus (raw matcher section).
--include-sharealike-companionoffAlso emit the segregated CC-BY-SA companion database.
--with-descriptionsrefusedFails loudly; see docs/legal/decisions/compact-vulndb-license-segregation-counsel-thread-reply.md.
--signoffvendor signs the intelligence manifest with the vendor intelligence key (purpose vendor-intelligence); tenant signs it with the tenant’s EvidenceBundle purpose key and writes the tenant public JWK beside it.
--vendor-key-idrequired with --sign vendorThe vendor key’s root-set identifier (sha256: of its SubjectPublicKeyInfo).
--vendor-key-fileprovider-held keyA runtime-mounted vendor key file; needs --vendor-key-provider.
--vendor-key-providerprofile orderThe crypto provider that holds or loads the vendor key.
--vendor-rootsSTELLAOPS_VENDOR_TRUST_ROOTSThe vendor trust-root set the vendor-signed envelope must verify against before the export is kept.
--from-hubrequiredBase URL of the Vulnerabilities owner.
--tokenSTELLA_VULN_DB_HUB_TOKENBearer token; needs advisory:read aoc:verify.
--generationcurrent publicationRequire this sourceGeneration.

The CLI downloads the publication sections by pinned byte ranges and checks each section’s size, SHA-256, format version and same-origin URL before projection. The export writes <output>/<db-version>/ (vuln-db.sqlite, manifest, optional companion, optional bundle), repoints <output>/latest, and fails if latest does not resolve to vuln-db.sqlite. Every export also writes intelligence-manifest.json, which lists each file with its size and SHA-256 and the hub snapshot (source generation, publication time and manifest digest) the export was built from (contract). With --sign, the DSSE envelope intelligence-manifest.dsse.json covers it (payload type application/vnd.stellaops.vuln-intelligence-manifest.v1+json). A vendor signature is verified against the vendor trust-root set before the export is kept; a tenant signature is attributable to the tenant only. The console summary prints the snapshot generation and publication time, and the signer mode and key id. With --format bundle the archive is written after signing and carries the databases, their manifests, the intelligence manifest and its envelope.

Exit codes: 0 success; 1 command or local export failure; 2 hub unreachable or non-success HTTP; 3 corpus contract refused; 4 empty corpus.

6.9 Crypto profiles, installation settings and tenant overrides

crypto profiles list|show|select manage the regional profile (international, fips, eidas, gost, sm). select persists the choice: with a backend URL it calls PUT /api/v1/admin/crypto-providers/preferences; without one it writes ~/.stellaops/appsettings.crypto.yaml (StellaOps:Crypto:Registry:ActiveProfile). In both modes it appends an entry to ~/.stellaops/audit/crypto-profile-select.jsonl.

Exit codeCondition
0Persistence succeeded.
10Local YAML file read-only or permission denied.
11Platform endpoint unreachable or timed out.
12Platform returned 401/403. The hint text names stella auth login.
13Unknown profile name.
14Other persistence error.

Installation-scoped settings mirror the setup wizard and require a Platform backend (GET /platform/envsettings/db/, PUT /platform/envsettings/db/{key} with UpdatedBy=stella-cli):

CommandKey written or read
`stella crypto provider set <internationaleidas
stella crypto provider showCrypto:Region
stella crypto algorithm set --provider <provider> --signing <algorithm>Crypto:<provider>:Algorithm
stella crypto fips enableCrypto:FipsMode=true after confirming Crypto:Region=international
stella crypto fips disableCrypto:FipsMode=false
stella crypto statusCrypto:* plus NIS2/DORA/CRA enabled flags
`stella compliance nis2 enabledisable`
`stella compliance dora enabledisable`
`stella compliance cra enabledisable`
stella compliance statusNIS2/DORA/CRA enabled flags

Tenant-scoped variants call /api/v1/admin/crypto-providers/compliance-profile and /api/v1/admin/crypto-providers/compliance-overrides with the tenant header:

CommandPlatform state
`stella crypto profile set --tenant<worldfips
stella crypto profile show --tenant <id>active tenant profile row
`stella compliance nis2 enabledisable --tenant`
`stella compliance dora enabledisable --tenant`
`stella compliance cra enabledisable --tenant`
stella compliance status --tenant <id>merged effective tenant pack state and source

Authorization failures return 12; other Platform failures return 14.

6.10 Evidence bundle export and OCI referrers

6.11 Release orchestration

release exposes the operator decision verbs approve, reject, promote, deploy, rollback and show; deployment exposes list, show, logs, events, watch; agent exposes list, show, token create and token list. Release creation/listing and environment lifecycle are deliberately Console/API-only for RC1: use /api/v1/release-orchestrator/releases, /api/v1/release-orchestrator/environments, or the authenticated Console setup/release pages. There is no stella release create|list or stella env group in RC1.

6.12 Utilities


7) Restart-time plug-ins

CliCommandModuleLoader reads *.manifest.json files under <base>/plugins/cli/ and loads assemblies matching StellaOps.Cli.Plugin.*.dll / StellaOps.Cli.Plugins.*.dll. Plug-ins load at startup only; hot reload is not supported (RestartOnlyCliPluginGuard). Before each module registers, the loader snapshots the existing root tokens and removes any new root command whose name or alias already exists, so a plug-in cannot shadow a core command.

Shipped plug-ins (one manifest each under src/Cli/plugins/cli/): NonCore, Policy, Symbols, Timestamp and Verdict. Their policy, symbols, ts and verify roots duplicate core roots and are skipped. The Aoc and Vex plug-ins, whose aoc and vex roots were always skipped the same way, were withdrawn to src/__Obsoleted/Cli/; the core aoc group was withdrawn on 2026-10-01 as well. The effective additions come from NonCore: excititor (init, pull, resume, list-providers, show-provider, enable-provider, disable-provider, run-provider, update-provider, export, backfill-statements, verify, reconcile), runtime (runtime policy test), and offline kit status added to the core offline command.

src/Cli/__Libraries/StellaOps.Cli.Plugins.DeltaSig/ has no manifest and is not built by the Dockerfiles or build-cli.sh; it is not a shipped plug-in. The GroundTruth plug-in was withdrawn (frozen under src/__Obsoleted/Cli/).


8) Exit codes

Exit codes are family-specific; read the handler before asserting an exact code.


9) Output

OutputFormat defines table (default), json, yaml and sarif; each command declares which of them it accepts. JSON output is intended for automation and golden tests. JSON documents go directly to standard output (Console.WriteLine or Console.Out), including JSON errors. They bypass the Spectre renderer, so redirecting output or using a narrow terminal does not insert line breaks into string values. Human-readable tables and status messages use the renderer.


10) Packaging and distribution

See release and packaging and the distribution matrix.


11) Tests and CI gates

The CLI test project runs collections serially by default (PCD-299). Command tests share process-global console writers, Spectre Console and environment state. A class-local lock does not isolate those resources from other test classes. Three unfiltered default runs measure the serial execution cost in the sprint receipt.


12) Retired surfaces

The following are removed from the command tree; do not document them as current:


Evidence

ClaimSource
Root command tree, global options, scan graph attachment, plug-in loading callsrc/Cli/StellaOps.Cli/Commands/CommandFactory.cs (Create)
Process model, DI composition, HTTP clients, exit-code precedencesrc/Cli/StellaOps.Cli/Program.cs
Parser-error exit codesrc/Cli/StellaOps.Cli/Commands/CliInvocation.cs
Configuration sources and precedencesrc/__Libraries/StellaOps.Configuration/StellaOpsConfigurationBootstrapper.cs, StellaOpsConfigurationOptions.cs
Configuration keys and defaultssrc/Cli/StellaOps.Cli/Configuration/CliBootstrapper.cs, StellaOpsCliOptions.cs
Profiles and profile secretssrc/Cli/StellaOps.Cli/Configuration/CliProfile.cs, Configuration/Secrets/SecretProtectorFactory.cs
Grant rule, cache key, DI authenticationsrc/Cli/StellaOps.Cli/Configuration/AuthorityTokenUtilities.cs
Tenant rule (token and header)src/Cli/StellaOps.Cli/Services/TenantProfileStore.cs
Token grants, configured token endpointsrc/Authority/StellaOps.Authority/StellaOps.Auth.Client/StellaOpsTokenClient.cs
Token file cache (JSON, owner-only permissions)src/Authority/StellaOps.Authority/StellaOps.Auth.Client/FileTokenCache.cs, ServiceCollectionExtensions.cs
auth login caching and --no-savesrc/Cli/StellaOps.Cli/Commands/CommandHandlers.cs (HandleAuthLoginAsync)
Scope cataloguesrc/Authority/StellaOps.Authority/StellaOps.Auth.Abstractions/StellaOpsScopes.cs
Client scopessrc/Cli/StellaOps.Cli/Services/SbomClient.cs, HubMirrorSeedClient.cs, CliLocalTransparencyRekorClient.cs
Registered score commands, Scanner DTOs and transportsrc/Cli/StellaOps.Cli/Commands/ScoreReplayCommandGroup.cs, Program.cs, src/Scanner/StellaOps.Scanner.WebService/Endpoints/ScoreReplayEndpoints.cs; score replay guide
Conformance tests (tenant, grant, scope, raw HttpClient)src/Cli/__Tests/StellaOps.Cli.Tests/Services/CliClientTenantResolutionConformanceTests.cs, CliTenantHeaderConformanceTests.cs, CliClientGrantParityTests.cs, CliRequestedScopeCatalogueConformanceTests.cs, CliHttpClientsTests.cs
Egress guardsrc/Cli/StellaOps.Cli/Configuration/EgressPolicyHttpMessageHandler.cs, HttpClientBuilderExtensions.cs
Policy-gateway URL resolutionsrc/Cli/StellaOps.Cli/Configuration/PolicyGatewayEndpoint.cs
Local-transparency owner endpointsrc/Cli/StellaOps.Cli/Services/CliLocalTransparencyRekorClient.cs
Evidence host prefix for the Attestor surfacesrc/Evidence/StellaOps.Evidence.WebService/Program.cs (ConsolidatedRoutePrefix)
Attestor transparency client routessrc/Cli/StellaOps.Cli/Services/BackendOperationsClient.cs
scan, sbom, db, auth, config, airgap, mirror subcommandssrc/Cli/StellaOps.Cli/Commands/CommandFactory.cs, Commands/MirrorSeedCommandGroup.cs
Unregistered compare buildersrc/Cli/StellaOps.Cli/Commands/Compare/CompareCommandBuilder.cs
vuln-db options and exit codessrc/Cli/StellaOps.Cli/Commands/VulnDb/VulnDbCommandGroup.cs, HubCorpusExporter.cs
Crypto profile persistence and settingssrc/Cli/StellaOps.Cli/Commands/CryptoCommandGroup.cs, ComplianceCommandGroup.cs, Services/CryptoProfilePreferenceStore.cs, Services/PlatformEnvironmentSettingsClient.cs, Services/TenantCryptoComplianceClient.cs
Regional providerssrc/Cli/StellaOps.Cli/CliRegionalCryptoComposition.cs, src/__Libraries/StellaOps.Cryptography.Plugin.SmRemote/DependencyInjection/ServiceCollectionExtensions.cs
OCI referrer commandssrc/Cli/StellaOps.Cli/Commands/EvidenceReferrerCommands.cs
Release, deployment and agent verbssrc/Cli/StellaOps.Cli/Commands/ReleaseOperatorDecisionCommandGroup.cs, DeploymentCommandGroup.cs, AgentCommandGroup.cs
Identity-provider group and aliassrc/Cli/StellaOps.Cli/Commands/IdentityProviderCommandGroup.cs
Exit-code constantssrc/Cli/StellaOps.Cli/Commands/CliExitCodes.cs
Output formatssrc/Cli/StellaOps.Cli/Output/OutputFormat.cs
Plug-in loader and duplicate-root removalsrc/Cli/StellaOps.Cli/Plugins/CliCommandModuleLoader.cs
Shipped plug-in manifestssrc/Cli/plugins/cli/*/*.manifest.json
NonCore plug-in commandssrc/Cli/__Libraries/StellaOps.Cli.Plugins.NonCore/NonCoreCliCommandModule.cs
Published CLI imagedevops/stella-cli/Dockerfile, .gitea/workflows/stella-cli-publish.yml
Operator image with plug-ins, compose runnerdevops/docker/Dockerfile.cli, devops/compose/docker-compose.cli.yml, devops/compose/scripts/stella-cli.sh
Binary builds.gitea/scripts/build/build-cli.sh
Documentation example gatesrc/Cli/__Tests/StellaOps.Cli.Tests/Commands/CliDocumentationContractTests.cs, docs/modules/cli/unshipped-command-examples.json
Plug-in integration and doctor-crypto parity lanes.gitea/workflows/cli-plugin-integration.yml, .gitea/workflows/docs-cli-parity.yml
Retired CLI sourcesrc/__Obsoleted/Cli/