Skip to content

improvement(slack): merge slack_v2 auth into one credential picker for accounts and custom bots#5800

Merged
TheodoreSpeaks merged 3 commits into
stagingfrom
feat/simplify-slack-v2
Jul 21, 2026
Merged

improvement(slack): merge slack_v2 auth into one credential picker for accounts and custom bots#5800
TheodoreSpeaks merged 3 commits into
stagingfrom
feat/simplify-slack-v2

Conversation

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator

Summary

  • slack_v2's authMethod dropdown is gone — one credential picker (credentialKind: 'any') lists Slack OAuth accounts and custom bots together in a grouped dropdown, with a connect action per group; the credential's kind is resolved server-side from credential.type
  • slack_oauth trigger is custom-bot-only: removed the hidden appType field and the sim-mode OAuth picker, event dropdown is the full static catalog, deploy routing always uses routingKey = botCredentialId (native Sim-app path removed for now — ingest route stays for a future ship)
  • collapsed the ~13 dependsOn: { all: ['authMethod'], ... } gates to ['credential'] and dropped the dead sim-event constants
  • added customBotCredential/manualBotCredential to CREDENTIAL_SUBBLOCK_IDS so credential deletion cleans trigger references
  • no value migration: slack_v2 is preview-gated; old bot-auth action blocks fail loudly at required-field validation and re-pick from the merged dropdown

Type of Change

  • Improvement

Testing

Tested manually on a live canvas (merged picker groups + both connect actions, trigger shows no App Type, stale authMethod ignored on load). lint, check:api-validation:strict, typecheck, and slack/deploy/serializer test suites pass; added deploy tests for the bot-credential canonical collapse (branch previously untested).

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

🤖 Generated with Claude Code

@vercel

vercel Bot commented Jul 21, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Jul 21, 2026 7:00pm

Request Review

@cursor

cursor Bot commented Jul 21, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Webhook deploy routing for Slack triggers is simplified (Sim OAuth path removed), which can break existing sim-mode trigger configs outside preview-gated slack_v2; credential picker and deploy changes touch auth-adjacent workflow configuration.

Overview
slack_v2 drops the authMethod / raw bot-token / separate custom-bot fields in favor of one credentialKind: 'any' picker that groups Sim OAuth accounts and custom bots, with separate connect actions and optional credentialLabels copy.

The shared CredentialSelector gains merged-mode combobox groups (ComboboxOptionGroup), searchable non-editable UX, and a single ConnectServiceAccountModal path (including Slack bot onCreated); the dedicated custom-bot kind and inline ConnectSlackBotModal usage are removed.

slack_oauth is custom-bot-only: hidden appType, Sim OAuth trigger credential, and sim-event gating are removed; the event list is the full catalog; deploy always validates botCredential, sets routingKey to the bot credential id, and no longer supports the native Sim-app OAuth routing branch.

Supporting updates: subblock dependsOn gates move from authMethod to credential for v2; trigger bot credential ids are included in credential deletion cleanup; deploy tests cover botCredential canonical collapse.

Reviewed by Cursor Bugbot for commit 19769ef. Bugbot is set up for automated code reviews on this repo. Configure here.

@greptile-apps

greptile-apps Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR combines Slack v2 authentication into one credential flow. The main changes are:

  • Groups Slack OAuth accounts and custom bots in one credential picker.
  • Makes the Slack OAuth trigger use custom-bot credentials only.
  • Routes custom-bot events by credential ID during deployment.
  • Cleans deleted custom-bot references from saved workflows.

Confidence Score: 5/5

This looks safe to merge.

  • No blocking issues found in the changed code.

Important Files Changed

Filename Overview
apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/credential-selector/credential-selector.tsx Adds grouped selection and separate connection actions for Slack OAuth accounts and custom bots.
apps/sim/blocks/blocks/slack.ts Replaces Slack v2 authentication fields with one merged credential input.
apps/sim/triggers/slack/oauth.ts Makes the Slack trigger custom-bot-only and exposes the full event catalog.
apps/sim/lib/webhooks/deploy.ts Validates custom-bot credentials and routes deployed Slack triggers by credential ID.
apps/sim/lib/workflows/persistence/utils.ts Adds custom-bot fields to credential-reference cleanup.

Reviews (4): Last reviewed commit: "improvement(slack): move provider-specif..." | Re-trigger Greptile

Comment thread apps/sim/lib/webhooks/deploy.ts
@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@greptile

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 3669a0a. Configure here.

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@greptile

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 85f40a4. Configure here.

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@greptile

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@cursor review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 19769ef. Configure here.

@TheodoreSpeaks
TheodoreSpeaks merged commit 5be35b5 into staging Jul 21, 2026
20 checks passed
@TheodoreSpeaks
TheodoreSpeaks deleted the feat/simplify-slack-v2 branch July 21, 2026 19:15
TheodoreSpeaks added a commit that referenced this pull request Jul 22, 2026
…al connect hook

