From c61f87c94ee5625f34db1bb2bd84b614bad0a773 Mon Sep 17 00:00:00 2001 From: Brian Lou Date: Wed, 13 Nov 2024 11:46:17 -0800 Subject: [PATCH] Change generic webhook API --- .github/workflows/ci.yml | 28 +++++- .github/workflows/migration.yml | 10 +- bin/deploy.sh | 1 + src/config/secrets.ts | 2 + src/types/index.ts | 47 ++++++---- src/utils/misc/serviceRegistry.ts | 8 ++ src/webhooks/README.md | 36 +++++--- .../generic-notifier/generic-notifier.test.ts | 42 +++++++-- .../generic-notifier/generic-notifier.ts | 91 +++++++++++++------ .../generic-notifier/testMegaPayload.json | 29 +++--- .../generic-notifier/testPayload.json | 34 ++++--- .../generic-notifier/testServicePayload.json | 12 +++ 12 files changed, 248 insertions(+), 92 deletions(-) create mode 100644 src/utils/misc/serviceRegistry.ts create mode 100644 test/payloads/generic-notifier/testServicePayload.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2bcc129e..34eb8e3d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,13 +58,22 @@ jobs: - name: Checkout uses: actions/checkout@v4 + - name: Install Git + run: | + sudo apt-get update + sudo apt-get install git -y + - name: Set up SSH agent (for service-registry) + uses: webfactory/ssh-agent@v0.8.0 + with: + ssh-private-key: ${{ secrets.SENTRY_INTERNAL_GH_SSH_PRIVATE_KEY }} + - name: Setup node uses: actions/setup-node@v4 with: node-version: '18' - name: yarn install - run: yarn install --immutable + run: yarn install --immutable && yarn up "service-registry@git+ssh://git@github.com:getsentry/service-registry#main" - name: tsc run: yarn build @@ -85,8 +94,13 @@ jobs: steps: - uses: actions/checkout@v3 + - name: Set up SSH agent (for service-registry) + uses: webfactory/ssh-agent@v0.8.0 + with: + ssh-private-key: ${{ secrets.SENTRY_INTERNAL_GH_SSH_PRIVATE_KEY }} + - name: Builds docker image - run: docker build -t ci-tooling . + run: DOCKER_BUILDKIT=1 docker build --ssh default -t ci-tooling . build-deploy: name: build and deploy @@ -110,6 +124,14 @@ jobs: with: # for Sentry releases fetch-depth: 0 + - name: Install Git + run: | + sudo apt-get update + sudo apt-get install git -y + - name: Set up SSH agent (for service-registry) + uses: webfactory/ssh-agent@v0.8.0 + with: + ssh-private-key: ${{ secrets.SENTRY_INTERNAL_GH_SSH_PRIVATE_KEY }} - name: Setup node uses: actions/setup-node@v4 @@ -117,7 +139,7 @@ jobs: node-version: '18' - name: yarn install - run: yarn install --immutable + run: yarn install --immutable && yarn up "service-registry@git+ssh://git@github.com:getsentry/service-registry#main" - name: tsc run: yarn build diff --git a/.github/workflows/migration.yml b/.github/workflows/migration.yml index a66c1bda..7fca1419 100644 --- a/.github/workflows/migration.yml +++ b/.github/workflows/migration.yml @@ -33,6 +33,14 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + - name: Install Git + run: | + sudo apt-get update + sudo apt-get install git -y + - name: Set up SSH agent (for service-registry) + uses: webfactory/ssh-agent@v0.8.0 + with: + ssh-private-key: ${{ secrets.SENTRY_INTERNAL_GH_SSH_PRIVATE_KEY }} - name: Setup node uses: actions/setup-node@v4 @@ -59,7 +67,7 @@ jobs: - name: yarn install run: | - yarn install --immutable + yarn install --immutable && yarn up "service-registry@git+ssh://git@github.com:getsentry/service-registry#main" - name: Run migration env: diff --git a/bin/deploy.sh b/bin/deploy.sh index c0b62162..92edb3c7 100755 --- a/bin/deploy.sh +++ b/bin/deploy.sh @@ -27,6 +27,7 @@ GOCD_WEBHOOK_SECRET KAFKA_CONTROL_PLANE_WEBHOOK_SECRET SENTRY_OPTIONS_WEBHOOK_SECRET " +# TODO: Revamp this and make it easier to add secrets & deploy to GCP secrets="" for secret_name in $secret_names; do diff --git a/src/config/secrets.ts b/src/config/secrets.ts index 02af665a..c2ea6d5b 100644 --- a/src/config/secrets.ts +++ b/src/config/secrets.ts @@ -6,6 +6,8 @@ This file contains secrets used for verifying incoming events from different HTT export const EVENT_NOTIFIER_SECRETS = { // Follow the pattern below to add a new secret + // The secret will also need to be added in the deploy.sh script and in + // Google Secret manager // 'example-service': process.env.EXAMPLE_SERVICE_SECRET, }; if (process.env.ENV !== 'production') diff --git a/src/types/index.ts b/src/types/index.ts index ea3cf403..0416b9b8 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -29,23 +29,38 @@ export interface KafkaControlPlaneResponse { body: string; } +export interface SlackMessage { + type: 'slack'; + channels: string[]; + text: string; + blocks?: KnownBlock[] | Block[]; +} + +export interface DatadogEvent { + type: 'datadog'; + title: string; + text: string; + tags: string[]; + alertType: EventAlertType; +} + +export interface JiraEvent { + type: 'jira'; + projectId: string; + title: string; +} + export type GenericEvent = { source: string; timestamp: number; - service_name?: string; // Official service registry name if applicable - data: { - title: string; - message: string; - channels: { - slack?: string[]; // list of Slack Channels - datadog?: string[]; // list of DD Monitors - jira?: string[]; // list of Jira Projects - bigquery?: string; - }; - tags?: string[]; // Not used for Slack - misc: { - alertType?: EventAlertType; // Datadog alert type - blocks?: (KnownBlock | Block)[]; // Optional Slack blocks - }; - }; + data: (DatadogEvent | JiraEvent | SlackMessage | ServiceSlackMessage)[]; }; + +// Currently only used for Slack notifications since +// service registry only contains Slack channels (and not DD or Jira or others) +export interface ServiceSlackMessage { + type: 'service_notification'; + service_name: string; // Official service registry service id + text: string; + blocks?: KnownBlock[] | Block[]; +} diff --git a/src/utils/misc/serviceRegistry.ts b/src/utils/misc/serviceRegistry.ts new file mode 100644 index 00000000..564d7880 --- /dev/null +++ b/src/utils/misc/serviceRegistry.ts @@ -0,0 +1,8 @@ +import servicesData from 'service-registry/sentry_service_registry/config/combined/service_registry.json'; +import type { Service, ServiceRegistry } from 'service-registry/types/index'; + +const services: ServiceRegistry = servicesData; + +export function getService(serviceId: string): Service { + return services[serviceId]; +} diff --git a/src/webhooks/README.md b/src/webhooks/README.md index 21a95384..d2b85980 100644 --- a/src/webhooks/README.md +++ b/src/webhooks/README.md @@ -7,27 +7,35 @@ The folder `generic-notifier` provides a generic webhook which can be used to send messages to Sentry Slack channels and Sentry Datadog. Using this webhook is VERY simple. -Simply, go to `@/config/secrets.ts` and add an entry to the `EVENT_NOTIFIER_SECRETS` object. This entry should contain a mapping from the name of your service (for example, `example-service`) to an environment variable. [TODO: Fill in how to set the prod env var here]. Make a PR with this change and get it approved & merged. +Simply, go to `@/config/secrets.ts` and add an entry to the `EVENT_NOTIFIER_SECRETS` object. This entry should contain a mapping from the source of the message (for example, `example-service`) to an environment variable. As of now, you will also need to edit `bin/deploy.sh` to add the new secret to the deployment and also add the secret to Google Secret Manager. Make a PR with this change and get it approved & merged. -Once this has been deployed, all you have to do is send a POST request to `https://product-eng-webhooks-vmrqv3f7nq-uw.a.run.app/event-notifier/v1` with a JSON payload in the format of the type `GenericEvent` defined in `@/types/index.ts`. Example: +Once this has been deployed, all you have to do is send a POST request to `https://product-eng-webhooks-vmrqv3f7nq-uw.a.run.app/event-notifier/v1` with a JSON payload in the format of the type `GenericEvent` defined in `@/types/index.ts`. Currently, only Datadog and Slack messages are supported. Example: ```json { "source": "example-service", // This must match the mapping string you define in the EVENT_NOTIFIER_SECRETS obj "timestamp": 0, - "service_name": "official_service_name", - "data": { - "title": "This is an Example Notification", - "message": "Random text here", - "tags": [ - "source:example-service", "sentry-region:all", "sentry-user:bob" - ], - "misc": {}, - "channels": { - "slack": ["C07EH2QGGQ5"], - "jira": ["TEST"] + "data": [ + { + "type": "slack", // Basic Slack message + "text": "Random text here", + "channels": ["#aaaaaa"], + // Optionally, include Slack Blocks + "blocks": [] + }, { + "type": "service_notification", // Slack message using service registry information + "service_name": "eng_pipes_gh_notifications", + "text": "Random text here", + // Optionally, include Slack Blocks + "blocks": [] + }, { + "type": "datadog", // Datadog message + "title": "This is an Example Notification", + "text": "Random text here", + "tags": ["source:example-service", "sentry-region:all", "sentry-user:bob"], + "alertType": "info" } - } + ] } ``` diff --git a/src/webhooks/generic-notifier/generic-notifier.test.ts b/src/webhooks/generic-notifier/generic-notifier.test.ts index 2995eeb0..9db372ac 100644 --- a/src/webhooks/generic-notifier/generic-notifier.test.ts +++ b/src/webhooks/generic-notifier/generic-notifier.test.ts @@ -1,12 +1,14 @@ import testInvalidPayload from '@test/payloads/generic-notifier/testInvalidPayload.json'; import testPayload from '@test/payloads/generic-notifier/testPayload.json'; +import testServicePayload from '@test/payloads/generic-notifier/testServicePayload.json'; import { createNotifierRequest } from '@test/utils/createGenericMessageRequest'; import { buildServer } from '@/buildServer'; import { DATADOG_API_INSTANCE } from '@/config'; +import { GenericEvent, ServiceSlackMessage, SlackMessage } from '@/types'; import { bolt } from '@api/slack'; -import { messageSlack } from './generic-notifier'; +import { handleServiceSlackMessage, messageSlack } from './generic-notifier'; describe('generic messages webhook', function () { let fastify; @@ -24,7 +26,10 @@ describe('generic messages webhook', function () { jest .spyOn(DATADOG_API_INSTANCE, 'createEvent') .mockImplementation(jest.fn()); - const response = await createNotifierRequest(fastify, testPayload); + const response = await createNotifierRequest( + fastify, + testPayload as GenericEvent + ); expect(response.statusCode).toBe(200); }); @@ -65,7 +70,7 @@ describe('generic messages webhook', function () { it('writes to slack', async function () { const postMessageSpy = jest.spyOn(bolt.client.chat, 'postMessage'); - await messageSlack(testPayload); + await messageSlack(testPayload.data[0] as SlackMessage); expect(postMessageSpy).toHaveBeenCalledTimes(1); const message = postMessageSpy.mock.calls[0][0]; expect(message).toEqual({ @@ -75,18 +80,43 @@ describe('generic messages webhook', function () { }); }); }); + describe('handleServiceSlackMessage tests', function () { + afterEach(function () { + jest.clearAllMocks(); + }); + + it('writes to slack', async function () { + const postMessageSpy = jest.spyOn(bolt.client.chat, 'postMessage'); + await handleServiceSlackMessage( + testServicePayload.data[0] as ServiceSlackMessage + ); + expect(postMessageSpy).toHaveBeenCalledTimes(1); + const message = postMessageSpy.mock.calls[0][0]; + expect(message).toEqual({ + channel: 'feed-datdog', + text: 'Random text here', + unfurl_links: false, + }); + }); + }); it('checks that slack msg is sent', async function () { const postMessageSpy = jest.spyOn(bolt.client.chat, 'postMessage'); - const response = await createNotifierRequest(fastify, testPayload); + const response = await createNotifierRequest( + fastify, + testPayload as GenericEvent + ); - expect(postMessageSpy).toHaveBeenCalledTimes(1); + expect(postMessageSpy).toHaveBeenCalledTimes(2); expect(response.statusCode).toBe(200); }); it('checks that dd msg is sent', async function () { const ddMessageSpy = jest.spyOn(DATADOG_API_INSTANCE, 'createEvent'); - const response = await createNotifierRequest(fastify, testPayload); + const response = await createNotifierRequest( + fastify, + testPayload as GenericEvent + ); expect(ddMessageSpy).toHaveBeenCalledTimes(1); diff --git a/src/webhooks/generic-notifier/generic-notifier.ts b/src/webhooks/generic-notifier/generic-notifier.ts index 4fbc8aa4..17b2c2d9 100644 --- a/src/webhooks/generic-notifier/generic-notifier.ts +++ b/src/webhooks/generic-notifier/generic-notifier.ts @@ -1,15 +1,21 @@ import { v1 } from '@datadog/datadog-api-client'; import * as Sentry from '@sentry/node'; import { FastifyReply, FastifyRequest } from 'fastify'; -import moment from 'moment-timezone'; -import { GenericEvent } from '@types'; +import { + DatadogEvent, + GenericEvent, + ServiceSlackMessage, + SlackMessage, +} from '@types'; import { bolt } from '@/api/slack'; import { DATADOG_API_INSTANCE } from '@/config'; import { EVENT_NOTIFIER_SECRETS } from '@/config/secrets'; import { extractAndVerifySignature } from '@/utils/auth/extractAndVerifySignature'; +import { getService } from '../../utils/misc/serviceRegistry'; + export async function genericEventNotifier( request: FastifyRequest<{ Body: GenericEvent }>, reply: FastifyReply @@ -24,7 +30,6 @@ export async function genericEventNotifier( reply.code(400).send('Invalid source or missing secret'); throw new Error('Invalid source or missing secret'); } - const isVerified = await extractAndVerifySignature( request, reply, @@ -35,9 +40,15 @@ export async function genericEventNotifier( // If the signature is not verified, return (since extractAndVerifySignature sends the response) return; } - - await messageSlack(body); - await sendEventToDatadog(body, moment().unix()); + for (const message of body.data) { + if (message.type === 'slack') { + await messageSlack(message); + } else if (message.type === 'service_notification') { + await handleServiceSlackMessage(message); + } else if (message.type === 'datadog') { + await sendEventToDatadog(message, body.timestamp); + } + } reply.code(200).send('OK'); return; } catch (err) { @@ -49,36 +60,64 @@ export async function genericEventNotifier( } export async function sendEventToDatadog( - message: GenericEvent, + message: DatadogEvent, timestamp: number ) { - if (message.data.channels.datadog) { + try { const params: v1.EventCreateRequest = { - title: message.data.title, - text: message.data.message, - alertType: message.data.misc.alertType, + title: message.title, + text: message.text, + alertType: message.alertType, dateHappened: timestamp, - tags: message.data.tags, + tags: message.tags, }; await DATADOG_API_INSTANCE.createEvent({ body: params }); + } catch (err) { + Sentry.setContext('dd msg:', { text: message.text }); + Sentry.captureException(err); + } +} + +export async function messageSlack(message: SlackMessage) { + const channels = message.channels ?? []; + for (const channel of channels) { + try { + const args = { + channel: channel, + blocks: message.blocks, + text: message.text, + unfurl_links: false, + }; + if (message.blocks) { + args.blocks = message.blocks; + } + await bolt.client.chat.postMessage(args); + } catch (err) { + Sentry.setContext('slack msg:', { text: message.text }); + Sentry.captureException(err); + } } } -export async function messageSlack(message: GenericEvent) { - if (message.data.channels.slack) { - for (const channel of message.data.channels.slack) { - const text = message.data.message; - try { - await bolt.client.chat.postMessage({ - channel: channel, - blocks: message.data.misc.blocks, - text: text, - unfurl_links: false, - }); - } catch (err) { - Sentry.setContext('msg:', { text }); - Sentry.captureException(err); +export async function handleServiceSlackMessage(message: ServiceSlackMessage) { + const service = getService(message.service_name); + const channels = service.alert_slack_channels ?? []; + for (const channel of channels) { + try { + const args = { + channel: channel, + blocks: message.blocks, + text: message.text, + unfurl_links: false, + }; + if (message.blocks) { + args.blocks = message.blocks; } + await bolt.client.chat.postMessage(args); + } catch (err) { + Sentry.setContext('slack msg:', { text: message.text }); + Sentry.captureException(err); } } + // TODO: Add other types of notifications (Jira, DD, etc.) } diff --git a/test/payloads/generic-notifier/testMegaPayload.json b/test/payloads/generic-notifier/testMegaPayload.json index 1f51f5ef..4122309a 100644 --- a/test/payloads/generic-notifier/testMegaPayload.json +++ b/test/payloads/generic-notifier/testMegaPayload.json @@ -1,18 +1,21 @@ { "source": "example-service", "timestamp": 0, - "service_name": "official_service_name", - "data": { - "title": "This is an Example Notification", - "message": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.\nSed fringilla venenatis ipsum eu vestibulum.\nNam ultricies, elit sed commodo eleifend, ipsum est tempus lorem, porttitor molestie urna sem in eros.\nSuspendisse non interdum sapien, vel commodo dui.\nNunc eu scelerisque augue.\nAliquam eget rhoncus leo.\nDonec nulla elit, aliquet ut porttitor at, sodales quis ex.\nMaecenas sit amet pretium neque.\nIn eu nisi vel purus mattis vehicula in sed mauris.\nPellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.\nProin varius eget nisl sed vulputate.\nFusce quis nibh eu enim blandit bibendum.\nCras volutpat est erat, sit amet molestie ante commodo hendrerit.\nPellentesque in luctus augue.Lorem ipsum dolor sit amet, consectetur adipiscing elit.\nIn ac bibendum odio, condimentum finibus nisi.\nIn at enim vel elit aliquet dictum.\nNullam efficitur gravida gravida.\nNullam scelerisque euismod mi, non dictum elit posuere sed.\nSed dictum quam in ornare lacinia.\nDonec vulputate dictum tortor quis volutpat.\nCurabitur at nulla hendrerit, placerat nibh sed, gravida metus.\nMaecenas nec eros sollicitudin, consectetur nibh sit amet, fringilla nibh.\nUt efficitur convallis luctus.\nIn ultricies lectus non urna faucibus, a venenatis ipsum mollis.\nVivamus tincidunt interdum lorem vitae fermentum.\nVivamus ante nunc, facilisis sed velit egestas, maximus euismod enim.\nSed pretium et ligula ac suscipit.\nSed et metus ut orci faucibus lacinia.\nInteger vestibulum commodo blandit.\nIn dapibus libero nec mauris sagittis, vel accumsan erat feugiat.\nCurabitur tempus, arcu non accumsan faucibus, sapien nisl pharetra justo, id fringilla mauris sem eu ante.\nProin ac feugiat dolor.\nNulla auctor vestibulum tortor at placerat.\nCras tempus non tortor ut dictum.\nSed eleifend velit nisi, sit amet lacinia velit convallis non.\nCurabitur imperdiet tortor sit amet massa condimentum, nec cursus lectus placerat.\nUt egestas suscipit est, at ultricies tellus viverra ut.\nSed elementum dignissim nulla, a feugiat massa mollis quis.\nPellentesque a lobortis dolor.\nCras eleifend condimentum orci, a venenatis arcu feugiat at.\nSuspendisse condimentum neque metus, non faucibus libero ultricies nec.\nInteger quis orci at enim aliquet dapibus id quis nisl.\nMaecenas et convallis massa.\nSed ornare sagittis erat, et hendrerit neque auctor quis.\nSed dignissim erat nisl, sed pharetra mauris sollicitudin sed.\nNullam eu purus quis augue scelerisque aliquam id sed enim.\nMaecenas in posuere ex.\nVivamus quis sem faucibus, suscipit eros nec, bibendum purus.\nUt in urna orci.\nAenean id bibendum urna.\nDuis gravida ac massa vel egestas.\nFusce in erat hendrerit nunc tempus dictum.\nCras sapien diam, eleifend vitae commodo in, bibendum ut eros.\nNam sit amet massa tincidunt neque rutrum sodales.\nNunc vitae felis ut diam lobortis pellentesque.\nNunc nulla ante, sodales non tempor pretium, vulputate vel nisi.\nNulla facilisis dolor sit amet aliquam imperdiet.\nPellentesque lacinia augue eget nulla finibus tincidunt.\nNam urna tellus, aliquam sit amet velit vestibulum, dictum eleifend dolor.\nDonec eu commodo est, non tincidunt orci.\nCras vel nisl libero.\nPraesent cursus neque massa.\nNunc convallis vitae sem nec tincidunt.\nEtiam eget dui in ligula dictum sodales nec quis ante.\nCras sagittis, dui at tempus porttitor, lectus ipsum malesuada augue, vitae suscipit felis lacus facilisis nisl.\nDonec tristique tellus at aliquet accumsan.\nInteger elementum venenatis mollis.\nSuspendisse rutrum eros eget justo scelerisque facilisis.\nDonec vehicula neque at lectus interdum egestas.\nPellentesque dolor dui, feugiat ac placerat sit amet, lacinia sed massa.\nMaecenas aliquam, massa sodales ultrices pellentesque, est tortor pharetra metus, at congue libero ligula ut purus.\nVestibulum mattis scelerisque tellus, vitae volutpat velit ultrices nec.\nUt mollis hendrerit magna vitae mollis.\nNulla pharetra magna eros, quis facilisis arcu accumsan sodales.\nIn pharetra quam maximus turpis volutpat blandit.\nIn at dui nec velit sagittis tincidunt.\nIn felis orci, vulputate non luctus ac, molestie vitae urna.\nIn iaculis velit id convallis condimentum.", - "tags": [ - "source:example-service", "sentry-region:all", "sentry-user:bob" - ], - "misc": {}, - "channels": { - "slack": ["#C07GZR8LA82"], - "datadog": ["example-proj-id"], - "jira": ["INC"] + "data": [ + { + "type": "slack", + "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.\nSed fringilla venenatis ipsum eu vestibulum.\nNam ultricies, elit sed commodo eleifend, ipsum est tempus lorem, porttitor molestie urna sem in eros.\nSuspendisse non interdum sapien, vel commodo dui.\nNunc eu scelerisque augue.\nAliquam eget rhoncus leo.\nDonec nulla elit, aliquet ut porttitor at, sodales quis ex.\nMaecenas sit amet pretium neque.\nIn eu nisi vel purus mattis vehicula in sed mauris.\nPellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.\nProin varius eget nisl sed vulputate.\nFusce quis nibh eu enim blandit bibendum.\nCras volutpat est erat, sit amet molestie ante commodo hendrerit.\nPellentesque in luctus augue.Lorem ipsum dolor sit amet, consectetur adipiscing elit.\nIn ac bibendum odio, condimentum finibus nisi.\nIn at enim vel elit aliquet dictum.\nNullam efficitur gravida gravida.\nNullam scelerisque euismod mi, non dictum elit posuere sed.\nSed dictum quam in ornare lacinia.\nDonec vulputate dictum tortor quis volutpat.\nCurabitur at nulla hendrerit, placerat nibh sed, gravida metus.\nMaecenas nec eros sollicitudin, consectetur nibh sit amet, fringilla nibh.\nUt efficitur convallis luctus.\nIn ultricies lectus non urna faucibus, a venenatis ipsum mollis.\nVivamus tincidunt interdum lorem vitae fermentum.\nVivamus ante nunc, facilisis sed velit egestas, maximus euismod enim.\nSed pretium et ligula ac suscipit.\nSed et metus ut orci faucibus lacinia.\nInteger vestibulum commodo blandit.\nIn dapibus libero nec mauris sagittis, vel accumsan erat feugiat.\nCurabitur tempus, arcu non accumsan faucibus, sapien nisl pharetra justo, id fringilla mauris sem eu ante.\nProin ac feugiat dolor.\nNulla auctor vestibulum tortor at placerat.\nCras tempus non tortor ut dictum.\nSed eleifend velit nisi, sit amet lacinia velit convallis non.\nCurabitur imperdiet tortor sit amet massa condimentum, nec cursus lectus placerat.\nUt egestas suscipit est, at ultricies tellus viverra ut.\nSed elementum dignissim nulla, a feugiat massa mollis quis.\nPellentesque a lobortis dolor.\nCras eleifend condimentum orci, a venenatis arcu feugiat at.\nSuspendisse condimentum neque metus, non faucibus libero ultricies nec.\nInteger quis orci at enim aliquet dapibus id quis nisl.\nMaecenas et convallis massa.\nSed ornare sagittis erat, et hendrerit neque auctor quis.\nSed dignissim erat nisl, sed pharetra mauris sollicitudin sed.\nNullam eu purus quis augue scelerisque aliquam id sed enim.\nMaecenas in posuere ex.\nVivamus quis sem faucibus, suscipit eros nec, bibendum purus.\nUt in urna orci.\nAenean id bibendum urna.\nDuis gravida ac massa vel egestas.\nFusce in erat hendrerit nunc tempus dictum.\nCras sapien diam, eleifend vitae commodo in, bibendum ut eros.\nNam sit amet massa tincidunt neque rutrum sodales.\nNunc vitae felis ut diam lobortis pellentesque.\nNunc nulla ante, sodales non tempor pretium, vulputate vel nisi.\nNulla facilisis dolor sit amet aliquam imperdiet.\nPellentesque lacinia augue eget nulla finibus tincidunt.\nNam urna tellus, aliquam sit amet velit vestibulum, dictum eleifend dolor.\nDonec eu commodo est, non tincidunt orci.\nCras vel nisl libero.\nPraesent cursus neque massa.\nNunc convallis vitae sem nec tincidunt.\nEtiam eget dui in ligula dictum sodales nec quis ante.\nCras sagittis, dui at tempus porttitor, lectus ipsum malesuada augue, vitae suscipit felis lacus facilisis nisl.\nDonec tristique tellus at aliquet accumsan.\nInteger elementum venenatis mollis.\nSuspendisse rutrum eros eget justo scelerisque facilisis.\nDonec vehicula neque at lectus interdum egestas.\nPellentesque dolor dui, feugiat ac placerat sit amet, lacinia sed massa.\nMaecenas aliquam, massa sodales ultrices pellentesque, est tortor pharetra metus, at congue libero ligula ut purus.\nVestibulum mattis scelerisque tellus, vitae volutpat velit ultrices nec.\nUt mollis hendrerit magna vitae mollis.\nNulla pharetra magna eros, quis facilisis arcu accumsan sodales.\nIn pharetra quam maximus turpis volutpat blandit.\nIn at dui nec velit sagittis tincidunt.\nIn felis orci, vulputate non luctus ac, molestie vitae urna.\nIn iaculis velit id convallis condimentum.", + "channels": ["#aaaaaa"] + }, { + "type": "datadog", + "title": "This is an Example Notification", + "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.\nSed fringilla venenatis ipsum eu vestibulum.\nNam ultricies, elit sed commodo eleifend, ipsum est tempus lorem, porttitor molestie urna sem in eros.\nSuspendisse non interdum sapien, vel commodo dui.\nNunc eu scelerisque augue.\nAliquam eget rhoncus leo.\nDonec nulla elit, aliquet ut porttitor at, sodales quis ex.\nMaecenas sit amet pretium neque.\nIn eu nisi vel purus mattis vehicula in sed mauris.\nPellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.\nProin varius eget nisl sed vulputate.\nFusce quis nibh eu enim blandit bibendum.\nCras volutpat est erat, sit amet molestie ante commodo hendrerit.\nPellentesque in luctus augue.Lorem ipsum dolor sit amet, consectetur adipiscing elit.\nIn ac bibendum odio, condimentum finibus nisi.\nIn at enim vel elit aliquet dictum.\nNullam efficitur gravida gravida.\nNullam scelerisque euismod mi, non dictum elit posuere sed.\nSed dictum quam in ornare lacinia.\nDonec vulputate dictum tortor quis volutpat.\nCurabitur at nulla hendrerit, placerat nibh sed, gravida metus.\nMaecenas nec eros sollicitudin, consectetur nibh sit amet, fringilla nibh.\nUt efficitur convallis luctus.\nIn ultricies lectus non urna faucibus, a venenatis ipsum mollis.\nVivamus tincidunt interdum lorem vitae fermentum.\nVivamus ante nunc, facilisis sed velit egestas, maximus euismod enim.\nSed pretium et ligula ac suscipit.\nSed et metus ut orci faucibus lacinia.\nInteger vestibulum commodo blandit.\nIn dapibus libero nec mauris sagittis, vel accumsan erat feugiat.\nCurabitur tempus, arcu non accumsan faucibus, sapien nisl pharetra justo, id fringilla mauris sem eu ante.\nProin ac feugiat dolor.\nNulla auctor vestibulum tortor at placerat.\nCras tempus non tortor ut dictum.\nSed eleifend velit nisi, sit amet lacinia velit convallis non.\nCurabitur imperdiet tortor sit amet massa condimentum, nec cursus lectus placerat.\nUt egestas suscipit est, at ultricies tellus viverra ut.\nSed elementum dignissim nulla, a feugiat massa mollis quis.\nPellentesque a lobortis dolor.\nCras eleifend condimentum orci, a venenatis arcu feugiat at.\nSuspendisse condimentum neque metus, non faucibus libero ultricies nec.\nInteger quis orci at enim aliquet dapibus id quis nisl.\nMaecenas et convallis massa.\nSed ornare sagittis erat, et hendrerit neque auctor quis.\nSed dignissim erat nisl, sed pharetra mauris sollicitudin sed.\nNullam eu purus quis augue scelerisque aliquam id sed enim.\nMaecenas in posuere ex.\nVivamus quis sem faucibus, suscipit eros nec, bibendum purus.\nUt in urna orci.\nAenean id bibendum urna.\nDuis gravida ac massa vel egestas.\nFusce in erat hendrerit nunc tempus dictum.\nCras sapien diam, eleifend vitae commodo in, bibendum ut eros.\nNam sit amet massa tincidunt neque rutrum sodales.\nNunc vitae felis ut diam lobortis pellentesque.\nNunc nulla ante, sodales non tempor pretium, vulputate vel nisi.\nNulla facilisis dolor sit amet aliquam imperdiet.\nPellentesque lacinia augue eget nulla finibus tincidunt.\nNam urna tellus, aliquam sit amet velit vestibulum, dictum eleifend dolor.\nDonec eu commodo est, non tincidunt orci.\nCras vel nisl libero.\nPraesent cursus neque massa.\nNunc convallis vitae sem nec tincidunt.\nEtiam eget dui in ligula dictum sodales nec quis ante.\nCras sagittis, dui at tempus porttitor, lectus ipsum malesuada augue, vitae suscipit felis lacus facilisis nisl.\nDonec tristique tellus at aliquet accumsan.\nInteger elementum venenatis mollis.\nSuspendisse rutrum eros eget justo scelerisque facilisis.\nDonec vehicula neque at lectus interdum egestas.\nPellentesque dolor dui, feugiat ac placerat sit amet, lacinia sed massa.\nMaecenas aliquam, massa sodales ultrices pellentesque, est tortor pharetra metus, at congue libero ligula ut purus.\nVestibulum mattis scelerisque tellus, vitae volutpat velit ultrices nec.\nUt mollis hendrerit magna vitae mollis.\nNulla pharetra magna eros, quis facilisis arcu accumsan sodales.\nIn pharetra quam maximus turpis volutpat blandit.\nIn at dui nec velit sagittis tincidunt.\nIn felis orci, vulputate non luctus ac, molestie vitae urna.\nIn iaculis velit id convallis condimentum.", + "tags": ["source:example-service", "sentry-region:all", "sentry-user:bob"], + "alertType": "info" + }, { + "type": "jira", + "title": "This is an Example Notification", + "projectId": "TEST" } - } + ] } \ No newline at end of file diff --git a/test/payloads/generic-notifier/testPayload.json b/test/payloads/generic-notifier/testPayload.json index 77330298..4b4da639 100644 --- a/test/payloads/generic-notifier/testPayload.json +++ b/test/payloads/generic-notifier/testPayload.json @@ -1,18 +1,26 @@ { "source": "example-service", "timestamp": 0, - "service_name": "official_service_name", - "data": { - "title": "This is an Example Notification", - "message": "Random text here", - "tags": [ - "source:example-service", "sentry-region:all", "sentry-user:bob" - ], - "misc": {}, - "channels": { - "slack": ["#aaaaaa"], - "datadog": ["example-proj-id"], - "jira": ["TEST"] + "data": [ + { + "type": "slack", + "text": "Random text here", + "channels": ["#aaaaaa"] + }, { + "type": "service_notification", + "service_name": "eng_pipes_gh_notifications", + "text": "Random text here", + "channels": ["#aaaaaa"] + }, { + "type": "datadog", + "title": "This is an Example Notification", + "text": "Random text here", + "tags": ["source:example-service", "sentry-region:all", "sentry-user:bob"], + "alertType": "info" + }, { + "type": "jira", + "title": "This is an Example Notification", + "projectId": "TEST" } - } + ] } \ No newline at end of file diff --git a/test/payloads/generic-notifier/testServicePayload.json b/test/payloads/generic-notifier/testServicePayload.json new file mode 100644 index 00000000..26e0521d --- /dev/null +++ b/test/payloads/generic-notifier/testServicePayload.json @@ -0,0 +1,12 @@ +{ + "source": "example-service", + "timestamp": 0, + "data": [ + { + "type": "service_notification", + "service_name": "eng_pipes_gh_notifications", + "text": "Random text here", + "channels": ["#aaaaaa"] + } + ] +} \ No newline at end of file