@oneuptime/common 12.0.17 → 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.
Files changed (220) hide show
  1. package/Models/DatabaseModels/EnterpriseLicense.ts +23 -0
  2. package/Models/DatabaseModels/Index.ts +4 -2
  3. package/Models/DatabaseModels/Monitor.ts +39 -9
  4. package/Models/DatabaseModels/UserMicrosoftTeams.ts +344 -0
  5. package/Models/DatabaseModels/UserNotificationRule.ts +144 -8
  6. package/Models/DatabaseModels/UserNotificationSetting.ts +34 -0
  7. package/Models/DatabaseModels/UserOnCallLogTimeline.ts +95 -0
  8. package/Models/DatabaseModels/UserSlack.ts +341 -0
  9. package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +9 -0
  10. package/Server/API/UserMicrosoftTeamsAPI.ts +127 -0
  11. package/Server/API/UserSlackAPI.ts +125 -0
  12. package/Server/EnvironmentConfig.ts +12 -107
  13. package/Server/Infrastructure/Postgres/SchemaMigrations/1788700000000-RemoveMarketingConversionUploadState.ts +33 -0
  14. package/Server/Infrastructure/Postgres/SchemaMigrations/1788800000000-DropMarketingConversionAddEnterpriseLicenseEmail.ts +51 -0
  15. package/Server/Infrastructure/Postgres/SchemaMigrations/1788900000000-RedactStoredMonitorIngestSecrets.ts +117 -0
  16. package/Server/Infrastructure/Postgres/SchemaMigrations/1789000000000-AddUserSlackAndMicrosoftTeams.ts +197 -0
  17. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
  18. package/Server/Infrastructure/Queue.ts +7 -0
  19. package/Server/Services/BillingService.ts +8 -0
  20. package/Server/Services/EnterpriseLicenseService.ts +60 -0
  21. package/Server/Services/Index.ts +6 -2
  22. package/Server/Services/LlmLogService.ts +25 -9
  23. package/Server/Services/OnCallReadinessService.ts +86 -2
  24. package/Server/Services/ProjectService.ts +67 -0
  25. package/Server/Services/UserMicrosoftTeamsService.ts +208 -0
  26. package/Server/Services/UserNotificationMethodAdminService.ts +167 -5
  27. package/Server/Services/UserNotificationRuleAdminService.ts +40 -6
  28. package/Server/Services/UserNotificationRuleService.ts +589 -11
  29. package/Server/Services/UserNotificationSettingService.ts +138 -0
  30. package/Server/Services/UserService.ts +28 -0
  31. package/Server/Services/UserSlackService.ts +218 -0
  32. package/Server/Services/WorkspaceProjectAuthTokenService.ts +67 -1
  33. package/Server/Services/WorkspaceUserAuthTokenService.ts +73 -0
  34. package/Server/Services/WorkspaceUserNotificationService.ts +190 -0
  35. package/Server/Utils/Marketing/MarketingEventUtil.ts +145 -0
  36. package/Server/Utils/Marketing/MarketingEventWebhook.ts +114 -0
  37. package/Server/Utils/Monitor/MonitorLogUtil.ts +14 -1
  38. package/Server/Utils/Monitor/MonitorPayloadRedaction.ts +321 -0
  39. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +191 -4
  40. package/Tests/App/Dashboard/AdminNotificationRulesPage.test.tsx +22 -14
  41. package/Tests/App/Dashboard/AdminUserNotificationMethodsPage.test.tsx +22 -11
  42. package/Tests/App/Dashboard/OnCallPreventionGuards.test.tsx +37 -1
  43. package/Tests/App/Dashboard/OnCallRulesTable.test.tsx +18 -10
  44. package/Tests/App/Dashboard/PayAsYouGoNotices.test.tsx +17 -0
  45. package/Tests/Models/DatabaseModels/DomainRoleTierCoverage.test.ts +27 -1
  46. package/Tests/Models/DatabaseModels/MonitorSecretKeyColumnAccessControl.test.ts +214 -0
  47. package/Tests/Server/API/OnCallReadinessAPI.test.ts +145 -26
  48. package/Tests/Server/API/UserNotificationMethodAdminAPI.test.ts +2 -2
  49. package/Tests/Server/Services/AIServiceDailyBudget.test.ts +11 -1
  50. package/Tests/Server/Services/AdminRuleEditGuards.test.ts +22 -8
  51. package/Tests/Server/Services/BillingService.test.ts +20 -0
  52. package/Tests/Server/Services/DeliverNotificationForRuleExtraction.test.ts +18 -2
  53. package/Tests/Server/Services/EpisodeRuleSeverityRepair.test.ts +5 -1
  54. package/Tests/Server/Services/LlmLogServiceTokenAggregateParams.test.ts +640 -0
  55. package/Tests/Server/Services/NotificationChannelEventCoverage.test.ts +246 -22
  56. package/Tests/Server/Services/NotificationDeletionImpact.test.ts +136 -8
  57. package/Tests/Server/Services/OnCallNotificationFallback.test.ts +191 -8
  58. package/Tests/Server/Services/OnCallReadinessService.test.ts +343 -18
  59. package/Tests/Server/Services/SeverityRuleBackfill.test.ts +5 -1
  60. package/Tests/Server/Services/UserMicrosoftTeamsService.test.ts +343 -0
  61. package/Tests/Server/Services/UserNotificationMethodAdminService.test.ts +209 -8
  62. package/Tests/Server/Services/UserNotificationRuleAdminGuards.test.ts +22 -6
  63. package/Tests/Server/Services/UserNotificationRuleDefaultCreation.test.ts +12 -6
  64. package/Tests/Server/Services/UserNotificationRuleExecuteItem.test.ts +37 -3
  65. package/Tests/Server/Services/UserNotificationRuleWorkspaceDelivery.test.ts +669 -0
  66. package/Tests/Server/Services/UserNotificationSettingWorkspaceChannels.test.ts +410 -0
  67. package/Tests/Server/Services/UserSlackService.test.ts +407 -0
  68. package/Tests/Server/Services/WorkspaceProjectAuthTokenDisconnectCascade.test.ts +224 -0
  69. package/Tests/Server/Services/WorkspaceUserAuthTokenNotificationMethodCascade.test.ts +189 -0
  70. package/Tests/Server/Services/WorkspaceUserNotificationService.test.ts +496 -0
  71. package/Tests/Server/Types/Database/Permissions/AdminNotificationRuleAccess.test.ts +30 -17
  72. package/Tests/Server/Types/Database/Permissions/CreateOwnershipScoping.test.ts +8 -3
  73. package/Tests/Server/Types/Database/Permissions/OwnerOnlyColumns.test.ts +72 -3
  74. package/Tests/Server/Types/Database/Permissions/UserNotificationRuleScoping.test.ts +22 -18
  75. package/Tests/Server/Types/Database/Permissions/WorkspaceMethodStampedColumnCreate.test.ts +178 -0
  76. package/Tests/Server/Utils/Marketing/MarketingEventUtil.test.ts +259 -0
  77. package/Tests/Server/Utils/Marketing/MarketingEventWebhook.test.ts +257 -0
  78. package/Tests/Server/Utils/Monitor/MonitorLogUtilRedaction.test.ts +300 -0
  79. package/Tests/Server/Utils/Monitor/MonitorPayloadRedaction.test.ts +381 -0
  80. package/Tests/Server/Utils/Runbook/RunbookExecutePermission.test.ts +228 -0
  81. package/Tests/Server/Utils/SessionReplay/SessionReplayErasureTombstone.test.ts +189 -0
  82. package/Tests/Server/Utils/SessionReplay/SessionReplayUsage.test.ts +205 -0
  83. package/Tests/Server/Utils/Telemetry/AppMetrics.test.ts +275 -0
  84. package/Tests/Server/Utils/Telemetry/TelemetryContext.test.ts +279 -0
  85. package/Tests/Server/Utils/Workspace/MicrosoftTeamsDirectMessage.test.ts +454 -0
  86. package/Tests/Types/Kubernetes/KubernetesObjectParsers.test.ts +794 -0
  87. package/Tests/Types/Kubernetes/KubernetesRightSizing.test.ts +53 -0
  88. package/Tests/Types/Measurement/MeasurementAggregationType.test.ts +100 -0
  89. package/Tests/Types/Monitor/MonitorStepConfigHelpers.test.ts +114 -0
  90. package/Tests/Types/Workspace/WorkspaceType.test.ts +53 -0
  91. package/Tests/UI/Utils/NotificationMethodUtil.test.ts +137 -9
  92. package/Tests/UI/Utils/PermissionGate.test.ts +105 -0
  93. package/Tests/Utils/Dashboard/Components/DashboardComponentDefaults.test.ts +257 -0
  94. package/Types/Billing/PayAsYouGoPricing.ts +1 -1
  95. package/Types/Marketing/MarketingEvent.ts +97 -0
  96. package/UI/Utils/NotificationMethodUtil.ts +41 -1
  97. package/UI/Utils/PermissionGate.ts +56 -0
  98. package/build/dist/Models/DatabaseModels/EnterpriseLicense.js +24 -0
  99. package/build/dist/Models/DatabaseModels/EnterpriseLicense.js.map +1 -1
  100. package/build/dist/Models/DatabaseModels/Index.js +4 -2
  101. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  102. package/build/dist/Models/DatabaseModels/Monitor.js +39 -9
  103. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  104. package/build/dist/Models/DatabaseModels/UserMicrosoftTeams.js +363 -0
  105. package/build/dist/Models/DatabaseModels/UserMicrosoftTeams.js.map +1 -0
  106. package/build/dist/Models/DatabaseModels/UserNotificationRule.js +145 -8
  107. package/build/dist/Models/DatabaseModels/UserNotificationRule.js.map +1 -1
  108. package/build/dist/Models/DatabaseModels/UserNotificationSetting.js +38 -0
  109. package/build/dist/Models/DatabaseModels/UserNotificationSetting.js.map +1 -1
  110. package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js +96 -0
  111. package/build/dist/Models/DatabaseModels/UserOnCallLogTimeline.js.map +1 -1
  112. package/build/dist/Models/DatabaseModels/UserSlack.js +361 -0
  113. package/build/dist/Models/DatabaseModels/UserSlack.js.map +1 -0
  114. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
  115. package/build/dist/Server/API/UserMicrosoftTeamsAPI.js +82 -0
  116. package/build/dist/Server/API/UserMicrosoftTeamsAPI.js.map +1 -0
  117. package/build/dist/Server/API/UserSlackAPI.js +81 -0
  118. package/build/dist/Server/API/UserSlackAPI.js.map +1 -0
  119. package/build/dist/Server/EnvironmentConfig.js +10 -70
  120. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  121. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788700000000-RemoveMarketingConversionUploadState.js +26 -0
  122. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788700000000-RemoveMarketingConversionUploadState.js.map +1 -0
  123. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788800000000-DropMarketingConversionAddEnterpriseLicenseEmail.js +37 -0
  124. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788800000000-DropMarketingConversionAddEnterpriseLicenseEmail.js.map +1 -0
  125. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788900000000-RedactStoredMonitorIngestSecrets.js +106 -0
  126. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1788900000000-RedactStoredMonitorIngestSecrets.js.map +1 -0
  127. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789000000000-AddUserSlackAndMicrosoftTeams.js +78 -0
  128. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1789000000000-AddUserSlackAndMicrosoftTeams.js.map +1 -0
  129. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
  130. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  131. package/build/dist/Server/Infrastructure/Queue.js +7 -0
  132. package/build/dist/Server/Infrastructure/Queue.js.map +1 -1
  133. package/build/dist/Server/Services/BillingService.js +6 -0
  134. package/build/dist/Server/Services/BillingService.js.map +1 -1
  135. package/build/dist/Server/Services/EnterpriseLicenseService.js +65 -0
  136. package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
  137. package/build/dist/Server/Services/Index.js +6 -2
  138. package/build/dist/Server/Services/Index.js.map +1 -1
  139. package/build/dist/Server/Services/LlmLogService.js +25 -9
  140. package/build/dist/Server/Services/LlmLogService.js.map +1 -1
  141. package/build/dist/Server/Services/OnCallReadinessService.js +74 -2
  142. package/build/dist/Server/Services/OnCallReadinessService.js.map +1 -1
  143. package/build/dist/Server/Services/ProjectService.js +56 -0
  144. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  145. package/build/dist/Server/Services/UserMicrosoftTeamsService.js +183 -0
  146. package/build/dist/Server/Services/UserMicrosoftTeamsService.js.map +1 -0
  147. package/build/dist/Server/Services/UserNotificationMethodAdminService.js +138 -2
  148. package/build/dist/Server/Services/UserNotificationMethodAdminService.js.map +1 -1
  149. package/build/dist/Server/Services/UserNotificationRuleAdminService.js +32 -4
  150. package/build/dist/Server/Services/UserNotificationRuleAdminService.js.map +1 -1
  151. package/build/dist/Server/Services/UserNotificationRuleService.js +499 -67
  152. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  153. package/build/dist/Server/Services/UserNotificationSettingService.js +118 -0
  154. package/build/dist/Server/Services/UserNotificationSettingService.js.map +1 -1
  155. package/build/dist/Server/Services/UserService.js +26 -1
  156. package/build/dist/Server/Services/UserService.js.map +1 -1
  157. package/build/dist/Server/Services/UserSlackService.js +195 -0
  158. package/build/dist/Server/Services/UserSlackService.js.map +1 -0
  159. package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js +64 -1
  160. package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js.map +1 -1
  161. package/build/dist/Server/Services/WorkspaceUserAuthTokenService.js +70 -0
  162. package/build/dist/Server/Services/WorkspaceUserAuthTokenService.js.map +1 -1
  163. package/build/dist/Server/Services/WorkspaceUserNotificationService.js +129 -0
  164. package/build/dist/Server/Services/WorkspaceUserNotificationService.js.map +1 -0
  165. package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js +94 -0
  166. package/build/dist/Server/Utils/Marketing/MarketingEventUtil.js.map +1 -0
  167. package/build/dist/Server/Utils/Marketing/MarketingEventWebhook.js +93 -0
  168. package/build/dist/Server/Utils/Marketing/MarketingEventWebhook.js.map +1 -0
  169. package/build/dist/Server/Utils/Monitor/MonitorLogUtil.js +12 -1
  170. package/build/dist/Server/Utils/Monitor/MonitorLogUtil.js.map +1 -1
  171. package/build/dist/Server/Utils/Monitor/MonitorPayloadRedaction.js +233 -0
  172. package/build/dist/Server/Utils/Monitor/MonitorPayloadRedaction.js.map +1 -0
  173. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +141 -4
  174. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  175. package/build/dist/Types/Billing/PayAsYouGoPricing.js +1 -1
  176. package/build/dist/Types/Billing/PayAsYouGoPricing.js.map +1 -1
  177. package/build/dist/Types/Marketing/MarketingEvent.js +43 -0
  178. package/build/dist/Types/Marketing/MarketingEvent.js.map +1 -0
  179. package/build/dist/UI/Utils/NotificationMethodUtil.js +33 -1
  180. package/build/dist/UI/Utils/NotificationMethodUtil.js.map +1 -1
  181. package/build/dist/UI/Utils/PermissionGate.js +32 -0
  182. package/build/dist/UI/Utils/PermissionGate.js.map +1 -1
  183. package/package.json +1 -1
  184. package/Models/DatabaseModels/MarketingConversion.ts +0 -410
  185. package/Server/Services/MarketingConversionService.ts +0 -10
  186. package/Server/Utils/Marketing/ConversionUploadProvider.ts +0 -215
  187. package/Server/Utils/Marketing/ConversionUploadProviders.ts +0 -22
  188. package/Server/Utils/Marketing/Providers/GoogleAds.ts +0 -333
  189. package/Server/Utils/Marketing/Providers/LinkedIn.ts +0 -185
  190. package/Server/Utils/Marketing/Providers/Meta.ts +0 -182
  191. package/Server/Utils/Marketing/Providers/MicrosoftAds.ts +0 -223
  192. package/Server/Utils/Marketing/Providers/Reddit.ts +0 -208
  193. package/Tests/Server/Utils/Marketing/AdUploadableConversionTypes.test.ts +0 -315
  194. package/Tests/Server/Utils/Marketing/ConversionUploadProvider.test.ts +0 -300
  195. package/Tests/Server/Utils/Marketing/GoogleAds.test.ts +0 -592
  196. package/Tests/Server/Utils/Marketing/LinkedIn.test.ts +0 -282
  197. package/Tests/Server/Utils/Marketing/Meta.test.ts +0 -304
  198. package/Tests/Server/Utils/Marketing/MicrosoftAds.test.ts +0 -263
  199. package/Tests/Server/Utils/Marketing/Reddit.test.ts +0 -259
  200. package/Types/Marketing/MarketingConversion.ts +0 -53
  201. package/build/dist/Models/DatabaseModels/MarketingConversion.js +0 -445
  202. package/build/dist/Models/DatabaseModels/MarketingConversion.js.map +0 -1
  203. package/build/dist/Server/Services/MarketingConversionService.js +0 -9
  204. package/build/dist/Server/Services/MarketingConversionService.js.map +0 -1
  205. package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js +0 -93
  206. package/build/dist/Server/Utils/Marketing/ConversionUploadProvider.js.map +0 -1
  207. package/build/dist/Server/Utils/Marketing/ConversionUploadProviders.js +0 -20
  208. package/build/dist/Server/Utils/Marketing/ConversionUploadProviders.js.map +0 -1
  209. package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js +0 -221
  210. package/build/dist/Server/Utils/Marketing/Providers/GoogleAds.js.map +0 -1
  211. package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js +0 -137
  212. package/build/dist/Server/Utils/Marketing/Providers/LinkedIn.js.map +0 -1
  213. package/build/dist/Server/Utils/Marketing/Providers/Meta.js +0 -133
  214. package/build/dist/Server/Utils/Marketing/Providers/Meta.js.map +0 -1
  215. package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js +0 -143
  216. package/build/dist/Server/Utils/Marketing/Providers/MicrosoftAds.js.map +0 -1
  217. package/build/dist/Server/Utils/Marketing/Providers/Reddit.js +0 -145
  218. package/build/dist/Server/Utils/Marketing/Providers/Reddit.js.map +0 -1
  219. package/build/dist/Types/Marketing/MarketingConversion.js +0 -52
  220. package/build/dist/Types/Marketing/MarketingConversion.js.map +0 -1