The workflow-editor credential selector (from #5800's merged picker) resolved
its service-account setup surface inline and mounted the modal with NO preview
gate — so a `credentialKind: 'service-account'` picker would offer a custom-bot
setup even when slack_v2 is preview-gated off, the leak the integrations page
and chat already guard against.

Route it through the shared useServiceAccountConnectTarget hook (the same
resolver chat and the integrations page use): suppress the setup action when
`hidden`, and use the hook's vendor-accurate label ("Add private app token",
"Set up a custom bot") as the default connect-row copy. Existing service
accounts stay selectable; the per-block `credentialLabels.serviceAccountConnect`
override still wins. One resolver now backs all three SA connect surfaces.
TheodoreSpeaks added a commit that referenced this pull request Jul 22, 2026
The add-block skill had no mention of credentialKind — the mechanism (#5800)
that controls whether an oauth-input offers OAuth, service-account, or a merged
picker — and its example was a plain oauth-input mislabeled "Service Account".
Documents the three credentialKind modes, that a default oauth-input already
lets users select an existing service account (they fold in), and the
credentialLabels / allowServiceAccounts companions. Regenerates the .claude and
.cursor projections.
TheodoreSpeaks added a commit that referenced this pull request Jul 22, 2026
* feat(copilot): add service_account_get_setup_link handler

Resolves a loosely-specified integration name to the catalog slug whose
detail page mounts ConnectServiceAccountModal, and returns
`/integrations/{slug}?connect=service-account`. The agent surfaces it via
the existing <credential type="link"> tag, so the user gets a Connect
button and supplies the key material in Sim's own form — the agent never
handles the secret.

Exact matches beat fuzzy ones so a caller naming a specific service lands
on it (gmail stays Gmail rather than collapsing to Drive), and family
names resolve through an explicit canonical map rather than to whichever
member sorts first.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Phx1MLjf8Ui3M3VpwisZds

* fix(copilot): reject service account ids in oauth_get_auth_link

The fuzzy provider match falls back to substring containment, so
`slack-custom-bot` contains `slack` and resolved to the Slack OAuth
service. The tool then returned a personal-OAuth authorize URL and
reported success — a user who asked for a shared custom bot got a
Connect button that linked their own account instead. Every service
account id degraded this way (notion-, salesforce-, zoom-, linear-),
always silently.

Guard runs before the fuzzy pass and points at
service_account_get_setup_link. Keys off the id being a service-account
id, not off the integration offering one, so `slack` and `notion` still
resolve for OAuth.

Moves the narrowing predicate out of the integration catalog module so
callers that need only the predicate skip the integrations.json load and
the OAUTH_PROVIDERS walk.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Phx1MLjf8Ui3M3VpwisZds

* feat(copilot): open the service account form in-chat instead of linking out

The tool handed back a /integrations/{slug}?connect=service-account URL,
so accepting the agent's offer navigated away from the conversation that
asked for the credential. Adds a `service_account` credential tag that
mounts ConnectServiceAccountModal over the chat; setup_url stays as the
headless/MCP fallback.

The tag carries a provider and no value — the secret is typed into Sim's
own form and never enters the transcript — so the validator gets a branch
alongside secret_input/sim_key rather than falling through to the
value-required check.

Extracts useServiceAccountConnectTarget so the chat and the integrations
page share one source of truth for the connect label and the preview
gate. Custom Slack bots ride the slack_v2 flag; without the shared gate
the chat would have surfaced a setup form the integrations page hides.

Modal is lazy-loaded off the deep path (not the barrel) to keep three
provider-specific setup forms out of the chat's initial chunk.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Phx1MLjf8Ui3M3VpwisZds

* fix(copilot): gate service account tool on the same preview flag as the UI

The in-chat connect button hides itself when the provider's gating block
is preview-hidden (a custom Slack bot needs slack_v2). The tool didn't
check this, so it returned success for slack-custom-bot even when slack_v2
was preview-gated off — the agent said "here's the setup form" and the
button silently rendered nothing, leaving the user with no form at all.

Adds getServiceAccountGatingBlockType as the single source for the
provider→gating-block mapping, consumed by both the tool (server-side, via
getBlockVisibilityForCopilot) and the connect hook (client overlay). When
the gating block is hidden the tool now fails with a fall-back-to-OAuth
message instead of promising an invisible form.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Phx1MLjf8Ui3M3VpwisZds

* feat(copilot): make the tool own service-account discovery

Removes the VFS auth-metadata exposure and returns connectNoun from the
service_account_get_setup_link result instead. The VFS aggregate was a
second, viewer-independent source of truth that couldn't agree with the
per-viewer preview gate (it always hid slack-custom-bot, even for viewers
with slack_v2 revealed, while the tool accepts it for them). The tool now
resolves the provider, applies the per-viewer gate, and returns either the
in-chat button + connectNoun or a fall-back-to-oauth error — one source of
truth. connectNoun stays DRY via getServiceAccountConnectNoun, shared with
the connect-button label.

* feat(copilot): make service-account setup a direct tag, no tool

The agent now emits the service_account credential tag directly from
intent — like secret_input — instead of round-tripping through a tool.
Removes service_account_get_setup_link (handler, registration, display
title, Go tool def) and restores auth.serviceAccount as the VFS discovery
field so the agent knows which providers support a service account.

The link-vs-tag distinction was the wrong axis: only oauth needs a tool,
because its button carries a minted URL that can't be reconstructed. The
service_account tag carries just a provider name the agent already knows,
so it needs no tool — discovery lives in the VFS (auth.serviceAccount,
GA-only, so slack's preview-gated custom bot is never proactively
offered), and the per-viewer gate lives in the renderer, which renders
nothing when a provider isn't available for the viewer (no OAuth
fallback — a shared credential and a personal one are different intents).

