@oneuptime/common 12.0.18 → 12.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Models/DatabaseModels/EnterpriseLicense.ts +23 -0
- package/Models/DatabaseModels/Index.ts +4 -2
- package/Models/DatabaseModels/Monitor.ts +39 -9
- package/Models/DatabaseModels/UserMicrosoftTeams.ts +344 -0
- package/Models/DatabaseModels/UserNotificationRule.ts +144 -8
- package/Models/DatabaseModels/UserNotificationSetting.ts +34 -0
- package/Models/DatabaseModels/UserOnCallLogTimeline.ts +95 -0
- package/Models/DatabaseModels/UserSlack.ts +341 -0
- package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +9 -0
- package/Server/API/UserMicrosoftTeamsAPI.ts +127 -0
- package/Server/API/UserSlackAPI.ts +125 -0
- package/Server/EnvironmentConfig.ts +12 -107
- package/Server/Infrastructure/Postgres/SchemaMigrations/1788700000000-RemoveMarketingConversionUploadState.ts +33 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1788800000000-DropMarketingConversionAddEnterpriseLicenseEmail.ts +51 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1788900000000-RedactStoredMonitorIngestSecrets.ts +117 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1789000000000-AddUserSlackAndMicrosoftTeams.ts +197 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
- package/Server/Infrastructure/Queue.ts +7 -0
- package/Server/Services/EnterpriseLicenseService.ts +60 -0
- package/Server/Services/Index.ts +6 -2
- package/Server/Services/LlmLogService.ts +25 -9
- package/Server/Services/OnCallReadinessService.ts +86 -2
- package/Server/Services/ProjectService.ts +67 -0
- package/Server/Services/UserMicrosoftTeamsService.ts +208 -0
- package/Server/Services/UserNotificationMethodAdminService.ts +167 -5
- package/Server/Services/UserNotificationRuleAdminService.ts +40 -6
- package/Server/Services/UserNotificationRuleService.ts +589 -11
- package/Server/Services/UserNotificationSettingService.ts +138 -0
- package/Server/Services/UserService.ts +28 -0
- package/Server/Services/UserSlackService.ts +218 -0
- package/Server/Services/WorkspaceProjectAuthTokenService.ts +67 -1
- package/Server/Services/WorkspaceUserAuthTokenService.ts +73 -0
- package/Server/Services/WorkspaceUserNotificationService.ts +190 -0
- package/Server/Utils/Marketing/MarketingEventUtil.ts +145 -0
- package/Server/Utils/Marketing/MarketingEventWebhook.ts +114 -0
- package/Server/Utils/Monitor/MonitorLogUtil.ts +14 -1
- package/Server/Utils/Monitor/MonitorPayloadRedaction.ts +321 -0
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +191 -4
- package/Tests/App/Dashboard/AdminNotificationRulesPage.test.tsx +22 -14
- package/Tests/App/Dashboard/AdminUserNotificationMethodsPage.test.tsx +22 -11
- package/Tests/App/Dashboard/OnCallPreventionGuards.test.tsx +37 -1
- package/Tests/App/Dashboard/OnCallRulesTable.test.tsx +18 -10
- package/Tests/Models/DatabaseModels/DomainRoleTierCoverage.test.ts +27 -1
- package/Tests/Models/DatabaseModels/MonitorSecretKeyColumnAccessControl.test.ts +214 -0
- package/Tests/Server/API/OnCallReadinessAPI.test.ts +145 -26
- package/Tests/Server/API/UserNotificationMethodAdminAPI.test.ts +2 -2
- package/Tests/Server/Services/AIServiceDailyBudget.test.ts +11 -1
- package/Tests/Server/Services/AdminRuleEditGuards.test.ts +22 -8
- package/Tests/Server/Services/DeliverNotificationForRuleExtraction.test.ts +18 -2
- package/Tests/Server/Services/EpisodeRuleSeverityRepair.test.ts +5 -1
- package/Tests/Server/Services/LlmLogServiceTokenAggregateParams.test.ts +640 -0
- package/Tests/Server/Services/NotificationChannelEventCoverage.test.ts +246 -22
- package/Tests/Server/Services/NotificationDeletionImpact.test.ts +136 -8
- package/Tests/Server/Services/OnCallNotificationFallback.test.ts +191 -8
- package/Tests/Server/Services/OnCallReadinessService.test.ts +343 -18
- package/Tests/Server/Services/SeverityRuleBackfill.test.ts +5 -1
- package/Tests/Server/Services/UserMicrosoftTeamsService.test.ts +343 -0
- package/Tests/Server/Services/UserNotificationMethodAdminService.test.ts +209 -8
- package/Tests/Server/Services/UserNotificationRuleAdminGuards.test.ts +22 -6
- package/Tests/Server/Services/UserNotificationRuleDefaultCreation.test.ts +12 -6
- package/Tests/Server/Services/UserNotificationRuleExecuteItem.test.ts +37 -3
- package/Tests/Server/Services/UserNotificationRuleWorkspaceDelivery.test.ts +669 -0
- package/Tests/Server/Services/UserNotificationSettingWorkspaceChannels.test.ts +410 -0
- package/Tests/Server/Services/UserSlackService.test.ts +407 -0
- package/Tests/Server/Services/WorkspaceProjectAuthTokenDisconnectCascade.test.ts +224 -0
- package/Tests/Server/Services/WorkspaceUserAuthTokenNotificationMethodCascade.test.ts +189 -0
- package/Tests/Server/Services/WorkspaceUserNotificationService.test.ts +496 -0
- package/Tests/Server/Types/Database/Permissions/AdminNotificationRuleAccess.test.ts +30 -17
- package/Tests/Server/Types/Database/Permissions/CreateOwnershipScoping.test.ts +8 -3
- package/Tests/Server/Types/Database/Permissions/OwnerOnlyColumns.test.ts +72 -3
- package/Tests/Server/Types/Database/Permissions/UserNotificationRuleScoping.test.ts +22 -18
- package/Tests/Server/Types/Database/Permissions/WorkspaceMethodStampedColumnCreate.test.ts +178 -0
- package/Tests/Server/Utils/Marketing/MarketingEventUtil.test.ts +259 -0
- package/Tests/Server/Utils/Marketing/MarketingEventWebhook.test.ts +257 -0
- package/Tests/Server/Utils/Monitor/MonitorLogUtilRedaction.test.ts +300 -0
- package/Tests/Server/Utils/Monitor/MonitorPayloadRedaction.test.ts +381 -0
- package/Tests/Server/Utils/Runbook/RunbookExecutePermission.test.ts +228 -0
- package/Tests/Server/Utils/SessionReplay/SessionReplayErasureTombstone.test.ts +189 -0
- package/Tests/Server/Utils/SessionReplay/SessionReplayUsage.test.ts +205 -0
- package/Tests/Server/Utils/Telemetry/AppMetrics.test.ts +275 -0
- package/Tests/Server/Utils/Telemetry/TelemetryContext.test.ts +279 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsDirectMessage.test.ts +454 -0
- package/Tests/UI/Utils/NotificationMethodUtil.test.ts +137 -9
- package/Tests/UI/Utils/PermissionGate.test.ts +105 -0
- package/Types/Marketing/MarketingEvent.ts +97 -0
- package/UI/Utils/NotificationMethodUtil.ts +41 -1
- package/UI/Utils/PermissionGate.ts +56 -0
- package/build/dist/Models/DatabaseModels/EnterpriseLicense.js +24 -0
- package/build/dist/Models/DatabaseModels/EnterpriseLicense.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +4 -2
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Monitor.js +39 -9
- package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserMicrosoftTeams.js +363 -0
- package/build/dist/Models/DatabaseModels/UserMicrosoftTeams.js.map +1 -0
- package/build/dist/Models/DatabaseModels/UserNotificationRule.js +145 -8
- package/build/dist/Models/DatabaseModels/UserNotificationRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserNotificationSetting.js +38 -0
- package/build/dist/Models/DatabaseModels/UserNotificationSetting.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js +96 -0
- package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js.map +1 -1
- package/build/dist/Models/DatabaseModels/UserSlack.js +361 -0
- package/build/dist/Models/DatabaseModels/UserSlack.js.map +1 -0
- package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
- package/build/dist/Server/API/UserMicrosoftTeamsAPI.js +82 -0
- package/build/dist/Server/API/UserMicrosoftTeamsAPI.js.map +1 -0
- package/build/dist/Server/API/UserSlackAPI.js +81 -0
- package/build/dist/Server/API/UserSlackAPI.js.map +1 -0
- package/build/dist/Server/EnvironmentConfig.js +10 -70
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788700000000-RemoveMarketingConversionUploadState.js +26 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788700000000-RemoveMarketingConversionUploadState.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788800000000-DropMarketingConversionAddEnterpriseLicenseEmail.js +37 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788800000000-DropMarketingConversionAddEnterpriseLicenseEmail.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788900000000-RedactStoredMonitorIngestSecrets.js +106 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788900000000-RedactStoredMonitorIngestSecrets.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789000000000-AddUserSlackAndMicrosoftTeams.js +78 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789000000000-AddUserSlackAndMicrosoftTeams.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Infrastructure/Queue.js +7 -0
- package/build/dist/Server/Infrastructure/Queue.js.map +1 -1
- package/build/dist/Server/Services/EnterpriseLicenseService.js +65 -0
- package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +6 -2
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/LlmLogService.js +25 -9
- package/build/dist/Server/Services/LlmLogService.js.map +1 -1
- package/build/dist/Server/Services/OnCallReadinessService.js +74 -2
- package/build/dist/Server/Services/OnCallReadinessService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +56 -0
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/UserMicrosoftTeamsService.js +183 -0
- package/build/dist/Server/Services/UserMicrosoftTeamsService.js.map +1 -0
- package/build/dist/Server/Services/UserNotificationMethodAdminService.js +138 -2
- package/build/dist/Server/Services/UserNotificationMethodAdminService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationRuleAdminService.js +32 -4
- package/build/dist/Server/Services/UserNotificationRuleAdminService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationRuleService.js +499 -67
- package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Services/UserNotificationSettingService.js +118 -0
- package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +26 -1
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Services/UserSlackService.js +195 -0
- package/build/dist/Server/Services/UserSlackService.js.map +1 -0
- package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js +64 -1
- package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceUserAuthTokenService.js +70 -0
- package/build/dist/Server/Services/WorkspaceUserAuthTokenService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceUserNotificationService.js +129 -0
- package/build/dist/Server/Services/WorkspaceUserNotificationService.js.map +1 -0
- package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js +94 -0
- package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js.map +1 -0
- package/build/dist/Server/Utils/Marketing/MarketingEventWebhook.js +93 -0
- package/build/dist/Server/Utils/Marketing/MarketingEventWebhook.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/MonitorLogUtil.js +12 -1
- package/build/dist/Server/Utils/Monitor/MonitorLogUtil.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorPayloadRedaction.js +233 -0
- package/build/dist/Server/Utils/Monitor/MonitorPayloadRedaction.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +141 -4
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
- package/build/dist/Types/Marketing/MarketingEvent.js +43 -0
- package/build/dist/Types/Marketing/MarketingEvent.js.map +1 -0
- package/build/dist/UI/Utils/NotificationMethodUtil.js +33 -1
- package/build/dist/UI/Utils/NotificationMethodUtil.js.map +1 -1
- package/build/dist/UI/Utils/PermissionGate.js +32 -0
- package/build/dist/UI/Utils/PermissionGate.js.map +1 -1
- package/package.json +1 -1
- package/Models/DatabaseModels/MarketingConversion.ts +0 -410
- package/Server/Services/MarketingConversionService.ts +0 -10
- package/Server/Utils/Marketing/ConversionUploadProvider.ts +0 -215
- package/Server/Utils/Marketing/ConversionUploadProviders.ts +0 -22
- package/Server/Utils/Marketing/Providers/GoogleAds.ts +0 -333
- package/Server/Utils/Marketing/Providers/LinkedIn.ts +0 -185
- package/Server/Utils/Marketing/Providers/Meta.ts +0 -182
- package/Server/Utils/Marketing/Providers/MicrosoftAds.ts +0 -223
- package/Server/Utils/Marketing/Providers/Reddit.ts +0 -208
- package/Tests/Server/Utils/Marketing/AdUploadableConversionTypes.test.ts +0 -315
- package/Tests/Server/Utils/Marketing/ConversionUploadProvider.test.ts +0 -300
- package/Tests/Server/Utils/Marketing/GoogleAds.test.ts +0 -592
- package/Tests/Server/Utils/Marketing/LinkedIn.test.ts +0 -282
- package/Tests/Server/Utils/Marketing/Meta.test.ts +0 -304
- package/Tests/Server/Utils/Marketing/MicrosoftAds.test.ts +0 -263
- package/Tests/Server/Utils/Marketing/Reddit.test.ts +0 -259
- package/Types/Marketing/MarketingConversion.ts +0 -53
- package/build/dist/Models/DatabaseModels/MarketingConversion.js +0 -445
- package/build/dist/Models/DatabaseModels/MarketingConversion.js.map +0 -1
- package/build/dist/Server/Services/MarketingConversionService.js +0 -9
- package/build/dist/Server/Services/MarketingConversionService.js.map +0 -1
- package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js +0 -93
- package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js.map +0 -1
- package/build/dist/Server/Utils/Marketing/ConversionUploadProviders.js +0 -20
- package/build/dist/Server/Utils/Marketing/ConversionUploadProviders.js.map +0 -1
- package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js +0 -221
- package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js.map +0 -1
- package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js +0 -137
- package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js.map +0 -1
- package/build/dist/Server/Utils/Marketing/Providers/Meta.js +0 -133
- package/build/dist/Server/Utils/Marketing/Providers/Meta.js.map +0 -1
- package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js +0 -143
- package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js.map +0 -1
- package/build/dist/Server/Utils/Marketing/Providers/Reddit.js +0 -145
- package/build/dist/Server/Utils/Marketing/Providers/Reddit.js.map +0 -1
- package/build/dist/Types/Marketing/MarketingConversion.js +0 -52
- package/build/dist/Types/Marketing/MarketingConversion.js.map +0 -1
|
@@ -24,9 +24,11 @@ import TeamMemberService from "../../../Server/Services/TeamMemberService";
|
|
|
24
24
|
import TeamService from "../../../Server/Services/TeamService";
|
|
25
25
|
import UserCallService from "../../../Server/Services/UserCallService";
|
|
26
26
|
import UserEmailService from "../../../Server/Services/UserEmailService";
|
|
27
|
+
import UserMicrosoftTeamsService from "../../../Server/Services/UserMicrosoftTeamsService";
|
|
27
28
|
import UserNotificationRuleService from "../../../Server/Services/UserNotificationRuleService";
|
|
28
29
|
import UserPushService from "../../../Server/Services/UserPushService";
|
|
29
30
|
import UserService from "../../../Server/Services/UserService";
|
|
31
|
+
import UserSlackService from "../../../Server/Services/UserSlackService";
|
|
30
32
|
import UserSmsService from "../../../Server/Services/UserSmsService";
|
|
31
33
|
import UserTelegramService from "../../../Server/Services/UserTelegramService";
|
|
32
34
|
import UserWebhookService from "../../../Server/Services/UserWebhookService";
|
|
@@ -46,8 +48,10 @@ import TeamMember from "../../../Models/DatabaseModels/TeamMember";
|
|
|
46
48
|
import User from "../../../Models/DatabaseModels/User";
|
|
47
49
|
import UserCall from "../../../Models/DatabaseModels/UserCall";
|
|
48
50
|
import UserEmail from "../../../Models/DatabaseModels/UserEmail";
|
|
51
|
+
import UserMicrosoftTeams from "../../../Models/DatabaseModels/UserMicrosoftTeams";
|
|
49
52
|
import UserNotificationRule from "../../../Models/DatabaseModels/UserNotificationRule";
|
|
50
53
|
import UserPush from "../../../Models/DatabaseModels/UserPush";
|
|
54
|
+
import UserSlack from "../../../Models/DatabaseModels/UserSlack";
|
|
51
55
|
import UserSMS from "../../../Models/DatabaseModels/UserSMS";
|
|
52
56
|
import UserTelegram from "../../../Models/DatabaseModels/UserTelegram";
|
|
53
57
|
import UserWebhook from "../../../Models/DatabaseModels/UserWebhook";
|
|
@@ -185,6 +189,12 @@ const TELEGRAM_METHOD_ID: ObjectID = new ObjectID(
|
|
|
185
189
|
const WEBHOOK_METHOD_ID: ObjectID = new ObjectID(
|
|
186
190
|
"c0000000-0000-4000-8000-000000000007",
|
|
187
191
|
);
|
|
192
|
+
const SLACK_METHOD_ID: ObjectID = new ObjectID(
|
|
193
|
+
"c0000000-0000-4000-8000-000000000008",
|
|
194
|
+
);
|
|
195
|
+
const MICROSOFT_TEAMS_METHOD_ID: ObjectID = new ObjectID(
|
|
196
|
+
"c0000000-0000-4000-8000-000000000009",
|
|
197
|
+
);
|
|
188
198
|
|
|
189
199
|
/*
|
|
190
200
|
* Raw identifiers that must never reach a caller. Each is deliberately
|
|
@@ -196,6 +206,18 @@ const RAW_SMS_PHONE: string = "+14155554821";
|
|
|
196
206
|
const RAW_CALL_PHONE: string = "+442071838750";
|
|
197
207
|
const RAW_WHATSAPP_PHONE: string = "+61293744000";
|
|
198
208
|
const RAW_TELEGRAM_HANDLE: string = "@ada_night_pager";
|
|
209
|
+
const RAW_SLACK_USERNAME: string = "ada.pager.slack";
|
|
210
|
+
const RAW_MICROSOFT_TEAMS_USERNAME: string = "Ada Lovelace [Overnight]";
|
|
211
|
+
/*
|
|
212
|
+
* The addressable targets behind the two workspace channels - the Slack member
|
|
213
|
+
* id the bot DMs and the Entra object id the Teams bot resolves. They sit on
|
|
214
|
+
* the fixture rows deliberately, the same way the webhook fixture carries its
|
|
215
|
+
* bearer url: the production select must never ask for them, and if it ever
|
|
216
|
+
* widens the leak assertions downstream see a real target rather than an
|
|
217
|
+
* undefined.
|
|
218
|
+
*/
|
|
219
|
+
const RAW_SLACK_USER_ID: string = "U0SLACKMEMBERLEAK";
|
|
220
|
+
const RAW_MICROSOFT_TEAMS_USER_ID: string = "aad-ENTRAIDLEAK-4242";
|
|
199
221
|
const RAW_WEBHOOK_NAME: string = "Payments Incident Bridge";
|
|
200
222
|
const RAW_WEBHOOK_URL: string =
|
|
201
223
|
"https://hooks.example.com/T0LEAK/B0LEAK/xoxbSUPERSECRETTOKEN";
|
|
@@ -261,6 +283,8 @@ let smsFindBy: jest.SpyInstance;
|
|
|
261
283
|
let callFindBy: jest.SpyInstance;
|
|
262
284
|
let whatsAppFindBy: jest.SpyInstance;
|
|
263
285
|
let telegramFindBy: jest.SpyInstance;
|
|
286
|
+
let slackFindBy: jest.SpyInstance;
|
|
287
|
+
let microsoftTeamsFindBy: jest.SpyInstance;
|
|
264
288
|
let webhookFindBy: jest.SpyInstance;
|
|
265
289
|
let notificationRuleFindBy: jest.SpyInstance;
|
|
266
290
|
let incidentSeverityFindBy: jest.SpyInstance;
|
|
@@ -518,6 +542,52 @@ function telegramMethod(data: {
|
|
|
518
542
|
return model;
|
|
519
543
|
}
|
|
520
544
|
|
|
545
|
+
/*
|
|
546
|
+
* The two workspace fixtures deliberately CARRY their addressable ids -
|
|
547
|
+
* slackUserId and microsoftTeamsUserId - even though the production selects
|
|
548
|
+
* must never ask for them. If either select ever widens, the leak assertions
|
|
549
|
+
* downstream see a real target rather than an undefined.
|
|
550
|
+
*/
|
|
551
|
+
function slackMethod(data: {
|
|
552
|
+
userId: ObjectID;
|
|
553
|
+
userName: string;
|
|
554
|
+
slackUserId?: string | undefined;
|
|
555
|
+
isVerified: boolean;
|
|
556
|
+
id?: ObjectID | undefined;
|
|
557
|
+
}): UserSlack {
|
|
558
|
+
const model: UserSlack = new UserSlack();
|
|
559
|
+
model.id = data.id || ObjectID.generate();
|
|
560
|
+
model.userId = data.userId;
|
|
561
|
+
model.slackUserName = data.userName;
|
|
562
|
+
model.isVerified = data.isVerified;
|
|
563
|
+
|
|
564
|
+
if (data.slackUserId !== undefined) {
|
|
565
|
+
model.slackUserId = data.slackUserId;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
return model;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
function microsoftTeamsMethod(data: {
|
|
572
|
+
userId: ObjectID;
|
|
573
|
+
userName: string;
|
|
574
|
+
microsoftTeamsUserId?: string | undefined;
|
|
575
|
+
isVerified: boolean;
|
|
576
|
+
id?: ObjectID | undefined;
|
|
577
|
+
}): UserMicrosoftTeams {
|
|
578
|
+
const model: UserMicrosoftTeams = new UserMicrosoftTeams();
|
|
579
|
+
model.id = data.id || ObjectID.generate();
|
|
580
|
+
model.userId = data.userId;
|
|
581
|
+
model.microsoftTeamsUserName = data.userName;
|
|
582
|
+
model.isVerified = data.isVerified;
|
|
583
|
+
|
|
584
|
+
if (data.microsoftTeamsUserId !== undefined) {
|
|
585
|
+
model.microsoftTeamsUserId = data.microsoftTeamsUserId;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
return model;
|
|
589
|
+
}
|
|
590
|
+
|
|
521
591
|
/*
|
|
522
592
|
* A webhook fixture that deliberately CARRIES its bearer url, even though the
|
|
523
593
|
* production select must never ask for it. If the select ever widens, the
|
|
@@ -602,6 +672,8 @@ function everySpy(): Array<jest.SpyInstance> {
|
|
|
602
672
|
callFindBy,
|
|
603
673
|
whatsAppFindBy,
|
|
604
674
|
telegramFindBy,
|
|
675
|
+
slackFindBy,
|
|
676
|
+
microsoftTeamsFindBy,
|
|
605
677
|
webhookFindBy,
|
|
606
678
|
notificationRuleFindBy,
|
|
607
679
|
incidentSeverityFindBy,
|
|
@@ -840,6 +912,12 @@ beforeEach(() => {
|
|
|
840
912
|
telegramFindBy = jest
|
|
841
913
|
.spyOn(UserTelegramService, "findBy")
|
|
842
914
|
.mockResolvedValue([] as never);
|
|
915
|
+
slackFindBy = jest
|
|
916
|
+
.spyOn(UserSlackService, "findBy")
|
|
917
|
+
.mockResolvedValue([] as never);
|
|
918
|
+
microsoftTeamsFindBy = jest
|
|
919
|
+
.spyOn(UserMicrosoftTeamsService, "findBy")
|
|
920
|
+
.mockResolvedValue([] as never);
|
|
843
921
|
webhookFindBy = jest
|
|
844
922
|
.spyOn(UserWebhookService, "findBy")
|
|
845
923
|
.mockResolvedValue([] as never);
|
|
@@ -1953,6 +2031,30 @@ describe("status", () => {
|
|
|
1953
2031
|
] as never);
|
|
1954
2032
|
},
|
|
1955
2033
|
],
|
|
2034
|
+
[
|
|
2035
|
+
"Slack",
|
|
2036
|
+
(): void => {
|
|
2037
|
+
slackFindBy.mockResolvedValue([
|
|
2038
|
+
slackMethod({
|
|
2039
|
+
userId: USER_A_ID,
|
|
2040
|
+
userName: RAW_SLACK_USERNAME,
|
|
2041
|
+
isVerified: true,
|
|
2042
|
+
}),
|
|
2043
|
+
] as never);
|
|
2044
|
+
},
|
|
2045
|
+
],
|
|
2046
|
+
[
|
|
2047
|
+
"Microsoft Teams",
|
|
2048
|
+
(): void => {
|
|
2049
|
+
microsoftTeamsFindBy.mockResolvedValue([
|
|
2050
|
+
microsoftTeamsMethod({
|
|
2051
|
+
userId: USER_A_ID,
|
|
2052
|
+
userName: RAW_MICROSOFT_TEAMS_USERNAME,
|
|
2053
|
+
isVerified: true,
|
|
2054
|
+
}),
|
|
2055
|
+
] as never);
|
|
2056
|
+
},
|
|
2057
|
+
],
|
|
1956
2058
|
[
|
|
1957
2059
|
"Webhook",
|
|
1958
2060
|
(): void => {
|
|
@@ -2509,12 +2611,14 @@ describe("opt-out", () => {
|
|
|
2509
2611
|
|
|
2510
2612
|
/*
|
|
2511
2613
|
* ---------------------------------------------------------------------------
|
|
2512
|
-
* (G) All
|
|
2614
|
+
* (G) All nine channels.
|
|
2513
2615
|
*
|
|
2514
2616
|
* TeamComplianceService counted call/SMS/email/push only, so a responder whose
|
|
2515
2617
|
* only method was Telegram, WhatsApp or Webhook was reported non-compliant
|
|
2516
2618
|
* while the runtime paged them perfectly happily. A false alarm teaches admins
|
|
2517
|
-
* to ignore the table, which is worse than no table.
|
|
2619
|
+
* to ignore the table, which is worse than no table. Slack and Microsoft Teams
|
|
2620
|
+
* arrived after that defect was closed, and each gets the same "alone is
|
|
2621
|
+
* enough" pin so the defect cannot quietly return one channel at a time.
|
|
2518
2622
|
* ---------------------------------------------------------------------------
|
|
2519
2623
|
*/
|
|
2520
2624
|
describe("notification channels", () => {
|
|
@@ -2560,7 +2664,47 @@ describe("notification channels", () => {
|
|
|
2560
2664
|
expect((await onlyUser()).status).not.toBe(ReadinessStatus.NotReachable);
|
|
2561
2665
|
});
|
|
2562
2666
|
|
|
2563
|
-
|
|
2667
|
+
/*
|
|
2668
|
+
* The two workspace channels have no verification-code flow - their rows are
|
|
2669
|
+
* born verified from the user's own OAuth workspace link - but the row still
|
|
2670
|
+
* carries isVerified, and a verified row alone has to be enough. These are
|
|
2671
|
+
* the same "alone is enough" pins the four-channel defect earned Telegram and
|
|
2672
|
+
* WhatsApp, written down the day the channel arrived rather than the day it
|
|
2673
|
+
* was missed.
|
|
2674
|
+
*/
|
|
2675
|
+
test("a verified SLACK account alone makes a responder reachable", async () => {
|
|
2676
|
+
slackFindBy.mockResolvedValue([
|
|
2677
|
+
slackMethod({
|
|
2678
|
+
userId: USER_A_ID,
|
|
2679
|
+
userName: RAW_SLACK_USERNAME,
|
|
2680
|
+
isVerified: true,
|
|
2681
|
+
}),
|
|
2682
|
+
] as never);
|
|
2683
|
+
|
|
2684
|
+
const readiness: UserReadiness = await onlyUser();
|
|
2685
|
+
|
|
2686
|
+
expect(readiness.status).not.toBe(ReadinessStatus.NotReachable);
|
|
2687
|
+
expect(methodTypes(readiness)).toEqual([ReadinessMethodType.Slack]);
|
|
2688
|
+
});
|
|
2689
|
+
|
|
2690
|
+
test("a verified MICROSOFT TEAMS account alone makes a responder reachable", async () => {
|
|
2691
|
+
microsoftTeamsFindBy.mockResolvedValue([
|
|
2692
|
+
microsoftTeamsMethod({
|
|
2693
|
+
userId: USER_A_ID,
|
|
2694
|
+
userName: RAW_MICROSOFT_TEAMS_USERNAME,
|
|
2695
|
+
isVerified: true,
|
|
2696
|
+
}),
|
|
2697
|
+
] as never);
|
|
2698
|
+
|
|
2699
|
+
const readiness: UserReadiness = await onlyUser();
|
|
2700
|
+
|
|
2701
|
+
expect(readiness.status).not.toBe(ReadinessStatus.NotReachable);
|
|
2702
|
+
expect(methodTypes(readiness)).toEqual([
|
|
2703
|
+
ReadinessMethodType.MicrosoftTeams,
|
|
2704
|
+
]);
|
|
2705
|
+
});
|
|
2706
|
+
|
|
2707
|
+
test("all nine channels are read, and listed in fallback-attempt order", async () => {
|
|
2564
2708
|
pushFindBy.mockResolvedValue([
|
|
2565
2709
|
pushMethod({
|
|
2566
2710
|
userId: USER_A_ID,
|
|
@@ -2599,6 +2743,20 @@ describe("notification channels", () => {
|
|
|
2599
2743
|
isVerified: true,
|
|
2600
2744
|
}),
|
|
2601
2745
|
] as never);
|
|
2746
|
+
slackFindBy.mockResolvedValue([
|
|
2747
|
+
slackMethod({
|
|
2748
|
+
userId: USER_A_ID,
|
|
2749
|
+
userName: RAW_SLACK_USERNAME,
|
|
2750
|
+
isVerified: true,
|
|
2751
|
+
}),
|
|
2752
|
+
] as never);
|
|
2753
|
+
microsoftTeamsFindBy.mockResolvedValue([
|
|
2754
|
+
microsoftTeamsMethod({
|
|
2755
|
+
userId: USER_A_ID,
|
|
2756
|
+
userName: RAW_MICROSOFT_TEAMS_USERNAME,
|
|
2757
|
+
isVerified: true,
|
|
2758
|
+
}),
|
|
2759
|
+
] as never);
|
|
2602
2760
|
webhookFindBy.mockResolvedValue([
|
|
2603
2761
|
webhookMethod({ userId: USER_A_ID, name: RAW_WEBHOOK_NAME }),
|
|
2604
2762
|
] as never);
|
|
@@ -2607,11 +2765,15 @@ describe("notification channels", () => {
|
|
|
2607
2765
|
|
|
2608
2766
|
/*
|
|
2609
2767
|
* Display order IS fallback order, deliberately: the first row an admin
|
|
2610
|
-
* reads is the channel a fallback page would actually arrive on.
|
|
2768
|
+
* reads is the channel a fallback page would actually arrive on. The
|
|
2769
|
+
* zero-cost tier - Push, Email, Slack, Microsoft Teams - leads, then the
|
|
2770
|
+
* paid channels in escalating-intrusiveness order, then Webhook.
|
|
2611
2771
|
*/
|
|
2612
2772
|
expect(methodTypes(readiness)).toEqual([
|
|
2613
2773
|
ReadinessMethodType.Push,
|
|
2614
2774
|
ReadinessMethodType.Email,
|
|
2775
|
+
ReadinessMethodType.Slack,
|
|
2776
|
+
ReadinessMethodType.MicrosoftTeams,
|
|
2615
2777
|
ReadinessMethodType.SMS,
|
|
2616
2778
|
ReadinessMethodType.Call,
|
|
2617
2779
|
ReadinessMethodType.WhatsApp,
|
|
@@ -2644,7 +2806,14 @@ describe("notification channels", () => {
|
|
|
2644
2806
|
});
|
|
2645
2807
|
});
|
|
2646
2808
|
|
|
2647
|
-
test("
|
|
2809
|
+
test("every zero-cost channel is named when the responder has all four - and no paid one alongside them", async () => {
|
|
2810
|
+
/*
|
|
2811
|
+
* The zero-cost tier is Push, Email, Slack, Microsoft Teams, and the
|
|
2812
|
+
* fallback takes ALL of them when any is present before it considers
|
|
2813
|
+
* spending money. The verified SMS staged here is the assertion's other
|
|
2814
|
+
* half: a sentence that named SMS beside four free channels would be
|
|
2815
|
+
* describing a fallback that does not happen.
|
|
2816
|
+
*/
|
|
2648
2817
|
pushFindBy.mockResolvedValue([
|
|
2649
2818
|
pushMethod({ userId: USER_A_ID, isVerified: true }),
|
|
2650
2819
|
] as never);
|
|
@@ -2655,11 +2824,74 @@ describe("notification channels", () => {
|
|
|
2655
2824
|
isVerified: true,
|
|
2656
2825
|
}),
|
|
2657
2826
|
] as never);
|
|
2827
|
+
slackFindBy.mockResolvedValue([
|
|
2828
|
+
slackMethod({
|
|
2829
|
+
userId: USER_A_ID,
|
|
2830
|
+
userName: RAW_SLACK_USERNAME,
|
|
2831
|
+
isVerified: true,
|
|
2832
|
+
}),
|
|
2833
|
+
] as never);
|
|
2834
|
+
microsoftTeamsFindBy.mockResolvedValue([
|
|
2835
|
+
microsoftTeamsMethod({
|
|
2836
|
+
userId: USER_A_ID,
|
|
2837
|
+
userName: RAW_MICROSOFT_TEAMS_USERNAME,
|
|
2838
|
+
isVerified: true,
|
|
2839
|
+
}),
|
|
2840
|
+
] as never);
|
|
2841
|
+
smsFindBy.mockResolvedValue([
|
|
2842
|
+
smsMethod({
|
|
2843
|
+
userId: USER_A_ID,
|
|
2844
|
+
phone: RAW_SMS_PHONE,
|
|
2845
|
+
isVerified: true,
|
|
2846
|
+
}),
|
|
2847
|
+
] as never);
|
|
2658
2848
|
|
|
2659
2849
|
const readiness: UserReadiness = await onlyUser();
|
|
2660
2850
|
|
|
2661
2851
|
expect(readiness.reasons[0]).toBe(
|
|
2662
|
-
"No rules for Sev1 incidents - pages fall back to Push, Email",
|
|
2852
|
+
"No rules for Sev1 incidents - pages fall back to Push, Email, Slack, Microsoft Teams",
|
|
2853
|
+
);
|
|
2854
|
+
});
|
|
2855
|
+
|
|
2856
|
+
test("a verified SLACK account alone is a zero-cost fallback, pre-empting a paid channel", async () => {
|
|
2857
|
+
slackFindBy.mockResolvedValue([
|
|
2858
|
+
slackMethod({
|
|
2859
|
+
userId: USER_A_ID,
|
|
2860
|
+
userName: RAW_SLACK_USERNAME,
|
|
2861
|
+
isVerified: true,
|
|
2862
|
+
}),
|
|
2863
|
+
] as never);
|
|
2864
|
+
smsFindBy.mockResolvedValue([
|
|
2865
|
+
smsMethod({
|
|
2866
|
+
userId: USER_A_ID,
|
|
2867
|
+
phone: RAW_SMS_PHONE,
|
|
2868
|
+
isVerified: true,
|
|
2869
|
+
}),
|
|
2870
|
+
] as never);
|
|
2871
|
+
|
|
2872
|
+
expect((await onlyUser()).reasons[0]).toBe(
|
|
2873
|
+
"No rules for Sev1 incidents - pages fall back to Slack",
|
|
2874
|
+
);
|
|
2875
|
+
});
|
|
2876
|
+
|
|
2877
|
+
test("a verified MICROSOFT TEAMS account alone is a zero-cost fallback, pre-empting a paid channel", async () => {
|
|
2878
|
+
microsoftTeamsFindBy.mockResolvedValue([
|
|
2879
|
+
microsoftTeamsMethod({
|
|
2880
|
+
userId: USER_A_ID,
|
|
2881
|
+
userName: RAW_MICROSOFT_TEAMS_USERNAME,
|
|
2882
|
+
isVerified: true,
|
|
2883
|
+
}),
|
|
2884
|
+
] as never);
|
|
2885
|
+
callFindBy.mockResolvedValue([
|
|
2886
|
+
callMethod({
|
|
2887
|
+
userId: USER_A_ID,
|
|
2888
|
+
phone: RAW_CALL_PHONE,
|
|
2889
|
+
isVerified: true,
|
|
2890
|
+
}),
|
|
2891
|
+
] as never);
|
|
2892
|
+
|
|
2893
|
+
expect((await onlyUser()).reasons[0]).toBe(
|
|
2894
|
+
"No rules for Sev1 incidents - pages fall back to Microsoft Teams",
|
|
2663
2895
|
);
|
|
2664
2896
|
});
|
|
2665
2897
|
|
|
@@ -2779,11 +3011,12 @@ describe("notification channels", () => {
|
|
|
2779
3011
|
* (G2) Method identity - referencing a method without reading it.
|
|
2780
3012
|
*
|
|
2781
3013
|
* The admin rule form has to POINT A RULE AT one of these methods, and it is not
|
|
2782
|
-
* allowed to read the row it points at: the
|
|
3014
|
+
* allowed to read the row it points at: the nine method models are scoped to
|
|
2783
3015
|
* their owner precisely because their columns are the raw phone number, the
|
|
2784
|
-
* webhook bearer url, the push device token, the telegram chat id
|
|
2785
|
-
*
|
|
2786
|
-
* tried, and the exposure it opened could
|
|
3016
|
+
* webhook bearer url, the push device token, the telegram chat id, the slack
|
|
3017
|
+
* member id, the teams object id and the verification code. Widening that scope
|
|
3018
|
+
* so a dropdown could be populated was tried, and the exposure it opened could
|
|
3019
|
+
* not be contained.
|
|
2787
3020
|
*
|
|
2788
3021
|
* `methodId` is what replaces it. The foreign key is not a secret - it is
|
|
2789
3022
|
* already stored in plain sight on every rule its owner created, and it
|
|
@@ -2801,7 +3034,7 @@ describe("method identity", () => {
|
|
|
2801
3034
|
attachDirectly(USER_A_ID);
|
|
2802
3035
|
});
|
|
2803
3036
|
|
|
2804
|
-
function
|
|
3037
|
+
function attachEveryNineChannels(): void {
|
|
2805
3038
|
pushFindBy.mockResolvedValue([
|
|
2806
3039
|
pushMethod({
|
|
2807
3040
|
userId: USER_A_ID,
|
|
@@ -2850,6 +3083,24 @@ describe("method identity", () => {
|
|
|
2850
3083
|
id: TELEGRAM_METHOD_ID,
|
|
2851
3084
|
}),
|
|
2852
3085
|
] as never);
|
|
3086
|
+
slackFindBy.mockResolvedValue([
|
|
3087
|
+
slackMethod({
|
|
3088
|
+
userId: USER_A_ID,
|
|
3089
|
+
userName: RAW_SLACK_USERNAME,
|
|
3090
|
+
slackUserId: RAW_SLACK_USER_ID,
|
|
3091
|
+
isVerified: true,
|
|
3092
|
+
id: SLACK_METHOD_ID,
|
|
3093
|
+
}),
|
|
3094
|
+
] as never);
|
|
3095
|
+
microsoftTeamsFindBy.mockResolvedValue([
|
|
3096
|
+
microsoftTeamsMethod({
|
|
3097
|
+
userId: USER_A_ID,
|
|
3098
|
+
userName: RAW_MICROSOFT_TEAMS_USERNAME,
|
|
3099
|
+
microsoftTeamsUserId: RAW_MICROSOFT_TEAMS_USER_ID,
|
|
3100
|
+
isVerified: true,
|
|
3101
|
+
id: MICROSOFT_TEAMS_METHOD_ID,
|
|
3102
|
+
}),
|
|
3103
|
+
] as never);
|
|
2853
3104
|
webhookFindBy.mockResolvedValue([
|
|
2854
3105
|
webhookMethod({
|
|
2855
3106
|
userId: USER_A_ID,
|
|
@@ -2860,8 +3111,8 @@ describe("method identity", () => {
|
|
|
2860
3111
|
] as never);
|
|
2861
3112
|
}
|
|
2862
3113
|
|
|
2863
|
-
test("all
|
|
2864
|
-
|
|
3114
|
+
test("all nine channels carry the id of their OWN row, which is what a rule references", async () => {
|
|
3115
|
+
attachEveryNineChannels();
|
|
2865
3116
|
|
|
2866
3117
|
const readiness: UserReadiness = await onlyUser();
|
|
2867
3118
|
|
|
@@ -2887,17 +3138,26 @@ describe("method identity", () => {
|
|
|
2887
3138
|
expect(
|
|
2888
3139
|
methodOfType(readiness, ReadinessMethodType.Telegram).methodId.toString(),
|
|
2889
3140
|
).toBe(TELEGRAM_METHOD_ID.toString());
|
|
3141
|
+
expect(
|
|
3142
|
+
methodOfType(readiness, ReadinessMethodType.Slack).methodId.toString(),
|
|
3143
|
+
).toBe(SLACK_METHOD_ID.toString());
|
|
3144
|
+
expect(
|
|
3145
|
+
methodOfType(
|
|
3146
|
+
readiness,
|
|
3147
|
+
ReadinessMethodType.MicrosoftTeams,
|
|
3148
|
+
).methodId.toString(),
|
|
3149
|
+
).toBe(MICROSOFT_TEAMS_METHOD_ID.toString());
|
|
2890
3150
|
expect(
|
|
2891
3151
|
methodOfType(readiness, ReadinessMethodType.Webhook).methodId.toString(),
|
|
2892
3152
|
).toBe(WEBHOOK_METHOD_ID.toString());
|
|
2893
3153
|
});
|
|
2894
3154
|
|
|
2895
3155
|
test("no methodId is the USER's id - a rule pointed at a user id points at no method at all", async () => {
|
|
2896
|
-
|
|
3156
|
+
attachEveryNineChannels();
|
|
2897
3157
|
|
|
2898
3158
|
const readiness: UserReadiness = await onlyUser();
|
|
2899
3159
|
|
|
2900
|
-
expect(readiness.methods).toHaveLength(
|
|
3160
|
+
expect(readiness.methods).toHaveLength(9);
|
|
2901
3161
|
|
|
2902
3162
|
for (const method of readiness.methods) {
|
|
2903
3163
|
/*
|
|
@@ -3052,6 +3312,22 @@ describe("identifier exposure", () => {
|
|
|
3052
3312
|
isVerified: true,
|
|
3053
3313
|
}),
|
|
3054
3314
|
] as never);
|
|
3315
|
+
slackFindBy.mockResolvedValue([
|
|
3316
|
+
slackMethod({
|
|
3317
|
+
userId: USER_A_ID,
|
|
3318
|
+
userName: RAW_SLACK_USERNAME,
|
|
3319
|
+
slackUserId: RAW_SLACK_USER_ID,
|
|
3320
|
+
isVerified: true,
|
|
3321
|
+
}),
|
|
3322
|
+
] as never);
|
|
3323
|
+
microsoftTeamsFindBy.mockResolvedValue([
|
|
3324
|
+
microsoftTeamsMethod({
|
|
3325
|
+
userId: USER_A_ID,
|
|
3326
|
+
userName: RAW_MICROSOFT_TEAMS_USERNAME,
|
|
3327
|
+
microsoftTeamsUserId: RAW_MICROSOFT_TEAMS_USER_ID,
|
|
3328
|
+
isVerified: true,
|
|
3329
|
+
}),
|
|
3330
|
+
] as never);
|
|
3055
3331
|
webhookFindBy.mockResolvedValue([
|
|
3056
3332
|
webhookMethod({
|
|
3057
3333
|
userId: USER_A_ID,
|
|
@@ -3090,6 +3366,15 @@ describe("identifier exposure", () => {
|
|
|
3090
3366
|
expect(masked.get(ReadinessMethodType.Telegram)).toBe(
|
|
3091
3367
|
`@ad${IDENTIFIER_MASK}`,
|
|
3092
3368
|
);
|
|
3369
|
+
/*
|
|
3370
|
+
* Both workspace channels mask their human-facing NAME column with the
|
|
3371
|
+
* handle rule. The addressable ids - the Slack member id, the Entra object
|
|
3372
|
+
* id - are never selected at all, which the select tests below pin.
|
|
3373
|
+
*/
|
|
3374
|
+
expect(masked.get(ReadinessMethodType.Slack)).toBe(`ad${IDENTIFIER_MASK}`);
|
|
3375
|
+
expect(masked.get(ReadinessMethodType.MicrosoftTeams)).toBe(
|
|
3376
|
+
`Ad${IDENTIFIER_MASK}`,
|
|
3377
|
+
);
|
|
3093
3378
|
expect(masked.get(ReadinessMethodType.Webhook)).toBe(
|
|
3094
3379
|
`Pa${IDENTIFIER_MASK}`,
|
|
3095
3380
|
);
|
|
@@ -3098,7 +3383,7 @@ describe("identifier exposure", () => {
|
|
|
3098
3383
|
test("a method carries FOUR fields and no fifth - the id is the ONLY thing beside the mask", async () => {
|
|
3099
3384
|
const readiness: UserReadiness = await onlyUser();
|
|
3100
3385
|
|
|
3101
|
-
expect(readiness.methods).toHaveLength(
|
|
3386
|
+
expect(readiness.methods).toHaveLength(9);
|
|
3102
3387
|
|
|
3103
3388
|
/*
|
|
3104
3389
|
* An exact key set, not a "does not contain the url" check, and this is the
|
|
@@ -3145,6 +3430,10 @@ describe("identifier exposure", () => {
|
|
|
3145
3430
|
RAW_CALL_PHONE,
|
|
3146
3431
|
RAW_WHATSAPP_PHONE,
|
|
3147
3432
|
RAW_TELEGRAM_HANDLE,
|
|
3433
|
+
RAW_SLACK_USERNAME,
|
|
3434
|
+
RAW_SLACK_USER_ID,
|
|
3435
|
+
RAW_MICROSOFT_TEAMS_USERNAME,
|
|
3436
|
+
RAW_MICROSOFT_TEAMS_USER_ID,
|
|
3148
3437
|
RAW_WEBHOOK_NAME,
|
|
3149
3438
|
RAW_WEBHOOK_URL,
|
|
3150
3439
|
RAW_PUSH_DEVICE,
|
|
@@ -3158,6 +3447,10 @@ describe("identifier exposure", () => {
|
|
|
3158
3447
|
"2071838",
|
|
3159
3448
|
"6129374",
|
|
3160
3449
|
"night_pager",
|
|
3450
|
+
"pager.slack",
|
|
3451
|
+
"SLACKMEMBERLEAK",
|
|
3452
|
+
"Overnight",
|
|
3453
|
+
"ENTRAIDLEAK",
|
|
3161
3454
|
"Incident Bridge",
|
|
3162
3455
|
"SUPERSECRETTOKEN",
|
|
3163
3456
|
"iPhone",
|
|
@@ -3200,6 +3493,30 @@ describe("identifier exposure", () => {
|
|
|
3200
3493
|
expect(select["telegramUserHandle"]).toBe(true);
|
|
3201
3494
|
});
|
|
3202
3495
|
|
|
3496
|
+
test("the slack read never asks for the member id, which is the addressable target", async () => {
|
|
3497
|
+
await policySummary();
|
|
3498
|
+
|
|
3499
|
+
const select: Record<string, unknown> = firstCall(slackFindBy).select!;
|
|
3500
|
+
|
|
3501
|
+
/*
|
|
3502
|
+
* Same rule as the telegram chat id: the member id is what the bot sends
|
|
3503
|
+
* to, the username is the label the owner recognises, and only the label
|
|
3504
|
+
* belongs on a readiness surface.
|
|
3505
|
+
*/
|
|
3506
|
+
expect(Object.keys(select)).not.toContain("slackUserId");
|
|
3507
|
+
expect(select["slackUserName"]).toBe(true);
|
|
3508
|
+
});
|
|
3509
|
+
|
|
3510
|
+
test("the microsoft teams read never asks for the entra object id, which is the addressable target", async () => {
|
|
3511
|
+
await policySummary();
|
|
3512
|
+
|
|
3513
|
+
const select: Record<string, unknown> =
|
|
3514
|
+
firstCall(microsoftTeamsFindBy).select!;
|
|
3515
|
+
|
|
3516
|
+
expect(Object.keys(select)).not.toContain("microsoftTeamsUserId");
|
|
3517
|
+
expect(select["microsoftTeamsUserName"]).toBe(true);
|
|
3518
|
+
});
|
|
3519
|
+
|
|
3203
3520
|
test("a method with no identifier at all still reports the bare mask, not an empty cell", async () => {
|
|
3204
3521
|
pushFindBy.mockResolvedValue([
|
|
3205
3522
|
pushMethod({ userId: USER_A_ID, isVerified: true }),
|
|
@@ -3349,6 +3666,8 @@ describe("batching and paging", () => {
|
|
|
3349
3666
|
callFindBy,
|
|
3350
3667
|
whatsAppFindBy,
|
|
3351
3668
|
telegramFindBy,
|
|
3669
|
+
slackFindBy,
|
|
3670
|
+
microsoftTeamsFindBy,
|
|
3352
3671
|
webhookFindBy,
|
|
3353
3672
|
notificationRuleFindBy,
|
|
3354
3673
|
]) {
|
|
@@ -3364,6 +3683,8 @@ describe("batching and paging", () => {
|
|
|
3364
3683
|
callFindBy,
|
|
3365
3684
|
whatsAppFindBy,
|
|
3366
3685
|
telegramFindBy,
|
|
3686
|
+
slackFindBy,
|
|
3687
|
+
microsoftTeamsFindBy,
|
|
3367
3688
|
webhookFindBy,
|
|
3368
3689
|
notificationRuleFindBy,
|
|
3369
3690
|
]) {
|
|
@@ -3393,7 +3714,7 @@ describe("batching and paging", () => {
|
|
|
3393
3714
|
const calls: Array<FindByCall> = everyFindByCall();
|
|
3394
3715
|
|
|
3395
3716
|
// A guard that asserts over an empty list guards nothing.
|
|
3396
|
-
expect(calls.length).toBeGreaterThanOrEqual(
|
|
3717
|
+
expect(calls.length).toBeGreaterThanOrEqual(17);
|
|
3397
3718
|
|
|
3398
3719
|
for (const call of calls) {
|
|
3399
3720
|
/*
|
|
@@ -3467,7 +3788,7 @@ describe("batching and paging", () => {
|
|
|
3467
3788
|
|
|
3468
3789
|
const calls: Array<FindByCall> = everyFindByCall();
|
|
3469
3790
|
|
|
3470
|
-
expect(calls.length).toBeGreaterThanOrEqual(
|
|
3791
|
+
expect(calls.length).toBeGreaterThanOrEqual(17);
|
|
3471
3792
|
|
|
3472
3793
|
for (const call of calls) {
|
|
3473
3794
|
/*
|
|
@@ -3497,6 +3818,8 @@ describe("batching and paging", () => {
|
|
|
3497
3818
|
callFindBy,
|
|
3498
3819
|
whatsAppFindBy,
|
|
3499
3820
|
telegramFindBy,
|
|
3821
|
+
slackFindBy,
|
|
3822
|
+
microsoftTeamsFindBy,
|
|
3500
3823
|
webhookFindBy,
|
|
3501
3824
|
notificationRuleFindBy,
|
|
3502
3825
|
]) {
|
|
@@ -3929,6 +4252,8 @@ describe("getReadinessForUsers", () => {
|
|
|
3929
4252
|
callFindBy,
|
|
3930
4253
|
whatsAppFindBy,
|
|
3931
4254
|
telegramFindBy,
|
|
4255
|
+
slackFindBy,
|
|
4256
|
+
microsoftTeamsFindBy,
|
|
3932
4257
|
webhookFindBy,
|
|
3933
4258
|
notificationRuleFindBy,
|
|
3934
4259
|
]) {
|
|
@@ -148,6 +148,8 @@ type RuleMethodColumn =
|
|
|
148
148
|
| "userPushId"
|
|
149
149
|
| "userWhatsAppId"
|
|
150
150
|
| "userTelegramId"
|
|
151
|
+
| "userSlackId"
|
|
152
|
+
| "userMicrosoftTeamsId"
|
|
151
153
|
| "userWebhookId";
|
|
152
154
|
|
|
153
155
|
type RuleIdColumn =
|
|
@@ -164,6 +166,8 @@ const METHOD_COLUMNS: Array<RuleMethodColumn> = [
|
|
|
164
166
|
"userPushId",
|
|
165
167
|
"userWhatsAppId",
|
|
166
168
|
"userTelegramId",
|
|
169
|
+
"userSlackId",
|
|
170
|
+
"userMicrosoftTeamsId",
|
|
167
171
|
"userWebhookId",
|
|
168
172
|
];
|
|
169
173
|
|
|
@@ -180,7 +184,7 @@ const ID_COLUMNS: Array<RuleIdColumn> = [
|
|
|
180
184
|
* An in-memory stand-in for the UserNotificationRule table.
|
|
181
185
|
*
|
|
182
186
|
* Rows are real model instances, because that is what the job reads: it asks
|
|
183
|
-
* rules for `.userId`, `.isOptOut`, `.notifyAfterMinutes` and the
|
|
187
|
+
* rules for `.userId`, `.isOptOut`, `.notifyAfterMinutes` and the nine method
|
|
184
188
|
* foreign keys, and hands `create` a model it built itself.
|
|
185
189
|
* -------------------------------------------------------------------------
|
|
186
190
|
*/
|