Skip to content

fix(slack): allow channel-id reads for name-allowlisted channels#95313

Merged
steipete merged 5 commits into
openclaw:mainfrom
jontsai:fix/slack-read-allowlist-channel-name-public
Jul 4, 2026
Merged

fix(slack): allow channel-id reads for name-allowlisted channels#95313
steipete merged 5 commits into
openclaw:mainfrom
jontsai:fix/slack-read-allowlist-channel-name-public

Conversation

@jontsai

@jontsai jontsai commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

Slack read actions receive channel IDs, while operators may intentionally configure channel access by human-readable name with dangerouslyAllowNameMatching: true. Before this fix, read messages, file downloads, pin lists, and reaction lists rejected those otherwise-allowed targets before Slack's trusted channel name could be considered.

Why This Change Was Made

When direct ID/wildcard policy cannot authorize a read and name matching is explicitly enabled, the Slack action runtime now resolves the target through conversations.info and re-evaluates the same channel policy with the returned name.

The final implementation keeps the authorization boundary narrow:

  • Explicit channel-ID denials take precedence and never trigger name fallback.
  • Generic tool context such as Channel: "slack" is never trusted as a room name.
  • Name resolution uses the same bot or user credential that performs the protected read, matching Slack's permission model.
  • Mutable channel names and transient lookup failures are not cached by this authorization path.
  • Missing names, lookup failures, and non-matching names fail closed before the protected read.

User Impact

Operators who opted into Slack channel-name matching can again use read-like actions against allowed channels addressed by ID. Disallowed channels remain blocked, including explicit ID denials and non-matching targets. Config shape, default policy, write actions, and users who do not enable name matching are unchanged.

Evidence

  • Contributor live proof on Slack: an allowed channel-ID read succeeded against a name-keyed allowlist while a different channel remained denied; see the redacted runtime proof and the before/after screenshots retained in this PR's history.
  • Slack contract: conversations.info returns the conversation name according to the presented token's scopes and access; both bot and user tokens are supported.
  • Focused final-head proof: 135 tests passed across Slack action runtime, direct API helper, threading context, channel typing, and action dispatch.
  • Fresh autoreview after maintainer hardening: clean; no accepted/actionable findings (patch is correct, confidence 0.96).
  • Blacksmith Testbox tbx_01kwpvwqzx81eqn3ck8kny9yqj, Actions run 28710832081, exit 0: focused tests, full production build, extension and extension-test type checks, lint, database/media guards, and runtime cycle checks.
  • git diff --check passed.

Live-proof scope: the contributor's real Slack run exercised the same conversations.info authorization behavior before maintainer hardening. The final head additionally changes credential alignment and cache behavior; those refinements have exact mocked-network, type, build, and Testbox coverage but were not repeated against a live workspace.

@openclaw-barnacle openclaw-barnacle Bot added channel: slack Channel integration: slack size: S triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. labels Jun 20, 2026
@clawsweeper

clawsweeper Bot commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed July 4, 2026, 12:00 PM ET / 16:00 UTC.

Summary
The PR updates Slack read-like action authorization to resolve Slack channel IDs through Slack before applying existing name allowlists, and its branch also contains duplicate extended-stable release commits whose non-Slack file contents already match current main.

PR surface: Source +49, Tests +973, Docs +108, Config +93, Other +499. Total +1722 across 20 files.

Reproducibility: yes. Current main source denies a Slack channel-ID read when the allowlist is keyed only by channel name, and the contributor supplied redacted live Slack proof showing the failure and the after-fix allowed/denied outcomes.

Review metrics: 2 noteworthy metrics.

  • Protected Slack reads: 4 read-like action paths gated. readMessages, reactions, downloadFile, and listPins now share the same pre-read authorization fallback.
  • Current-main duplicate content: 14 non-Slack files match current main blobs. The workflow/docs/script files inflate PR stats but do not add a net content delta against current main.

Stored data model
Persistent data-model change detected: migration/backfill/repair: docs/ci.md, serialized state: scripts/openclaw-npm-publish.sh, serialized state: test/scripts/openclaw-npm-publish.test.ts, vector/embedding metadata: test/scripts/openclaw-npm-publish.test.ts. Confirm migration or upgrade compatibility proof before merge.

Merge readiness
Overall: 🦞 diamond lobster
Proof: 🦞 diamond lobster
Patch quality: 🦞 diamond lobster
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Risk before merge

  • [P1] This PR intentionally changes a Slack authorization boundary: opted-in name matching can now authorize a channel-ID read after a same-token conversations.info lookup, so maintainers should explicitly accept that trust model before landing.

