fix(integrations): allow listing Slack DM/user remote dirs within event scope#186
Conversation
…nt scope Slack DM and per-user message paths (/slack/users/*/messages/** and /slack/channels/D*/**) are delivered as events when DM listening is enabled, but they are not part of the canonical channel mount paths. The list-remote-dir / read-remote-file scope guards only consulted the channel mount set, so when the renderer opened a delivered DM/user event it threw "Integration remote directory is outside this project integration scope". Recognize those exact event-subscribed DM roots and permit list/read of them only when DM listening is on for a visible Slack integration — without widening scope to non-DM channels. - Add isSlackDmListablePath() pure predicate for /slack/users/** and /slack/channels/D*/** (Slack's DM channel-id convention). - Export slackListenDms() and gate the predicate behind slackDmListingEnabledForProject() so the relaxation applies only when DM listening is enabled. - Apply the gate in readRemoteFile, listRemoteDirectory, and the directory entry filter. - Regression tests: vitest covers readRemoteFile on a /slack/users path (allowed with DM on, rejected with DM off); node tests cover the pure predicate including D* DM channels and non-DM rejection. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Your free trial PR review limit of 300 PRs has been reached. Please upgrade your plan to continue using CodeAnt AI. |
|
Caution Review failedPull request was closed or merged during review 📝 WalkthroughWalkthroughThis PR extends the integrations manager to permit access to Slack direct-message and user-message paths when a project's Slack integration has DM listening enabled, using a new path predicate and project-level DM configuration check applied to file reads and directory listings. ChangesSlack DM Access Control
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
pr-reviewer could not complete review for #186 in AgentWorkforce/pear. |
There was a problem hiding this comment.
Code Review
This pull request enables listing and reading Slack direct-message (DM) and per-user message paths when DM listening is enabled, even if they fall outside the canonical channel mount paths. This is implemented via a new isSlackDmListablePath helper and checking the project's DM listening status. The review feedback suggests simplifying the path segment parsing in isSlackDmListablePath by removing a redundant trailing slash replacement.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| // non-DM channels. The "D" prefix on a channel segment is Slack's DM channel | ||
| // convention, which a plain root path cannot express. | ||
| export function isSlackDmListablePath(remotePath: string): boolean { | ||
| const segments = (remotePath || '').trim().replace(/\/+$/, '').split('/').filter(Boolean) |
There was a problem hiding this comment.
The .replace(/\/+$/, '') call is redundant because .split('/') followed by .filter(Boolean) already discards any empty segments, including those resulting from trailing slashes. Removing it simplifies the code and slightly improves performance.
| const segments = (remotePath || '').trim().replace(/\/+$/, '').split('/').filter(Boolean) | |
| const segments = (remotePath || '').trim().split('/').filter(Boolean) |
|
ℹ️ pr-reviewer: review only — no file changes were applied to the PR (nothing to commit after review). The notes below are advisory and were not pushed. pr-reviewer could not complete review for #186 in AgentWorkforce/pear. |
|
pr-reviewer could not complete review for #186 in AgentWorkforce/pear. |
|
ℹ️ pr-reviewer: review only — no file changes were applied to the PR (nothing to commit after review). The notes below are advisory and were not pushed. pr-reviewer could not complete review for #186 in AgentWorkforce/pear. |
|
pr-reviewer could not complete review for #186 in AgentWorkforce/pear. |
|
ℹ️ pr-reviewer: review only — no file changes were applied to the PR (nothing to commit after review). The notes below are advisory and were not pushed. pr-reviewer could not complete review for #186 in AgentWorkforce/pear. |
|
pr-reviewer could not complete review for #186 in AgentWorkforce/pear. |
|
ℹ️ pr-reviewer: review only — no file changes were applied to the PR (nothing to commit after review). The notes below are advisory and were not pushed. pr-reviewer could not complete review for #186 in AgentWorkforce/pear. |
|
pr-reviewer could not complete review for #186 in AgentWorkforce/pear. |
|
ℹ️ pr-reviewer: review only — no file changes were applied to the PR (nothing to commit after review). The notes below are advisory and were not pushed. pr-reviewer could not complete review for #186 in AgentWorkforce/pear. |
|
pr-reviewer could not complete review for #186 in AgentWorkforce/pear. |
|
ℹ️ pr-reviewer: review only — no file changes were applied to the PR (nothing to commit after review). The notes below are advisory and were not pushed. pr-reviewer could not complete review for #186 in AgentWorkforce/pear. |
Symptom
Inbox error:
It fired whenever a Slack DM / per-user message event arrived (e.g.
.integrations/slack/users/U0ADJH4P83T/messages/<ts>/meta.json) and the renderer tried to list or read that remote directory.Root cause
integrations:list-remote-dir→IntegrationsManager.listRemoteDirectory(andreadRemoteFile) gate the requested path againstlistableRemoteMountPaths(), which is the discovery path + canonical channel mount paths for each visible integration.SLACK_DM_EVENT_GLOBS=/slack/channels/D*/**,/slack/users/*/messages/**(seeintegration-event-bridge.ts).Fix
Recognize the exact event-subscribed Slack DM roots and permit list/read of them only when DM listening is on for a visible Slack integration — without widening scope to non-DM channels.
isSlackDmListablePath()— pure predicate matching/slack/users/**and/slack/channels/D*/**(Slack'sD-prefixed DM channel-id convention, which a plain root path can't express).slackListenDms()is now exported;slackDmListingEnabledForProject()gates the predicate so the relaxation applies only when DM listening is actually enabled.readRemoteFile,listRemoteDirectory, and the directory-entry filter. The existing mount-path guards are otherwise unchanged.Tests
integrations.test.ts): reading/slack/users/<id>/messages/<ts>/meta.jsonsucceeds with DM listening on, and is still rejected with DM listening off (proving the gate is scoped to the flag, not a blanket loosening).integration-remote-paths.test.ts): unit coverage forisSlackDmListablePath, includingD*DM channels and rejection of non-DM Slack / other-provider / discovery paths.integration-event-bridgesuite (75) andintegrationssuite (30) pass.🤖 Generated with Claude Code