feat: phase 1c/1d - Connect Slack (OAuth), SlackApi, readiness and health, templates, PHI guard #5

Merged
KofTwentyTwo merged 4 commits from feature/api-connect into develop 2026-10-14 17:37:42 +00:00
KofTwentyTwo commented 2026-10-14 17:28:51 +00:00 (Migrated from github.com)

Phases 1c and 1d of docs/DESIGN.md. It's stacked on #2, so review after #2 merges; until then the diff includes #2's commits.

What's in it

  • Connect Slack (DESIGN 3.3).
    • The OAuth state is signed and expires. It's bound to the user, tenant and session, and verified without server state, so the callback can land on any pod; each pod also keeps a replay set.
    • The callback is a route through the Javalin extension, which the host provides.
    • Tokens are encrypted and bound to their rows.
    • Install for my organization needs slack.workspace.install.
    • Disconnect (calls auth.revoke) and Uninstall are record actions with Review and Result.
  • com.kingsrook.qbits.slack.api.SlackApi, which mirrors EmailApi:
    • send, sendOnce, reply and update;
    • lookups, readiness, connectionsFor, listTargets and ensureTemplate;
    • projections never carry tokens, bodies or variables.
  • Readiness checks the app, the workspace (auth.test and scopes), the connection, registered channels and the outbox. There's a Check readiness action and a scheduled refresh. The health check is registered only when qqq-middleware-health is present (an optional dependency). It reports deployment-level status, without calling Slack per probe.
  • Templates.
    • The variable language is the same as qbit-email's.
    • Slack escaping blocks mention injection.
    • Block Kit variables are allowed in string positions only, within the size and block limits.
    • Built-in templates: notification, digest and delivery.
  • PHI guard.
    • Classified variables are tokenized or refused, and the refusal names the variable.
    • SSN and MRN patterns are refused.
    • SECURITY notices send the title and link only.
    • STAND-IN(core=QRun-IO/qqq#1142, removeBy=4.1.0-RC.8): RC.6 lacks ClassifiedValueTokens.

Tests

verify is green locally: 131 tests, 92.3% instruction coverage and 98.9% of classes. The tests cover:

  • the PHI canary CANARY-PHI-7f3a, sent through a template variable, a bound field, a linked record, free text, SECURITY and update; it is absent from every slack_* column, every fake-server request and the logs;
  • OAuth tampering, wrong owner or tenant, expiry, and replay, including the other-pod case;
  • readiness negatives;
  • template constructs and budgets;
  • the API projections, and listTargets tenant isolation.

Implemented by Codex from a brief I wrote. I reviewed it and fixed the multi-pod OAuth state, the provided scope and the test depth before committing.

🤖 Generated with Claude Code

Phases 1c and 1d of `docs/DESIGN.md`. It's stacked on #2, so review after #2 merges; until then the diff includes #2's commits. ## What's in it - **Connect Slack** (DESIGN 3.3). - The OAuth state is signed and expires. It's bound to the user, tenant and session, and verified without server state, so the callback can land on any pod; each pod also keeps a replay set. - The callback is a route through the Javalin extension, which the host provides. - Tokens are encrypted and bound to their rows. - **Install for my organization** needs `slack.workspace.install`. - **Disconnect** (calls `auth.revoke`) and **Uninstall** are record actions with Review and Result. - **`com.kingsrook.qbits.slack.api.SlackApi`**, which mirrors `EmailApi`: - `send`, `sendOnce`, `reply` and `update`; - lookups, `readiness`, `connectionsFor`, `listTargets` and `ensureTemplate`; - projections never carry tokens, bodies or variables. - **Readiness** checks the app, the workspace (auth.test and scopes), the connection, registered channels and the outbox. There's a **Check readiness** action and a scheduled refresh. The health check is registered only when `qqq-middleware-health` is present (an optional dependency). It reports deployment-level status, without calling Slack per probe. - **Templates.** - The variable language is the same as qbit-email's. - Slack escaping blocks mention injection. - Block Kit variables are allowed in string positions only, within the size and block limits. - Built-in templates: `notification`, `digest` and `delivery`. - **PHI guard.** - Classified variables are tokenized or refused, and the refusal names the variable. - SSN and MRN patterns are refused. - SECURITY notices send the title and link only. - `STAND-IN(core=QRun-IO/qqq#1142, removeBy=4.1.0-RC.8)`: RC.6 lacks ClassifiedValueTokens. ## Tests `verify` is green locally: 131 tests, 92.3% instruction coverage and 98.9% of classes. The tests cover: - the PHI canary `CANARY-PHI-7f3a`, sent through a template variable, a bound field, a linked record, free text, SECURITY and update; it is absent from every `slack_*` column, every fake-server request and the logs; - OAuth tampering, wrong owner or tenant, expiry, and replay, including the other-pod case; - readiness negatives; - template constructs and budgets; - the API projections, and `listTargets` tenant isolation. Implemented by Codex from a brief I wrote. I reviewed it and fixed the multi-pod OAuth state, the provided scope and the test depth before committing. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.