@@ -59,7 +59,7 @@ import getJestMockFunction, { MockFunction } from "../../MockType";
59
59
  * to be tempted will add a button, not a sentence.
60
60
  *
61
61
  * - AN ADMIN READING SOMEBODY ELSE'S PHONE NUMBER, which is the same defect
62
- * one step earlier and is what this page originally did. The seven method
62
+ * one step earlier and is what this page originally did. The nine method
63
63
  * models are scoped to the person who owns the device - the columns behind
64
64
  * them are the raw number, the webhook bearer url, the push device token,
65
65
  * the telegram chat id and the verification code - and that scope was
@@ -389,8 +389,10 @@ import TeamMember from "../../../Models/DatabaseModels/TeamMember";
389
389
  import User from "../../../Models/DatabaseModels/User";
390
390
  import UserCall from "../../../Models/DatabaseModels/UserCall";
391
391
  import UserEmail from "../../../Models/DatabaseModels/UserEmail";
392
+ import UserMicrosoftTeams from "../../../Models/DatabaseModels/UserMicrosoftTeams";
392
393
  import UserNotificationRule from "../../../Models/DatabaseModels/UserNotificationRule";
393
394
  import UserPush from "../../../Models/DatabaseModels/UserPush";
395
+ import UserSlack from "../../../Models/DatabaseModels/UserSlack";
394
396
  import UserSMS from "../../../Models/DatabaseModels/UserSMS";
