Skip to content

feat: add Slack as an installable connector - #1537

Merged
lilyshen0722 merged 18 commits into
mainfrom
kai/slack-installable-backend
Sep 4, 2026
Merged

lilyshen0722 merged 18 commits into
mainfrom
kai/slack-installable-backend

Conversation

@lilyshen0722

Copy link
Copy Markdown
Contributor

Summary

  • add encrypted per-workspace Slack connector secrets with rotation and rewrap tooling
  • seed Slack as a user-scoped installable; make event dispatch provider-generic while retaining Telegram-only legacy fallback
  • add owner-confirmed Slack OAuth, signed Events/commands routes, DM bridge, receipt dedupe, and scheduled recovery

Verification

  • cd backend && npx jest --runInBand __tests__/unit/routes/slackOAuth.installables.test.js __tests__/unit/routes/slack.webhook.signature.test.js __tests__/unit/services/slackBridgeService.test.js __tests__/unit/services/installableInstallationService.test.js __tests__/unit/services/slackEventReceiptService.test.js __tests__/unit/services/installableEventHandlers.test.js __tests__/unit/services/connectorSecrets.test.js __tests__/unit/services/installableReconciler.schedule.test.js (43 passed)
  • cd backend && npm run tsc:check
  • scoped ESLint on touched production files

Follow-up / operator setup

Comment thread backend/routes/webhooks/slack.ts Fixed
Comment thread backend/routes/webhooks/slack.ts Fixed
Comment thread backend/routes/webhooks/slack.ts Fixed
Comment thread backend/routes/webhooks/slack.ts Fixed
Comment thread backend/routes/webhooks/slack.ts Fixed
Comment thread backend/routes/webhooks/slack.ts Fixed
Comment thread backend/routes/installables.ts Fixed
Comment thread backend/routes/installables.ts Fixed
Comment thread backend/routes/installables.ts Fixed
Comment thread backend/routes/installables.ts Fixed
@samxu01
samxu01 force-pushed the kai/slack-installable-backend branch 2 times, most recently from f3b864d to 01bce2a Compare September 4, 2026 13:44
samxu01 pushed a commit that referenced this pull request Sep 4, 2026
… time — no digest

Matches #1537 b801a6e. The hashed cookie was CodeQL's js/insufficient-password-hash
(#1779) on every digest variant, and the hash defended against nothing: a row reader
already holds state in the same document. Confirm is the wall.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@samxu01
samxu01 force-pushed the kai/slack-installable-backend branch from 54256df to 35e79a3 Compare September 4, 2026 19:04
@samxu01
samxu01 force-pushed the kai/slack-installable-backend branch from d1b31d8 to 18b4d46 Compare September 4, 2026 20:04
lilyshen0722 added a commit that referenced this pull request Sep 4, 2026
…(TASK-006) (#1535)

* docs(plans): Slack as the second installable connector — design note (TASK-006)

Telegram with two substitutions: the OAuth state is the connect code and the
callback is the enable command; the per-workspace bot token makes ADR-025 D6's
secret reference a prerequisite. Everything else in #1527/#1531 is reused.

* docs(plans): Slack note — the #1527 invariants checked one by one, and the one secret that enters outside the activation CAS

* docs(plans): Slack note — the callback proves a Slack identity, not the right one: session nonce + confirm-in-Commonly before any bind routes (Vera)

* docs(plans): Slack note — the one-write window after the exchange, and why token rotation stays off

* docs(plans): Slack note — pending-bind expiry enforced at Confirm; reconciler goes on the scheduler (Vera)

* docs(plans): Slack note — cite Slack's OAuth and rotation docs; drop the uncited same-token claim from the crash path

* docs(plans): Slack note — the dropped-exchange log line names the workspace (Vera)

* docs(plans): Slack note — shared event_id receipts (rollouts run two processes) and a key ring with a re-wrap path (Vera)

* docs(plans): Slack note — the event receipt is a claim with state; stale processing is taken over by CAS (Vera)

* docs(slack): the OAuth nonce is stored plain and compared in constant time — no digest

Matches #1537 b801a6e. The hashed cookie was CodeQL's js/insufficient-password-hash
(#1779) on every digest variant, and the hash defended against nothing: a row reader
already holds state in the same document. Confirm is the wall.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
@lilyshen0722
lilyshen0722 merged commit 8300fb8 into main Sep 4, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants