From 0bfca34b7c085c3607db59e73350b25956f4ba41 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Thu, 26 Sep 2024 16:21:20 +0200 Subject: [PATCH 1/3] docs: use Slack notifications --- docs/admin/notifications/slack.md | 204 ++++++++++++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 docs/admin/notifications/slack.md diff --git a/docs/admin/notifications/slack.md b/docs/admin/notifications/slack.md new file mode 100644 index 0000000000000..1c7cbb5fbf1d8 --- /dev/null +++ b/docs/admin/notifications/slack.md @@ -0,0 +1,204 @@ +# Slack Notifications + +[Slack](https://slack.com/) is a popular messaging platform designed for teams +and businesses, enabling real-time collaboration through channels, direct +messages, and integrations with external tools. With Coder's integration, you +can enable automated notifications directly within a self-hosted +[Slack app](https://api.slack.com/apps), keeping your team updated on key events +in your Coder environment. + +Administrators can configure Coder to send notifications via an incoming webhook +endpoint. These notifications appear as conversation with a custom Slack app. + +## Requirements + +Before setting up Slack notifications, ensure that you have the following: + +- Administrator access to the Slack platform to create apps +- Coder platform with notifications enabled + +## Create Slack Application + +To integrate Slack with Coder, follow these steps to create a Slack application: + +1. Go to the [Slack Apps](https://api.slack.com/apps) dashboard and create a new + Slack App. + +2. Under "Basic Information," you'll find a "Signing Secret." Keep it safe for + verification if needed. + +3. Under "OAuth & Permissions", add the following OAuth scopes: + +- `chat:write`: To send messages as the app. +- `users:read`: To find the user details. +- `users:read.email`: To find user emails. + +4. Install the app to your workspace and note down the **Bot User OAuth Token** + from the "OAuth & Permissions" section. + +## Build a Webserver to Receive Webhooks + +The Slack bot for Coder runs as a _Bolt application_, which is a framework +designed for building Slack apps using the Slack API. +[Bolt for JavaScript](https://github.com/slackapi/bolt-js) provides an +easy-to-use API for responding to events, commands, and interactions from Slack. + +To build the server to receive webhooks and interact with Slack: + +1. Initialize your project by running: + +```bash +npm init -y +``` + +2. Install the Bolt library: + +```bash +npm install @slack/bolt +``` + +3. Create and edit the `app.js` file. Below is an example of the basic + structure: + +```js +const { App, LogLevel, ExpressReceiver } = require("@slack/bolt"); +const bodyParser = require("body-parser"); + +const port = process.env.PORT || 6000; + +// Create a Bolt Receiver +const receiver = new ExpressReceiver({ + signingSecret: process.env.SLACK_SIGNING_SECRET, +}); +receiver.router.use(bodyParser.json()); + +// Create the Bolt App, using the receiver +const app = new App({ + token: process.env.SLACK_BOT_TOKEN, + logLevel: LogLevel.DEBUG, + receiver, +}); + +receiver.router.post("/webhook", async (req, res) => { + try { + if (!req.body) { + return res.status(400).send("Error: request body is missing"); + } + + const { title, body } = req.body; + if (!title || !body) { + return res.status(400).send('Error: missing fields: "title", or "body"'); + } + + const payload = req.body.payload; + if (!payload) { + return res.status(400).send('Error: missing "payload" field'); + } + + const { user_email, actions } = payload; + if (!user_email || !actions) { + return res + .status(400) + .send('Error: missing fields: "user_email", "actions"'); + } + + // Get the user ID using Slack API + const userByEmail = await app.client.users.lookupByEmail({ + email: user_email, + }); + + const slackMessage = { + channel: userByEmail.user.id, + text: body, + blocks: [ + { + type: "header", + text: { type: "plain_text", text: title }, + }, + { + type: "section", + text: { type: "mrkdwn", text: body }, + }, + ], + }; + + // Add action buttons if they exist + if (actions && actions.length > 0) { + slackMessage.blocks.push({ + type: "actions", + elements: actions.map((action) => ({ + type: "button", + text: { type: "plain_text", text: action.label }, + url: action.url, + })), + }); + } + + // Post message to the user on Slack + await app.client.chat.postMessage(slackMessage); + + res.status(204).send(); + } catch (error) { + console.error("Error sending message:", error); + res.status(500).send(); + } +}); + +// Acknowledge clicks on link_button, otherwise Slack UI +// complains about missing events. +app.action("button_click", async ({ body, ack, say }) => { + await ack(); // no specific action needed +}); + +// Start the Bolt app +(async () => { + await app.start(port); + console.log("⚡️ Coder Slack bot is running!"); +})(); +``` + +3. Set environment variables to identify the Slack app: + +```bash +export SLACK_BOT_TOKEN=xoxb-... +export SLACK_SIGNING_SECRET=0da4b... +``` + +4. Start the web application by running: + +```bash +node app.js +``` + +## Enable Interactivity in Slack + +Slack requires the bot to acknowledge when a user clicks on a URL action button. +This is handled by setting up interactivity. + +1. Under "Interactivity & Shortcuts" in your Slack app settings, set the Request + URL to match the public URL of your web server's endpoint. + +> Notice: You can use any public endpoint that accepts and responds to POST +> requests with HTTP 200. For temporary testing, you can set it to +> `https://httpbin.org/status/200`. + +Once this is set, Slack will send interaction payloads to your server, which +must respond appropriately. + +## Enable Webhook Integration in Coder + +To enable webhook integration in Coder, ensure the "notifications" experiment is +activated by running the following command: + +```bash +export CODER_EXPERIMENTS=notifications +``` + +Then, define the POST webhook endpoint matching the deployed Slack bot: + +```bash +export CODER_NOTIFICATIONS_WEBHOOK_ENDPOINT=http://localhost:6000/webhook` +``` + +Finally, go to the **Notification Settings** in Coder and switch the notifier to +**Webhook**. From 44a4cbaddde12e1c45105c0ff53f259d69c04d5a Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Thu, 26 Sep 2024 16:25:25 +0200 Subject: [PATCH 2/3] beta --- docs/manifest.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/manifest.json b/docs/manifest.json index e6663816af052..119da3108a06a 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -518,6 +518,12 @@ "path": "./admin/notifications.md", "icon_path": "./images/icons/info.svg", "children": [ + { + "title": "Slack Notifications", + "description": "Learn how to setup Slack notifications", + "path": "./admin/notifications/slack.md", + "state": "beta" + }, { "title": "Microsoft Teams Notifications", "description": "Learn how to setup Microsoft Teams notifications", From bff1739aababe9582da25fbf2a7d1c1c6ba0c376 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Fri, 27 Sep 2024 09:37:04 +0200 Subject: [PATCH 3/3] fixes --- docs/admin/notifications/slack.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/docs/admin/notifications/slack.md b/docs/admin/notifications/slack.md index 1c7cbb5fbf1d8..aa6a4dcdb5655 100644 --- a/docs/admin/notifications/slack.md +++ b/docs/admin/notifications/slack.md @@ -8,14 +8,17 @@ can enable automated notifications directly within a self-hosted in your Coder environment. Administrators can configure Coder to send notifications via an incoming webhook -endpoint. These notifications appear as conversation with a custom Slack app. +endpoint. These notifications will be delivered as Slack messages direct to the +user. Routing is based on the user's email address, and this should be +consistent between Slack and their Coder login. ## Requirements Before setting up Slack notifications, ensure that you have the following: - Administrator access to the Slack platform to create apps -- Coder platform with notifications enabled +- Coder platform with + [notifications enabled](../notifications#enable-experiment) ## Create Slack Application @@ -24,8 +27,10 @@ To integrate Slack with Coder, follow these steps to create a Slack application: 1. Go to the [Slack Apps](https://api.slack.com/apps) dashboard and create a new Slack App. -2. Under "Basic Information," you'll find a "Signing Secret." Keep it safe for - verification if needed. +2. Under "Basic Information," you'll find a "Signing Secret." The Slack + application uses it to + [verify requests](https://api.slack.com/authentication/verifying-requests-from-slack) + coming from Slack. 3. Under "OAuth & Permissions", add the following OAuth scopes: @@ -79,7 +84,7 @@ const app = new App({ receiver, }); -receiver.router.post("/webhook", async (req, res) => { +receiver.router.post("/v1/webhook", async (req, res) => { try { if (!req.body) { return res.status(400).send("Error: request body is missing"); @@ -197,7 +202,7 @@ export CODER_EXPERIMENTS=notifications Then, define the POST webhook endpoint matching the deployed Slack bot: ```bash -export CODER_NOTIFICATIONS_WEBHOOK_ENDPOINT=http://localhost:6000/webhook` +export CODER_NOTIFICATIONS_WEBHOOK_ENDPOINT=http://localhost:6000/v1/webhook` ``` Finally, go to the **Notification Settings** in Coder and switch the notifier to