395
397
  import UserTelegram from "../../../Models/DatabaseModels/UserTelegram";
396
398
  import UserWebhook from "../../../Models/DatabaseModels/UserWebhook";
@@ -413,7 +415,7 @@ const PROJECT_ID: ObjectID = new ObjectID(PROJECT_ID_STRING);
413
415
  const SIGNED_IN_USER_ID: ObjectID = new ObjectID(SIGNED_IN_USER_ID_STRING);
414
416
 
415
417
  /*
416
- * The seven models only their owner may read. They are asserted as a SET because
418
+ * The nine models only their owner may read. They are asserted as a SET because
417
419
  * which one an admin surface reaches for hardly matters - every one of them
418
420
  * carries a raw identifier and most carry a credential.
419
421
  */
@@ -424,11 +426,13 @@ const NOTIFICATION_METHOD_MODELS: Array<unknown> = [
424
426
  UserPush,
425
427
  UserWhatsApp,
426
428
  UserTelegram,
429
+ UserSlack,
430
+ UserMicrosoftTeams,
427
431
  UserWebhook,
428
432
  ];
429
433
 
430
434
  /*
431
- * The RELATION spelling of those same seven, as they appear in a nested select
435
+ * The RELATION spelling of those same nine, as they appear in a nested select
432
436
  * on UserNotificationRule. Selecting any of them pulls a column out of the
433
437
  * method model itself - the address, the number, the handle - through a table
434
438
  * an administrator may read and which is not row-scoped for them. It is the
@@ -442,6 +446,8 @@ const METHOD_RELATION_KEYS: Array<string> = [
442
446
  "userPush",
443
447
  "userWhatsApp",
444
448
  "userTelegram",
449
+ "userSlack",
450
+ "userMicrosoftTeams",
445
451
  "userWebhook",
446
452
  ];
447
453
 
@@ -453,6 +459,8 @@ const METHOD_FOREIGN_KEYS: Array<keyof UserNotificationRule> = [
453
459
  "userPushId",
454
460
  "userWhatsAppId",
455
461
  "userTelegramId",
462
+ "userSlackId",
463
+ "userMicrosoftTeamsId",
456
464
  "userWebhookId",
457
465
  ];
458
466
 
@@ -673,7 +681,7 @@ const setUpLists: SetUpListsFunction = (
673
681
  }
674
682
 
675
683
  /*
676
- * Anything else, INCLUDING the seven notification-method models - which this
684
+ * Anything else, INCLUDING the nine notification-method models - which this
677
685
  * page must never ask for. A non-empty answer here would make a leak look
678
686
  * like a feature working, so the fallback stays empty and the assertion that
679
687
  * matters is about the request rather than the response: see "never reads a
@@ -1172,7 +1180,7 @@ afterEach(async (): Promise<void> => {
1172
1180
 
1173
1181
  /*
1174
1182
  * Unmounting stops the RENDERING, not the fetching. A rule table that belongs
1175
- * to the viewer loads the seven notification-method models one after another,
1183
+ * to the viewer loads the nine notification-method models one after another,
1176
1184
  * so a test that reads its own page leaves a chain of awaits running after its
1177
1185
  * last assertion - and every one of those calls is recorded on the same
1178
1186
  * `getListMock` the next test resets and then asserts against.
@@ -1365,14 +1373,14 @@ describe("the page is read at rest, whichever order its fetches land in", () =>
1365
1373
  assertEveryTableIsSettled();
1366
1374
  });
1367
1375
 
1368
- test("waits out the seven method reads a self-serve page makes for its owner", async () => {
1376
+ test("waits out the nine method reads a self-serve page makes for its owner", async () => {
1369
1377
  // A self-serve page is always the viewer's own, so this is the owner path.
1370
1378
  await renderSelfServePage(IncidentOnCallRules);
1371
1379
 
1372
1380
  /*
1373
- * A rule table belonging to the viewer loads the seven notification-method
1381
+ * A rule table belonging to the viewer loads the nine notification-method
1374
1382
  * models one after another, and unmounting the page does not stop that
1375
- * chain - it stops the rendering. Any of those seven still running when the
1383
+ * chain - it stops the rendering. Any of those nine still running when the
1376
1384
  * next test resets `getListMock` is recorded as that test's request, which
1377
1385
  * is how "never reads a notification method model" comes to fail on a page
1378
1386
  * that never asked for one.
@@ -1484,7 +1492,7 @@ describe("the shared rules table, as the admin page wires it", () => {
1484
1492
  /*
1485
1493
  * The redesign, in one assertion.
1486
1494
  *
1487
- * These seven models are readable only by the person who owns the row, and
1495
+ * These nine models are readable only by the person who owns the row, and
1488
1496
  * that is the whole protection: the table scope pins every read to the
1489
1497
  * caller. Widening it so this page could fill a dropdown exposed the raw
1490
1498
  * email and phone, the webhook url, the push device token, the telegram chat
@@ -1619,7 +1627,7 @@ describe("the shared rules table, as the admin page wires it", () => {
1619
1627
  });
1620
1628
 
1621
1629
  /*
1622
- * The seven foreign keys are mutually exclusive, and writing an SMS id into
1630
+ * The nine foreign keys are mutually exclusive, and writing an SMS id into
1623
1631
  * `userEmailId` would page an address instead of a phone without erroring
1624
1632
  * anywhere, so the whole set is asserted rather than the one column.
1625
1633
  */
