Open tasks from Slack and post questions back
The tasks open on the team's delivery line, and a reply in a question's Slack thread answers it. You need:
- A Slack app you can configure, installed in your Slack workspace.
- Terraform set up with the Spotlight provider, using a token that has the
configureandsecretsscopes. See Manage Spotlight with Terraform. - A team with a line whose role is
deliveryand a station keyedtriage, as the built-in Delivery line has. - A Spotlight deployment that allows outbound calls to
slack.com, since Spotlight calls Slack's API from its own servers.
Prepare the Slack app
In the Slack app's settings:
Give the app's bot the scopes app_mentions:read, chat:write and
channels:history, and reinstall the app.
Copy the app's bot token and its signing secret.
Note the ID of the Slack channel that questions from other tasks should go to.
Keep the two values as secrets
Keep the signing secret without bindings: the integration uses it to check
that deliveries come from Slack. Bind the bot token to slack.com, in the
authorization header.
variable "slack_signing_secret" {
type = string
sensitive = true
}
variable "slack_bot_token" {
type = string
sensitive = true
}
data "spotlight_workspace" "acme" {
slug = "acme"
}
resource "spotlight_secret" "slack_signing_secret" {
workspace_id = data.spotlight_workspace.acme.id
name = "SLACK_SIGNING_SECRET"
value_wo = var.slack_signing_secret
value_wo_version = 1
}
resource "spotlight_secret" "slack_bot_token" {
workspace_id = data.spotlight_workspace.acme.id
name = "SLACK_BOT_TOKEN"
bindings = [
{ host = "slack.com", carrier = "header", name = "authorization", prefix = "Bearer " },
]
value_wo = var.slack_bot_token
value_wo_version = 1
}Define the integration
A task opened from Slack posts its questions to the channel it was opened
from. routes names the channel for questions from a line's other tasks, by
the line's key (delivery is the built-in Delivery line's key): replace
<channel id> with the channel you noted.
data "spotlight_team" "core" {
workspace_id = data.spotlight_workspace.acme.id
key = "core"
}
resource "spotlight_integration" "slack" {
team_id = data.spotlight_team.core.id
definition = {
integration = "slack"
name = "Slack"
webhook = {
verify = {
hmac = {
algorithm = "sha256"
secret = "secret.${spotlight_secret.slack_signing_secret.name}"
header = "x-slack-signature"
prefix = "v0="
signed = "$${{ \"v0:\" + headers[\"x-slack-request-timestamp\"] + \":\" + raw }}"
freshness = {
at = "$${{ headers[\"x-slack-request-timestamp\"] }}"
within = "300s"
}
}
}
respond = {
when = "$${{ body.type == \"url_verification\" }}"
body = "$${{ body.challenge }}"
}
mine = "$${{ body.event.bot_id != \"\" }}"
events = [
{
when = "$${{ body.event.type == \"app_mention\" }}"
raise = {
happening = "slack.app_mention"
label = "Mentioned"
told = "Mentioned Spotlight in Slack."
opens = {
onto = "delivery"
at = "triage"
title = "$${{ body.event.text }}"
}
marks = [
{ kind = "slack.thread", value = "$${{ body.event.channel + \":\" + (has(body.event.thread_ts) ? body.event.thread_ts : body.event.ts) }}" },
{ kind = "slack.channel", find = false, value = "$${{ body.event.channel }}" },
]
}
},
{
when = "$${{ body.event.type == \"message\" && body.event.thread_ts != \"\" }}"
raise = {
happening = "slack.message.replied"
label = "Replied"
told = "Replied in a Slack thread."
spoken = true
say = "$${{ body.event.text }}"
marks = [
{ kind = "slack.thread", value = "$${{ body.event.channel + \":\" + body.event.thread_ts }}" },
]
}
},
]
}
actions = {
post-message = {
request = {
method = "POST"
url = "https://slack.com/api/chat.postMessage"
auth = { secrets = ["secret.${spotlight_secret.slack_bot_token.name}"] }
body = "$${{ {\"channel\": target.channel, \"text\": ask.body} }}"
expect = { success = "$${{ response.ok }}" }
capture = {
thread = "$${{ target.channel + \":\" + response.ts }}"
}
}
}
}
on = {
"task.asked" = {
do = "post-message"
to = {
channel = "$${{ task.marks[\"slack.channel\"] }}"
thread = "$${{ task.marks[\"slack.thread\"] }}"
}
routes = {
delivery = "<channel id>"
}
mark = [
{ kind = "slack.thread", value = "$${{ capture.thread }}" },
]
}
}
}
}onto names the line's role, and at the key of the station new tasks start
at. The keys under routes are line keys. Change any of them that differ on
your team, and if your team's key is not core, change it in
spotlight_team. Run
terraform apply. If the plan fails at an expression,
Expressions lists what each one can read.
Point Slack at the team
Slack sends events to the team's webhook address:
https://app.usespotlight.ai/api/webhooks/w/<workspace slug>/t/<team key>/slackOn a self-hosted Spotlight, the address starts with your deployment's address instead.
<workspace slug> is the part after /w/ in the workspace's address, and
<team key> is the key of the team that holds the integration (core in the
example above).
In the Slack app's event subscription settings:
Turn events on and give the address as the request URL. Slack sends a challenge, Spotlight responds to it, and Slack marks the address verified.
Subscribe the bot to the app_mention and message.channels events.
Save, and reinstall the app if Slack asks.
Check it
Mention the app in a channel it has joined. A task opens at Triage on the delivery line, titled with the message. When the task asks a question, the question appears in the channel, and a reply in its thread answers it and resumes the work.
Related
spotlight_integration: every field of a definition.- How outside events reach a task, on marks and happenings.
- Asking a person