Maintainer options:

  1. Land with boundary acceptance (recommended)
    Maintainers can land the current PR if they accept Slack conversations.info as the same-token name source for the existing dangerouslyAllowNameMatching path.
  2. Require narrower boundary proof
    If maintainers want a lower-risk merge, ask for additional live or mocked proof across every read-like action before landing.

Next step before merge

  • No automated repair is needed; the remaining action is a maintainer land or hold decision for a Slack read-authorization security boundary change.

Security
Cleared: No concrete security or supply-chain defect was found; the remaining concern is maintainer acceptance of the intended Slack authorization-boundary change.

Review details

Best possible solution:

Land the Slack runtime fix after maintainer acceptance of the same-token conversations.info fallback for opted-in name matching and exact-head checks finish green.

Do we have a high-confidence way to reproduce the issue?

Yes. Current main source denies a Slack channel-ID read when the allowlist is keyed only by channel name, and the contributor supplied redacted live Slack proof showing the failure and the after-fix allowed/denied outcomes.

Is this the best way to solve the issue?

Yes. The Slack action runtime is the narrow owner because it can authorize immediately before protected Slack read API calls using the same read credential; the previous context-name shortcut was removed so generic Channel:"slack" cannot authorize a room.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against e643828af6fa.

Label changes

Label changes:

  • add rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • remove rating: 🐚 platinum hermit: Current PR rating is rating: 🦞 diamond lobster, so this older rating label is no longer current.

Label justifications:

  • P1: The PR repairs a real Slack workflow regression in allowlisted read actions for users who opted into name matching.
  • merge-risk: 🚨 security-boundary: The patch changes the authorization decision for Slack read actions before provider API reads.
  • rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (logs): The PR includes redacted live Slack runtime output showing a name-allowlisted channel-ID read succeeding and a different channel remaining denied, with final hardening covered by focused tests and Testbox proof.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR includes redacted live Slack runtime output showing a name-allowlisted channel-ID read succeeding and a different channel remaining denied, with final hardening covered by focused tests and Testbox proof.
Evidence reviewed

PR surface:

Source +49, Tests +973, Docs +108, Config +93, Other +499. Total +1722 across 20 files.

View PR surface stats
Area Files Added Removed Net
Source 3 67 18 +49
Tests 8 980 7 +973
Docs 3 129 21 +108
Config 3 127 34 +93
Generated 0 0 0 0
Other 3 521 22 +499
Total 20 1824 102 +1722

What I checked:

  • Repository policy read: Read the root and scoped AGENTS.md files for the touched Slack plugin, scripts, docs, and tests before review; the guidance made Slack authorization, dependency contracts, and workflow/supply-chain surfaces part of the review scope. (AGENTS.md:1, e643828af6fa)
  • Current-main behavior: Current main checks Slack read targets with only the channel ID, so a name-only allowlist entry cannot be considered before readMessages, file download, pin, or reaction read authorization fails. (extensions/slack/src/action-runtime.ts:146, e643828af6fa)
  • Proposed Slack authorization path: The PR adds a closed SlackReadTargetDecision flow that falls back to Slack name resolution only for allowlist policy, configured channel entries, explicit dangerouslyAllowNameMatching, no already-provided channelName, and no explicit ID denial. (extensions/slack/src/action-runtime.ts:147, d195f15fdeab)
  • Same-token lookup before protected reads: The PR wires resolveSlackConversationName through the same read opts used for the protected Slack read, then calls the shared guard before reactions, readMessages, downloadFile, and listPins. (extensions/slack/src/action-runtime.ts:255, d195f15fdeab)
  • Slack API helper: The PR adds resolveSlackConversationName using conversations.info and trims empty names to undefined, so unresolved names fail closed in the action-runtime guard. (extensions/slack/src/actions.ts:299, d195f15fdeab)
  • Regression coverage: Tests cover the name-allowlisted read path, generic Channel:"slack" non-trust, different target denial, user-token lookup, wildcard-deny fallback, explicit ID denial precedence, lookup failure, and protected read-like action denials. (extensions/slack/src/action-runtime.test.ts:1003, d195f15fdeab)

