feat(chat): Slack bidirectional driver with attested approvals#1804
Conversation
Replaces the NotImplementedError stub in ``src/bernstein/core/chat/drivers/slack.py`` with a Socket Mode driver that conforms to ``BridgeProtocol`` end to end: slash dispatch, button decode, edit debounce, signed outbound messages, worktree-pinned approvals, and chained audit-log entries. * Outbound messages carry an Ed25519 detached signature over ``(install_id, session_id, content_hash)``; ``verify_chat_signature`` lets a recipient with the install's public key confirm authenticity and reject foreign-install forgeries. * Each Slack approval resolution lands as a ``chat.slack.approval`` event in the existing HMAC-chained ``AuditLog``; replay over the exported chain reproduces the post-approval scheduler state byte-identically (covered by the new integration test). * Cross-worktree approvals raise ``CrossWorktreeApprovalError`` and log a ``chat.slack.approval_rejected`` entry so the bypass attempt is visible to the operator. * ``edit_message`` debounces ``chat.update`` to one call per channel per second, comfortably below Slack's per-channel rate limit. * Optional ``bernstein[slack]`` extra pulls in ``slack-sdk``; the ``start()`` path raises ``SlackDependencyError`` with a pointer to the extra when the SDK is absent. CLI integration: ``bernstein chat serve --platform=slack`` reads the bot token from ``BERNSTEIN_SLACK_TOKEN`` and the Socket Mode app token from ``BERNSTEIN_SLACK_APP_TOKEN``. Docs added at ``docs/operations/chat-bridges.md``. Closes #1794
There was a problem hiding this comment.
Sorry @chernistry, you have reached your weekly rate limit of 2500000 diff characters.
Please try again later or upgrade to continue using Sourcery
Sonar insights (advisory, no merge-block)Snapshot of
Run This comment is a soft signal. The Sonar scan runs on push to |
Review-bot acknowledgement summary
All must-address findings are resolved or acknowledged. |
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: ⛔ Files ignored due to path filters (2)
📒 Files selected for processing (8)
📝 WalkthroughWalkthroughThis PR implements a complete Slack Socket Mode bidirectional driver with attested approvals, replacing the stub. The driver supports slash commands, approval routing with cross-worktree enforcement, edit debouncing, HMAC-chained audit logging, and Ed25519 message signing. CLI and optional dependency changes enable app-token support. Comprehensive unit and integration tests verify audit-chain reproducibility and security invariants. ChangesSlack bidirectional driver with attested approvals
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related issues
Possibly related PRs
Suggested labels
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
|
bernstein doctor observe for PR #1804 ( sonar -- WARN (project bernstein)
code-scanning -- WARN (4 open alert(s))
Skipped backends (credentials not configured)
See docs/observability/unified-doctor.md for backend setup notes. |
|
|
||
| def approved_tool_call_hashes(self) -> set[str]: | ||
| """Return a snapshot of every tool-call hash that has been approved.""" | ||
| return set(self._approved_tool_call_hashes) |
Closes #1794.
Summary
NotImplementedErrorstub atsrc/bernstein/core/chat/drivers/slack.pywith a Socket Mode driver conforming toBridgeProtocolend to end.(install_id, session_id, content_hash);verify_chat_signaturelets a recipient with the install's public key confirm authenticity and reject foreign-install forgeries.chat.slack.approvalentry in the existing HMAC-chainedAuditLog; replay over the exported chain reproduces the post-approval scheduler state byte-identically (covered by the integration test).CrossWorktreeApprovalErrorand emitchat.slack.approval_rejectedso the bypass attempt is auditable.edit_messagedebounceschat.updateto one call per channel per second, below Slack's per-channel rate limit.bernstein[slack]extra pulls inslack-sdk;start()raisesSlackDependencyErrorwith a pointer to the extra when the SDK is missing.Files touched
src/bernstein/core/chat/drivers/slack.py-- driver implementation, signing helpers, audit-chain wiring.src/bernstein/cli/commands/chat_cmd.py-- two-token bridge construction for Slack (BERNSTEIN_SLACK_TOKEN+BERNSTEIN_SLACK_APP_TOKEN).pyproject.toml,uv.lock-- newbernstein[slack]extra (slack-sdk>=3.27,aiohttp>=3.9).tests/unit/core/chat/test_slack_driver.py-- 14 unit tests covering slash dispatch, button decode, edit-debounce, missing-SDK error path, audit-chain entry shape, cross-worktree resolution rejection, signature verification (including foreign-install rejection).tests/integration/test_slack_audit_chain_roundtrip.py-- replays a real HMAC-chainedAuditLogafter Slack approvals and asserts the reconstructed scheduler state matches the live state byte-for-byte.tests/unit/test_chat_drivers.py-- drops the stub-message assertions for Slack now that the driver is live.docs/operations/chat-bridges.md-- new operator-facing doc covering Telegram + Slack setup, env vars, signed-envelope verification, and missing-SDK behaviour.CHANGELOG.md-- documents the new driver + docs under[Unreleased].Acceptance criteria
All seven AC bullets from #1794 are covered:
BridgeProtocolimplemented end to end -- noNotImplementedErrorremains.chat.slack.approvalentry whose digest covers(approver, message_ts, decision, tool_call_hash, prev_chain_digest); replay reproduces post-approval state byte-identically./approvefromwt-arefuses pending approvals onwt-b.edit_messagedebounces toEDIT_THROTTLE_S = 1.0sper channel.bernstein[slack]extra wired;start()raises a structuredSlackDependencyErrorwhenslack-sdkis absent.Test plan
uv run pytest tests/unit/core/chat/ -q --no-cov --timeout=120-- 14 passed.uv run pytest tests/integration/test_slack_audit_chain_roundtrip.py -q --no-cov --timeout=120-- 1 passed.uv run ruff check .-- all checks passed.uv run ruff format .-- all files left unchanged (formatted on commit).uv run pyright src/bernstein/core/chat/drivers/slack.py-- 0 errors.tests/unit/core/,tests/unit/test_chat_*.py,tests/unit/test_audit*.py,tests/unit/test_handoff_chat.py,tests/unit/notifications/test_sinks_shell_telegram.py-- 120 passed.Summary by CodeRabbit
New Features
Documentation