# Scanner Endpoint Registration Matrix Last updated: 2026-02-23 (Sprint `20260222.057`, tasks `SCAN-TEN-08`, `SCAN-TEN-11`, `SCAN-TEN-12`, and `SCAN-TEN-13`). This file is the Scanner WebService source-of-truth for endpoint registration intent and authorization posture. ## Active endpoint maps (registered in `Program.cs`) | Map method | Base path | Authorization posture | Notes | | --- | --- | --- | --- | | `MapHealthEndpoints` | `/healthz`, `/readyz` | `scanner.scans.read` | Health and readiness are authenticated. | | `MapObservabilityEndpoints` | `/metrics` | `AllowAnonymous` | Prometheus scrape path is explicitly anonymous. | | `MapOfflineKitEndpoints` | `/offline-kit` | Mixed explicit policies | Offline import/status/manifest/validate policies are explicit per route. | | `MapScanEndpoints` | `/api/v1/scans` | Explicit policies per route | Includes nested scan maps (`callgraphs`, `sbom`, `reachability`, `export`, `evidence`, `approval`, `manifest`, `github-code-scanning`). | | `MapSourcesEndpoints` | `/api/v1/sources` | `scanner.sources.read/write/admin` | Tenant-aware source CRUD and source-run operations (`sbom_source_runs` reads/writes are tenant-filtered). | | `MapWebhookEndpoints` | `/api/v1/webhooks` | `AllowAnonymous` | External provider ingress; tenant-scoped source resolution for name routes. | | `MapSbomUploadEndpoints` | `/api/v1/sbom` | Explicit policies per route | Includes SBOM upload and hot lookup maps. | | `MapReachabilityDriftRootEndpoints` | `/api/v1/reachability` | `scanner.scans.read/write` | Root drift query/compute routes. | | `MapDeltaCompareEndpoints` | `/api/v1/delta` | Explicit policies per route | Delta compare operations. | | `MapSmartDiffEndpoints` | `/api/v1/smart-diff` | Explicit policies per route | Smart diff + VEX candidate workflows. | | `MapBaselineEndpoints` | `/api/v1/baselines` | Explicit policies per route | Baseline operations. | | `MapActionablesEndpoints` | `/api/v1/actionables` | Explicit policies per route | Actionable findings operations. | | `MapCounterfactualEndpoints` | `/api/v1/counterfactuals` | Explicit policies per route | Counterfactual analysis operations. | | `MapProofSpineEndpoints` | `/api/v1/spines` | Explicit policies per route | Proof spine APIs. | | `MapReplayEndpoints` | `/api/v1/replay` | Explicit policies per route | Replay command and verification APIs. | | `MapScoreReplayEndpoints` (feature-gated) | `/api/v1/replay/score` | Explicit policies per route | Enabled only when `scanner:scoreReplay:enabled=true`. | | `MapWitnessEndpoints` | `/api/v1/witnesses` | Explicit policies per route | Witness management APIs. | | `MapEpssEndpoints` | `/api/v1/epss` | Explicit policies per route | EPSS ingestion/query APIs. | | `MapTriageStatusEndpoints` | `/api/v1/triage` | `scanner.triage.read/write` | Triage status workflows. | | `MapTriageInboxEndpoints` | `/api/v1/triage` | `scanner.triage.read/write` | Triage inbox workflows. | | `MapBatchTriageEndpoints` | `/api/v1/triage` | `scanner.triage.read/write` | Bulk triage operations. | | `MapProofBundleEndpoints` | `/api/v1/triage` | `scanner.triage.read` | Triage proof bundle retrieval. | | `MapUnknownsEndpoints` | `/api/v1/unknowns` | `scanner.scans.read` | Tenant-scoped unknown listing/detail/evidence/history/stats/bands routes. | | `MapSecretDetectionSettingsEndpoints` | `/api/v1/secrets/config` | `scanner.secret-settings.*` / `scanner.secret-exceptions.*` | Secret detection config APIs with tenant-scoped exception get/update/delete lookups. | | `MapSecurityAdapterEndpoints` | `/api/v1/security` | Explicit policies per route | Security adapter read-model routes. | | `MapPolicyEndpoints` (feature-gated) | `/api/v1/policy` | Explicit policies per route | Enabled only when policy preview feature flag is true. | | `MapReportEndpoints` | `/api/v1/reports` | `scanner.reports` | Report generation and retrieval routes. | | `MapRuntimeEndpoints` | `/api/v1/runtime` | `scanner.runtime.ingest` and scan policies | Runtime ingest/reconcile APIs. | | `MapSliceEndpoints` | `/api/slices` | Explicit policies per route | Reachability slice query/replay APIs. | ## Webhook tenant contract (name routes) - Name-based webhook routes are: - `POST /api/v1/webhooks/docker/{sourceName}` - `POST /api/v1/webhooks/github/{sourceName}` - `POST /api/v1/webhooks/gitlab/{sourceName}` - `POST /api/v1/webhooks/harbor/{sourceName}` - Tenant context is required for name-based routes (claim or `X-StellaOps-Tenant`/compatibility alias). Missing tenant returns `400` with `tenant_missing`; claim/header mismatch returns `400` with `tenant_conflict`. - Source lookup is tenant-scoped via `GetByNameAsync(tenantId, sourceName)`, so same-name sources in different tenants cannot cross-dispatch. - `POST /api/v1/webhooks/{sourceId}` accepts optional tenant context; if present and it does not match source ownership, the endpoint returns `404`. ## Triage tenant contract - Triage and finding-evidence routes resolve tenant context via `ScannerRequestContextResolver`. - Resolution precedence: claim (`tenant`, compatibility aliases `tid`/`tenant_id`), then headers (`X-StellaOps-Tenant`, `X-Stella-Tenant`, `X-Tenant-Id`), then fallback tenant `default` for triage flows configured with `allowDefaultTenant`. - If multiple claim/header values conflict, Scanner returns `400` with `tenant_conflict`. - Triage-facing contracts now require tenant input (`ITriageStatusService`, `ITriageQueryService`, `IFindingQueryService`, `IGatingReasonService`, `IUnifiedEvidenceService`, `IReplayCommandService`, `IFindingRationaleService`) and enforce tenant-filtered data access. - Triage persistence is tenant partitioned (`triage_scan.tenant_id`, `triage_finding.tenant_id`), and the active-case uniqueness key includes `tenant_id` to avoid cross-tenant collisions. - Cross-tenant finding lookups are treated as deterministic not-found responses (`404`) on triage/finding endpoints. ## Unknowns tenant contract - Unknowns routes resolve tenant context via `ScannerRequestContextResolver` using canonical and compatibility claim/header paths with conflict detection. - Unknown queries are tenant-scoped by data access predicates (`tenant_id::text = @tenantId`) in the Scanner WebService query service. - Missing records across tenant boundaries resolve as deterministic `404` for detail/evidence/history endpoints. ## Reachability + SmartDiff tenant contract (SCAN-TEN-11) - Reachability drift routes (`/api/v1/scans/{scanId}/drift`, `/api/v1/drift/{driftId}/sinks`) now resolve tenant context via `ScannerRequestContextResolver` before repository access. - Drift persistence/retrieval paths are tenant-parameterized end-to-end (`call_graph_snapshots`, `code_changes`, `reachability_drift_results`, `drifted_sinks`) instead of using a fixed tenant scope. - SmartDiff routes (`/api/v1/smart-diff/**`) now resolve tenant context and pass it explicitly to material-change and VEX-candidate stores. - SmartDiff persistence/retrieval paths are tenant-parameterized (`material_risk_changes`, `vex_candidates`), so candidate ID collisions across tenants resolve as deterministic not-found. - Remaining reachability/SmartDiff storage adapters used by these flows are tenant-parameterized as well (`risk_state_snapshots`, `reachability_results`), removing fixed-tenant constants from Postgres adapter implementations. ## Source-runs + secret-exception tenant contract (SCAN-TEN-13) - Source run routes (`/api/v1/sources/{sourceId}/runs`, `/api/v1/sources/{sourceId}/runs/{runId}`) now pass resolved tenant context into `ISbomSourceRunRepository` and SQL predicates (`tenant_id = @tenantId`) for `scanner.sbom_source_runs`. - Secret exception routes (`/api/v1/secrets/config/exceptions/{tenantId}/{exceptionId}`) now use tenant-scoped repository methods for get/update/delete against `secret_exception_pattern` rather than ID-only lookups. - The generic webhook route (`POST /api/v1/webhooks/{sourceId}`) remains compatibility-tolerant for missing tenant context, but enforces ownership match when tenant context is present. ## Deferred endpoint maps (not registered by design) | Map method | Current state | Reason for deferral | Activation prerequisite | | --- | --- | --- | --- | | `MapValidationEndpoints` | Deferred | Validation endpoint stack is not wired in `Program.cs` (validator service graph and option bindings are not part of default webservice startup contract). | Add explicit validation DI and contract docs, then register in `Program.cs`. | | `MapReachabilityEvidenceEndpoints` | Deferred | Legacy standalone `/api/reachability` surface is not part of current `/api/v1/scans`/triage scanner API contract. | Contract decision to promote or remove this surface. | | `MapReachabilityStackEndpoints` | Deferred | Stack endpoints depend on optional repository path and are not part of the current public API registration set. | Contract decision and stable backing repository implementation. | | `MapFidelityEndpoints` | Deferred | Fidelity analyzer endpoints are experimental and require explicit analyzer service contract decisions before exposure. | Product sign-off and DI contract hardening. |