Likely related people:

  • pgondhi987: Authored the merged allowlist-enforcement PR that added Slack read-target checks in action-runtime.ts, which made the name-keyed allowlist regression visible. (role: introduced related behavior; confidence: high; commits: ea5f2abb4873; files: extensions/slack/src/action-runtime.ts, extensions/slack/src/action-runtime.test.ts)
  • steipete: Recent Slack action-runtime history includes Slack action validation work, and this PR's final hardening commits and maintainer pass were authored by steipete. (role: recent area contributor and reviewer; confidence: high; commits: c3ff31e7708d, 7932a4aa743a, 9dbff450b45b; files: extensions/slack/src/action-runtime.ts, extensions/slack/src/actions.ts, extensions/slack/src/actions.read.test.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (3 earlier review cycles)
  • reviewed 2026-06-27T17:57:37.721Z sha e3cd608 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-04T15:37:50.014Z sha 9dbff45 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-04T15:51:55.955Z sha f892a88 :: needs maintainer review before merge. :: none

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P1 High-priority user-facing bug, regression, or broken workflow. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. labels Jun 20, 2026
@jontsai
jontsai force-pushed the fix/slack-read-allowlist-channel-name-public branch from 3a40afc to 641838c Compare June 20, 2026 11:25
@jontsai jontsai changed the title fix(slack): allow name-allowlisted reads by channel id fix(slack): allow channel-id reads for name-allowlisted channels Jun 20, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. label Jun 20, 2026
@jontsai
jontsai force-pushed the fix/slack-read-allowlist-channel-name-public branch from 641838c to ee83402 Compare June 20, 2026 12:39
@jontsai

jontsai commented Jun 20, 2026

Copy link
Copy Markdown
Contributor Author

Not sure if this is acceptable proof, but in the past month, I had multiple OpenClaws on different machines collaborate with one another via a shared whitelisted Slack channel.

Recently (as in the past ~3-5 days), after I upgraded to 2026.6.8, the ability for me to have bot-to-bot conversations went away.

My use case was Bot A does dev work on a repo; Bot B does deployment of a said PR to servers C it has access to. A does not have access to C, but can do so indirectly through B.

Example of it working from the past month:
image

Example of it NOT working:
image

Example of it working again after this patch:
I'm having a bit of difficulty patching the source, reinstalling OpenClaw from source, and then generating this proof... As it's 6am now and I haven't slept, I'll have to try to resume this later.

@jontsai

jontsai commented Jun 20, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review.

@clawsweeper

clawsweeper Bot commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@jontsai

jontsai commented Jun 20, 2026

Copy link
Copy Markdown
Contributor Author

Redacted local runtime behavior proof

I installed and ran this branch from source on a local OpenClaw gateway, then exercised the Slack message.read path against a live Slack account. The real workspace/channel/user identifiers are intentionally replaced below with fabricated fixtures.

Build under test:

OpenClaw 2026.6.8 (ee83402)
branch: fix/slack-read-allowlist-channel-name-public

Relevant redacted config shape:

{
  channels: {
    slack: {
      groupPolicy: "allowlist",
      dangerouslyAllowNameMatching: true,
      channels: {
        "#allowed-channel": { enabled: true }
      }
    }
  }
}

Allowed-channel read by Slack channel ID:

action: message.read
target: channel:C0123456789
threadId: 1234567890.123456

result: ok=true
result.messages.length: 1
result.hasMore: true

This verifies the patched runtime can accept a Slack read where the action target is a Slack channel ID, while the allowlist entry is a channel name resolved at runtime.

Denied-channel read by Slack channel ID:

action: message.read
target: channel:C9876543210

result.status: error
result.error: Slack read target channel is not allowed.

This verifies non-matching channel-ID reads still fail closed.

Additional regression coverage on the same head:

pnpm vitest run extensions/slack/src/action-runtime.test.ts extensions/slack/src/channel-type.test.ts
# 2 files / 74 tests passed

pnpm test:extension slack
# 101 files / 1334 tests passed

pnpm tsgo:extensions
# passed

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jun 20, 2026
@jontsai
jontsai force-pushed the fix/slack-read-allowlist-channel-name-public branch from ee83402 to 7e1596f Compare June 20, 2026 19:34
@jontsai

jontsai commented Jun 20, 2026

Copy link
Copy Markdown
Contributor Author

Follow-up on the three failing checks from run 27871463802:

  • build-artifacts: failed in core-support-boundary due extension-test-boundary.test.ts catching extensions/feishu/src/media.test.ts on a repo helper bridge.
  • check-additional-boundaries-bcd: same lint:plugins:no-extension-test-core-imports boundary failure.
  • checks-node-core-tooling: stale tooling process-cleanup failure (process still alive).

