kestra-io / kestra

Infinitely scalable, event-driven, language-agnostic orchestration and scheduling platform to manage millions of workflows declaratively in code.
https://kestra.io
Apache License 2.0
7.14k stars 426 forks source link

[Slack Events API] Allow the webhook to send another API Request as a response to the webhook API call #3095

Closed anna-geller closed 4 months ago

anna-geller commented 5 months ago

Feature description

It would be great to support Slack Events API directly from a webhook trigger.

For now the biggest challenge it seems is that Slack expects our webhook to send a plain text response with a challenge attribute returned from the initial API response https://api.slack.com/events/url_verification

Here is an example payload that Slack sends:

{
  "body": {
    "type": "url_verification",
    "token": "wW3CI68YhGl79XefqKpbnuMY",
    "challenge": "W6S4yr5gXTIxyjMBEVowN79L6UnUct1TilRWmpT2phWdRh009AFB"
  },
  "headers": {
    "Host": [
      "18.153.185.126:8080"
    ],
    "Accept": [
      "*/*"
    ],
    "Connection": [
      "keep-alive"
    ],
    "User-Agent": [
      "Slackbot 1.0 (+https://api.slack.com/robots)"
    ],
    "Content-Type": [
      "application/json"
    ],
    "Cache-Control": [
      "max-age=259200"
    ],
    "Content-Length": [
      "129"
    ],
    "Accept-Encoding": [
      "gzip,deflate"
    ],
    "X-Slack-Signature": [
      "v0=5a58d6fd6a2bc98aa795f1a6613f7e8e0a88cd4d0d495e161bf13f15d406dcc1"
    ],
    "X-Slack-Request-Timestamp": [
      "1708349077"
    ]
  }
}

Related to https://github.com/kestra-io/plugin-notifications/issues/110

This is our attempt to solve the issue with @Ben8t but all events that we configured resulted in no executions being created. It might be due to the challenge but hard to tell/troubleshoot:

id: slack
namespace: dev

tasks:
  - id: body
    type: io.kestra.core.tasks.log.Log
    message: "{{ trigger }}"  

  - id: response
    type: io.kestra.plugin.fs.http.Request
    uri: https://api.slack.com/robots
    contentType: application/json
    body: |
      {
        "challenge": "{{trigger.body.challenge}}" # ⚡️ this should happen automatically
      }

triggers:
  - id: webhook
    type: io.kestra.core.models.triggers.types.Webhook
    key: test

For now, the webhook response will be one of the following HTTP status codes:

Ben8t commented 5 months ago

I would add to this that it seems that Kestra doesn't give back the whole body: in the Slack documentation they show an example with Python:

slack_signing_secret = 'MY_SLACK_SIGNING_SECRET' // Set this as an environment variable
>>> 8f742231b10e8888abcd99yyyzzz85a5
request_body = request.body()
>>> token=xyzz0WbapA4vBCDEFasx0q6G&team_id=T1DC2JH3J&team_domain=testteamnow&channel_id=G8PSS9T3V&channel_name=foobar&user_id=U2CERLKJA&user_name=roadrunner&command=%2Fwebhook-collect&text=&response_url=https%3A%2F%2Fhooks.slack.com%2Fcommands%2FT1DC2JH3J%2F397700885554%2F96rGlfmibIGlgcZRskXaIFfN&trigger_id=398738663015.47445629121.803a0bc887a14d10d2c447fce8b6703c

👉 we can see a response_url that is not exposed by Kestra trigger.body (see issue description above) 🤔

More generally speaking: this feature can be generalized to any server to server handshake where one HTTP call expect a specific response. In that sense, the last addition of outputs properties in flow/subflow coupled with http.Trigger/webhook is the way to go: let people customize HTTP response from flow triggered by webhook/http.Trigger

Ben8t commented 5 months ago

cc @anna-geller @Skraye

I've made a quick Loom to show how I can handle Slack events with a small Python API (handling POST request); let me know if it helps; happy to give feedback if needed :)

https://www.loom.com/share/289c4c40623b458cae2182b51ac236fd?sid=ca489edd-6922-4dde-b142-839f4b3d6a44

Ben8t commented 5 months ago

TL;DR; What would be lovely: allow users to set custom body for the webhook response 🙏

In my case I would love to see something like:

id: slack-event
namespace: dev
tasks:
  - id: hello
    type: io.kestra.core.tasks.log.Log
    message: Kestra team wishes you a great day! 👋

outputs:
   - id: challenge
     value: {{ trigger.body.challenge }} # this being exposed by webhook HTTP response

triggers:
  - id: webhook
    type: io.kestra.core.models.triggers.types.Webhook
    key: "test"
anna-geller commented 4 months ago

Ludo mentioned it would be complex so for now, we implement it in the form of a tutorial https://kestra.io/docs/tutorials/slack-webhook#example-automation-ai-chatbot

if insufficient for the users, we can reopen later with the flow outputs solution suggested by @Ben8t:

id: slack-event
namespace: dev
tasks:
  - id: hello
    type: io.kestra.core.tasks.log.Log
    message: Kestra team wishes you a great day!

outputs:
   - id: challenge
     value: {{ trigger.body.challenge }} # this being exposed by webhook HTTP response

triggers:
  - id: webhook
    type: io.kestra.core.models.triggers.types.Webhook
    key: "test"