Skip to content

fix(slack): register /commands HTTP endpoint for slash commands#767

Merged
penso merged 2 commits intomainfrom
buttery-patella
Apr 17, 2026
Merged

fix(slack): register /commands HTTP endpoint for slash commands#767
penso merged 2 commits intomainfrom
buttery-patella

Conversation

@penso
Copy link
Copy Markdown
Collaborator

@penso penso commented Apr 17, 2026

Summary

  • Register POST /api/channels/slack/{account_id}/commands in 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)
  • Add handle_verified_command_webhook() that parses Slack's form-encoded slash command payload and dispatches via ChannelEventSink::dispatch_command(), mirroring the existing Socket Mode handler
  • Extract reusable extract_form_field() helper from the existing extract_form_payload()

Validation

Completed

  • cargo +nightly-2025-11-30 fmt --all -- --check
  • just lint
  • just test — 367 tests pass
  • New tests: missing command field rejection, no-event-sink fallback, form field extraction edge cases

Remaining

  • ./scripts/local-validate.sh <PR_NUMBER> — full CI validation
  • Manual QA with a Slack app configured in Events API / HTTP webhook mode

Manual QA

  1. Deploy with a Slack channel in Events API (HTTP webhook) mode
  2. Configure the Slack app manifest with /api/channels/slack/{account_id}/commands as the slash command URL
  3. Send /new in Slack — should start a new session instead of returning 404
  4. Send /help — should return the help text
  5. Verify Socket Mode still works unchanged

🤖 Generated with Claude Code

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-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 17, 2026

Greptile Summary

Adds the missing POST /api/channels/slack/{account_id}/commands HTTP endpoint so slash commands work in Events API / webhook mode, fixing the 404 reported in #766. The implementation parses Slack's form-encoded payload, refactors a reusable extract_form_field helper, and correctly returns an empty 200 for deduplicated requests so Slack doesn't surface the JSON body to users.

Confidence Score: 5/5

Safe 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.

Important Files Changed

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
Loading

Reviews (2): Last reviewed commit: "fix(slack): address greptile review feed..." | Re-trigger Greptile

Comment thread crates/slack/src/webhook.rs
Comment thread crates/httpd/src/server/gateway.rs Outdated
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 17, 2026

Codecov Report

❌ Patch coverage is 52.63158% with 72 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
crates/httpd/src/server/gateway.rs 0.00% 50 Missing ⚠️
crates/slack/src/webhook.rs 84.21% 15 Missing ⚠️
crates/slack/src/plugin.rs 0.00% 7 Missing ⚠️

📢 Thoughts on this report? Let us know!

@codspeed-hq
Copy link
Copy Markdown
Contributor

codspeed-hq Bot commented Apr 17, 2026

Merging this PR will not alter performance

✅ 39 untouched benchmarks
⏩ 5 skipped benchmarks1


Comparing buttery-patella (772855b) with main (b351fbd)

Open in CodSpeed

Footnotes

  1. 5 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

- 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
@penso
Copy link
Copy Markdown
Collaborator Author

penso commented Apr 17, 2026

@greptile review

@penso penso merged commit 16df0ce into main Apr 17, 2026
24 of 32 checks passed
@penso penso deleted the buttery-patella branch April 17, 2026 13:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Slack /commands endpoint missing in HTTP gateway, slash commands 404

1 participant