Scanner tenant settings API
The Scanner settings surface exposes only tenant controls that the worker pipeline currently enforces. The initial contract controls which admitted, signed OS and language analyzers are skipped for subsequent scans.
Authorization and tenancy
- Base path:
/api/v1/scanner/settings. GETpolicy:scanner.operations.read, satisfied byscanner:reador the legacy escape-hatchscanner.admin.PUTpolicy:scanner.operations.write, satisfied byscanner:writeor the legacy escape-hatchscanner.admin.- Tenant: resolved from the validated
stellaops:tenantclaim. The canonical tenant-switch header is accepted only for an authenticated global administrator through the shared tenant resolver. There is no default-tenant fallback.
The default stella-ops-ui client and professional interactive role bundles request scanner:read, but do not request or grant scanner:write. The Console therefore renders this contract read-only unless an operator explicitly provisions the existing canonical write scope; this API does not imply a default interactive write grant.
Read settings
GET /api/v1/scanner/settings
Response 200 OK:
{
"disabledAnalyzerIds": ["stellaops.scanner.plugin.os.dpkg", "stellaops.scanner.plugin.ruby"],
"etag": "c6e20fbb68c4f7a0d19d754cbdb30a4da244875bba0e2bba6e788c2cc7c2c23d",
"updatedAt": "2026-07-16T18:00:00Z",
"updatedBy": "operator-subject"
}
The response also carries the strong ETag: "<sha256>" header. A tenant with no persisted row receives an empty disabledAnalyzerIds array, a deterministic ETag, and null update metadata.
Replace settings
PUT /api/v1/scanner/settings
The request must carry exactly one strong If-Match value copied from the latest GET. Weak and wildcard values are rejected.
{
"disabledAnalyzerIds": ["stellaops.scanner.plugin.ruby", "stellaops.scanner.plugin.os.dpkg"]
}
Analyzer IDs are the signed bundle manifest IDs returned by GET /api/v1/scanner/analyzers(for example, stellaops.scanner.plugin.ruby). IDs are trimmed, lower-cased, deduplicated, and sorted before storage. At most 256 IDs are accepted; each ID is at most 128 ASCII letters, digits, ., _, :, or -. Worker also recognizes legacy runtime analyzer IDs for compatibility, but new clients should persist manifest IDs.
On success, the endpoint returns 200 OK with the updated response document and new ETag. It emits a Scanner audit event containing the tenant, actor, timestamp, and before/after analyzer lists and ETags.
Error contract:
| Status | Meaning |
|---|---|
400 | Missing tenant, malformed body, invalid analyzer ID, weak/wildcard ETag, or otherwise invalid request. |
401 / 403 | Authentication failed, or the caller lacks scanner:read for GET / scanner:write for PUT (legacy scanner.admin remains compatible). |
412 | If-Match is stale; the response ETag and problem extension currentEtag identify the current version. |
428 | If-Match is missing or does not contain exactly one value. |
Runtime effect
Settings are stored in scanner.tenant_settings by the Scanner Storage startup migration. For each job, Scanner Worker resolves the job tenant, reads this row, and filters matching admitted OS and language analyzer IDs before execution. Repository or database failures fail the analyzer stage rather than silently running tenant-disabled analyzers. Jobs without a tenant preserve the legacy analyzer set because they cannot be associated with a tenant settings row.
