Skip to content

Commit a3ffab6

Browse files
authored
docs: enable Slack notifications (coder#14830)
1 parent 3fdeaf7 commit a3ffab6

File tree

2 files changed

+215
-0
lines changed

2 files changed

+215
-0
lines changed

docs/admin/notifications/slack.md

+209
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
# Slack Notifications
2+
3+
[Slack](https://slack.com/) is a popular messaging platform designed for teams
4+
and businesses, enabling real-time collaboration through channels, direct
5+
messages, and integrations with external tools. With Coder's integration, you
6+
can enable automated notifications directly within a self-hosted
7+
[Slack app](https://api.slack.com/apps), keeping your team updated on key events
8+
in your Coder environment.
9+
10+
Administrators can configure Coder to send notifications via an incoming webhook
11+
endpoint. These notifications will be delivered as Slack messages direct to the
12+
user. Routing is based on the user's email address, and this should be
13+
consistent between Slack and their Coder login.
14+
15+
## Requirements
16+
17+
Before setting up Slack notifications, ensure that you have the following:
18+
19+
- Administrator access to the Slack platform to create apps
20+
- Coder platform with
21+
[notifications enabled](../notifications#enable-experiment)
22+
23+
## Create Slack Application
24+
25+
To integrate Slack with Coder, follow these steps to create a Slack application:
26+
27+
1. Go to the [Slack Apps](https://api.slack.com/apps) dashboard and create a new
28+
Slack App.
29+
30+
2. Under "Basic Information," you'll find a "Signing Secret." The Slack
31+
application uses it to
32+
[verify requests](https://api.slack.com/authentication/verifying-requests-from-slack)
33+
coming from Slack.
34+
35+
3. Under "OAuth & Permissions", add the following OAuth scopes:
36+
37+
- `chat:write`: To send messages as the app.
38+
- `users:read`: To find the user details.
39+
- `users:read.email`: To find user emails.
40+
41+
4. Install the app to your workspace and note down the **Bot User OAuth Token**
42+
from the "OAuth & Permissions" section.
43+
44+
## Build a Webserver to Receive Webhooks
45+
46+
The Slack bot for Coder runs as a _Bolt application_, which is a framework
47+
designed for building Slack apps using the Slack API.
48+
[Bolt for JavaScript](https://github.com/slackapi/bolt-js) provides an
49+
easy-to-use API for responding to events, commands, and interactions from Slack.
50+
51+
To build the server to receive webhooks and interact with Slack:
52+
53+
1. Initialize your project by running:
54+
55+
```bash
56+
npm init -y
57+
```
58+
59+
2. Install the Bolt library:
60+
61+
```bash
62+
npm install @slack/bolt
63+
```
64+
65+
3. Create and edit the `app.js` file. Below is an example of the basic
66+
structure:
67+
68+
```js
69+
const { App, LogLevel, ExpressReceiver } = require("@slack/bolt");
70+
const bodyParser = require("body-parser");
71+
72+
const port = process.env.PORT || 6000;
73+
74+
// Create a Bolt Receiver
75+
const receiver = new ExpressReceiver({
76+
signingSecret: process.env.SLACK_SIGNING_SECRET,
77+
});
78+
receiver.router.use(bodyParser.json());
79+
80+
// Create the Bolt App, using the receiver
81+
const app = new App({
82+
token: process.env.SLACK_BOT_TOKEN,
83+
logLevel: LogLevel.DEBUG,
84+
receiver,
85+
});
86+
87+
receiver.router.post("/v1/webhook", async (req, res) => {
88+
try {
89+
if (!req.body) {
90+
return res.status(400).send("Error: request body is missing");
91+
}
92+
93+
const { title, body } = req.body;
94+
if (!title || !body) {
95+
return res.status(400).send('Error: missing fields: "title", or "body"');
96+
}
97+
98+
const payload = req.body.payload;
99+
if (!payload) {
100+
return res.status(400).send('Error: missing "payload" field');
101+
}
102+
103+
const { user_email, actions } = payload;
104+
if (!user_email || !actions) {
105+
return res
106+
.status(400)
107+
.send('Error: missing fields: "user_email", "actions"');
108+
}
109+
110+
// Get the user ID using Slack API
111+
const userByEmail = await app.client.users.lookupByEmail({
112+
email: user_email,
113+
});
114+
115+
const slackMessage = {
116+
channel: userByEmail.user.id,
117+
text: body,
118+
blocks: [
119+
{
120+
type: "header",
121+
text: { type: "plain_text", text: title },
122+
},
123+
{
124+
type: "section",
125+
text: { type: "mrkdwn", text: body },
126+
},
127+
],
128+
};
129+
130+
// Add action buttons if they exist
131+
if (actions && actions.length > 0) {
132+
slackMessage.blocks.push({
133+
type: "actions",
134+
elements: actions.map((action) => ({
135+
type: "button",
136+
text: { type: "plain_text", text: action.label },
137+
url: action.url,
138+
})),
139+
});
140+
}
141+
142+
// Post message to the user on Slack
143+
await app.client.chat.postMessage(slackMessage);
144+
145+
res.status(204).send();
146+
} catch (error) {
147+
console.error("Error sending message:", error);
148+
res.status(500).send();
149+
}
150+
});
151+
152+
// Acknowledge clicks on link_button, otherwise Slack UI
153+
// complains about missing events.
154+
app.action("button_click", async ({ body, ack, say }) => {
155+
await ack(); // no specific action needed
156+
});
157+
158+
// Start the Bolt app
159+
(async () => {
160+
await app.start(port);
161+
console.log("⚡️ Coder Slack bot is running!");
162+
})();
163+
```
164+
165+
3. Set environment variables to identify the Slack app:
166+
167+
```bash
168+
export SLACK_BOT_TOKEN=xoxb-...
169+
export SLACK_SIGNING_SECRET=0da4b...
170+
```
171+
172+
4. Start the web application by running:
173+
174+
```bash
175+
node app.js
176+
```
177+
178+
## Enable Interactivity in Slack
179+
180+
Slack requires the bot to acknowledge when a user clicks on a URL action button.
181+
This is handled by setting up interactivity.
182+
183+
1. Under "Interactivity & Shortcuts" in your Slack app settings, set the Request
184+
URL to match the public URL of your web server's endpoint.
185+
186+
> Notice: You can use any public endpoint that accepts and responds to POST
187+
> requests with HTTP 200. For temporary testing, you can set it to
188+
> `https://httpbin.org/status/200`.
189+
190+
Once this is set, Slack will send interaction payloads to your server, which
191+
must respond appropriately.
192+
193+
## Enable Webhook Integration in Coder
194+
195+
To enable webhook integration in Coder, ensure the "notifications" experiment is
196+
activated by running the following command:
197+
198+
```bash
199+
export CODER_EXPERIMENTS=notifications
200+
```
201+
202+
Then, define the POST webhook endpoint matching the deployed Slack bot:
203+
204+
```bash
205+
export CODER_NOTIFICATIONS_WEBHOOK_ENDPOINT=http://localhost:6000/v1/webhook`
206+
```
207+
208+
Finally, go to the **Notification Settings** in Coder and switch the notifier to
209+
**Webhook**.

docs/manifest.json

+6
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,12 @@
518518
"path": "./admin/notifications.md",
519519
"icon_path": "./images/icons/info.svg",
520520
"children": [
521+
{
522+
"title": "Slack Notifications",
523+
"description": "Learn how to setup Slack notifications",
524+
"path": "./admin/notifications/slack.md",
525+
"state": "beta"
526+
},
521527
{
522528
"title": "Microsoft Teams Notifications",
523529
"description": "Learn how to setup Microsoft Teams notifications",

0 commit comments

Comments
 (0)