102 lines
16 KiB
Markdown
102 lines
16 KiB
Markdown
# Route Access Inventory
|
|
|
|
This document publishes the checked Hono API route access classification from `apps/api/src/route-access-inventory.ts`. It is a static security review aid only: it records route boundaries, access classes, rationale, and redacted data-sensitivity notes without changing route handlers, OpenAPI metadata, authorization middleware, or runtime behavior.
|
|
|
|
Historical-plan note: route keys and access classes in this document are
|
|
current only when the focused verification below passes. Do not copy route
|
|
paths from older improvement-plan files into this inventory without confirming
|
|
the typed source of truth.
|
|
|
|
## Scope and Source of Truth
|
|
|
|
- Source of truth: `apps/api/src/route-access-inventory.ts`.
|
|
- Scanner reference: `tools/api-inventory/scan-api-routes.ts` discovers `app.get/post/patch/delete` route registrations from `apps/api/src/app.ts` for coverage checks.
|
|
- Verification: `apps/api/src/route-access-inventory.test.ts` checks scanner-discovered route coverage and OpenAPI security expectations; `apps/api/src/route-access-inventory-doc.test.ts` checks this document for drift.
|
|
- Route keys are written as `METHOD path` and must match the typed inventory exactly once.
|
|
- This inventory covers all current Hono API routes, including health, documentation, authentication, analytics, accounts, usage, notifications, workspaces, entity, relationship, export, webhook, maintenance, and AI upload surfaces.
|
|
- Adjacent coverage: `docs/security/csrf-inventory.md` documents CSRF posture and mutating API route classes. This document references that coverage but does not duplicate its mutating-route-only table.
|
|
|
|
## Redaction Rules
|
|
|
|
- Do not include tokens, plaintext credentials, fixture tenant identifiers, customer data, environment variable values, or concrete database identifiers.
|
|
- Keep sensitive-data notes categorical and redacted, for example “returns aggregate counts” or “consumes uploaded file content.”
|
|
- Do not paste authorization headers, JWTs, API keys, passwords, emails, tenant fixtures, or customer examples into this document.
|
|
- Route parameters such as `:entity`, `:rowId`, and `:id` are schema placeholders, not real identifiers.
|
|
|
|
## Access Class Legend
|
|
|
|
| Class | Boundary |
|
|
| --- | --- |
|
|
| `public-health` | Unauthenticated infrastructure health or readiness endpoint exposing only service/dependency status metadata. |
|
|
| `public-docs` | Unauthenticated API documentation or schema discovery surface exposing schema metadata only. |
|
|
| `service-token` | Service/API-token style boundary, including stored API key or service credential checks where implemented. |
|
|
| `service-or-tenant-api-key` | Service credential or tenant-bound stored API-key boundary with route-specific tenant and permission checks. |
|
|
| `optional-api-key-validation` | Public validation helper that optionally accepts a presented stored API key or service token and returns redacted validation status. |
|
|
| `tenant-api-key` | Tenant-bound stored API-key boundary where the credential scopes the tenant and available usage metadata. |
|
|
| `jwt-auth` | Bearer JWT authenticated user boundary. |
|
|
| `auth-credential-exchange` | Public credential exchange that consumes submitted credentials and issues authenticated API state after validation. |
|
|
| `public-analytics-token` | Public analytics ingress or aggregate read surface scoped by analytics token/payload semantics rather than browser session state. |
|
|
| `webhook-signature` | Signed webhook ingress boundary that verifies provider signing headers before processing an addressed webhook retry. |
|
|
| `canonical-redirect` | Runtime-only compatibility shim that redirects removed API-prefix requests to the canonical API path without reading request data. |
|
|
|
|
## Full Route Access Table
|
|
|
|
| Route | Access class | Sensitive data note | Rationale |
|
|
| --- | --- | --- | --- |
|
|
| `GET /healthz` | `public-health` | No sensitive data. | Unauthenticated liveness probe returns only service status and request correlation metadata. |
|
|
| `GET /readyz` | `public-health` | Dependency health state is exposed without implementation details. | Unauthenticated readiness probe returns redacted dependency status for infrastructure checks. |
|
|
| `GET /v1/health` | `public-health` | No sensitive data. | Versioned liveness probe returns only service status and request correlation metadata. |
|
|
| `GET /v1/openapi.json` | `public-docs` | No sensitive data. | OpenAPI discovery is intentionally public for client integration and contains schema metadata only. |
|
|
| `GET /v1/docs` | `public-docs` | No sensitive data. | Documentation shell is intentionally public and renders the OpenAPI document without runtime data. |
|
|
| `GET /v1/session/current-user` | `service-token` | Returns authenticated principal type metadata only. | Current service principal endpoint requires a bearer service token before returning authentication state. |
|
|
| `POST /v1/auth/login` | `auth-credential-exchange` | Consumes credentials and returns a JWT plus basic user identity. | Login exchanges submitted email and password credentials for a short-lived JWT after password verification. |
|
|
| `POST /v1/auth/refresh-token` | `jwt-auth` | Returns a JWT plus basic user identity. | Refresh requires an existing bearer JWT before issuing a replacement token for the same user. |
|
|
| `POST /v1/auth/logout` | `jwt-auth` | Consumes JWT credential material but returns only a success envelope and expired cookie attributes. | Logout requires an existing bearer JWT before revoking the active API session and clearing the API cookie. |
|
|
| `POST /v1/api-keys/validate` | `optional-api-key-validation` | Returns redacted stored API-key metadata but never plaintext key material. | API-key validation optionally accepts a presented stored API key or service token and reports redacted validation status without requiring a prior credential. |
|
|
| `POST /v1/ai/upload` | `service-token` | Consumes uploaded file content and may return a public storage URL. | AI upload writes request content through configured service storage credentials and depends on server-side upload configuration. |
|
|
| `POST /v1/support/inbound-email` | `webhook-signature` | Consumes signed email metadata and message body while omitting provider payloads and signing material from responses. | Inbound support email verifies Mailjet webhook signing headers before resolving tenant inbound addresses and creating tickets. |
|
|
| `POST /v1/analytics/events` | `public-analytics-token` | Consumes analytics identifiers, URLs, routes, and event labels. | Analytics event ingestion is public-facing and scoped by analytics payload identifiers rather than browser session state. |
|
|
| `POST /v1/analytics/page-views` | `public-analytics-token` | Consumes analytics identifiers, URLs, and route names. | Analytics page-view ingestion is public-facing and scoped by analytics payload identifiers plus ignore-page settings. |
|
|
| `GET /v1/analytics/public` | `public-analytics-token` | Returns aggregate analytics counts and top-level chart data. | Public analytics overview requires the analytics token header before returning aggregate metrics. |
|
|
| `GET /v1/analytics/admin` | `service-token` | Returns aggregate analytics metrics that may be scoped to a portal identifier. | Admin analytics overview requires service credentials before returning tenant or portal scoped metrics. |
|
|
| `GET /v1/notifications/stream` | `service-token` | Returns bounded, sanitized notification delivery snapshots and cursors without provider payloads, metadata, or raw delivery secrets. | Notification stream requires service credentials before returning tenant and user scoped in-app delivery diagnostics over SSE. |
|
|
| `GET /v1/accounts` | `service-token` | Returns tenant identifiers, names, slugs, icons, and subscription summary fields without plaintext secrets. | Account listing requires service credentials before returning tenant account metadata and subscription summaries. |
|
|
| `GET /v1/accounts/:id` | `service-token` | Returns tenant identifiers, names, slugs, icons, and subscription summary fields without plaintext secrets. | Account lookup requires service credentials before returning one tenant account metadata and subscription summary. |
|
|
| `GET /v1/usage` | `tenant-api-key` | Returns plan and remaining API usage metadata for the credential-scoped tenant. | Usage lookups enter through the canonical API host and validate tenant API-key credentials in the API runtime. |
|
|
| `POST /v1/billing/stripe/webhooks` | `webhook-signature` | Consumes signed billing lifecycle webhook payloads without returning signing material or plaintext credentials. | Stripe billing webhook ingress enters through the canonical API host and verifies the raw signed payload in the API runtime. |
|
|
| `POST /v1/email-sequences/mailjet/webhooks` | `webhook-signature` | Consumes signed delivery event metadata while responses omit provider payloads, recipient data, and signing material. | Email-sequence provider webhooks verify Mailjet signing headers before correlating bounce events to provider message ids. |
|
|
| `GET /v1/workspaces/:tenantId/auth/providers` | `service-token` | Returns redacted OIDC/SAML provider metadata only; client secrets, SAML certificate bodies, private keys, token hashes, invite tokens, and raw metadata documents are omitted. | Workspace auth-provider discovery requires a service token before returning tenant-scoped SSO metadata. |
|
|
| `POST /v1/workspaces/:tenantId/context/revalidate` | `service-token` | Consumes tenant and user identifiers and returns a redacted validity envelope without provider secrets, invite tokens, token hashes, or SSO secret material. | Workspace context revalidation requires a service token before confirming tenant/user membership for a context switch. |
|
|
| `GET /v1/workspaces/:tenantId/invites` | `service-token` | Returns invite recipient details, lifecycle timestamps, audit user ids, and tokenPrefix only; plaintext tokens and token hashes are omitted. | Workspace invite listing requires a service token before returning tenant-scoped invite lifecycle state. |
|
|
| `POST /v1/workspaces/:tenantId/invites` | `service-token` | Consumes invite recipient details and returns the one-time plaintext invite token only in the create response. | Workspace invite creation requires a service token before issuing a tenant-scoped invite token. |
|
|
| `POST /v1/workspaces/:tenantId/invites/:inviteId/accept` | `service-token` | Consumes plaintext invite token and returns redacted invite lifecycle metadata without echoing the token. | Workspace invite acceptance requires a service token and a one-time invite token before finalizing tenant membership invitation state. |
|
|
| `POST /v1/workspaces/:tenantId/invites/:inviteId/revoke` | `service-token` | Consumes revoke audit metadata and returns redacted invite lifecycle metadata without token material. | Workspace invite revocation requires a service token before finalizing the tenant-scoped invite as revoked. |
|
|
| `POST /v1/events/webhooks/attempts/:id` | `webhook-signature` | Consumes signed webhook delivery metadata and an attempt id while omitting provider payloads and signing material from responses. | Webhook retry verifies Mailjet webhook signing headers before looking up or queueing a known delivery attempt. |
|
|
| `POST /v1/maintenance/export-retention/enqueue` | `service-token` | Consumes an optional bounded batch size and returns only queue task metadata plus request correlation. | Export artifact retention cleanup is an operator maintenance action and requires service credentials before enqueueing work. |
|
|
| `GET /v1/entities/:entity/rows` | `service-or-tenant-api-key` | Returns tenant-scoped legacy entity row data. | Entity row listing requires a service token or scoped stored API key with read permission for the resolved entity. |
|
|
| `POST /v1/entities/:entity/rows` | `service-or-tenant-api-key` | Consumes and stores tenant-scoped legacy entity row data. | Entity row creation requires a service token or scoped stored API key with create permission for the resolved entity. |
|
|
| `GET /v1/entities/:entity/rows/:rowId` | `service-or-tenant-api-key` | Returns tenant-scoped legacy entity row data. | Entity row lookup requires a service token or scoped stored API key with read permission for the resolved entity. |
|
|
| `PATCH /v1/entities/:entity/rows/:rowId` | `service-or-tenant-api-key` | Consumes and returns tenant-scoped legacy entity row data. | Entity row update requires a service token or scoped stored API key with update permission for the resolved entity. |
|
|
| `DELETE /v1/entities/:entity/rows/:rowId` | `service-or-tenant-api-key` | Deletes tenant-scoped legacy entity row data and returns the deleted row id. | Entity row deletion requires a service token or scoped stored API key with delete permission for the resolved entity. |
|
|
| `POST /v1/relationships` | `service-or-tenant-api-key` | Consumes row identifiers and returns relationship metadata. | Relationship creation requires a service token or scoped stored API key with create permission for both related entities. |
|
|
| `GET /v1/relationships/:id` | `service-or-tenant-api-key` | Returns relationship metadata with parent and child row envelopes. | Relationship lookup requires a service token or scoped stored API key with read permission for both related entities. |
|
|
| `DELETE /v1/relationships/:id` | `service-or-tenant-api-key` | Deletes and returns relationship metadata with parent and child row envelopes. | Relationship deletion requires a service token or scoped stored API key with delete permission for both related entities. |
|
|
| `GET /v1/exports/:exportJobId/download-url` | `service-or-tenant-api-key` | Returns a signed artifact URL envelope without artifact bucket/key values, storage credentials, pause reason internals, filters, or object bodies. | Export download URL creation requires service credentials or a tenant-bound stored API key and blocks compliance-paused exports before returning a short-lived signed artifact URL envelope. |
|
|
| `GET /v1/exports/:exportJobId/progress` | `service-or-tenant-api-key` | Returns export progress envelope (status, percent, rowCount) — no artifact URLs, no compliance-pause internals, no filters. | Export progress polling requires service credentials or a tenant-bound stored API key; the handler scopes lookups to the caller's tenant and never leaks artifact bucket/key details. |
|
|
| `POST /v1/devices/register` | `service-token` | Persists device-bound push token. Stored token is hashed at rest; response contains only the registration id + masked token preview. | Mobile push-token registration requires a service credential (bearer/API-key) carrying user identity; the body's userId + tenantId are reconciled against the authenticated principal downstream. |
|
|
| `POST /v1/devices/revoke` | `service-token` | Returns revocation confirmation without echoing the device token or push provider internals. | Mobile push-token revocation requires a service credential; the handler revokes by token hash and never echoes the raw token. |
|
|
| `GET /v1/entities/:entity` | `service-token` | Returns legacy entity schema and relationship details. | Legacy entity lookup requires service credentials before returning the named entity detail graph. |
|
|
| `GET /status` | `public-health` | Boolean health state and deployment region tag only — no connection strings, hostnames or stack traces. | Unauthenticated status probe for external uptime monitors. Returns boolean-only health, revision, region, uptime. |
|
|
| `GET /metrics` | `service-token` | Prom text-format counters and gauges — includes business KPIs (AI tokens, mail, webhook, queue depth). Token-protected. | Prometheus scrape endpoint requires bearer METRICS_TOKEN. Returns 404 when METRICS_ENABLED is false. |
|
|
|
|
## Verification Commands
|
|
|
|
Run focused verification from the repository root after changing Hono routes, OpenAPI security metadata, the typed route access inventory, or this document:
|
|
|
|
```bash
|
|
pnpm exec vitest run apps/api/src/route-access-inventory.test.ts apps/api/src/route-access-inventory-doc.test.ts
|
|
pnpm exec eslint apps/api/src/route-access-inventory.ts apps/api/src/route-access-inventory.test.ts apps/api/src/route-access-inventory-doc.test.ts --max-warnings=0
|
|
```
|
|
|
|
Expected diagnostics name stale or missing route keys in `METHOD path` form, OpenAPI security drift, redaction matches, and missing required section headings by heading text.
|