@oneuptime/common 12.0.11 → 12.0.13

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 (251) hide show
  1. package/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.ts +32 -5
  2. package/Models/DatabaseModels/NetworkDevice.ts +64 -0
  3. package/Models/DatabaseModels/StatusPage.ts +59 -0
  4. package/Models/DatabaseModels/StatusPageOidc.ts +2 -0
  5. package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +19 -2
  6. package/Server/API/AIChatAPI.ts +55 -56
  7. package/Server/API/CommonAPI.ts +89 -0
  8. package/Server/API/MicrosoftTeamsAPI.ts +20 -9
  9. package/Server/API/SlackAPI.ts +13 -10
  10. package/Server/API/StatusPageAPI.ts +2197 -2128
  11. package/Server/API/TelemetryAPI.ts +72 -3
  12. package/Server/Infrastructure/Postgres/SchemaMigrations/1787500000000-AddEnableSearchEngineIndexingToStatusPage.ts +30 -0
  13. package/Server/Infrastructure/Postgres/SchemaMigrations/1787600000000-AddNetworkDeviceReachabilityColumns.ts +47 -0
  14. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
  15. package/Server/Middleware/UserAuthorization.ts +11 -2
  16. package/Server/Services/ApiKeyPermissionService.ts +116 -2
  17. package/Server/Services/DatabaseService.ts +17 -6
  18. package/Server/Services/LogAggregationService.ts +34 -0
  19. package/Server/Services/LogService.ts +21 -0
  20. package/Server/Services/NetworkSiteService.ts +12 -0
  21. package/Server/Services/SpanService.ts +21 -0
  22. package/Server/Services/TraceAggregationService.ts +15 -0
  23. package/Server/Services/WorkspaceNotificationRuleService.ts +172 -220
  24. package/Server/Types/AnalyticsDatabase/ModelPermission.ts +9 -0
  25. package/Server/Types/Database/Permissions/AccessControlPermission.ts +47 -16
  26. package/Server/Types/Workflow/Components/Conditions/IfElse.ts +9 -0
  27. package/Server/Types/Workflow/Components/JavaScript.ts +9 -0
  28. package/Server/Utils/APIKey/AccessPermission.ts +16 -40
  29. package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +144 -0
  30. package/Server/Utils/LogRedaction.ts +576 -0
  31. package/Server/Utils/Logger.ts +123 -46
  32. package/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.ts +94 -23
  33. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +12 -0
  34. package/Server/Utils/Monitor/MonitorResource.ts +29 -9
  35. package/Server/Utils/Monitor/NetworkInventoryUtil.ts +28 -7
  36. package/Server/Utils/SessionReplay/SessionReplayGateCacheStore.ts +56 -10
  37. package/Server/Utils/StartServer.ts +30 -9
  38. package/Server/Utils/StatusPageSearchEngineIndexing.ts +33 -0
  39. package/Server/Utils/Telemetry/ResourceEntityFilter.ts +441 -0
  40. package/Server/Utils/VM/VMRunner.ts +693 -874
  41. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +488 -46
  42. package/Tests/App/Dashboard/MonitorTypePicker.test.tsx +300 -0
  43. package/Tests/App/StatusPage/StatusPageIndexPageRobotsMeta.test.ts +130 -0
  44. package/Tests/Models/DatabaseModels/DatabaseBaseModelToJSONObjectCache.test.ts +180 -0
  45. package/Tests/Models/StatusPageEnableSearchEngineIndexing.test.ts +157 -0
  46. package/Tests/Server/API/AIChatCancelAndFeedback.test.ts +23 -1
  47. package/Tests/Server/API/AIChatRouteAuthorization.test.ts +785 -0
  48. package/Tests/Server/API/BaseAPIApiKeyAuth.test.ts +21 -8
  49. package/Tests/Server/API/CommonAPIAuthGuard.test.ts +290 -0
  50. package/Tests/Server/API/MicrosoftTeamsManifest.test.ts +7 -1
  51. package/Tests/Server/API/StatusPageOverviewCache.test.ts +474 -0
  52. package/Tests/Server/API/StatusPageSeoSearchEngineIndexing.test.ts +189 -0
  53. package/Tests/Server/Infrastructure/InMemoryTTLCache.test.ts +158 -0
  54. package/Tests/Server/Infrastructure/Postgres/DeviceRoleAndDeclaredLinkParentMigration.test.ts +9 -60
  55. package/Tests/Server/Middleware/ProjectAuthorizationApiKeyMiddleware.test.ts +24 -15
  56. package/Tests/Server/Middleware/UserAuthorization.test.ts +79 -0
  57. package/Tests/Server/Services/AddNetworkDeviceReachabilityColumnsMigration.test.ts +332 -0
  58. package/Tests/Server/Services/ApiKeyPermissionService.test.ts +347 -0
  59. package/Tests/Server/Services/DatabaseServiceUpdateDebugLogging.test.ts +282 -0
  60. package/Tests/Server/Services/NetworkSiteService.test.ts +56 -2
  61. package/Tests/Server/Services/TelemetryResourceFacetFilters.test.ts +267 -0
  62. package/Tests/Server/Services/WorkspaceNotificationRuleTestRuleChannels.test.ts +702 -0
  63. package/Tests/Server/Types/Database/Permissions/AccessControlPermission.test.ts +165 -0
  64. package/Tests/Server/Types/Workflow/Components/CustomCodeScriptError.test.ts +121 -0
  65. package/Tests/Server/Utils/APIKey/AccessPermission.test.ts +48 -36
  66. package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +213 -0
  67. package/Tests/Server/Utils/LogRedaction.test.ts +415 -0
  68. package/Tests/Server/Utils/LoggerCredentialLeak.test.ts +245 -0
  69. package/Tests/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.test.ts +374 -4
  70. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorJavascriptExpression.test.ts +92 -0
  71. package/Tests/Server/Utils/Monitor/MonitorResourceIngestedStepSelection.test.ts +455 -0
  72. package/Tests/Server/Utils/Monitor/NetworkDeviceReachabilityRoundTrip.test.ts +369 -0
  73. package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +86 -8
  74. package/Tests/Server/Utils/PrivacyFilterUtil.test.ts +64 -0
  75. package/Tests/Server/Utils/SessionReplay/SessionReplayGateCacheStore.test.ts +207 -0
  76. package/Tests/Server/Utils/StartServerBodyVerify.test.ts +335 -0
  77. package/Tests/Server/Utils/StatusPageSearchEngineIndexing.test.ts +60 -0
  78. package/Tests/Server/Utils/Telemetry/ResourceEntityFilter.test.ts +435 -0
  79. package/Tests/Server/Utils/VM/VMRunnerIsolation.test.ts +385 -0
  80. package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +3 -0
  81. package/Tests/Server/Utils/Workspace/MicrosoftTeamsChannelSend.test.ts +607 -62
  82. package/Tests/Server/Utils/Workspace/MicrosoftTeamsInstalledTeamIdSpace.test.ts +778 -0
  83. package/Tests/Server/Utils/Workspace/MicrosoftTeamsTeamInstalls.test.ts +44 -10
  84. package/Tests/Types/API/HostnameFromAuthority.test.ts +164 -0
  85. package/Tests/Types/Database/AccessControl/ColumnAccessControlCache.test.ts +344 -0
  86. package/Tests/Types/Database/DatabasePropertyFindOperator.test.ts +518 -0
  87. package/Tests/Types/Database/TableColumnMetadataCache.test.ts +286 -0
  88. package/Tests/Types/Monitor/MonitorStep.test.ts +100 -0
  89. package/Tests/Types/Monitor/MonitorTypeKeywords.test.ts +360 -0
  90. package/Tests/Types/StatusPage/SearchEngineIndexing.test.ts +86 -0
  91. package/Tests/Types/Telemetry/ResourceEntityFacet.test.ts +254 -0
  92. package/Tests/UI/Components/CardSelect.test.tsx +1021 -0
  93. package/Tests/UI/Components/MasterPage.test.tsx +36 -1
  94. package/Tests/Utils/Monitor/MonitorMetricType.test.ts +66 -1
  95. package/Tests/Utils/Monitor/NetworkTopologyUtil.test.ts +115 -6
  96. package/Tests/Utils/NetworkDevice/DeviceReachabilityUtil.test.ts +610 -0
  97. package/Tests/Utils/NetworkSite/SiteStatusRollupUtil.test.ts +114 -45
  98. package/Types/API/Hostname.ts +79 -0
  99. package/Types/Database/AccessControl/ColumnAccessControl.ts +33 -11
  100. package/Types/Database/AccessControl/ColumnBillingAccessControl.ts +33 -11
  101. package/Types/Database/DatabaseProperty.ts +38 -0
  102. package/Types/Database/TableColumn.ts +34 -7
  103. package/Types/Events/Recurring.ts +16 -1
  104. package/Types/Monitor/CustomCodeMonitor/CustomCodeMonitorResponse.ts +14 -2
  105. package/Types/Monitor/MonitorStep.ts +13 -1
  106. package/Types/Monitor/MonitorType.ts +345 -40
  107. package/Types/Monitor/SSLMonitor/SslMonitorResponse.ts +43 -0
  108. package/Types/StatusPage/SearchEngineIndexing.ts +61 -0
  109. package/Types/Telemetry/ResourceEntityFacet.ts +211 -0
  110. package/UI/Components/CardSelect/CardSelect.tsx +714 -105
  111. package/UI/Components/EmptyState/EmptyState.tsx +8 -1
  112. package/UI/Components/Footer/Footer.tsx +32 -6
  113. package/UI/Components/Forms/Fields/FormField.tsx +3 -0
  114. package/UI/Components/Forms/Types/Field.ts +8 -0
  115. package/UI/Components/Loader/PageLoader.tsx +29 -8
  116. package/UI/Components/LogsViewer/components/LogsAnalyticsView.tsx +26 -4
  117. package/UI/Components/Markdown.tsx/LazyMarkdownViewer.tsx +17 -1
  118. package/UI/Components/MasterPage/MasterPage.tsx +24 -11
  119. package/Utils/Monitor/MonitorMetricType.ts +16 -1
  120. package/Utils/Monitor/NetworkTopologyUtil.ts +60 -8
  121. package/Utils/NetworkDevice/DeviceReachabilityUtil.ts +262 -0
  122. package/Utils/NetworkSite/SiteStatusRollupUtil.ts +41 -24
  123. package/Utils/Telemetry/CrossSignalScope.ts +75 -4
  124. package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js +20 -4
  125. package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js.map +1 -1
  126. package/build/dist/Models/DatabaseModels/NetworkDevice.js +66 -0
  127. package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
  128. package/build/dist/Models/DatabaseModels/StatusPage.js +60 -0
  129. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  130. package/build/dist/Models/DatabaseModels/StatusPageOidc.js +2 -0
  131. package/build/dist/Models/DatabaseModels/StatusPageOidc.js.map +1 -1
  132. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
  133. package/build/dist/Server/API/AIChatAPI.js +48 -35
  134. package/build/dist/Server/API/AIChatAPI.js.map +1 -1
  135. package/build/dist/Server/API/CommonAPI.js +59 -0
  136. package/build/dist/Server/API/CommonAPI.js.map +1 -1
  137. package/build/dist/Server/API/MicrosoftTeamsAPI.js +20 -6
  138. package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
  139. package/build/dist/Server/API/SlackAPI.js +13 -10
  140. package/build/dist/Server/API/SlackAPI.js.map +1 -1
  141. package/build/dist/Server/API/StatusPageAPI.js +745 -673
  142. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  143. package/build/dist/Server/API/TelemetryAPI.js +34 -3
  144. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  145. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787500000000-AddEnableSearchEngineIndexingToStatusPage.js +23 -0
  146. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787500000000-AddEnableSearchEngineIndexingToStatusPage.js.map +1 -0
  147. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787600000000-AddNetworkDeviceReachabilityColumns.js +34 -0
  148. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787600000000-AddNetworkDeviceReachabilityColumns.js.map +1 -0
  149. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
  150. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  151. package/build/dist/Server/Middleware/UserAuthorization.js +6 -2
  152. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  153. package/build/dist/Server/Services/ApiKeyPermissionService.js +90 -1
  154. package/build/dist/Server/Services/ApiKeyPermissionService.js.map +1 -1
  155. package/build/dist/Server/Services/DatabaseService.js +15 -6
  156. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  157. package/build/dist/Server/Services/LogAggregationService.js +2 -0
  158. package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
  159. package/build/dist/Server/Services/LogService.js +16 -0
  160. package/build/dist/Server/Services/LogService.js.map +1 -1
  161. package/build/dist/Server/Services/NetworkSiteService.js +12 -0
  162. package/build/dist/Server/Services/NetworkSiteService.js.map +1 -1
  163. package/build/dist/Server/Services/SpanService.js +16 -0
  164. package/build/dist/Server/Services/SpanService.js.map +1 -1
  165. package/build/dist/Server/Services/TraceAggregationService.js +2 -0
  166. package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
  167. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +137 -164
  168. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
  169. package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js +9 -0
  170. package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js.map +1 -1
  171. package/build/dist/Server/Types/Database/Permissions/AccessControlPermission.js +21 -13
  172. package/build/dist/Server/Types/Database/Permissions/AccessControlPermission.js.map +1 -1
  173. package/build/dist/Server/Types/Workflow/Components/Conditions/IfElse.js +8 -0
  174. package/build/dist/Server/Types/Workflow/Components/Conditions/IfElse.js.map +1 -1
  175. package/build/dist/Server/Types/Workflow/Components/JavaScript.js +8 -0
  176. package/build/dist/Server/Types/Workflow/Components/JavaScript.js.map +1 -1
  177. package/build/dist/Server/Utils/APIKey/AccessPermission.js +9 -32
  178. package/build/dist/Server/Utils/APIKey/AccessPermission.js.map +1 -1
  179. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +87 -0
  180. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
  181. package/build/dist/Server/Utils/LogRedaction.js +449 -0
  182. package/build/dist/Server/Utils/LogRedaction.js.map +1 -0
  183. package/build/dist/Server/Utils/Logger.js +98 -45
  184. package/build/dist/Server/Utils/Logger.js.map +1 -1
  185. package/build/dist/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.js +65 -13
  186. package/build/dist/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.js.map +1 -1
  187. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +12 -1
  188. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  189. package/build/dist/Server/Utils/Monitor/MonitorResource.js +20 -3
  190. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  191. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +27 -7
  192. package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
  193. package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCacheStore.js +29 -10
  194. package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCacheStore.js.map +1 -1
  195. package/build/dist/Server/Utils/StartServer.js +10 -7
  196. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  197. package/build/dist/Server/Utils/StatusPageSearchEngineIndexing.js +24 -0
  198. package/build/dist/Server/Utils/StatusPageSearchEngineIndexing.js.map +1 -0
  199. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js +311 -0
  200. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js.map +1 -0
  201. package/build/dist/Server/Utils/VM/VMRunner.js +402 -525
  202. package/build/dist/Server/Utils/VM/VMRunner.js.map +1 -1
  203. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +366 -37
  204. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  205. package/build/dist/Types/API/Hostname.js +63 -0
  206. package/build/dist/Types/API/Hostname.js.map +1 -1
  207. package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js +20 -6
  208. package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js.map +1 -1
  209. package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js +20 -6
  210. package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js.map +1 -1
  211. package/build/dist/Types/Database/DatabaseProperty.js +38 -0
  212. package/build/dist/Types/Database/DatabaseProperty.js.map +1 -1
  213. package/build/dist/Types/Database/TableColumn.js +24 -6
  214. package/build/dist/Types/Database/TableColumn.js.map +1 -1
  215. package/build/dist/Types/Events/Recurring.js +13 -1
  216. package/build/dist/Types/Events/Recurring.js.map +1 -1
  217. package/build/dist/Types/Monitor/MonitorStep.js +9 -1
  218. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  219. package/build/dist/Types/Monitor/MonitorType.js +330 -31
  220. package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
  221. package/build/dist/Types/StatusPage/SearchEngineIndexing.js +55 -0
  222. package/build/dist/Types/StatusPage/SearchEngineIndexing.js.map +1 -0
  223. package/build/dist/Types/Telemetry/ResourceEntityFacet.js +156 -0
  224. package/build/dist/Types/Telemetry/ResourceEntityFacet.js.map +1 -0
  225. package/build/dist/UI/Components/CardSelect/CardSelect.js +360 -40
  226. package/build/dist/UI/Components/CardSelect/CardSelect.js.map +1 -1
  227. package/build/dist/UI/Components/EmptyState/EmptyState.js +1 -1
  228. package/build/dist/UI/Components/EmptyState/EmptyState.js.map +1 -1
  229. package/build/dist/UI/Components/Footer/Footer.js +7 -4
  230. package/build/dist/UI/Components/Footer/Footer.js.map +1 -1
  231. package/build/dist/UI/Components/Forms/Fields/FormField.js +1 -1
  232. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  233. package/build/dist/UI/Components/Loader/PageLoader.js +15 -5
  234. package/build/dist/UI/Components/Loader/PageLoader.js.map +1 -1
  235. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js +16 -3
  236. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js.map +1 -1
  237. package/build/dist/UI/Components/Markdown.tsx/LazyMarkdownViewer.js +13 -1
  238. package/build/dist/UI/Components/Markdown.tsx/LazyMarkdownViewer.js.map +1 -1
  239. package/build/dist/UI/Components/MasterPage/MasterPage.js +10 -2
  240. package/build/dist/UI/Components/MasterPage/MasterPage.js.map +1 -1
  241. package/build/dist/Utils/Monitor/MonitorMetricType.js +13 -1
  242. package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
  243. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +34 -7
  244. package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
  245. package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js +177 -0
  246. package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js.map +1 -0
  247. package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js +23 -27
  248. package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js.map +1 -1
  249. package/build/dist/Utils/Telemetry/CrossSignalScope.js +44 -4
  250. package/build/dist/Utils/Telemetry/CrossSignalScope.js.map +1 -1
  251. package/package.json +1 -1
