up
	
		
			
	
		
	
	
		
	
		
			Some checks failed
		
		
	
	
		
			
				
	
				Build Test Deploy / build-test (push) Has been cancelled
				
			
		
			
				
	
				Build Test Deploy / authority-container (push) Has been cancelled
				
			
		
			
				
	
				Build Test Deploy / docs (push) Has been cancelled
				
			
		
			
				
	
				Build Test Deploy / deploy (push) Has been cancelled
				
			
		
			
				
	
				Docs CI / lint-and-preview (push) Has been cancelled
				
			
		
		
	
	
				
					
				
			
		
			Some checks failed
		
		
	
	Build Test Deploy / build-test (push) Has been cancelled
				
			Build Test Deploy / authority-container (push) Has been cancelled
				
			Build Test Deploy / docs (push) Has been cancelled
				
			Build Test Deploy / deploy (push) Has been cancelled
				
			Docs CI / lint-and-preview (push) Has been cancelled
				
			This commit is contained in:
		| @@ -1,198 +1,198 @@ | ||||
| # API & CLI Reference | ||||
|  | ||||
| *Purpose* – give operators and integrators a single, authoritative spec for REST/GRPC calls **and** first‑party CLI tools (`stella-cli`, `zastava`, `stella`).   | ||||
| Everything here is *source‑of‑truth* for generated Swagger/OpenAPI and the `--help` screens in the CLIs. | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 0 Quick Glance | ||||
|  | ||||
| | Area               | Call / Flag                                 | Notes                                                                          | | ||||
| | ------------------ | ------------------------------------------- | ------------------------------------------------------------------------------ | | ||||
| | Scan entry         | `POST /scan`                                | Accepts SBOM or image; sub‑5 s target                                          | | ||||
| | Delta check        | `POST /layers/missing`                      | <20 ms reply; powers *delta SBOM* feature                                      | | ||||
| | Rate‑limit / quota | —                                           | Headers **`X‑Stella‑Quota‑Remaining`**, **`X‑Stella‑Reset`** on every response | | ||||
| | Policy I/O         | `GET /policy/export`, `POST /policy/import` | YAML now; Rego coming                                                          | | ||||
| | Policy lint        | `POST /policy/validate`                     | Returns 200 OK if ruleset passes                                               | | ||||
| | Auth               | `POST /connect/token` (OpenIddict)          | Client‑credentials preferred                                                   | | ||||
| | Health             | `GET /healthz`                              | Simple liveness probe                                                          | | ||||
| | Attestation *      | `POST /attest` (TODO Q1‑2026)               | SLSA provenance + Rekor log                                                    | | ||||
| | CLI flags          | `--sbom-type` `--delta` `--policy-file`     | Added to `stella`                                                             | | ||||
|  | ||||
| \* Marked **TODO** → delivered after sixth month (kept on Feature Matrix “To Do” list). | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 1 Authentication | ||||
|  | ||||
| Stella Ops uses **OAuth 2.0 / OIDC** (token endpoint mounted via OpenIddict). | ||||
|  | ||||
| ``` | ||||
| POST /connect/token | ||||
| Content‑Type: application/x-www-form-urlencoded | ||||
|  | ||||
| grant_type=client_credentials& | ||||
| client_id=ci‑bot& | ||||
| client_secret=REDACTED& | ||||
| scope=stella.api | ||||
| ``` | ||||
|  | ||||
| Successful response: | ||||
|  | ||||
| ```json | ||||
| { | ||||
|   "access_token": "eyJraWQi...", | ||||
|   "token_type": "Bearer", | ||||
|   "expires_in": 3600 | ||||
| } | ||||
| ``` | ||||
|  | ||||
| > **Tip** – pass the token via `Authorization: Bearer <token>` on every call. | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 2 REST API | ||||
|  | ||||
| ### 2.0 Obtain / Refresh Offline‑Token | ||||
|  | ||||
| ```text | ||||
| POST /token/offline | ||||
| Authorization: Bearer <admin‑token> | ||||
| ``` | ||||
|  | ||||
| | Body field | Required | Example | Notes | | ||||
| |------------|----------|---------|-------| | ||||
| | `expiresDays` | no | `30` | Max 90 days | | ||||
|  | ||||
| ```json | ||||
| { | ||||
|   "jwt": "eyJhbGciOiJSUzI1NiIsInR5cCI6...", | ||||
|   "expires": "2025‑08‑17T00:00:00Z" | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Token is signed with the backend’s private key and already contains | ||||
| `"maxScansPerDay": {{ quota_token }}`. | ||||
|  | ||||
|  | ||||
| ### 2.1 Scan – Upload SBOM **or** Image | ||||
|  | ||||
| ``` | ||||
| POST /scan | ||||
| ``` | ||||
|  | ||||
| | Param / Header       | In     | Required | Description                                                           | | ||||
| | -------------------- | ------ | -------- | --------------------------------------------------------------------- | | ||||
| | `X‑Stella‑Sbom‑Type` | header | no       | `trivy-json-v2`, `spdx-json`, `cyclonedx-json`; omitted ➞ auto‑detect | | ||||
| | `?threshold`         | query  | no       | `low`, `medium`, `high`, `critical`; default **critical**             | | ||||
| | body                 | body   | yes      | *Either* SBOM JSON *or* Docker image tarball/upload URL               | | ||||
|  | ||||
| Every successful `/scan` response now includes: | ||||
|  | ||||
| | Header | Example | | ||||
| |--------|---------| | ||||
| | `X‑Stella‑Quota‑Remaining` | `129` | | ||||
| | `X‑Stella‑Reset` | `2025‑07‑18T23:59:59Z` | | ||||
| | `X‑Stella‑Token‑Expires` | `2025‑08‑17T00:00:00Z` | | ||||
|  | ||||
| **Response 200** (scan completed): | ||||
|  | ||||
| ```json | ||||
| { | ||||
|   "digest": "sha256:…", | ||||
|   "summary": { | ||||
|     "Critical": 0, | ||||
|     "High": 3, | ||||
|     "Medium": 12, | ||||
|     "Low": 41 | ||||
|   }, | ||||
|   "policyStatus": "pass", | ||||
|   "quota": { | ||||
|     "remaining": 131, | ||||
|     "reset": "2025-07-18T00:00:00Z" | ||||
|   } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| **Response 202** – queued; polling URL in `Location` header. | ||||
|  | ||||
| --- | ||||
|  | ||||
| ### 2.2 Delta SBOM – Layer Cache Check | ||||
|  | ||||
| ``` | ||||
| POST /layers/missing | ||||
| Content‑Type: application/json | ||||
| Authorization: Bearer <token> | ||||
| ``` | ||||
|  | ||||
| ```json | ||||
| { | ||||
|   "layers": [ | ||||
|     "sha256:d38b...", | ||||
|     "sha256:af45..." | ||||
|   ] | ||||
| } | ||||
| ``` | ||||
|  | ||||
| **Response 200** — <20 ms target: | ||||
|  | ||||
| ```json | ||||
| { | ||||
|   "missing": [ | ||||
|     "sha256:af45..." | ||||
|   ] | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Client then generates SBOM **only** for the `missing` layers and re‑posts `/scan`. | ||||
|  | ||||
| --- | ||||
|  | ||||
| ### 2.3 Policy Endpoints | ||||
|  | ||||
| | Method | Path               | Purpose                              | | ||||
| | ------ | ------------------ | ------------------------------------ | | ||||
| | `GET`  | `/policy/export`   | Download live YAML ruleset           | | ||||
| | `POST` | `/policy/import`   | Upload YAML or Rego; replaces active | | ||||
| | `POST` | `/policy/validate` | Lint only; returns 400 on error      | | ||||
| | `GET`  | `/policy/history`  | Paginated change log (audit trail)   | | ||||
|  | ||||
| ```yaml | ||||
| # Example import payload (YAML) | ||||
| version: "1.0" | ||||
| rules: | ||||
|   - name: Ignore Low dev | ||||
|     severity: [Low, None] | ||||
|     environments: [dev, staging] | ||||
|     action: ignore | ||||
| ``` | ||||
|  | ||||
| Validation errors come back as: | ||||
|  | ||||
| ```json | ||||
| { | ||||
|   "errors": [ | ||||
|     { | ||||
|       "path": "$.rules[0].severity", | ||||
|       "msg": "Invalid level 'None'" | ||||
|     } | ||||
|   ] | ||||
| } | ||||
| ``` | ||||
|  | ||||
| --- | ||||
|  | ||||
| # API & CLI Reference | ||||
|  | ||||
| *Purpose* – give operators and integrators a single, authoritative spec for REST/GRPC calls **and** first‑party CLI tools (`stella-cli`, `zastava`, `stella`).   | ||||
| Everything here is *source‑of‑truth* for generated Swagger/OpenAPI and the `--help` screens in the CLIs. | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 0 Quick Glance | ||||
|  | ||||
| | Area               | Call / Flag                                 | Notes                                                                          | | ||||
| | ------------------ | ------------------------------------------- | ------------------------------------------------------------------------------ | | ||||
| | Scan entry         | `POST /scan`                                | Accepts SBOM or image; sub‑5 s target                                          | | ||||
| | Delta check        | `POST /layers/missing`                      | <20 ms reply; powers *delta SBOM* feature                                      | | ||||
| | Rate‑limit / quota | —                                           | Headers **`X‑Stella‑Quota‑Remaining`**, **`X‑Stella‑Reset`** on every response | | ||||
| | Policy I/O         | `GET /policy/export`, `POST /policy/import` | YAML now; Rego coming                                                          | | ||||
| | Policy lint        | `POST /policy/validate`                     | Returns 200 OK if ruleset passes                                               | | ||||
| | Auth               | `POST /connect/token` (OpenIddict)          | Client‑credentials preferred                                                   | | ||||
| | Health             | `GET /healthz`                              | Simple liveness probe                                                          | | ||||
| | Attestation *      | `POST /attest` (TODO Q1‑2026)               | SLSA provenance + Rekor log                                                    | | ||||
| | CLI flags          | `--sbom-type` `--delta` `--policy-file`     | Added to `stella`                                                             | | ||||
|  | ||||
| \* Marked **TODO** → delivered after sixth month (kept on Feature Matrix “To Do” list). | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 1 Authentication | ||||
|  | ||||
| Stella Ops uses **OAuth 2.0 / OIDC** (token endpoint mounted via OpenIddict). | ||||
|  | ||||
| ``` | ||||
| POST /connect/token | ||||
| Content‑Type: application/x-www-form-urlencoded | ||||
|  | ||||
| grant_type=client_credentials& | ||||
| client_id=ci‑bot& | ||||
| client_secret=REDACTED& | ||||
| scope=stella.api | ||||
| ``` | ||||
|  | ||||
| Successful response: | ||||
|  | ||||
| ```json | ||||
| { | ||||
|   "access_token": "eyJraWQi...", | ||||
|   "token_type": "Bearer", | ||||
|   "expires_in": 3600 | ||||
| } | ||||
| ``` | ||||
|  | ||||
| > **Tip** – pass the token via `Authorization: Bearer <token>` on every call. | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 2 REST API | ||||
|  | ||||
| ### 2.0 Obtain / Refresh Offline‑Token | ||||
|  | ||||
| ```text | ||||
| POST /token/offline | ||||
| Authorization: Bearer <admin‑token> | ||||
| ``` | ||||
|  | ||||
| | Body field | Required | Example | Notes | | ||||
| |------------|----------|---------|-------| | ||||
| | `expiresDays` | no | `30` | Max 90 days | | ||||
|  | ||||
| ```json | ||||
| { | ||||
|   "jwt": "eyJhbGciOiJSUzI1NiIsInR5cCI6...", | ||||
|   "expires": "2025‑08‑17T00:00:00Z" | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Token is signed with the backend’s private key and already contains | ||||
| `"maxScansPerDay": {{ quota_token }}`. | ||||
|  | ||||
|  | ||||
| ### 2.1 Scan – Upload SBOM **or** Image | ||||
|  | ||||
| ``` | ||||
| POST /scan | ||||
| ``` | ||||
|  | ||||
| | Param / Header       | In     | Required | Description                                                           | | ||||
| | -------------------- | ------ | -------- | --------------------------------------------------------------------- | | ||||
| | `X‑Stella‑Sbom‑Type` | header | no       | `trivy-json-v2`, `spdx-json`, `cyclonedx-json`; omitted ➞ auto‑detect | | ||||
| | `?threshold`         | query  | no       | `low`, `medium`, `high`, `critical`; default **critical**             | | ||||
| | body                 | body   | yes      | *Either* SBOM JSON *or* Docker image tarball/upload URL               | | ||||
|  | ||||
| Every successful `/scan` response now includes: | ||||
|  | ||||
| | Header | Example | | ||||
| |--------|---------| | ||||
| | `X‑Stella‑Quota‑Remaining` | `129` | | ||||
| | `X‑Stella‑Reset` | `2025‑07‑18T23:59:59Z` | | ||||
| | `X‑Stella‑Token‑Expires` | `2025‑08‑17T00:00:00Z` | | ||||
|  | ||||
| **Response 200** (scan completed): | ||||
|  | ||||
| ```json | ||||
| { | ||||
|   "digest": "sha256:…", | ||||
|   "summary": { | ||||
|     "Critical": 0, | ||||
|     "High": 3, | ||||
|     "Medium": 12, | ||||
|     "Low": 41 | ||||
|   }, | ||||
|   "policyStatus": "pass", | ||||
|   "quota": { | ||||
|     "remaining": 131, | ||||
|     "reset": "2025-07-18T00:00:00Z" | ||||
|   } | ||||
| } | ||||
| ``` | ||||
|  | ||||
| **Response 202** – queued; polling URL in `Location` header. | ||||
|  | ||||
| --- | ||||
|  | ||||
| ### 2.2 Delta SBOM – Layer Cache Check | ||||
|  | ||||
| ``` | ||||
| POST /layers/missing | ||||
| Content‑Type: application/json | ||||
| Authorization: Bearer <token> | ||||
| ``` | ||||
|  | ||||
| ```json | ||||
| { | ||||
|   "layers": [ | ||||
|     "sha256:d38b...", | ||||
|     "sha256:af45..." | ||||
|   ] | ||||
| } | ||||
| ``` | ||||
|  | ||||
| **Response 200** — <20 ms target: | ||||
|  | ||||
| ```json | ||||
| { | ||||
|   "missing": [ | ||||
|     "sha256:af45..." | ||||
|   ] | ||||
| } | ||||
| ``` | ||||
|  | ||||
| Client then generates SBOM **only** for the `missing` layers and re‑posts `/scan`. | ||||
|  | ||||
| --- | ||||
|  | ||||
| ### 2.3 Policy Endpoints | ||||
|  | ||||
| | Method | Path               | Purpose                              | | ||||
| | ------ | ------------------ | ------------------------------------ | | ||||
| | `GET`  | `/policy/export`   | Download live YAML ruleset           | | ||||
| | `POST` | `/policy/import`   | Upload YAML or Rego; replaces active | | ||||
| | `POST` | `/policy/validate` | Lint only; returns 400 on error      | | ||||
| | `GET`  | `/policy/history`  | Paginated change log (audit trail)   | | ||||
|  | ||||
| ```yaml | ||||
| # Example import payload (YAML) | ||||
| version: "1.0" | ||||
| rules: | ||||
|   - name: Ignore Low dev | ||||
|     severity: [Low, None] | ||||
|     environments: [dev, staging] | ||||
|     action: ignore | ||||
| ``` | ||||
|  | ||||
| Validation errors come back as: | ||||
|  | ||||
| ```json | ||||
| { | ||||
|   "errors": [ | ||||
|     { | ||||
|       "path": "$.rules[0].severity", | ||||
|       "msg": "Invalid level 'None'" | ||||
|     } | ||||
|   ] | ||||
| } | ||||
| ``` | ||||
|  | ||||
| --- | ||||
|  | ||||
| ### 2.4 Attestation (Planned – Q1‑2026) | ||||
|  | ||||
| ``` | ||||
| POST /attest | ||||
| ``` | ||||
|  | ||||
| | Param       | Purpose                               | | ||||
| | ----------- | ------------------------------------- | | ||||
| | body (JSON) | SLSA v1.0 provenance doc              | | ||||
| |             | Signed + stored in local Rekor mirror | | ||||
|  | ||||
| | Param       | Purpose                               | | ||||
| | ----------- | ------------------------------------- | | ||||
| | body (JSON) | SLSA v1.0 provenance doc              | | ||||
| |             | Signed + stored in local Rekor mirror | | ||||
|  | ||||
| Returns `202 Accepted` and `Location: /attest/{id}` for async verify. | ||||
|  | ||||
| @@ -211,11 +211,14 @@ Configuration follows the same precedence chain everywhere: | ||||
| | Command | Purpose | Key Flags / Arguments | Notes | | ||||
| |---------|---------|-----------------------|-------| | ||||
| | `stellaops-cli scanner download` | Fetch and install scanner container | `--channel <stable\|beta\|nightly>` (default `stable`)<br>`--output <path>`<br>`--overwrite`<br>`--no-install` | Saves artefact under `ScannerCacheDirectory`, verifies digest/signature, and executes `docker load` unless `--no-install` is supplied. | | ||||
| | `stellaops-cli scan run` | Execute scanner container against a directory (auto-upload) | `--target <directory>` (required)<br>`--runner <docker\|dotnet\|self>` (default from config)<br>`--entry <image-or-entrypoint>`<br>`[scanner-args...]` | Runs the scanner, writes results into `ResultsDirectory`, and automatically uploads the artefact when the exit code is `0`. | | ||||
| | `stellaops-cli scan run` | Execute scanner container against a directory (auto-upload) | `--target <directory>` (required)<br>`--runner <docker\|dotnet\|self>` (default from config)<br>`--entry <image-or-entrypoint>`<br>`[scanner-args...]` | Runs the scanner, writes results into `ResultsDirectory`, emits a structured `scan-run-*.json` metadata file, and automatically uploads the artefact when the exit code is `0`. | | ||||
| | `stellaops-cli scan upload` | Re-upload existing scan artefact | `--file <path>` | Useful for retries when automatic upload fails or when operating offline. | | ||||
| | `stellaops-cli db fetch` | Trigger connector jobs | `--source <id>` (e.g. `redhat`, `osv`)<br>`--stage <fetch\|parse\|map>` (default `fetch`)<br>`--mode <resume|init|cursor>` | Translates to `POST /jobs/source:{source}:{stage}` with `trigger=cli` | | ||||
| | `stellaops-cli db merge` | Run canonical merge reconcile | — | Calls `POST /jobs/merge:reconcile`; exit code `0` on acceptance, `1` on failures/conflicts | | ||||
| | `stellaops-cli db export` | Kick JSON / Trivy exports | `--format <json\|trivy-db>` (default `json`)<br>`--delta` | Sets `{ delta = true }` parameter when requested | | ||||
| | `stellaops-cli db export` | Kick JSON / Trivy exports | `--format <json\|trivy-db>` (default `json`)<br>`--delta`<br>`--publish-full/--publish-delta`<br>`--bundle-full/--bundle-delta` | Sets `{ delta = true }` parameter when requested and can override ORAS/bundle toggles per run | | ||||
| | `stellaops-cli auth <login\|logout\|status>` | Manage cached tokens for StellaOps Authority | `auth login --force` (ignore cache)<br>`auth status` | Uses `StellaOps.Auth.Client` under the hood; honours `StellaOps:Authority:*` configuration | | ||||
|  | ||||
| When running on an interactive terminal without explicit override flags, the CLI uses Spectre.Console prompts to let you choose per-run ORAS/offline bundle behaviour. | ||||
| | `stellaops-cli config show` | Display resolved configuration | — | Masks secret values; helpful for air‑gapped installs | | ||||
|  | ||||
| **Logging & exit codes** | ||||
| @@ -229,12 +232,51 @@ Configuration follows the same precedence chain everywhere: | ||||
| - Downloads are verified against the `X-StellaOps-Digest` header (SHA-256). When `StellaOps:ScannerSignaturePublicKeyPath` points to a PEM-encoded RSA key, the optional `X-StellaOps-Signature` header is validated as well. | ||||
| - Metadata for each bundle is written alongside the artefact (`*.metadata.json`) with digest, signature, source URL, and timestamps. | ||||
| - Retry behaviour is controlled via `StellaOps:ScannerDownloadAttempts` (default **3** with exponential backoff). | ||||
| - Successful `scan run` executions create timestamped JSON artefacts inside `ResultsDirectory`; these are posted back to Feedser automatically. | ||||
| - Successful `scan run` executions create timestamped JSON artefacts inside `ResultsDirectory` plus a `scan-run-*.json` metadata envelope documenting the runner, arguments, timing, and stdout/stderr. The artefact is posted back to Feedser automatically. | ||||
|  | ||||
| #### Trivy DB export metadata (`metadata.json`) | ||||
|  | ||||
| `stellaops-cli db export --format trivy-db` (and the backing `POST /jobs/export:trivy-db`) always emits a `metadata.json` document in the OCI layout root. Operators consuming the bundle or delta updates should inspect the following fields: | ||||
|  | ||||
| | Field | Type | Purpose | | ||||
| | ----- | ---- | ------- | | ||||
| | `mode` | `full` \| `delta` | Indicates whether the current run rebuilt the entire database (`full`) or only the changed files (`delta`). | | ||||
| | `baseExportId` | string? | Export ID of the last full baseline that the delta builds upon. Only present for `mode = delta`. | | ||||
| | `baseManifestDigest` | string? | SHA-256 digest of the manifest belonging to the baseline OCI layout. | | ||||
| | `resetBaseline` | boolean | `true` when the exporter rotated the baseline (e.g., repo change, delta chain reset). Treat as a full refresh. | | ||||
| | `treeDigest` | string | Canonical SHA-256 digest of the JSON tree used to build the database. | | ||||
| | `treeBytes` | number | Total bytes across exported JSON files. | | ||||
| | `advisoryCount` | number | Count of advisories included in the export. | | ||||
| | `exporterVersion` | string | Version stamp of `StellaOps.Feedser.Exporter.TrivyDb`. | | ||||
| | `builder` | object? | Raw metadata emitted by `trivy-db build` (version, update cadence, etc.). | | ||||
| | `delta.changedFiles[]` | array | Present when `mode = delta`. Each entry lists `{ "path": "<relative json>", "length": <bytes>, "digest": "sha256:..." }`. | | ||||
| | `delta.removedPaths[]` | array | Paths that existed in the previous manifest but were removed in the new run. | | ||||
|  | ||||
| When the planner opts for a delta run, the exporter copies unmodified blobs from the baseline layout identified by `baseManifestDigest`. Consumers that cache OCI blobs only need to fetch the `changedFiles` and the new manifest/metadata unless `resetBaseline` is true. | ||||
| When pushing to ORAS, set `feedser:exporters:trivyDb:oras:publishFull` / `publishDelta` to control whether full or delta runs are copied to the registry. Offline bundles follow the analogous `includeFull` / `includeDelta` switches under `offlineBundle`. | ||||
|  | ||||
| Example configuration (`appsettings.yaml`): | ||||
|  | ||||
| ```yaml | ||||
| feedser: | ||||
|   exporters: | ||||
|     trivyDb: | ||||
|       oras: | ||||
|         enabled: true | ||||
|         publishFull: true | ||||
|         publishDelta: false | ||||
|       offlineBundle: | ||||
|         enabled: true | ||||
|         includeFull: true | ||||
|         includeDelta: false | ||||
| ``` | ||||
|  | ||||
|  | ||||
| **Authentication** | ||||
|  | ||||
| - API key is sent as `Authorization: Bearer <token>` automatically when configured.   | ||||
| - Anonymous operation (empty key) is permitted for offline use cases but backend calls will fail with 401 unless the Feedser instance allows guest access. | ||||
| - When `StellaOps:Authority:Url` is set the CLI initialises the StellaOps auth client. Use `stellaops-cli auth login` to obtain a token (password grant when `Username`/`Password` are set, otherwise client credentials). Tokens are cached under `~/.stellaops/tokens` by default; `auth status` shows expiry and `auth logout` removes the cached entry. | ||||
|  | ||||
| **Configuration file template** | ||||
|  | ||||
| @@ -247,7 +289,16 @@ Configuration follows the same precedence chain everywhere: | ||||
|     "ResultsDirectory": "results", | ||||
|     "DefaultRunner": "docker", | ||||
|     "ScannerSignaturePublicKeyPath": "", | ||||
|     "ScannerDownloadAttempts": 3 | ||||
|     "ScannerDownloadAttempts": 3, | ||||
|     "Authority": { | ||||
|       "Url": "https://authority.example.org", | ||||
|       "ClientId": "feedser-cli", | ||||
|       "ClientSecret": "REDACTED", | ||||
|       "Username": "", | ||||
|       "Password": "", | ||||
|       "Scope": "feedser.jobs.trigger", | ||||
|       "TokenCacheDirectory": "" | ||||
|     } | ||||
|   } | ||||
| } | ||||
| ``` | ||||
| @@ -256,132 +307,132 @@ Drop `appsettings.local.json` or `.yaml` beside the binary to override per envir | ||||
|  | ||||
| --- | ||||
|  | ||||
| ### 2.5 Misc Endpoints | ||||
|  | ||||
| | Path       | Method | Description                  | | ||||
| | ---------- | ------ | ---------------------------- | | ||||
| | `/healthz` | GET    | Liveness; returns `"ok"`     | | ||||
| | `/metrics` | GET    | Prometheus exposition (OTel) | | ||||
| | `/version` | GET    | Git SHA + build date         | | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 3 First‑Party CLI Tools | ||||
|  | ||||
| ### 3.1 `stella` | ||||
|  | ||||
| > *Package SBOM + Scan + Exit code* – designed for CI. | ||||
|  | ||||
| ``` | ||||
| Usage: stella [OPTIONS] IMAGE_OR_SBOM | ||||
| ``` | ||||
|  | ||||
| | Flag / Option   | Default                 | Description                                        | | ||||
| | --------------- | ----------------------- | -------------------------------------------------- | | ||||
| | `--server`      | `http://localhost:8080` | API root                                           | | ||||
| | `--token`       | *env `STELLA_TOKEN`*    | Bearer token                                       | | ||||
| | `--sbom-type`   | *auto*                  | Force `trivy-json-v2`/`spdx-json`/`cyclonedx-json` | | ||||
| | `--delta`       | `false`                 | Enable delta layer optimisation                    | | ||||
| | `--policy-file` | *none*                  | Override server rules with local YAML/Rego         | | ||||
| | `--threshold`   | `critical`              | Fail build if ≥ level found                        | | ||||
| | `--output-json` | *none*                  | Write raw scan result to file                      | | ||||
| | `--wait-quota`  | `true`                  | If 429 received, automatically wait `Retry‑After` and retry once. | | ||||
|  | ||||
| **Exit codes** | ||||
|  | ||||
| | Code | Meaning                                     | | ||||
| | ---- | ------------------------------------------- | | ||||
| | 0    | Scan OK, policy passed                      | | ||||
| | 1    | Vulnerabilities ≥ threshold OR policy block | | ||||
| | 2    | Internal error (network etc.)               | | ||||
|  | ||||
| --- | ||||
|  | ||||
| ### 3.2 `stella‑zastava` | ||||
|  | ||||
| > *Daemon / K8s DaemonSet* – watch container runtime, push SBOMs. | ||||
|  | ||||
| Core flags (excerpt): | ||||
|  | ||||
| | Flag             | Purpose                            | | ||||
| | ---------------- | ---------------------------------- | | ||||
| | `--mode`         | `listen` (default) / `enforce`     | | ||||
| | `--filter-image` | Regex; ignore infra/busybox images | | ||||
| | `--threads`      | Worker pool size                   | | ||||
|  | ||||
| --- | ||||
|  | ||||
| ### 3.3 `stellopsctl` | ||||
|  | ||||
| > *Admin utility* – policy snapshots, feed status, user CRUD. | ||||
|  | ||||
| Examples: | ||||
|  | ||||
| ``` | ||||
| stellopsctl policy export > policies/backup-2025-07-14.yaml | ||||
| stellopsctl feed refresh  # force OSV merge | ||||
| stellopsctl user add dev-team --role developer | ||||
| ``` | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 4 Error Model | ||||
|  | ||||
| Uniform problem‑details object (RFC 7807): | ||||
|  | ||||
| ```json | ||||
| { | ||||
|   "type": "https://stella-ops.org/probs/validation", | ||||
|   "title": "Invalid request", | ||||
|   "status": 400, | ||||
|   "detail": "Layer digest malformed", | ||||
|   "traceId": "00-7c39..." | ||||
| } | ||||
| ``` | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 5 Rate Limits | ||||
|  | ||||
| Default **40 requests / second / token**.   | ||||
| 429 responses include `Retry-After` seconds header. | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 6 FAQ & Tips | ||||
|  | ||||
| * **Skip SBOM generation in CI** – supply a *pre‑built* SBOM and add `?sbom-only=true` to `/scan` for <1 s path.   | ||||
| * **Air‑gapped?** – point `--server` to `http://oukgw:8080` inside the Offline Update Kit.   | ||||
| * **YAML vs Rego** – YAML simpler; Rego unlocks time‑based logic (see samples).   | ||||
| * **Cosign verify plug‑ins** – enable `SCANNER_VERIFY_SIG=true` env to refuse unsigned plug‑ins. | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 7 Planned Changes (Beyond 6 Months) | ||||
|  | ||||
| These stay in *Feature Matrix → To Do* until design is frozen. | ||||
|  | ||||
| | Epic / Feature               | API Impact Sketch                  | | ||||
| | ---------------------------- | ---------------------------------- | | ||||
| | **SLSA L1‑L3** attestation   | `/attest` (see §2.4)               | | ||||
| | Rekor transparency log       | `/rekor/log/{id}` (GET)            | | ||||
| | Plug‑in Marketplace metadata | `/plugins/market` (catalog)        | | ||||
| | Horizontal scaling controls  | `POST /cluster/node` (add/remove)  | | ||||
| | Windows agent support        | Update LSAPI to PDE, no API change | | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 8 References | ||||
|  | ||||
| * OpenAPI YAML → `/openapi/v1.yaml` (served by backend)   | ||||
| * OAuth2 spec: <https://datatracker.ietf.org/doc/html/rfc6749>   | ||||
| * SLSA spec: <https://slsa.dev/spec/v1.0>   | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 9 Changelog (truncated) | ||||
|  | ||||
| * **2025‑07‑14** – added *delta SBOM*, policy import/export, CLI `--sbom-type`.   | ||||
| * **2025‑07‑12** – initial public reference. | ||||
|  | ||||
| --- | ||||
| ### 2.5 Misc Endpoints | ||||
|  | ||||
| | Path       | Method | Description                  | | ||||
| | ---------- | ------ | ---------------------------- | | ||||
| | `/healthz` | GET    | Liveness; returns `"ok"`     | | ||||
| | `/metrics` | GET    | Prometheus exposition (OTel) | | ||||
| | `/version` | GET    | Git SHA + build date         | | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 3 First‑Party CLI Tools | ||||
|  | ||||
| ### 3.1 `stella` | ||||
|  | ||||
| > *Package SBOM + Scan + Exit code* – designed for CI. | ||||
|  | ||||
| ``` | ||||
| Usage: stella [OPTIONS] IMAGE_OR_SBOM | ||||
| ``` | ||||
|  | ||||
| | Flag / Option   | Default                 | Description                                        | | ||||
| | --------------- | ----------------------- | -------------------------------------------------- | | ||||
| | `--server`      | `http://localhost:8080` | API root                                           | | ||||
| | `--token`       | *env `STELLA_TOKEN`*    | Bearer token                                       | | ||||
| | `--sbom-type`   | *auto*                  | Force `trivy-json-v2`/`spdx-json`/`cyclonedx-json` | | ||||
| | `--delta`       | `false`                 | Enable delta layer optimisation                    | | ||||
| | `--policy-file` | *none*                  | Override server rules with local YAML/Rego         | | ||||
| | `--threshold`   | `critical`              | Fail build if ≥ level found                        | | ||||
| | `--output-json` | *none*                  | Write raw scan result to file                      | | ||||
| | `--wait-quota`  | `true`                  | If 429 received, automatically wait `Retry‑After` and retry once. | | ||||
|  | ||||
| **Exit codes** | ||||
|  | ||||
| | Code | Meaning                                     | | ||||
| | ---- | ------------------------------------------- | | ||||
| | 0    | Scan OK, policy passed                      | | ||||
| | 1    | Vulnerabilities ≥ threshold OR policy block | | ||||
| | 2    | Internal error (network etc.)               | | ||||
|  | ||||
| --- | ||||
|  | ||||
| ### 3.2 `stella‑zastava` | ||||
|  | ||||
| > *Daemon / K8s DaemonSet* – watch container runtime, push SBOMs. | ||||
|  | ||||
| Core flags (excerpt): | ||||
|  | ||||
| | Flag             | Purpose                            | | ||||
| | ---------------- | ---------------------------------- | | ||||
| | `--mode`         | `listen` (default) / `enforce`     | | ||||
| | `--filter-image` | Regex; ignore infra/busybox images | | ||||
| | `--threads`      | Worker pool size                   | | ||||
|  | ||||
| --- | ||||
|  | ||||
| ### 3.3 `stellopsctl` | ||||
|  | ||||
| > *Admin utility* – policy snapshots, feed status, user CRUD. | ||||
|  | ||||
| Examples: | ||||
|  | ||||
| ``` | ||||
| stellopsctl policy export > policies/backup-2025-07-14.yaml | ||||
| stellopsctl feed refresh  # force OSV merge | ||||
| stellopsctl user add dev-team --role developer | ||||
| ``` | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 4 Error Model | ||||
|  | ||||
| Uniform problem‑details object (RFC 7807): | ||||
|  | ||||
| ```json | ||||
| { | ||||
|   "type": "https://stella-ops.org/probs/validation", | ||||
|   "title": "Invalid request", | ||||
|   "status": 400, | ||||
|   "detail": "Layer digest malformed", | ||||
|   "traceId": "00-7c39..." | ||||
| } | ||||
| ``` | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 5 Rate Limits | ||||
|  | ||||
| Default **40 requests / second / token**.   | ||||
| 429 responses include `Retry-After` seconds header. | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 6 FAQ & Tips | ||||
|  | ||||
| * **Skip SBOM generation in CI** – supply a *pre‑built* SBOM and add `?sbom-only=true` to `/scan` for <1 s path.   | ||||
| * **Air‑gapped?** – point `--server` to `http://oukgw:8080` inside the Offline Update Kit.   | ||||
| * **YAML vs Rego** – YAML simpler; Rego unlocks time‑based logic (see samples).   | ||||
| * **Cosign verify plug‑ins** – enable `SCANNER_VERIFY_SIG=true` env to refuse unsigned plug‑ins. | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 7 Planned Changes (Beyond 6 Months) | ||||
|  | ||||
| These stay in *Feature Matrix → To Do* until design is frozen. | ||||
|  | ||||
| | Epic / Feature               | API Impact Sketch                  | | ||||
| | ---------------------------- | ---------------------------------- | | ||||
| | **SLSA L1‑L3** attestation   | `/attest` (see §2.4)               | | ||||
| | Rekor transparency log       | `/rekor/log/{id}` (GET)            | | ||||
| | Plug‑in Marketplace metadata | `/plugins/market` (catalog)        | | ||||
| | Horizontal scaling controls  | `POST /cluster/node` (add/remove)  | | ||||
| | Windows agent support        | Update LSAPI to PDE, no API change | | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 8 References | ||||
|  | ||||
| * OpenAPI YAML → `/openapi/v1.yaml` (served by backend)   | ||||
| * OAuth2 spec: <https://datatracker.ietf.org/doc/html/rfc6749>   | ||||
| * SLSA spec: <https://slsa.dev/spec/v1.0>   | ||||
|  | ||||
| --- | ||||
|  | ||||
| ## 9 Changelog (truncated) | ||||
|  | ||||
| * **2025‑07‑14** – added *delta SBOM*, policy import/export, CLI `--sbom-type`.   | ||||
| * **2025‑07‑12** – initial public reference. | ||||
|  | ||||
| --- | ||||
|   | ||||
		Reference in New Issue
	
	Block a user