oauth_get_auth_link's service-account-id guard now points at the tag.

* feat(copilot): support service-account reconnect from chat

Reconnect had no service-account path — it required oauth_get_auth_link
and a link tag for every repair, so rotating a workspace service account
either errored or pushed the user through OAuth.

The service_account tag now takes an optional credentialId; when present
the renderer opens the modal in reconnect mode (rotates the secret on that
credential in place, id preserved) and labels the button "Reconnect X".
credentials.json now carries each credential's type (oauth vs
service_account) so the agent can branch: service accounts reconnect via
the tag + credentialId, oauth via oauth_get_auth_link as before.

* fix(copilot): coherent service-account rejection in oauth_get_auth_link

Review round on #5786:
- The service-account-id guard threw into the generic catch, which
  overwrote its recovery hint with a "connect manually" message and a
  workspace oauth_url — contradictory signals. It now returns a coherent
  failure directly, before the try, with no oauth_url.
- Normalize spaces/underscores before the check so a readable form
  ("slack custom bot", "google service account") is caught too, not
  passed to the fuzzy OAuth resolver.
- Remove listServiceAccountIntegrationNames — dead after the tool was
  removed (its only caller was the deleted handler's error copy).

* fix(copilot): service-account discovery must un-gate after the block GAs

Review round on #5786: describeServiceAccountForOAuthProvider used
`getBlock(...)?.preview ?? true`, which treats a GA'd gating block — one
that dropped its `preview` flag, exactly slack_v2's documented migration —
as still gated, so the custom bot would stay omitted from VFS discovery
forever after GA even though the UI shows it. Reuse the canonical
isHiddenUnder(null, block) predicate instead, so a non-preview block is
visible. Adds service-account-gate.test.ts covering preview → omit, GA →
include, and missing → fail-closed with a mocked getBlock (the block
registry is globally stubbed, so the real slack_v2 preview flag isn't
observable through serializeIntegrationSchema).

* fix(copilot): align SA resolver normalization and reject blank credentialId

Review round on #5786:
- resolveServiceAccountIntegration only lowercased/trimmed, but the
  oauth_get_auth_link guard normalizes spaces/underscores to hyphens
  before rejecting a service-account id and steering the agent to a
  service_account tag. The chat renderer then couldn't resolve those same
  readable forms ("slack custom bot", "notion_service_account") and
  rendered nothing. Apply the same normalization to the id lookups (raw
  query still used for display-name matches).
- service_account tag validation rejected a blank provider but allowed a
  whitespace-only credentialId, which is truthy — the renderer took the
  reconnect path and tried to rotate a non-existent credential. Reject a
  blank/whitespace credentialId.

* refactor(credentials): route the editor SA picker through the canonical connect hook

The workflow-editor credential selector (from #5800's merged picker) resolved
its service-account setup surface inline and mounted the modal with NO preview
gate — so a `credentialKind: 'service-account'` picker would offer a custom-bot
setup even when slack_v2 is preview-gated off, the leak the integrations page
and chat already guard against.

Route it through the shared useServiceAccountConnectTarget hook (the same
resolver chat and the integrations page use): suppress the setup action when
`hidden`, and use the hook's vendor-accurate label ("Add private app token",
"Set up a custom bot") as the default connect-row copy. Existing service
accounts stay selectable; the per-block `credentialLabels.serviceAccountConnect`
override still wins. One resolver now backs all three SA connect surfaces.

* docs(add-block): document credentialKind and the service-account picker

The add-block skill had no mention of credentialKind — the mechanism (#5800)
that controls whether an oauth-input offers OAuth, service-account, or a merged
picker — and its example was a plain oauth-input mislabeled "Service Account".
Documents the three credentialKind modes, that a default oauth-input already
lets users select an existing service account (they fold in), and the
credentialLabels / allowServiceAccounts companions. Regenerates the .claude and
.cursor projections.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

1 participant