@@ -1639,7 +1647,7 @@ describe("the shared rules table, as the admin page wires it", () => {
1639
1647
  /*
1640
1648
  * The failure mode this seam had to be designed around. Readiness is the
1641
1649
  * only source of methods here, so when it is down there are none to offer -
1642
- * and "then read the models directly" is not a fallback, it is seven refused
1650
+ * and "then read the models directly" is not a fallback, it is nine refused
1643
1651
  * requests that would replace the rule tables with an error page. The rules
1644
1652
  * stay editable; only the method choice is missing.
1645
1653
  */
@@ -2002,7 +2010,7 @@ describe("methods are a page of their own now, not a card on this one", () => {
2002
2010
  * It asserted that an administrator was offered NO control for adding a
2003
2011
  * notification method to somebody else's account: a masked, read-only list
2004
2012
  * and a prefilled "please add one yourself" email. That was correct for what
2005
- * the server could do at the time - the seven method models are scoped to
2013
+ * the server could do at the time - the nine method models are scoped to
2006
2014
  * their owner and the attempt to widen them leaked every raw column behind
2007
2015
  * them - but it left the commonest broken responder, a new joiner with no
2008
2016
  * method at all, fixable by nobody but themselves.
@@ -2167,7 +2175,7 @@ describe("the coverage grid, now shared with the readiness page", () => {
2167
2175
  * The edit path.
2168
2176
  *
2169
2177
  * `isEditable` was hardcoded false on the ModelTable, so this page issued no
2170
- * PATCH at all: the phase opened `notifyAfterMinutes` (and the seven method
2178
+ * PATCH at all: the phase opened `notifyAfterMinutes` (and the nine method
2171
2179
  * foreign keys) to update behind the largest guard in the codebase, and bought
2172
2180
  * zero capability anybody could reach. These assertions are about the two halves
2173
2181
  * of making that real - the editor being on for exactly the viewers allowed to
@@ -2225,7 +2233,7 @@ describe("the rules are editable, not merely addable and removable", () => {
2225
2233
 
2226
2234
  /*
2227
2235
  * The dropdown is an override field: its value travels in `miscDataProps`
2228
- * and is mapped onto one of the seven foreign keys by `onBeforeCreate`.
2236
+ * and is mapped onto one of the nine foreign keys by `onBeforeCreate`.
2229
2237
  * ModelForm calls that hook only for FormType.Create and BaseAPI.updateItem
2230
2238
  * never reads `miscDataProps`, so on the edit path the choice is discarded
2231
2239
  * in transit. Rendering it anyway would give an administrator a control
@@ -33,7 +33,7 @@ import getJestMockFunction, { MockFunction } from "../../MockType";
33
33
  * decision satisfied by the new answer.
34
34
  *
35
35
  * The old surface showed a masked, read-only list and a prefilled "please add
36
- * one yourself" email, because the seven notification method models are scoped
36
+ * one yourself" email, because the nine notification method models are scoped
37
37
  * to the person who owns the device: the columns behind them are the raw
38
38
  * address, the phone number, the webhook bearer url, the push device token and
39
39
  * the verification code, and an attempt to widen that scope so an admin could
@@ -44,7 +44,7 @@ import getJestMockFunction, { MockFunction } from "../../MockType";
44
44
  * So the models are STILL owner-scoped, and this page talks to a narrow
45
45
  * server-side capability instead. What that buys, and what it must not:
46
46
  *
47
- * - NO METHOD MODEL IS READ. Not by ModelAPI over UserEmail and its six
47
+ * - NO METHOD MODEL IS READ. Not by ModelAPI over UserEmail and its eight
48
48
  * siblings, and not through a nested relation select on a rule, which
49
49
  * reaches the same columns through a table an administrator IS allowed to
50
50
  * read. The assertion is about the REQUEST, because a component that asks
@@ -192,7 +192,7 @@ jest.mock("react-i18next", () => {
192
192
  * A stand-in ModelTable that records the model it was mounted over.
193
193
  *
194
194
  * It renders nothing on purpose. What this file needs from it is the single
195
- * fact that a table over UserEmail (or any of its six siblings) would be
195
+ * fact that a table over UserEmail (or any of its eight siblings) would be
196
196
  * visible here at all — the self-serve method components mount exactly those,
197
197
  * so "did the admin branch accidentally render the self-serve one?" is answered
198
198
  * by this list.
@@ -217,7 +217,9 @@ import TeamMember from "../../../Models/DatabaseModels/TeamMember";
217
217
  import User from "../../../Models/DatabaseModels/User";
218
218
  import UserCall from "../../../Models/DatabaseModels/UserCall";
219
219
  import UserEmail from "../../../Models/DatabaseModels/UserEmail";
220
+ import UserMicrosoftTeams from "../../../Models/DatabaseModels/UserMicrosoftTeams";
220
221
  import UserPush from "../../../Models/DatabaseModels/UserPush";
222
+ import UserSlack from "../../../Models/DatabaseModels/UserSlack";
221
223
  import UserSMS from "../../../Models/DatabaseModels/UserSMS";
222
224
  import UserTelegram from "../../../Models/DatabaseModels/UserTelegram";
223
225
  import UserWebhook from "../../../Models/DatabaseModels/UserWebhook";
@@ -238,7 +240,7 @@ const PROJECT_ID: ObjectID = new ObjectID(PROJECT_ID_STRING);
238
240
  const SIGNED_IN_USER_ID: ObjectID = new ObjectID(SIGNED_IN_USER_ID_STRING);
239
241
 
240
242
  /*
241
- * The seven models only their owner may read. Asserted as a SET because which
243
+ * The nine models only their owner may read. Asserted as a SET because which
242
244
  * one an admin surface reaches for hardly matters — every one carries a raw
243
245
  * identifier and most carry a credential.
244
246
  */
@@ -249,6 +251,8 @@ const NOTIFICATION_METHOD_MODELS: Array<unknown> = [
249
251
  UserPush,
250
252
  UserWhatsApp,
251
253
  UserTelegram,
254
+ UserSlack,
255
+ UserMicrosoftTeams,
252
256
  UserWebhook,
253
257
  ];
254
258
 
@@ -486,7 +490,7 @@ beforeEach((): void => {
486
490
  }
487
491
 
488
492
  /*
489
- * Anything else, INCLUDING the seven method models this page must never ask
493
+ * Anything else, INCLUDING the nine method models this page must never ask
490
494
  * for. A non-empty answer would make a leak look like a feature working, so
491
495
  * the fallback stays empty and the assertion that matters is about the
492
496
  * request rather than the response.
@@ -570,7 +574,7 @@ describe("the list", () => {
570
574
  );
571
575
 
572
576
  /*
573
- * The assertion is about the REQUEST, not the render. The seven models are
577
+ * The assertion is about the REQUEST, not the render. The nine models are
574
578
  * scoped to their owner, so a read here would be refused — but a component
575
579
  * that asks is already wrong, and the refusal is not something this page
576
580
  * may rely on.
@@ -657,10 +661,11 @@ describe("adding a method on somebody's behalf", () => {
657
661
 
658
662
  /*
659
663
  * Push is a device token minted at registration — there is nothing to type.
660
- * Telegram needs the account holder to message the bot first. Webhook has
661
- * no verification at all, so an admin-created one would be live the instant
662
- * it was written, which is exactly the silent redirect this design rules
663
- * out.
664
+ * Telegram needs the account holder to message the bot first. Slack and
665
+ * Microsoft Teams are born from the account holder's own OAuth workspace
666
+ * link, which nobody can establish for them. Webhook has no verification
667
+ * at all, so an admin-created one would be live the instant it was
668
+ * written, which is exactly the silent redirect this design rules out.
664
669
  */
665
670
  const modalText: string = document.body.textContent || "";
666
671
 
@@ -674,7 +679,13 @@ describe("adding a method on somebody's behalf", () => {
674
679
  return option.textContent || "";
675
680
  });
676
681
 
677
- for (const forbidden of ["Push", "Telegram", "Webhook"]) {
682
+ for (const forbidden of [
683
+ "Push",
684
+ "Telegram",
685
+ "Slack",
686
+ "Microsoft Teams",
687
+ "Webhook",
688
+ ]) {
678
689
  expect(optionLabels).not.toContain(forbidden);
679
690
  }
680
691
  });
@@ -122,14 +122,18 @@ import CallMethods from "../../../../App/FeatureSet/Dashboard/src/Components/Not
122
122
  import PushMethods from "../../../../App/FeatureSet/Dashboard/src/Components/NotificationMethods/Push";
123
123
  import WhatsAppMethods from "../../../../App/FeatureSet/Dashboard/src/Components/NotificationMethods/WhatsApp";
124
124
  import TelegramMethods from "../../../../App/FeatureSet/Dashboard/src/Components/NotificationMethods/Telegram";
125
+ import SlackMethods from "../../../../App/FeatureSet/Dashboard/src/Components/NotificationMethods/Slack";
126
+ import MicrosoftTeamsMethods from "../../../../App/FeatureSet/Dashboard/src/Components/NotificationMethods/MicrosoftTeams";
125
127
  import WebhookMethods from "../../../../App/FeatureSet/Dashboard/src/Components/NotificationMethods/Webhook";
126
128
  import BaseModel, {
127
129
  DatabaseBaseModelType,
128
130
  } from "../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
129
131
  import UserCall from "../../../Models/DatabaseModels/UserCall";
130
132
  import UserEmail from "../../../Models/DatabaseModels/UserEmail";
133
+ import UserMicrosoftTeams from "../../../Models/DatabaseModels/UserMicrosoftTeams";
131
134
  import UserNotificationRule from "../../../Models/DatabaseModels/UserNotificationRule";
132
135
  import UserPush from "../../../Models/DatabaseModels/UserPush";
136
+ import UserSlack from "../../../Models/DatabaseModels/UserSlack";
133
137
  import UserSMS from "../../../Models/DatabaseModels/UserSMS";
134
138
  import UserTelegram from "../../../Models/DatabaseModels/UserTelegram";
135
139
  import UserWebhook from "../../../Models/DatabaseModels/UserWebhook";
@@ -1470,7 +1474,7 @@ describe("Escalation rules, wired: the delete confirmation says what it costs",
1470
1474
 
1471
1475
  /*
1472
1476
  * ---------------------------------------------------------------------------
1473
- * THE SEVEN METHOD TABLES, RENDERED FOR REAL.
1477
+ * THE NINE METHOD TABLES, RENDERED FOR REAL.
1474
1478
  * ---------------------------------------------------------------------------
1475
1479
  *
1476
1480
  * This block exists because the first cut of this feature shipped a correct,
@@ -1532,6 +1536,8 @@ const METHOD_ID_CALL: string = "33333333-9999-4999-8999-999999999999";
1532
1536
  const METHOD_ID_PUSH: string = "44444444-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
1533
1537
  const METHOD_ID_WHATSAPP: string = "55555555-bbbb-4bbb-8bbb-bbbbbbbbbbbb";
1534
1538
  const METHOD_ID_TELEGRAM: string = "66666666-cccc-4ccc-8ccc-cccccccccccc";
1539
+ const METHOD_ID_SLACK: string = "88888888-eeee-4eee-8eee-eeeeeeeeeeee";
1540
+ const METHOD_ID_TEAMS: string = "99999999-ffff-4fff-8fff-ffffffffffff";
1535
1541
  const METHOD_ID_WEBHOOK: string = "77777777-dddd-4ddd-8ddd-dddddddddddd";
1536
1542
 
1537
1543
  const METHOD_SURFACES: Array<MethodSurface> = [
@@ -1624,6 +1630,36 @@ const METHOD_SURFACES: Array<MethodSurface> = [
1624
1630
  modalTitle: "Delete Telegram Account",
1625
1631
  methodLabel: "Telegram: @alexchen",
1626
1632
  },
1633
+ {
1634
+ name: "Slack",
1635
+ Component: SlackMethods,
1636
+ modelType: UserSlack,
1637
+ relationName: "userSlack",
1638
+ methodId: METHOD_ID_SLACK,
1639
+ buildRow: (): BaseModel => {
1640
+ return buildMethodRow(UserSlack, METHOD_ID_SLACK, {
1641
+ slackUserName: "alexchen",
1642
+ isVerified: true,
1643
+ });
1644
+ },
1645
+ modalTitle: "Delete Slack Account",
1646
+ methodLabel: "Slack: alexchen",
1647
+ },
1648
+ {
1649
+ name: "Microsoft Teams",
1650
+ Component: MicrosoftTeamsMethods,
1651
+ modelType: UserMicrosoftTeams,
1652
+ relationName: "userMicrosoftTeams",
1653
+ methodId: METHOD_ID_TEAMS,
1654
+ buildRow: (): BaseModel => {
1655
+ return buildMethodRow(UserMicrosoftTeams, METHOD_ID_TEAMS, {
1656
+ microsoftTeamsUserName: "Alex Example",
1657
+ isVerified: true,
1658
+ });
1659
+ },
1660
+ modalTitle: "Delete Microsoft Teams Account",
1661
+ methodLabel: "Microsoft Teams: Alex Example",
1662
+ },
1627
1663
  {
1628
1664
  name: "Webhook",
1629
1665
  Component: WebhookMethods,
@@ -38,7 +38,7 @@ import getJestMockFunction, { MockFunction } from "../../MockType";
38
38
  *
39
39
  * The fourth is where the "Notification Method" dropdown comes from, which is
40
40
  * now two different places depending on whose rules are on screen. For the
41
- * signed-in user it is still seven reads of the seven method models, and that
41
+ * signed-in user it is still nine reads of the nine method models, and that
42
42
  * path is the four settings pages every existing user relies on. For anybody
43
43
  * else those reads are REFUSED - the models are scoped to the person who owns
44
44
  * the device, because the columns behind them are the raw phone number, the
@@ -186,8 +186,10 @@ import AlertSeverity from "../../../Models/DatabaseModels/AlertSeverity";
186
186
  import IncidentSeverity from "../../../Models/DatabaseModels/IncidentSeverity";
187
187
  import UserCall from "../../../Models/DatabaseModels/UserCall";
188
188
  import UserEmail from "../../../Models/DatabaseModels/UserEmail";
189
+ import UserMicrosoftTeams from "../../../Models/DatabaseModels/UserMicrosoftTeams";
189
190
  import UserNotificationRule from "../../../Models/DatabaseModels/UserNotificationRule";
190
191
  import UserPush from "../../../Models/DatabaseModels/UserPush";
192
+ import UserSlack from "../../../Models/DatabaseModels/UserSlack";
191
193
  import UserSMS from "../../../Models/DatabaseModels/UserSMS";
192
194
  import UserTelegram from "../../../Models/DatabaseModels/UserTelegram";
193
195
  import UserWebhook from "../../../Models/DatabaseModels/UserWebhook";
@@ -199,7 +201,7 @@ import ObjectID from "../../../Types/ObjectID";
199
201
  import ProjectUtil from "../../../UI/Utils/Project";
200
202
 
201
203
  /*
202
- * The seven models whose rows only their owner may read. They are listed
204
+ * The nine models whose rows only their owner may read. They are listed
203
205
  * together because the assertion that matters is about the SET: an admin
204
206
  * surface that reads any one of them is reading a row it is not entitled to,
205
207
  * and which one hardly matters.
@@ -211,13 +213,15 @@ const NOTIFICATION_METHOD_MODELS: Array<unknown> = [
211
213
  UserPush,
212
214
  UserWhatsApp,
213
215
  UserTelegram,
216
+ UserSlack,
217
+ UserMicrosoftTeams,
214
218
  UserWebhook,
215
219
  ];
216
220
 
217
221
  /*
218
222
  * What the admin surface hands over in place of those reads: a channel name, the
219
223
  * id of the row, and a mask. Telegram is unverified on purpose - the self-serve
220
- * path filters `isVerified: true` in six of its seven queries, so a supplied
224
+ * path filters `isVerified: true` in eight of its nine queries, so a supplied
221
225
  * list that offered unverified methods would be the two paths disagreeing about
222
226
  * what is pickable.
223
227
  */
@@ -250,6 +254,8 @@ const METHOD_FOREIGN_KEYS: Array<keyof UserNotificationRule> = [
250
254
  "userPushId",
251
255
  "userWhatsAppId",
252
256
  "userTelegramId",
257
+ "userSlackId",
258
+ "userMicrosoftTeamsId",
253
259
  "userWebhookId",
254
260
  ];
255
261
 
@@ -343,7 +349,7 @@ const getMethodOptions: GetMethodOptions = (
343
349
  };
344
350
 
345
351
  /*
346
- * The seven RELATION spellings. Selecting any of these on a rule pulls columns
352
+ * The nine RELATION spellings. Selecting any of these on a rule pulls columns
347
353
  * out of the method models themselves - the raw address, the raw number, the
348
354
  * telegram handle - through a table an administrator is allowed to read.
349
355
  *
@@ -366,6 +372,8 @@ const METHOD_RELATIONS: Array<string> = [
366
372
  "userPush",
367
373
  "userWhatsApp",
368
374
  "userTelegram",
375
+ "userSlack",
376
+ "userMicrosoftTeams",
369
377
  "userWebhook",
370
378
  ];
371
379
 
@@ -719,7 +727,7 @@ describe("OnCallRulesTable", () => {
719
727
 
720
728
  /*
721
729
  * The whole point of the redesign, in one assertion. Not "reads them and
722
- * shows fewer columns" - does not read them. Each of these seven models is
730
+ * shows fewer columns" - does not read them. Each of these nine models is
723
731
  * scoped to the person who owns the device, and the columns behind them are
724
732
  * the raw phone number, the webhook bearer url, the push device token, the
725
733
  * telegram chat id and the verification code. A request here is a request
@@ -748,7 +756,7 @@ describe("OnCallRulesTable", () => {
748
756
  * The readiness payload the admin page sources these from is fetched
749
757
  * asynchronously and can fail outright, so an absent list is a real state
750
758
  * rather than a caller mistake. Treating it as "then fetch them yourself"
751
- * would fire seven refused requests and turn this component's error state on
759
+ * would fire nine refused requests and turn this component's error state on
752
760
  * - taking the rule repair away because a DIFFERENT read failed.
753
761
  */
754
762
  await renderForOtherUser(undefined);
@@ -786,7 +794,7 @@ describe("OnCallRulesTable", () => {
786
794
 
787
795
  /*
788
796
  * The unverified Telegram method is absent, which mirrors the
789
- * `isVerified: true` filter on six of the seven self-serve queries. A rule
797
+ * `isVerified: true` filter on eight of the nine self-serve queries. A rule
790
798
  * pointed at an unverified device is a rule that pages nothing.
791
799
  */
792
800
  expect(
@@ -805,7 +813,7 @@ describe("OnCallRulesTable", () => {
805
813
  });
806
814
 
807
815
  /*
808
- * The seven foreign keys are mutually exclusive and nothing validates that
816
+ * The nine foreign keys are mutually exclusive and nothing validates that
809
817
  * client-side, so this asserts the whole set: an SMS id written to
810
818
  * `userEmailId` would page an address rather than a phone, and would not
811
819
  * error anywhere on the way.
@@ -968,7 +976,7 @@ describe("OnCallRulesTable", () => {
968
976
  test("the signed-in user's own table still reads the method models itself", async () => {
969
977
  /*
970
978
  * The regression surface. Four settings pages every existing user already
971
- * relies on read their own seven models to fill this dropdown, and reading
979
+ * relies on read their own nine models to fill this dropdown, and reading
972
980
  * your own rows is exactly what those models allow. Nothing about the admin
973
981
  * surface is a reason to change it - and an unmasked label is more use to
974
982
  * somebody looking at their own phone number than a mask of it.
@@ -985,7 +993,7 @@ describe("OnCallRulesTable", () => {
985
993
  getQueriedUserIds().filter((userId: string | undefined) => {
986
994
  return userId === CURRENT_USER_ID_STRING;
987
995
  }),
988
- ).toHaveLength(7);
996
+ ).toHaveLength(9);
989
997
 
990
998
  expect(getMethodOptions(capturedTables[0]!)).toEqual([
991
999
  { label: `Email: ${OWN_EMAIL_ADDRESS}`, value: OWN_EMAIL_ID },
@@ -120,6 +120,23 @@ describe("Pay as you go notices", () => {
120
120
  expect(card).toHaveTextContent("Starting at");
121
121
  });
122
122
 
123
+ it("names security events among the pillars billed at the telemetry rate", () => {
124
+ /*
125
+ * Security events ingest on the same key and meter at the same
126
+ * $0.10/GB as the other telemetry pillars. This sentence is the body of
127
+ * the consent checkbox a user has to tick to create a key, so a pillar
128
+ * missing from it is a pillar the user is charged for without ever
129
+ * having been told.
130
+ */
131
+ render(<TelemetryPayAsYouGoCard />);
132
+
133
+ expect(
134
+ screen.getByTestId("telemetry-pay-as-you-go-card"),
135
+ ).toHaveTextContent(
136
+ "Logs, traces, metrics, profiles and security events are billed at",
137
+ );
138
+ });
139
+
123
140
  it("says the charge stops when the key is deleted, so the notice is not just a threat", () => {
124
141
  render(<TelemetryPayAsYouGoCard />);
125
142
 
@@ -117,6 +117,30 @@ const NOT_READABLE_BY_THEIR_DOMAIN_ROLES: Array<string> = [
117
117
  "IncomingCallPolicyEscalationRule",
118
118
  ];
119
119
 
120
+ /*
121
+ * Columns inside an in-domain table whose read list deliberately stops short of
122
+ * the domain's full tier set, and why. The table-level list above is about
123
+ * whole tables a role holder is kept out of; this is the same idea one level
124
+ * down, for a table they are otherwise welcome in.
125
+ *
126
+ * Entries are the exact `<table>.<column> is missing <tier>` strings the sweep
127
+ * produces, so the list is self-policing: widen one of these read lists again
128
+ * and the entry stops being produced and the assertion fails.
129
+ *
130
+ * https://github.com/OneUptime/oneuptime/issues/3360 - Monitor's three secret
131
+ * keys are bearer credentials, not monitor data. Reading one is gated on being
132
+ * able to ROTATE it, which is what separates MonitorMember (may edit a monitor,
133
+ * so may see and reset its key) from MonitorViewer (read-only, so may not).
134
+ * Viewer used to be on these lists, which made "read-only" mean "can read a
135
+ * live credential for every agent in the project" -- the same reasoning that
136
+ * keeps MonitorSecret out of the table list above.
137
+ */
138
+ const COLUMNS_NOT_READABLE_BY_THEIR_DOMAIN_ROLES: Array<string> = [
139
+ "Monitor.incomingEmailSecretKey is missing MonitorViewer",
140
+ "Monitor.incomingRequestSecretKey is missing MonitorViewer",
141
+ "Monitor.serverMonitorSecretKey is missing MonitorViewer",
142
+ ];
143
+
120
144
  type ModelNameFunction = (modelType: ModelType) => string;
121
145
 
122
146
  const modelName: ModelNameFunction = (modelType: ModelType): string => {
@@ -317,7 +341,9 @@ describe("Domain role tier coverage", () => {
317
341
  }
318
342
  }
319
343
 
320
- expect(missing.sort()).toEqual([]);
344
+ expect(missing.sort()).toEqual(
345
+ COLUMNS_NOT_READABLE_BY_THEIR_DOMAIN_ROLES.slice().sort(),
346
+ );
321
347
  expect(checked).toBeGreaterThan(500);
322
348
  });
323
349
  });