fix(slack): register /commands HTTP endpoint for slash commands#767
fix(slack): register /commands HTTP endpoint for slash commands#767
Conversation
Slack slash commands sent via HTTP/webhook mode returned 404 because the
gateway only registered /events and /interactions routes. Socket Mode
worked via command_events_callback in socket.rs, but the equivalent HTTP
path was never wired up.
Add:
- handle_verified_command_webhook() in webhook.rs: parses form-encoded
slash command payloads (command, text, user_id, channel_id) and
dispatches via ChannelEventSink::dispatch_command()
- ingest_verified_command_webhook() on SlackPlugin
- POST /api/channels/slack/{account_id}/commands route in gateway.rs
with the same signature verification middleware as events/interactions
- extract_form_field() helper (generalizes extract_form_payload)
- Tests for missing command field, no-event-sink fallback, and field
extraction edge cases
Entire-Checkpoint: 3247f3875997
Greptile SummaryAdds the missing Confidence Score: 5/5Safe to merge; previous P1 concerns are resolved and the only remaining finding is a P2 design note about deferred responses. Both prior review issues (silently swallowed dispatch errors, dedup JSON body visible to users) are addressed. The one new finding — synchronous dispatch risking Slack's 3-second timeout — is P2 and worth addressing in a follow-up but does not block the core 404 fix. crates/slack/src/webhook.rs — handle_verified_command_webhook awaits dispatch inline; consider response_url-based deferred reply for long-running commands.
|
| Filename | Overview |
|---|---|
| crates/httpd/src/server/gateway.rs | Registers POST /api/channels/slack/{account_id}/commands; correctly returns empty 200 on dedup (addressing prior review concern) and reuses the existing middleware pipeline. |
| crates/slack/src/plugin.rs | Thin delegation method ingest_verified_command_webhook added; mirrors the existing ingest_verified_interaction_webhook pattern cleanly. |
| crates/slack/src/webhook.rs | Adds handle_verified_command_webhook and extract_form_field refactor; dispatch is awaited synchronously which risks exceeding Slack's 3-second response deadline for long-running commands. |
Sequence Diagram
sequenceDiagram
participant S as Slack
participant GW as HTTP Gateway /commands
participant MW as channel_webhook_gate
participant P as SlackPlugin
participant WH as handle_verified_command_webhook
participant DS as ChannelEventSink
S->>GW: POST /api/channels/slack/{id}/commands
GW->>GW: lookup verifier for account_id
alt unknown account
GW-->>S: 404 Not Found
end
GW->>MW: channel_webhook_gate(verifier, dedup, rate_limiter, headers, body)
alt signature invalid / rate-limited
MW-->>GW: Err(rejection)
GW-->>S: 401/429
else duplicate request
MW-->>GW: Ok(Duplicate)
GW-->>S: 200 empty body
else new request
MW-->>GW: Ok(verified_body)
GW->>P: ingest_verified_command_webhook(account_id, body)
P->>WH: handle_verified_command_webhook(account_id, body, accounts)
WH->>WH: parse command/text/user_id/channel_id
WH->>DS: dispatch_command(full_command, reply_to, sender)
DS-->>WH: Ok(response_text) / Err(e)
WH-->>P: Ok(response_text)
P-->>GW: Ok(response_text)
GW-->>S: 200 response_text
end
Reviews (2): Last reviewed commit: "fix(slack): address greptile review feed..." | Re-trigger Greptile
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
Merging this PR will not alter performance
Comparing Footnotes
|
- Log command dispatch errors at debug level before returning user- facing error text, matching the interaction webhook pattern - Return empty 200 for deduplicated slash commands instead of JSON that Slack would display verbatim in the channel Entire-Checkpoint: 6c34e5144323
|
@greptile review |
Summary
POST /api/channels/slack/{account_id}/commandsin the HTTP gateway, fixing 404s for slash commands when using webhook mode (closes [Bug]: Slack /commands endpoint missing in HTTP gateway, slash commands 404 #766)handle_verified_command_webhook()that parses Slack's form-encoded slash command payload and dispatches viaChannelEventSink::dispatch_command(), mirroring the existing Socket Mode handlerextract_form_field()helper from the existingextract_form_payload()Validation
Completed
cargo +nightly-2025-11-30 fmt --all -- --checkjust lintjust test— 367 tests passRemaining
./scripts/local-validate.sh <PR_NUMBER>— full CI validationManual QA
/api/channels/slack/{account_id}/commandsas the slash command URL/newin Slack — should start a new session instead of returning 404/help— should return the help text🤖 Generated with Claude Code