docs(m4.2): reconcile InboundAPI (Bearer/audit-timing/type-validation), Security (cookie session, role names), Notification (Email-only, AuditKind vocab) to code

This commit is contained in:
Joseph Doherty
2026-06-16 20:27:43 -04:00
parent 9106efafd8
commit c3b046457e
3 changed files with 41 additions and 29 deletions
+16 -11
View File
@@ -29,7 +29,7 @@ Central cluster only (active node). Not available at site clusters.
- **Enabled/Disabled Flag**: Keys can be disabled without deletion.
### Management
- Managed by users with the **Admin** role via the Central UI.
- Managed by users with the **Administrator** role via the Central UI.
- All key changes (create, enable/disable, delete) are audit logged.
## API Method Definition
@@ -48,7 +48,7 @@ Each API method definition includes:
- **Timeout**: Configurable per method. Defines the maximum time the method is allowed to execute (including any routed calls to sites) before returning a timeout error to the caller.
### Management
- Managed by users with the **Design** role via the Central UI.
- Managed by users with the **Designer** role via the Central UI.
- All method definition changes are audit logged.
## HTTP Contract
@@ -58,8 +58,12 @@ Each API method definition includes:
- Method names map directly to URL path segments (e.g., method "GetProductionReport" → `POST /api/GetProductionReport`).
- All calls are POST — these are RPC-style script invocations, not RESTful resource operations.
### API Key Header
- API key is passed via the `X-API-Key` HTTP header.
### Authentication Header
- The API key token (`sbk_<keyId>_<secret>`) is accepted from **either** of two headers:
- `Authorization: Bearer sbk_<keyId>_<secret>` — the preferred form.
- `X-API-Key: sbk_<keyId>_<secret>` — alternate form for callers that cannot set the Authorization header.
- When both headers are present, `Authorization` takes precedence.
- Both forms are processed by the same `IApiKeyVerifier` from the shared `ZB.MOM.WW.Auth.ApiKeys` library; the verifier strips the optional `Bearer ` prefix and performs the same peppered-HMAC constant-time verification regardless of which header was used.
### Request Format
- Content-Type: `application/json`.
@@ -130,7 +134,7 @@ API method scripts are compiled at central startup — all method definitions ar
- **Every request — success or failure — emits one `ApiInbound.Completed` row** to `ICentralAuditWriter` from request middleware before the HTTP response is flushed. The row captures the API key **name** (never the key material), remote IP, user-agent, response status, duration, and the request/response bodies. Bodies are captured in full up to `AuditLog:InboundMaxBytes` (default 1 MiB); `PayloadTruncated = 1` only when that ceiling is hit. Header redaction and per-target body redactors still apply (see Component-AuditLog.md, Payload Capture Policy). This supersedes the earlier failures-only stance: operational API traffic is now part of the centralized audit log, so configuration changes and call activity share a single retention/query surface.
- Script execution errors (500 responses) remain captured on the same `ApiInbound.Completed` row (response status + error fields) rather than emitting a separate failure-only event.
- **Fail-soft semantics.** The audit write is synchronous (inline before the response is flushed), but failures are caught: a write that throws is logged and increments `CentralAuditWriteFailures` (see Health Monitoring #11) and the request still returns its normal HTTP response. A failed audit append never turns a successful API call into an error returned to the caller.
- **Fail-soft semantics (fire-and-forget).** The audit write is **fire-and-forget** (`InboundAPI-018`): `WriteAsync` is called without `await` so the user-facing HTTP response is never blocked or delayed by the audit path. Asynchronous faults are observed via a `ContinueWith` continuation that logs at Warning and increments `CentralAuditWriteFailures` (see Health Monitoring #11) rather than being silently dropped. A failed audit append never turns a successful API call into an error returned to the caller.
- No rate limiting — this is a private API in a controlled industrial environment with a known set of callers. Misbehaving callers are handled operationally (disable the API key).
## Request Flow
@@ -216,12 +220,13 @@ Inbound API scripts **cannot** call shared scripts directly — shared scripts a
## Authentication Details
- API key is passed via the `X-API-Key` HTTP header.
- The API key token is accepted from **either** the `Authorization: Bearer <token>` header (preferred) **or** the `X-API-Key: <token>` header (alternate). `Authorization` takes precedence when both are present.
- The token format is `sbk_<keyId>_<secret>`. Both header forms are verified by the same `IApiKeyVerifier` from `ZB.MOM.WW.Auth.ApiKeys`.
- The system validates:
1. The key exists in the configuration database.
2. The key is enabled.
3. The key is in the approved list for the requested method.
- Failed authentication returns an appropriate HTTP error (401 Unauthorized or 403 Forbidden).
1. The token is well-formed and the key ID exists in the key store.
2. The key is enabled (not revoked).
3. The key's provisioned scopes include the requested method name (case-sensitive).
- Failed authentication returns an appropriate HTTP error (401 Unauthorized for invalid/missing credentials; 403 Forbidden for a valid key not approved for the method). For enumeration-safety, both "method not found" and "key not in scope" return 403 with an identical body.
## Error Handling
@@ -246,5 +251,5 @@ Inbound API scripts **cannot** call shared scripts directly — shared scripts a
- **External Systems**: Call the API with API keys.
- **Communication Layer**: API method scripts use this to reach sites.
- **Site Runtime (Instance Actors, Script Actors)**: Routed calls execute on site Instance Actors via their Script Actors.
- **Central UI**: Admin manages API keys; Design manages method definitions.
- **Central UI**: Administrator manages API keys; Designer manages method definitions.
- **Configuration Database (via IAuditService)**: Configuration changes are audited.