@@ -12,7 +12,6 @@ import {
12
12
  } from "../../../Server/Utils/Express";
13
13
  import Response from "../../../Server/Utils/Response";
14
14
  import { mockRouter } from "./Helpers";
15
- import ApiKeyPermission from "../../../Models/DatabaseModels/ApiKeyPermission";
16
15
  import LogPipeline from "../../../Models/DatabaseModels/LogPipeline";
17
16
  import Monitor from "../../../Models/DatabaseModels/Monitor";
18
17
  import BadDataException from "../../../Types/Exception/BadDataException";
@@ -25,6 +24,19 @@ import UserType from "../../../Types/UserType";
25
24
  import { getJestSpyOn } from "../../Spy";
26
25
  import { beforeEach, describe, expect, it, jest } from "@jest/globals";
27
26
 
27
+ /*
28
+ * PasswordHash has a known, pre-existing TS5.9 compile failure under ts-jest
29
+ * (Buffer vs BinaryLike) that breaks every suite whose import graph reaches
30
+ * it. Nothing here touches password hashing; stub the module before the
31
+ * service import graph drags it into compilation.
32
+ */
33
+ jest.mock("../../../Server/Utils/PasswordHash", () => {
34
+ return {
35
+ __esModule: true,
36
+ default: class PasswordHashStub {},
37
+ };
38
+ });
39
+
28
40
  jest.mock("../../../Server/Utils/Express", () => {
29
41
  return {
30
42
  getRouter: () => {
@@ -225,12 +237,13 @@ describe("BaseAPI CRUD auth contract for the ApiKey header (issue #3004)", () =>
225
237
  ): void => {
226
238
  findApiKey.mockResolvedValue({ id: API_KEY_ID, projectId: PROJECT_ID });
227
239
 
228
- const apiKeyPermission: ApiKeyPermission = new ApiKeyPermission();
229
- apiKeyPermission.permission = permission;
230
- apiKeyPermission.labels = [];
231
- apiKeyPermission.isBlockPermission = false;
232
-
233
- findApiKeyPermissions.mockResolvedValue([apiKeyPermission]);
240
+ findApiKeyPermissions.mockResolvedValue([
241
+ {
242
+ permission: permission,
243
+ labelIds: [],
244
+ isBlockPermission: false,
245
+ },
246
+ ]);
234
247
  };
235
248
 
236
249
  beforeEach(() => {
@@ -250,7 +263,7 @@ describe("BaseAPI CRUD auth contract for the ApiKey header (issue #3004)", () =>
250
263
  );
251
264
  findApiKeyPermissions = getJestSpyOn(
252
265
  ApiKeyPermissionService,
253
- "findBy",
266
+ "findPermissionsByApiKeyId",
254
267
  ).mockResolvedValue([]);
255
268
  getJestSpyOn(GlobalConfigService, "findOneBy").mockResolvedValue(null);
256
269
 
@@ -479,3 +479,293 @@ describe("CommonAPI.assertTenantScoped", () => {
479
479
  }).not.toThrow();
480
480
  });
481
481
  });
482
+
483
+ /*
484
+ * Tests for CommonAPI.assertPermittedInProject — the third guard in the set.
485
+ *
486
+ * assertAuthenticatedProjectMember answers "are you in this project?" and
487
+ * assertResourceBelongsToProject answers "is this row in that project?".
488
+ * Neither answers "are you allowed to read this KIND of thing?", which is the
489
+ * question a CRUD read answers from the model's own access control lists and
490
+ * a custom route reading with `isRoot: true` skips entirely.
491
+ *
492
+ * The subtle part, and the reason this has its own tests: models routinely
493
+ * list Permission.Public as a reader (LlmProvider does, so the shared global
494
+ * providers stay visible), while getUserPermissions merges Public into EVERY
495
+ * caller's permission set — anonymous ones included. Intersecting the two
496
+ * lists as they come would therefore admit anybody. The guard first narrows
497
+ * the model's list to the permissions a team can actually grant inside a
498
+ * project.
499
+ */
500
+ function buildPermittedProps(data: {
501
+ projectId: ObjectID;
502
+ granted: Array<Permission>;
503
+ blocked?: Array<Permission> | undefined;
504
+ isMasterAdmin?: boolean | undefined;
505
+ }): DatabaseCommonInteractionProps {
506
+ const permissions: Array<UserPermission> = data.granted.map(
507
+ (permission: Permission) => {
508
+ return {
509
+ _type: "UserPermission",
510
+ permission: permission,
511
+ labelIds: [],
512
+ isBlockPermission: false,
513
+ } as UserPermission;
514
+ },
515
+ );
516
+
517
+ for (const blocked of data.blocked || []) {
518
+ permissions.push({
519
+ _type: "UserPermission",
520
+ permission: blocked,
521
+ labelIds: [],
522
+ isBlockPermission: true,
523
+ } as UserPermission);
524
+ }
525
+
526
+ const tenantPermission: UserTenantAccessPermission = {
527
+ _type: "UserTenantAccessPermission",
528
+ projectId: data.projectId,
529
+ permissions: permissions,
530
+ } as UserTenantAccessPermission;
531
+
532
+ const dictionary: Dictionary<UserTenantAccessPermission> = {};
533
+ dictionary[data.projectId.toString()] = tenantPermission;
534
+
535
+ return {
536
+ tenantId: data.projectId,
537
+ userId: ObjectID.generate(),
538
+ userTenantAccessPermission: dictionary,
539
+ isMasterAdmin: data.isMasterAdmin,
540
+ };
541
+ }
542
+
543
+ describe("CommonAPI.assertPermittedInProject", () => {
544
+ test("admits a caller holding one of the allowed permissions", () => {
545
+ const projectId: ObjectID = ObjectID.generate();
546
+
547
+ expect(() => {
548
+ CommonAPI.assertPermittedInProject({
549
+ databaseProps: buildPermittedProps({
550
+ projectId: projectId,
551
+ granted: [Permission.ProjectMember],
552
+ }),
553
+ allowedPermissions: [Permission.ProjectOwner, Permission.ProjectMember],
554
+ });
555
+ }).not.toThrow();
556
+ });
557
+
558
+ test("admits a caller holding any one of several allowed permissions", () => {
559
+ const projectId: ObjectID = ObjectID.generate();
560
+
561
+ expect(() => {
562
+ CommonAPI.assertPermittedInProject({
563
+ databaseProps: buildPermittedProps({
564
+ projectId: projectId,
565
+ granted: [Permission.ReadProjectIncident, Permission.SettingsViewer],
566
+ }),
567
+ allowedPermissions: [
568
+ Permission.ProjectOwner,
569
+ Permission.SettingsViewer,
570
+ ],
571
+ });
572
+ }).not.toThrow();
573
+ });
574
+
575
+ test("refuses a member of the project who holds none of them", () => {
576
+ const projectId: ObjectID = ObjectID.generate();
577
+
578
+ const thrown: unknown = captureThrown(() => {
579
+ CommonAPI.assertPermittedInProject({
580
+ databaseProps: buildPermittedProps({
581
+ projectId: projectId,
582
+ granted: [Permission.ReadProjectIncident],
583
+ }),
584
+ allowedPermissions: [Permission.ProjectOwner, Permission.ProjectAdmin],
585
+ });
586
+ });
587
+
588
+ expect(thrown).toBeInstanceOf(NotAuthorizedException);
589
+ expect((thrown as Exception).message).toBe(
590
+ "You do not have permission to access this project's data.",
591
+ );
592
+ });
593
+
594
+ test("uses the caller-supplied message when one is given", () => {
595
+ const projectId: ObjectID = ObjectID.generate();
596
+
597
+ const thrown: unknown = captureThrown(() => {
598
+ CommonAPI.assertPermittedInProject({
599
+ databaseProps: buildPermittedProps({
600
+ projectId: projectId,
601
+ granted: [],
602
+ }),
603
+ allowedPermissions: [Permission.ProjectOwner],
604
+ errorMessage:
605
+ "You do not have permission to read this project's AI providers.",
606
+ });
607
+ });
608
+
609
+ expect((thrown as Exception).message).toBe(
610
+ "You do not have permission to read this project's AI providers.",
611
+ );
612
+ });
613
+
614
+ /*
615
+ * The regression this guard exists to prevent. Public is in many models'
616
+ * read lists and in every caller's permission set, so a naive intersection
617
+ * would always succeed.
618
+ */
619
+ test("Permission.Public in the allowed list does not admit an ordinary member", () => {
620
+ const projectId: ObjectID = ObjectID.generate();
621
+
622
+ expect(() => {
623
+ CommonAPI.assertPermittedInProject({
624
+ databaseProps: buildPermittedProps({
625
+ projectId: projectId,
626
+ granted: [Permission.ReadProjectIncident],
627
+ }),
628
+ allowedPermissions: [Permission.Public, Permission.ProjectOwner],
629
+ });
630
+ }).toThrow(NotAuthorizedException);
631
+ });
632
+
633
+ test("Permission.Public in the allowed list does not admit an anonymous caller", () => {
634
+ const props: DatabaseCommonInteractionProps = {
635
+ tenantId: ObjectID.generate(),
636
+ };
637
+
638
+ expect(() => {
639
+ CommonAPI.assertPermittedInProject({
640
+ databaseProps: props,
641
+ allowedPermissions: [Permission.Public],
642
+ });
643
+ }).toThrow(NotAuthorizedException);
644
+ });
645
+
646
+ test("Permission.CurrentUser, which every logged-in caller carries, does not admit them either", () => {
647
+ const projectId: ObjectID = ObjectID.generate();
648
+
649
+ expect(() => {
650
+ CommonAPI.assertPermittedInProject({
651
+ databaseProps: buildPermittedProps({
652
+ projectId: projectId,
653
+ granted: [Permission.ReadProjectIncident],
654
+ }),
655
+ allowedPermissions: [Permission.CurrentUser, Permission.ProjectOwner],
656
+ });
657
+ }).toThrow(NotAuthorizedException);
658
+ });
659
+
660
+ test("an allowed list with nothing tenant-assignable in it denies everyone", () => {
661
+ const projectId: ObjectID = ObjectID.generate();
662
+
663
+ expect(() => {
664
+ CommonAPI.assertPermittedInProject({
665
+ databaseProps: buildPermittedProps({
666
+ projectId: projectId,
667
+ granted: [Permission.ProjectOwner],
668
+ }),
669
+ allowedPermissions: [Permission.Public, Permission.CurrentUser],
670
+ });
671
+ }).toThrow(NotAuthorizedException);
672
+ });
673
+
674
+ test("an empty allowed list denies everyone", () => {
675
+ const projectId: ObjectID = ObjectID.generate();
676
+
677
+ expect(() => {
678
+ CommonAPI.assertPermittedInProject({
679
+ databaseProps: buildPermittedProps({
680
+ projectId: projectId,
681
+ granted: [Permission.ProjectOwner],
682
+ }),
683
+ allowedPermissions: [],
684
+ });
685
+ }).toThrow(NotAuthorizedException);
686
+ });
687
+
688
+ /*
689
+ * userTenantAccessPermission holds grants AND denials in one array,
690
+ * discriminated only by isBlockPermission. Reading it raw would count a
691
+ * team's explicit block row as a grant.
692
+ */
693
+ test("a BLOCK row for an allowed permission is not counted as a grant of it", () => {
694
+ const projectId: ObjectID = ObjectID.generate();
695
+
696
+ expect(() => {
697
+ CommonAPI.assertPermittedInProject({
698
+ databaseProps: buildPermittedProps({
699
+ projectId: projectId,
700
+ granted: [Permission.ReadProjectIncident],
701
+ blocked: [Permission.ProjectOwner, Permission.ProjectMember],
702
+ }),
703
+ allowedPermissions: [Permission.ProjectOwner, Permission.ProjectMember],
704
+ });
705
+ }).toThrow(NotAuthorizedException);
706
+ });
707
+
708
+ test("permissions granted in ANOTHER project do not count", () => {
709
+ const callersProjectId: ObjectID = ObjectID.generate();
710
+ const targetProjectId: ObjectID = ObjectID.generate();
711
+
712
+ const props: DatabaseCommonInteractionProps = buildPermittedProps({
713
+ projectId: callersProjectId,
714
+ granted: [Permission.ProjectOwner],
715
+ });
716
+
717
+ // The header names the target project; the grants are for another one.
718
+ props.tenantId = targetProjectId;
719
+
720
+ expect(() => {
721
+ CommonAPI.assertPermittedInProject({
722
+ databaseProps: props,
723
+ allowedPermissions: [Permission.ProjectOwner],
724
+ });
725
+ }).toThrow(NotAuthorizedException);
726
+ });
727
+
728
+ test("a master admin bypasses the permission check", () => {
729
+ const projectId: ObjectID = ObjectID.generate();
730
+
731
+ expect(() => {
732
+ CommonAPI.assertPermittedInProject({
733
+ databaseProps: buildPermittedProps({
734
+ projectId: projectId,
735
+ granted: [],
736
+ isMasterAdmin: true,
737
+ }),
738
+ allowedPermissions: [Permission.ProjectOwner],
739
+ });
740
+ }).not.toThrow();
741
+ });
742
+
743
+ /*
744
+ * The guard answers one question only. Membership is assertAuthenticated-
745
+ * ProjectMember's job, and a route must call both — this test documents
746
+ * that calling only this one is not enough.
747
+ */
748
+ test("does not itself check membership — that stays with assertAuthenticatedProjectMember", () => {
749
+ const projectId: ObjectID = ObjectID.generate();
750
+ const props: DatabaseCommonInteractionProps = buildPermittedProps({
751
+ projectId: projectId,
752
+ granted: [Permission.ProjectOwner],
753
+ });
754
+
755
+ expect(() => {
756
+ CommonAPI.assertPermittedInProject({
757
+ databaseProps: props,
758
+ allowedPermissions: [Permission.ProjectOwner],
759
+ });
760
+ }).not.toThrow();
761
+
762
+ props.userId = undefined;
763
+
764
+ expect(() => {
765
+ CommonAPI.assertPermittedInProject({
766
+ databaseProps: props,
767
+ allowedPermissions: [Permission.ProjectOwner],
768
+ });
769
+ }).not.toThrow();
770
+ });
771
+ });
@@ -127,7 +127,7 @@ describe("MicrosoftTeamsAPI.getTeamsAppManifest", () => {
127
127
  expect(names).not.toContain("ChatMessage.Send.Chat");
128
128
  });
129
129
 
130
- test("declares exactly the five expected resource-specific permissions", () => {
130
+ test("declares exactly the six expected resource-specific permissions", () => {
131
131
  const permissions: Array<JSONObject> =
132
132
  getResourceSpecificPermissions(getManifest());
133
133
  const names: Array<string> = permissions.map((permission: JSONObject) => {
@@ -140,6 +140,12 @@ describe("MicrosoftTeamsAPI.getTeamsAppManifest", () => {
140
140
  "Channel.Create.Group",
141
141
  "ChatMessage.Read.Chat",
142
142
  "ChatMember.Read.Chat",
143
+ /*
144
+ * Lets OneUptime verify, per team, that the installed OneUptime app
145
+ * is the package built from this deployment before telling an admin
146
+ * their app is missing.
147
+ */
148
+ "TeamsAppInstallation.Read.Group",
143
149
  ].sort(),
144
150
  );
145
151
  });