@rpallas/outcrop-chatops
Delivers platform alerts to Slack and Microsoft Teams incoming webhooks. ChatOpsNotifier subscribes one Lambda function to SNS topics (by default the four per-severity alert topics the account baseline publishes) and renders CloudWatch alarm state changes, AWS Budgets notifications, EventBridge events and plain text messages as Slack Block Kit messages or Teams Adaptive Cards.
npm install @rpallas/outcrop-chatopsCreating the webhook secrets
Webhook URLs are secrets. Store them in Secrets Manager, never in code or templates. With the account baseline (@rpallas/outcrop-account) declare them as shared secrets:
sharedSecrets: { secrets: { "slack-webhook": {}, "teams-webhook": {} } },The baseline generates placeholder values and publishes the ARNs under /platform/secrets/{name}/arn. Replace the values once with the real webhook URLs:
aws secretsmanager put-secret-value \
--secret-id platform-dev-slack-webhook \
--secret-string 'https://hooks.example.com/services/T000/B000/XXXX'Plain URL strings and JSON documents { "url": "https://..." } are both accepted.
Usage from a service stack
Inside a PlatformStack everything defaults to the SSM contract: the topics are the environment alert topics and the secrets are the shared slack-webhook / teams-webhook secrets.
import { ChatOpsNotifier } from "@rpallas/outcrop-chatops";
new ChatOpsNotifier(this, "ChatOps", {
destinations: [
{ kind: "slack", channelLabel: "#orders-alerts" },
{ kind: "teams", minimumSeverity: "high", webhookSecretName: "ops-teams-webhook" },
],
});Options:
| Prop | Default | Notes |
|---|---|---|
destinations | required | One or more Slack/Teams destinations |
topics | environment alert topics | Any ITopic[]; required outside a PlatformStack |
severities | all four | Subset of the default topics to subscribe to |
deadLetterQueue | true | false to disable, or an existing IQueue |
errorAlarm | true | errors alarm on the function (routed to the high topic) |
timeout | 30 seconds |
Per destination: kind (slack or teams), webhookSecretName or webhookSecret, minimumSeverity (default low, meaning everything) and an optional channelLabel rendered in the message.
The construct exposes handler (a PlatformFunction inside a PlatformStack), topics, destinations, deadLetterQueue and errorAlarm.
Usage from the account baseline
The account baseline stack is a plain Stack, and the natural place to route the environment's alert topics because it owns them. Outside a PlatformStack the construct falls back to a plain NodejsFunction (ARM64, Node.js 24, X-Ray, one-month log retention) and requires explicit topics and a webhookSecret per destination; the errors alarm is not created there.
import { ALERT_SEVERITIES } from "@rpallas/outcrop";
import { createAccountBaseline } from "@rpallas/outcrop-account";
import { ChatOpsNotifier } from "@rpallas/outcrop-chatops";
const { baseline } = createAccountBaseline(app, { config, modules });
const { alerting, sharedSecrets } = baseline.baseline;
const slackWebhook = sharedSecrets?.secrets["slack-webhook"];
if (alerting && slackWebhook) {
new ChatOpsNotifier(baseline, "ChatOps", {
topics: ALERT_SEVERITIES.map((severity) => alerting.topics[severity]),
destinations: [{ kind: "slack", webhookSecret: slackWebhook }],
});
}What gets delivered
Each SNS record is normalised into one message:
- CloudWatch alarms – header
:rotating_light: <alarm> is ALARM(:white_check_mark:forOK,:grey_question:forINSUFFICIENT_DATA), fields for severity, environment, service, account, region, time, metric and threshold, the state reason, and a deep link to the alarm in the console. Service and severity come from the platform alarm description ([high] orders: api-errors); the environment from the topic name (platform-dev-alerts-high). - AWS Budgets – budget name, threshold and current amount extracted from the notification text.
- EventBridge events –
detail-type,sourceand the pretty-printeddetail. - Anything else – subject and message text.
Severity is taken from the platform:severity SNS message attribute when present, otherwise from the topic name suffix (...-alerts-critical), otherwise medium. Destinations with a minimumSeverity above the message severity are skipped.
Slack messages use Block Kit (header, section fields, context with the console link). Teams messages are application/vnd.microsoft.card.adaptive attachments with an Adaptive Card 1.4 (TextBlock, FactSet, Action.OpenUrl).
Delivery failures with 429 or 5xx responses are retried once; a persistent failure makes the invocation fail so the SNS retry policy and the dead letter queue apply.
Limitations
- Incoming webhooks only; no interactive messages, threading or acknowledgements.
- Both Slack and Teams truncate long payloads; reasons and bodies are cut to fit.
- Webhook URLs are cached for the lifetime of the Lambda execution environment; rotate a secret and the function picks it up after the next cold start or a failed delivery.
- The
errorsalarm of the notifier itself routes to thehightopic, so a notifier that is permanently broken produces a notification it cannot deliver; the dead letter queue keeps those.
Classes
ChatOpsNotifier
Defined in: chatops.ts:78
Delivers SNS alert notifications (CloudWatch alarms, AWS Budgets, EventBridge events or plain text) to Slack and Microsoft Teams incoming webhooks.
Inside a PlatformStack the topics and webhook secrets default to the account baseline's contract and the function is a PlatformFunction with the usual naming, log retention and alarms. In a plain Stack (for example the account baseline itself) pass explicit topics and a webhookSecret per destination.
Extends
Construct
Constructors
Constructor
new ChatOpsNotifier(
scope,
id,
props
): ChatOpsNotifier;Defined in: chatops.ts:93
Parameters
| Parameter | Type |
|---|---|
scope | Construct |
id | string |
props | ChatOpsNotifierProps |
Returns
Overrides
Construct.constructorProperties
| Property | Modifier | Type | Description | Defined in |
|---|---|---|---|---|
deadLetterQueue | readonly | IQueue | undefined | Dead letter queue when enabled. | chatops.ts:89 |
destinations | readonly | readonly object[] | Resolved destinations with their secrets. | chatops.ts:84 |
errorAlarm | readonly | PlatformAlarm | undefined | Errors alarm when created. | chatops.ts:91 |
handler | readonly | NodejsFunction | The notifier function (PlatformFunction inside a PlatformStack). | chatops.ts:80 |
topics | readonly | readonly ITopic[] | Topics this notifier is subscribed to. | chatops.ts:82 |
Interfaces
AlertField
Defined in: message-templates.ts:24
Properties
| Property | Modifier | Type | Defined in |
|---|---|---|---|
label | readonly | string | message-templates.ts:25 |
value | readonly | string | message-templates.ts:26 |
AlertMessage
Defined in: message-templates.ts:7
Normalised notification, independent of the chat provider.
Properties
| Property | Modifier | Type | Description | Defined in |
|---|---|---|---|---|
account? | readonly | string | - | message-templates.ts:17 |
env? | readonly | string | - | message-templates.ts:15 |
fields | readonly | readonly AlertField[] | Extra label/value pairs rendered as fields. | message-templates.ts:21 |
kind | readonly | "alarm" | "budget" | "event" | "text" | - | message-templates.ts:8 |
link? | readonly | string | - | message-templates.ts:19 |
reason? | readonly | string | - | message-templates.ts:13 |
region? | readonly | string | - | message-templates.ts:18 |
service? | readonly | string | - | message-templates.ts:16 |
severity | readonly | "critical" | "high" | "medium" | "low" | - | message-templates.ts:11 |
state | readonly | AlertState | - | message-templates.ts:10 |
summary | readonly | string | - | message-templates.ts:12 |
time? | readonly | string | - | message-templates.ts:14 |
title | readonly | string | - | message-templates.ts:9 |
BudgetNotification
Defined in: message-templates.ts:51
Parsed AWS Budgets notification (plain text e-mail style message).
Properties
| Property | Modifier | Type | Defined in |
|---|---|---|---|
accountId? | readonly | string | message-templates.ts:53 |
actualText? | readonly | string | message-templates.ts:55 |
body | readonly | string | message-templates.ts:56 |
budgetName? | readonly | string | message-templates.ts:52 |
thresholdText? | readonly | string | message-templates.ts:54 |
ChatOpsDestination
Defined in: chatops.ts:26
Properties
| Property | Modifier | Type | Description | Defined in |
|---|---|---|---|---|
channelLabel? | readonly | string | Free-text label rendered in the message, for example the channel name. | chatops.ts:40 |
kind | readonly | ChatOpsKind | Chat provider; selects the payload format. | chatops.ts:28 |
minimumSeverity? | readonly | "critical" | "high" | "medium" | "low" | Lowest severity delivered to this destination. Default low (everything). | chatops.ts:38 |
webhookSecret? | readonly | ISecret | Explicit webhook secret instead of webhookSecretName. | chatops.ts:36 |
webhookSecretName? | readonly | string | Name of the shared secret (published by the account baseline under /platform/secrets/{name}/arn) holding the incoming webhook URL. Default slack-webhook / teams-webhook. Requires a PlatformStack. | chatops.ts:34 |
ChatOpsNotifierProps
Defined in: chatops.ts:43
Properties
| Property | Modifier | Type | Description | Defined in |
|---|---|---|---|---|
deadLetterQueue? | readonly | boolean | IQueue | Send failed deliveries to a dead letter queue. Default true. Pass an existing queue to reuse it. | chatops.ts:58 |
destinations | readonly | ChatOpsDestination[] | Where to deliver messages. At least one. | chatops.ts:53 |
errorAlarm? | readonly | boolean | Create the errors alarm on the notifier function (routed to the environment's high topic). Default true inside a PlatformStack; never created in a plain Stack. | chatops.ts:64 |
severities? | readonly | ("critical" | "high" | "medium" | "low")[] | Only subscribe to these severities when using the default topics. Default: all four. | chatops.ts:51 |
timeout? | readonly | Duration | Function timeout. Default 30 seconds. | chatops.ts:66 |
topics? | readonly | ITopic[] | Topics to subscribe to. Default: the environment alert topics published by the account baseline (/platform/env/{env}/alerts/topic-arn/{severity}), which requires a PlatformStack. | chatops.ts:49 |
CloudWatchAlarmNotification
Defined in: message-templates.ts:30
Subset of the CloudWatch alarm state change notification that is rendered.
Properties
| Property | Modifier | Type | Defined in |
|---|---|---|---|
AlarmArn? | readonly | string | message-templates.ts:35 |
AlarmDescription? | readonly | string | null | message-templates.ts:32 |
AlarmName | readonly | string | message-templates.ts:31 |
AWSAccountId? | readonly | string | message-templates.ts:33 |
NewStateReason? | readonly | string | message-templates.ts:37 |
NewStateValue | readonly | string | message-templates.ts:36 |
OldStateValue? | readonly | string | message-templates.ts:38 |
Region? | readonly | string | message-templates.ts:34 |
StateChangeTime? | readonly | string | message-templates.ts:39 |
Trigger? | readonly | object | message-templates.ts:40 |
Trigger.ComparisonOperator? | readonly | string | message-templates.ts:45 |
Trigger.Dimensions? | readonly | readonly object[] | message-templates.ts:46 |
Trigger.MetricName? | readonly | string | message-templates.ts:41 |
Trigger.Namespace? | readonly | string | message-templates.ts:42 |
Trigger.Statistic? | readonly | string | message-templates.ts:43 |
Trigger.Threshold? | readonly | number | message-templates.ts:44 |
DestinationConfig
Defined in: handlers/notify.ts:26
One destination as serialised into the DESTINATIONS environment variable.
Properties
| Property | Modifier | Type | Description | Defined in |
|---|---|---|---|---|
channelLabel? | readonly | string | - | handlers/notify.ts:31 |
kind | readonly | ChatOpsKind | - | handlers/notify.ts:27 |
minimumSeverity | readonly | "critical" | "high" | "medium" | "low" | - | handlers/notify.ts:30 |
webhookSecretArn | readonly | string | Secrets Manager ARN of the secret holding the webhook URL. | handlers/notify.ts:29 |
EventBridgeNotification
Defined in: message-templates.ts:60
Parsed EventBridge event (as delivered to SNS by a rule).
Properties
| Property | Modifier | Type | Defined in |
|---|---|---|---|
account? | readonly | string | message-templates.ts:63 |
detail | readonly | unknown | message-templates.ts:66 |
detailType | readonly | string | message-templates.ts:62 |
region? | readonly | string | message-templates.ts:64 |
source | readonly | string | message-templates.ts:61 |
time? | readonly | string | message-templates.ts:65 |
FormatMessageInput
Defined in: message-templates.ts:70
Inputs used to normalise one SNS record.
Properties
| Property | Modifier | Type | Description | Defined in |
|---|---|---|---|---|
attributes? | readonly | Readonly<Record<string, string>> | SNS message attributes flattened to name -> value. | message-templates.ts:75 |
message | readonly | string | - | message-templates.ts:71 |
subject? | readonly | string | - | message-templates.ts:72 |
topicArn? | readonly | string | - | message-templates.ts:73 |
PayloadOptions
Defined in: message-templates.ts:343
Properties
| Property | Modifier | Type | Description | Defined in |
|---|---|---|---|---|
channelLabel? | readonly | string | Free-text label shown in the message (for example the channel or team). | message-templates.ts:345 |
Type Aliases
AlertState
type AlertState = "ALARM" | "OK" | "INSUFFICIENT_DATA" | "INFO";Defined in: message-templates.ts:4
State of the thing that triggered a notification.
ChatOpsKind
type ChatOpsKind = "slack" | "teams";Defined in: handlers/notify.ts:23
Supported chat providers.
Variables
DEFAULT_WEBHOOK_SECRET_NAMES
const DEFAULT_WEBHOOK_SECRET_NAMES: Readonly<Record<ChatOpsKind, string>>;Defined in: chatops.ts:21
DESTINATIONS_ENV
const DESTINATIONS_ENV: "DESTINATIONS" = "DESTINATIONS";Defined in: handlers/notify.ts:35
Name of the environment variable carrying the JSON DestinationConfig[].
Functions
alarmConsoleUrl()
function alarmConsoleUrl(region, alarmName): string;Defined in: message-templates.ts:94
Deep link to a CloudWatch alarm in the console.
Parameters
| Parameter | Type |
|---|---|
region | string |
alarmName | string |
Returns
string
formatMessage()
function formatMessage(input): AlertMessage;Defined in: message-templates.ts:240
Normalise an SNS message (alarm, budget, EventBridge event or text) into an AlertMessage.
Parameters
| Parameter | Type |
|---|---|
input | FormatMessageInput |
Returns
meetsMinimumSeverity()
function meetsMinimumSeverity(severity, minimum): boolean;Defined in: message-templates.ts:87
True when severity is at least minimum.
Parameters
| Parameter | Type |
|---|---|
severity | "critical" | "high" | "medium" | "low" |
minimum | "critical" | "high" | "medium" | "low" |
Returns
boolean
parseAlarmMessage()
function parseAlarmMessage(message):
| CloudWatchAlarmNotification
| undefined;Defined in: message-templates.ts:138
Parse a CloudWatch alarm state change notification; undefined when the message is something else.
Parameters
| Parameter | Type |
|---|---|
message | string |
Returns
| CloudWatchAlarmNotification | undefined
parseAlarmName()
function parseAlarmName(alarmName, description?): object;Defined in: message-templates.ts:200
Platform alarms are described as [severity] service: name; recover the service (and severity) from that. Falls back to the alarm name segments.
Parameters
| Parameter | Type |
|---|---|
alarmName | string |
description? | string | null |
Returns
object
| Name | Type | Defined in |
|---|---|---|
service? | string | message-templates.ts:203 |
severity? | "critical" | "high" | "medium" | "low" | message-templates.ts:203 |
shortName? | string | message-templates.ts:203 |
parseBudgetMessage()
function parseBudgetMessage(message, subject?): BudgetNotification | undefined;Defined in: message-templates.ts:150
Parse an AWS Budgets notification; undefined when the message is not one.
Parameters
| Parameter | Type |
|---|---|
message | string |
subject? | string |
Returns
BudgetNotification | undefined
parseEventBridgeMessage()
function parseEventBridgeMessage(message): EventBridgeNotification | undefined;Defined in: message-templates.ts:178
Parse an EventBridge event; undefined when the message is not one.
Parameters
| Parameter | Type |
|---|---|
message | string |
Returns
EventBridgeNotification | undefined
severityFromTopicArn()
function severityFromTopicArn(topicArn): "critical" | "high" | "medium" | "low" | undefined;Defined in: message-templates.ts:102
Severity encoded in the platform alert topic name (...-alerts-critical).
Parameters
| Parameter | Type |
|---|---|
topicArn | string | undefined |
Returns
"critical" | "high" | "medium" | "low" | undefined
severityRank()
function severityRank(severity): number;Defined in: message-templates.ts:84
Numeric rank of a severity (low = 0 ... critical = 3).
Parameters
| Parameter | Type |
|---|---|
severity | "critical" | "high" | "medium" | "low" |
Returns
number
slackPayload()
function slackPayload(alert, options?): Record<string, unknown>;Defined in: message-templates.ts:359
Slack Block Kit payload for an incoming webhook.
Parameters
| Parameter | Type |
|---|---|
alert | AlertMessage |
options | PayloadOptions |
Returns
Record<string, unknown>
teamsPayload()
function teamsPayload(alert, options?): Record<string, unknown>;Defined in: message-templates.ts:397
Microsoft Teams incoming webhook payload with an Adaptive Card (schema 1.4).
Parameters
| Parameter | Type |
|---|---|
alert | AlertMessage |
options | PayloadOptions |
Returns
Record<string, unknown>