Skip to content

Commit 6c70632

Browse files
zimegClaude
andcommitted
fix: defer SignatureVerifier construction so Socket Mode apps init without a signing secret
slack_sdk>=3.43.0 validates the signing secret when a SignatureVerifier is constructed, raising "ValueError: signing_secret must not be empty." App.__init__ eagerly builds the RequestVerification middleware (and thus a SignatureVerifier) for every app, including Socket Mode apps that have no signing secret, so those apps now fail to initialize. Construct the SignatureVerifier lazily on first use instead. Request verification is already skipped for Socket Mode requests, so the verifier is never built for them. HTTP requests still require a valid signing secret as before. Fixes #1535 Co-Authored-By: Claude <svc-devxp-claude@slack-corp.com>
1 parent 29b9dbd commit 6c70632

4 files changed

Lines changed: 51 additions & 1 deletion

File tree

slack_bolt/middleware/request_verification/request_verification.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,20 @@ def __init__(self, signing_secret: str, base_logger: Optional[Logger] = None):
2020
signing_secret: The signing secret
2121
base_logger: The base logger
2222
"""
23-
self.verifier = SignatureVerifier(signing_secret=signing_secret)
23+
# The verifier is created lazily so that apps without a signing secret
24+
# (e.g. Socket Mode) can be initialized. slack_sdk>=3.43.0 rejects an
25+
# empty signing secret on construction, but request verification is
26+
# skipped for those requests anyway (see `_can_skip`).
27+
self._signing_secret = signing_secret
28+
self._verifier: Optional[SignatureVerifier] = None
2429
self.logger = get_bolt_logger(RequestVerification, base_logger=base_logger)
2530

31+
@property
32+
def verifier(self) -> SignatureVerifier:
33+
if self._verifier is None:
34+
self._verifier = SignatureVerifier(signing_secret=self._signing_secret)
35+
return self._verifier
36+
2637
def process(
2738
self,
2839
*,

tests/scenario_tests/test_app.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,16 @@ def test_token_verification_enabled_False(self):
9696

9797
assert self.received_requests.get("/auth.test") is None
9898

99+
def test_socket_mode_app_without_signing_secret(self):
100+
# A Socket Mode app has no signing secret. Initializing the app must not
101+
# raise, even though slack_sdk>=3.43.0 rejects an empty signing secret
102+
# when the request verification middleware builds its SignatureVerifier.
103+
app = App(
104+
client=self.web_client,
105+
token_verification_enabled=False,
106+
)
107+
assert app is not None
108+
99109
# --------------------------
100110
# multi teams auth
101111
# --------------------------

tests/slack_bolt/middleware/request_verification/test_request_verification.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,17 @@ def test_ssl_check_param_requires_valid_signature(self):
6060
resp = middleware.process(req=req, resp=resp, next=next)
6161
assert resp.status == 401
6262
assert resp.body == """{"error": "invalid request"}"""
63+
64+
def test_empty_signing_secret_does_not_raise_on_init(self):
65+
# A Socket Mode app has no signing secret. Constructing the middleware
66+
# must not raise, even though slack_sdk>=3.43.0 rejects an empty
67+
# signing secret when the SignatureVerifier is created.
68+
RequestVerification(signing_secret="")
69+
70+
def test_socket_mode_request_skips_verification_without_signing_secret(self):
71+
middleware = RequestVerification(signing_secret="")
72+
req = BoltRequest(mode="socket_mode", body="payload={}", headers={})
73+
resp = BoltResponse(status=404, body="default")
74+
resp = middleware.process(req=req, resp=resp, next=next)
75+
assert resp.status == 200
76+
assert resp.body == "next"

tests/slack_bolt_async/middleware/request_verification/test_request_verification.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,18 @@ async def test_ssl_check_param_requires_valid_signature(self):
6666
resp = await middleware.async_process(req=req, resp=resp, next=next)
6767
assert resp.status == 401
6868
assert resp.body == """{"error": "invalid request"}"""
69+
70+
def test_empty_signing_secret_does_not_raise_on_init(self):
71+
# A Socket Mode app has no signing secret. Constructing the middleware
72+
# must not raise, even though slack_sdk>=3.43.0 rejects an empty
73+
# signing secret when the SignatureVerifier is created.
74+
AsyncRequestVerification(signing_secret="")
75+
76+
@pytest.mark.asyncio
77+
async def test_socket_mode_request_skips_verification_without_signing_secret(self):
78+
middleware = AsyncRequestVerification(signing_secret="")
79+
req = AsyncBoltRequest(mode="socket_mode", body="payload={}", headers={})
80+
resp = BoltResponse(status=404, body="default")
81+
resp = await middleware.async_process(req=req, resp=resp, next=next)
82+
assert resp.status == 200
83+
assert resp.body == "next"

0 commit comments

Comments
 (0)