I rebased this PR onto current main, which already contains the boundary and child-process cleanup fixes, and force-pushed with lease:

  • previous head: ee834023a27bd88d5ce71b5c3c271c90b2038804
  • new head: 7e1596f9f303396d768aaa492a6c040fef5ebfe5

Local verification on the rebased head:

  • pnpm run lint:plugins:no-extension-test-core-imports
  • node scripts/run-vitest.mjs run --config test/vitest/vitest.tooling.config.ts src/scripts/test-projects.test.ts test/scripts/openclaw-cross-os-release-checks.test.ts --reporter=verbose
  • node scripts/test-projects.mjs extensions/slack/src/action-runtime.test.ts extensions/slack/src/channel-type.test.ts

The PR check rollup is now clean on the new head.

@jontsai

jontsai commented Jun 20, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the current status: waiting on author blocker from ClawSweeper.

Change in e3cd608f8a0:

  • Removed the currentChannelName threading shortcut from the Slack action context and generic threading tool context.
  • ChannelThreadingContext.Channel is no longer copied into Slack read authorization; read-like actions now use the trusted conversations.info lookup for channel-ID → room-name resolution when name matching is enabled.
  • Added regression coverage for the core-shaped context path where Channel: "slack" must not authorize a #slack allowlist entry.

Verification:

  • node scripts/run-vitest.mjs extensions/slack/src/action-runtime.test.ts extensions/slack/src/threading-tool-context.test.ts extensions/slack/src/channel-type.test.ts extensions/slack/src/message-action-dispatch.test.ts
  • pnpm test:extension slack
  • pnpm tsgo:extensions
  • git diff --check

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. labels Jun 20, 2026
@steipete
steipete force-pushed the fix/slack-read-allowlist-channel-name-public branch from e3cd608 to 9dbff45 Compare July 4, 2026 15:33

steipete commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Maintainer pass complete on final head 9dbff450b45bd4eae81a859e543df2597854e81a.

What changed during review:

  • Replaced the shared cached channel-type lookup with a lazy Slack actions-runtime lookup.
  • Used the same bot/user credential for conversations.info and the protected read.
  • Preserved explicit channel-ID deny precedence and ignored generic Channel: "slack" context as authorization data.
  • Added fail-closed coverage for lookup errors, different targets, wildcard fallback, transient failures, and user-token reads.

Proof:

  • node scripts/run-vitest.mjs extensions/slack/src/action-runtime.test.ts extensions/slack/src/actions.read.test.ts extensions/slack/src/threading-tool-context.test.ts extensions/slack/src/channel-type.test.ts extensions/slack/src/message-action-dispatch.test.ts --run — 135 tests passed.
  • Fresh autoreview after fixes — clean, no accepted/actionable findings (patch is correct, confidence 0.96).
  • Testbox tbx_01kwpvwqzx81eqn3ck8kny9yqj, Actions 28710832081, exit 0 — focused tests, full build, extension/test types, lint, guards, and cycle checks.
  • Exact-head hosted CI 28711001736 — green.
  • Contributor live Slack proof remains valid for the conversations.info name-authorization behavior; the final credential/cache refinements have exact mocked-network and Testbox coverage but were not repeated against a live workspace.

Review artifacts validate READY with zero findings. Ready to land.

@steipete
steipete requested a review from a team as a code owner July 4, 2026 15:45
@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation scripts Repository scripts size: XL and removed size: M labels Jul 4, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. and removed proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jul 4, 2026
@clawsweeper clawsweeper Bot added rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. labels Jul 4, 2026
@steipete
steipete merged commit 6169e5d into openclaw:main Jul 4, 2026
111 of 113 checks passed
@steipete

steipete commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Merged via squash.

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 5, 2026
…nclaw#95313)

* fix(slack): allow channel-id reads for name-allowlisted channels

* fix(slack): trust API lookup for read target names

* fix(slack): resolve name-allowlisted reads safely

Co-authored-by: Jonathan Tsai <[email protected]>

* fix(slack): resolve name-allowlisted reads safely

* fix(slack): resolve name-allowlisted reads safely

---------

Co-authored-by: Peter Steinberger <[email protected]>
@jontsai
jontsai deleted the fix/slack-read-allowlist-channel-name-public branch July 23, 2026 01:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: slack Channel integration: slack docs Improvements or additions to documentation merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. P1 High-priority user-facing bug, regression, or broken workflow. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. scripts Repository scripts size: XL status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants