# API & CLI Reference *Purpose* – give operators and integrators a single, authoritative spec for REST/GRPC calls **and** first‑party CLI tools (`santech`, `zastava`, `stellopsctl`). 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 `santech` | \* 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 ` on every call. --- ## 2 REST API ### 2.0 Obtain / Refresh Offline‑Token ```text POST /token/offline Authorization: Bearer ``` | 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": 333`. ### 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 ``` ```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 | Returns `202 Accepted` and `Location: /attest/{id}` for async verify. --- ### 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‑santech` > *Package SBOM + Scan + Exit code* – designed for CI. ``` Usage: santech [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.ru/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: * SLSA spec: --- ## 9 Changelog (truncated) * **2025‑07‑14** – added *delta SBOM*, policy import/export, CLI `--sbom-type`. * **2025‑07‑12** – initial public reference. ---