@oneuptime/common 12.0.12 → 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.
- package/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.ts +32 -5
- package/Models/DatabaseModels/NetworkDevice.ts +64 -0
- package/Models/DatabaseModels/StatusPage.ts +59 -0
- package/Models/DatabaseModels/StatusPageOidc.ts +2 -0
- package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +19 -2
- package/Server/API/AIChatAPI.ts +55 -56
- package/Server/API/CommonAPI.ts +89 -0
- package/Server/API/MicrosoftTeamsAPI.ts +20 -9
- package/Server/API/SlackAPI.ts +13 -10
- package/Server/API/StatusPageAPI.ts +2197 -2128
- package/Server/API/TelemetryAPI.ts +72 -3
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787500000000-AddEnableSearchEngineIndexingToStatusPage.ts +30 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1787600000000-AddNetworkDeviceReachabilityColumns.ts +47 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
- package/Server/Middleware/UserAuthorization.ts +11 -2
- package/Server/Services/ApiKeyPermissionService.ts +116 -2
- package/Server/Services/DatabaseService.ts +17 -6
- package/Server/Services/LogAggregationService.ts +34 -0
- package/Server/Services/LogService.ts +21 -0
- package/Server/Services/NetworkSiteService.ts +12 -0
- package/Server/Services/SpanService.ts +21 -0
- package/Server/Services/TraceAggregationService.ts +15 -0
- package/Server/Services/WorkspaceNotificationRuleService.ts +172 -220
- package/Server/Types/AnalyticsDatabase/ModelPermission.ts +9 -0
- package/Server/Types/Database/Permissions/AccessControlPermission.ts +47 -16
- package/Server/Utils/APIKey/AccessPermission.ts +16 -40
- package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +144 -0
- package/Server/Utils/LogRedaction.ts +576 -0
- package/Server/Utils/Logger.ts +123 -46
- package/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.ts +94 -23
- package/Server/Utils/Monitor/MonitorResource.ts +29 -9
- package/Server/Utils/Monitor/NetworkInventoryUtil.ts +28 -7
- package/Server/Utils/SessionReplay/SessionReplayGateCacheStore.ts +56 -10
- package/Server/Utils/StartServer.ts +30 -9
- package/Server/Utils/StatusPageSearchEngineIndexing.ts +33 -0
- package/Server/Utils/Telemetry/ResourceEntityFilter.ts +441 -0
- package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +488 -46
- package/Tests/App/Dashboard/MonitorTypePicker.test.tsx +300 -0
- package/Tests/App/StatusPage/StatusPageIndexPageRobotsMeta.test.ts +130 -0
- package/Tests/Models/DatabaseModels/DatabaseBaseModelToJSONObjectCache.test.ts +180 -0
- package/Tests/Models/StatusPageEnableSearchEngineIndexing.test.ts +157 -0
- package/Tests/Server/API/AIChatCancelAndFeedback.test.ts +23 -1
- package/Tests/Server/API/AIChatRouteAuthorization.test.ts +785 -0
- package/Tests/Server/API/BaseAPIApiKeyAuth.test.ts +21 -8
- package/Tests/Server/API/CommonAPIAuthGuard.test.ts +290 -0
- package/Tests/Server/API/MicrosoftTeamsManifest.test.ts +7 -1
- package/Tests/Server/API/StatusPageOverviewCache.test.ts +474 -0
- package/Tests/Server/API/StatusPageSeoSearchEngineIndexing.test.ts +189 -0
- package/Tests/Server/Infrastructure/InMemoryTTLCache.test.ts +158 -0
- package/Tests/Server/Infrastructure/Postgres/DeviceRoleAndDeclaredLinkParentMigration.test.ts +9 -60
- package/Tests/Server/Middleware/ProjectAuthorizationApiKeyMiddleware.test.ts +24 -15
- package/Tests/Server/Middleware/UserAuthorization.test.ts +79 -0
- package/Tests/Server/Services/AddNetworkDeviceReachabilityColumnsMigration.test.ts +332 -0
- package/Tests/Server/Services/ApiKeyPermissionService.test.ts +347 -0
- package/Tests/Server/Services/DatabaseServiceUpdateDebugLogging.test.ts +282 -0
- package/Tests/Server/Services/NetworkSiteService.test.ts +56 -2
- package/Tests/Server/Services/TelemetryResourceFacetFilters.test.ts +267 -0
- package/Tests/Server/Services/WorkspaceNotificationRuleTestRuleChannels.test.ts +702 -0
- package/Tests/Server/Types/Database/Permissions/AccessControlPermission.test.ts +165 -0
- package/Tests/Server/Utils/APIKey/AccessPermission.test.ts +48 -36
- package/Tests/Server/Utils/AnalyticsDatabase/StatementGenerator.test.ts +213 -0
- package/Tests/Server/Utils/LogRedaction.test.ts +415 -0
- package/Tests/Server/Utils/LoggerCredentialLeak.test.ts +245 -0
- package/Tests/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.test.ts +374 -4
- package/Tests/Server/Utils/Monitor/MonitorResourceIngestedStepSelection.test.ts +455 -0
- package/Tests/Server/Utils/Monitor/NetworkDeviceReachabilityRoundTrip.test.ts +369 -0
- package/Tests/Server/Utils/Monitor/NetworkInventoryUtil.test.ts +86 -8
- package/Tests/Server/Utils/PrivacyFilterUtil.test.ts +64 -0
- package/Tests/Server/Utils/SessionReplay/SessionReplayGateCacheStore.test.ts +207 -0
- package/Tests/Server/Utils/StartServerBodyVerify.test.ts +335 -0
- package/Tests/Server/Utils/StatusPageSearchEngineIndexing.test.ts +60 -0
- package/Tests/Server/Utils/Telemetry/ResourceEntityFilter.test.ts +435 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsChannelSend.test.ts +607 -62
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsInstalledTeamIdSpace.test.ts +778 -0
- package/Tests/Server/Utils/Workspace/MicrosoftTeamsTeamInstalls.test.ts +44 -10
- package/Tests/Types/API/HostnameFromAuthority.test.ts +164 -0
- package/Tests/Types/Database/AccessControl/ColumnAccessControlCache.test.ts +344 -0
- package/Tests/Types/Database/DatabasePropertyFindOperator.test.ts +518 -0
- package/Tests/Types/Database/TableColumnMetadataCache.test.ts +286 -0
- package/Tests/Types/Monitor/MonitorStep.test.ts +100 -0
- package/Tests/Types/Monitor/MonitorTypeKeywords.test.ts +360 -0
- package/Tests/Types/StatusPage/SearchEngineIndexing.test.ts +86 -0
- package/Tests/Types/Telemetry/ResourceEntityFacet.test.ts +254 -0
- package/Tests/UI/Components/CardSelect.test.tsx +1021 -0
- package/Tests/UI/Components/MasterPage.test.tsx +36 -1
- package/Tests/Utils/Monitor/MonitorMetricType.test.ts +66 -1
- package/Tests/Utils/Monitor/NetworkTopologyUtil.test.ts +115 -6
- package/Tests/Utils/NetworkDevice/DeviceReachabilityUtil.test.ts +610 -0
- package/Tests/Utils/NetworkSite/SiteStatusRollupUtil.test.ts +114 -45
- package/Types/API/Hostname.ts +79 -0
- package/Types/Database/AccessControl/ColumnAccessControl.ts +33 -11
- package/Types/Database/AccessControl/ColumnBillingAccessControl.ts +33 -11
- package/Types/Database/DatabaseProperty.ts +38 -0
- package/Types/Database/TableColumn.ts +34 -7
- package/Types/Events/Recurring.ts +16 -1
- package/Types/Monitor/MonitorStep.ts +13 -1
- package/Types/Monitor/MonitorType.ts +345 -40
- package/Types/Monitor/SSLMonitor/SslMonitorResponse.ts +43 -0
- package/Types/StatusPage/SearchEngineIndexing.ts +61 -0
- package/Types/Telemetry/ResourceEntityFacet.ts +211 -0
- package/UI/Components/CardSelect/CardSelect.tsx +714 -105
- package/UI/Components/EmptyState/EmptyState.tsx +8 -1
- package/UI/Components/Footer/Footer.tsx +32 -6
- package/UI/Components/Forms/Fields/FormField.tsx +3 -0
- package/UI/Components/Forms/Types/Field.ts +8 -0
- package/UI/Components/Loader/PageLoader.tsx +29 -8
- package/UI/Components/LogsViewer/components/LogsAnalyticsView.tsx +26 -4
- package/UI/Components/Markdown.tsx/LazyMarkdownViewer.tsx +17 -1
- package/UI/Components/MasterPage/MasterPage.tsx +24 -11
- package/Utils/Monitor/MonitorMetricType.ts +16 -1
- package/Utils/Monitor/NetworkTopologyUtil.ts +60 -8
- package/Utils/NetworkDevice/DeviceReachabilityUtil.ts +262 -0
- package/Utils/NetworkSite/SiteStatusRollupUtil.ts +41 -24
- package/Utils/Telemetry/CrossSignalScope.ts +75 -4
- package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js +20 -4
- package/build/dist/Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel.js.map +1 -1
- package/build/dist/Models/DatabaseModels/NetworkDevice.js +66 -0
- package/build/dist/Models/DatabaseModels/NetworkDevice.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPage.js +60 -0
- package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
- package/build/dist/Models/DatabaseModels/StatusPageOidc.js +2 -0
- package/build/dist/Models/DatabaseModels/StatusPageOidc.js.map +1 -1
- package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
- package/build/dist/Server/API/AIChatAPI.js +48 -35
- package/build/dist/Server/API/AIChatAPI.js.map +1 -1
- package/build/dist/Server/API/CommonAPI.js +59 -0
- package/build/dist/Server/API/CommonAPI.js.map +1 -1
- package/build/dist/Server/API/MicrosoftTeamsAPI.js +20 -6
- package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
- package/build/dist/Server/API/SlackAPI.js +13 -10
- package/build/dist/Server/API/SlackAPI.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +745 -673
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/API/TelemetryAPI.js +34 -3
- package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787500000000-AddEnableSearchEngineIndexingToStatusPage.js +23 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787500000000-AddEnableSearchEngineIndexingToStatusPage.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787600000000-AddNetworkDeviceReachabilityColumns.js +34 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787600000000-AddNetworkDeviceReachabilityColumns.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/UserAuthorization.js +6 -2
- package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
- package/build/dist/Server/Services/ApiKeyPermissionService.js +90 -1
- package/build/dist/Server/Services/ApiKeyPermissionService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +15 -6
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/LogAggregationService.js +2 -0
- package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
- package/build/dist/Server/Services/LogService.js +16 -0
- package/build/dist/Server/Services/LogService.js.map +1 -1
- package/build/dist/Server/Services/NetworkSiteService.js +12 -0
- package/build/dist/Server/Services/NetworkSiteService.js.map +1 -1
- package/build/dist/Server/Services/SpanService.js +16 -0
- package/build/dist/Server/Services/SpanService.js.map +1 -1
- package/build/dist/Server/Services/TraceAggregationService.js +2 -0
- package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +137 -164
- package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
- package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js +9 -0
- package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/AccessControlPermission.js +21 -13
- package/build/dist/Server/Types/Database/Permissions/AccessControlPermission.js.map +1 -1
- package/build/dist/Server/Utils/APIKey/AccessPermission.js +9 -32
- package/build/dist/Server/Utils/APIKey/AccessPermission.js.map +1 -1
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +87 -0
- package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
- package/build/dist/Server/Utils/LogRedaction.js +449 -0
- package/build/dist/Server/Utils/LogRedaction.js.map +1 -0
- package/build/dist/Server/Utils/Logger.js +98 -45
- package/build/dist/Server/Utils/Logger.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.js +65 -13
- package/build/dist/Server/Utils/Monitor/Criteria/SSLMonitorCriteria.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorResource.js +20 -3
- package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js +27 -7
- package/build/dist/Server/Utils/Monitor/NetworkInventoryUtil.js.map +1 -1
- package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCacheStore.js +29 -10
- package/build/dist/Server/Utils/SessionReplay/SessionReplayGateCacheStore.js.map +1 -1
- package/build/dist/Server/Utils/StartServer.js +10 -7
- package/build/dist/Server/Utils/StartServer.js.map +1 -1
- package/build/dist/Server/Utils/StatusPageSearchEngineIndexing.js +24 -0
- package/build/dist/Server/Utils/StatusPageSearchEngineIndexing.js.map +1 -0
- package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js +311 -0
- package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +366 -37
- package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
- package/build/dist/Types/API/Hostname.js +63 -0
- package/build/dist/Types/API/Hostname.js.map +1 -1
- package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js +20 -6
- package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js.map +1 -1
- package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js +20 -6
- package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js.map +1 -1
- package/build/dist/Types/Database/DatabaseProperty.js +38 -0
- package/build/dist/Types/Database/DatabaseProperty.js.map +1 -1
- package/build/dist/Types/Database/TableColumn.js +24 -6
- package/build/dist/Types/Database/TableColumn.js.map +1 -1
- package/build/dist/Types/Events/Recurring.js +13 -1
- package/build/dist/Types/Events/Recurring.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +9 -1
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorType.js +330 -31
- package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
- package/build/dist/Types/StatusPage/SearchEngineIndexing.js +55 -0
- package/build/dist/Types/StatusPage/SearchEngineIndexing.js.map +1 -0
- package/build/dist/Types/Telemetry/ResourceEntityFacet.js +156 -0
- package/build/dist/Types/Telemetry/ResourceEntityFacet.js.map +1 -0
- package/build/dist/UI/Components/CardSelect/CardSelect.js +360 -40
- package/build/dist/UI/Components/CardSelect/CardSelect.js.map +1 -1
- package/build/dist/UI/Components/EmptyState/EmptyState.js +1 -1
- package/build/dist/UI/Components/EmptyState/EmptyState.js.map +1 -1
- package/build/dist/UI/Components/Footer/Footer.js +7 -4
- package/build/dist/UI/Components/Footer/Footer.js.map +1 -1
- package/build/dist/UI/Components/Forms/Fields/FormField.js +1 -1
- package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
- package/build/dist/UI/Components/Loader/PageLoader.js +15 -5
- package/build/dist/UI/Components/Loader/PageLoader.js.map +1 -1
- package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js +16 -3
- package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/LazyMarkdownViewer.js +13 -1
- package/build/dist/UI/Components/Markdown.tsx/LazyMarkdownViewer.js.map +1 -1
- package/build/dist/UI/Components/MasterPage/MasterPage.js +10 -2
- package/build/dist/UI/Components/MasterPage/MasterPage.js.map +1 -1
- package/build/dist/Utils/Monitor/MonitorMetricType.js +13 -1
- package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js +34 -7
- package/build/dist/Utils/Monitor/NetworkTopologyUtil.js.map +1 -1
- package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js +177 -0
- package/build/dist/Utils/NetworkDevice/DeviceReachabilityUtil.js.map +1 -0
- package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js +23 -27
- package/build/dist/Utils/NetworkSite/SiteStatusRollupUtil.js.map +1 -1
- package/build/dist/Utils/Telemetry/CrossSignalScope.js +44 -4
- package/build/dist/Utils/Telemetry/CrossSignalScope.js.map +1 -1
- package/package.json +1 -1
|
@@ -3,6 +3,9 @@ import AccessControlPermission from "../../../../../Server/Types/Database/Permis
|
|
|
3
3
|
import QueryUtil from "../../../../../Server/Types/Database/QueryUtil";
|
|
4
4
|
import Monitor from "../../../../../Models/DatabaseModels/Monitor";
|
|
5
5
|
import DatabaseCommonInteractionProps from "../../../../../Types/BaseDatabase/DatabaseCommonInteractionProps";
|
|
6
|
+
import DatabaseCommonInteractionPropsUtil, {
|
|
7
|
+
PermissionType,
|
|
8
|
+
} from "../../../../../Types/BaseDatabase/DatabaseCommonInteractionPropsUtil";
|
|
6
9
|
import ObjectID from "../../../../../Types/ObjectID";
|
|
7
10
|
import Permission, {
|
|
8
11
|
UserTenantAccessPermission,
|
|
@@ -187,3 +190,165 @@ describe("AccessControlPermission.addAccessControlIdsToQuery", () => {
|
|
|
187
190
|
expect(result._id).toBeUndefined();
|
|
188
191
|
});
|
|
189
192
|
});
|
|
193
|
+
|
|
194
|
+
describe("AccessControlPermission.getAccessControlIdsForQuery", () => {
|
|
195
|
+
const projectId: ObjectID = ObjectID.generate();
|
|
196
|
+
const userId: ObjectID = ObjectID.generate();
|
|
197
|
+
const permittedLabelA: ObjectID = ObjectID.generate();
|
|
198
|
+
const permittedLabelB: ObjectID = ObjectID.generate();
|
|
199
|
+
|
|
200
|
+
function makeLabelRestrictedProps(): DatabaseCommonInteractionProps {
|
|
201
|
+
// A user whose ONLY read grant on Monitor is label-restricted.
|
|
202
|
+
const tenantPermission: UserTenantAccessPermission = {
|
|
203
|
+
projectId,
|
|
204
|
+
_type: "UserTenantAccessPermission",
|
|
205
|
+
permissions: [
|
|
206
|
+
{
|
|
207
|
+
_type: "UserPermission",
|
|
208
|
+
permission: Permission.ReadProjectMonitor,
|
|
209
|
+
labelIds: [permittedLabelA, permittedLabelB],
|
|
210
|
+
isBlockPermission: false,
|
|
211
|
+
},
|
|
212
|
+
],
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
return {
|
|
216
|
+
userId,
|
|
217
|
+
tenantId: projectId,
|
|
218
|
+
userTenantAccessPermission: {
|
|
219
|
+
[projectId.toString()]: tenantPermission,
|
|
220
|
+
},
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function toStrings(ids: Array<ObjectID>): Array<string> {
|
|
225
|
+
return ids.map((id: ObjectID) => {
|
|
226
|
+
return id.toString();
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
afterEach(() => {
|
|
231
|
+
jest.restoreAllMocks();
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it("returns the permitted label ids deduped for a multi-column select, same as a query-only call", () => {
|
|
235
|
+
const withSelect: Array<ObjectID> =
|
|
236
|
+
AccessControlPermission.getAccessControlIdsForQuery(
|
|
237
|
+
Monitor,
|
|
238
|
+
{ projectId } as any,
|
|
239
|
+
{ _id: true, createdAt: true, name: true } as any,
|
|
240
|
+
makeLabelRestrictedProps(),
|
|
241
|
+
DatabaseRequestType.Read,
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
const queryOnly: Array<ObjectID> =
|
|
245
|
+
AccessControlPermission.getAccessControlIdsForQuery(
|
|
246
|
+
Monitor,
|
|
247
|
+
{ projectId } as any,
|
|
248
|
+
null,
|
|
249
|
+
makeLabelRestrictedProps(),
|
|
250
|
+
DatabaseRequestType.Read,
|
|
251
|
+
);
|
|
252
|
+
|
|
253
|
+
expect(toStrings(withSelect)).toEqual([
|
|
254
|
+
permittedLabelA.toString(),
|
|
255
|
+
permittedLabelB.toString(),
|
|
256
|
+
]);
|
|
257
|
+
expect(toStrings(withSelect)).toEqual(toStrings(queryOnly));
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
it("returns an empty array for users with an unrestricted grant regardless of column count", () => {
|
|
261
|
+
const tenantPermission: UserTenantAccessPermission = {
|
|
262
|
+
projectId,
|
|
263
|
+
_type: "UserTenantAccessPermission",
|
|
264
|
+
permissions: [
|
|
265
|
+
{
|
|
266
|
+
_type: "UserPermission",
|
|
267
|
+
permission: Permission.ProjectMember,
|
|
268
|
+
labelIds: [],
|
|
269
|
+
isBlockPermission: false,
|
|
270
|
+
},
|
|
271
|
+
],
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
const result: Array<ObjectID> =
|
|
275
|
+
AccessControlPermission.getAccessControlIdsForQuery(
|
|
276
|
+
Monitor,
|
|
277
|
+
{ projectId } as any,
|
|
278
|
+
{ _id: true, createdAt: true, updatedAt: true, name: true } as any,
|
|
279
|
+
{
|
|
280
|
+
userId,
|
|
281
|
+
tenantId: projectId,
|
|
282
|
+
userTenantAccessPermission: {
|
|
283
|
+
[projectId.toString()]: tenantPermission,
|
|
284
|
+
},
|
|
285
|
+
},
|
|
286
|
+
DatabaseRequestType.Read,
|
|
287
|
+
);
|
|
288
|
+
|
|
289
|
+
expect(result).toEqual([]);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
it("computes user permissions exactly once regardless of column count", () => {
|
|
293
|
+
const getUserPermissionsSpy: jest.SpyInstance = jest.spyOn(
|
|
294
|
+
DatabaseCommonInteractionPropsUtil,
|
|
295
|
+
"getUserPermissions",
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
const props: DatabaseCommonInteractionProps = makeLabelRestrictedProps();
|
|
299
|
+
|
|
300
|
+
AccessControlPermission.getAccessControlIdsForQuery(
|
|
301
|
+
Monitor,
|
|
302
|
+
{ projectId } as any,
|
|
303
|
+
{ _id: true, createdAt: true, updatedAt: true, name: true } as any,
|
|
304
|
+
props,
|
|
305
|
+
DatabaseRequestType.Read,
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
/*
|
|
309
|
+
* Perf regression guard: the old code rebuilt the full user-permission
|
|
310
|
+
* set once per access-controlled column plus once for the model-level
|
|
311
|
+
* check. The context must be built exactly once per query.
|
|
312
|
+
*/
|
|
313
|
+
expect(getUserPermissionsSpy).toHaveBeenCalledTimes(1);
|
|
314
|
+
expect(getUserPermissionsSpy).toHaveBeenCalledWith(
|
|
315
|
+
props,
|
|
316
|
+
PermissionType.Allow,
|
|
317
|
+
);
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
it("still applies the idempotent Public push to props exactly once", () => {
|
|
321
|
+
const props: DatabaseCommonInteractionProps = makeLabelRestrictedProps();
|
|
322
|
+
|
|
323
|
+
AccessControlPermission.getAccessControlIdsForQuery(
|
|
324
|
+
Monitor,
|
|
325
|
+
{ projectId } as any,
|
|
326
|
+
{ _id: true, createdAt: true, name: true } as any,
|
|
327
|
+
props,
|
|
328
|
+
DatabaseRequestType.Read,
|
|
329
|
+
);
|
|
330
|
+
|
|
331
|
+
const globalPermissions: Array<Permission> =
|
|
332
|
+
props.userGlobalAccessPermission?.globalPermissions || [];
|
|
333
|
+
|
|
334
|
+
expect(
|
|
335
|
+
globalPermissions.filter((permission: Permission) => {
|
|
336
|
+
return permission === Permission.Public;
|
|
337
|
+
}),
|
|
338
|
+
).toHaveLength(1);
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
it("getAccessControlIdsForModel with three args still returns the model-level permitted ids", () => {
|
|
342
|
+
const result: Array<ObjectID> =
|
|
343
|
+
AccessControlPermission.getAccessControlIdsForModel(
|
|
344
|
+
Monitor,
|
|
345
|
+
makeLabelRestrictedProps(),
|
|
346
|
+
DatabaseRequestType.Read,
|
|
347
|
+
);
|
|
348
|
+
|
|
349
|
+
expect(toStrings(result)).toEqual([
|
|
350
|
+
permittedLabelA.toString(),
|
|
351
|
+
permittedLabelB.toString(),
|
|
352
|
+
]);
|
|
353
|
+
});
|
|
354
|
+
});
|
|
@@ -6,10 +6,24 @@ import {
|
|
|
6
6
|
it,
|
|
7
7
|
jest,
|
|
8
8
|
} from "@jest/globals";
|
|
9
|
+
|
|
10
|
+
/*
|
|
11
|
+
* PasswordHash has a known, pre-existing TS5.9 compile failure under ts-jest
|
|
12
|
+
* (Buffer vs BinaryLike) that breaks every suite whose import graph reaches
|
|
13
|
+
* it. Nothing here touches password hashing; stub the module before the
|
|
14
|
+
* service import graph drags it into compilation.
|
|
15
|
+
*/
|
|
16
|
+
jest.mock("../../../../Server/Utils/PasswordHash", () => {
|
|
17
|
+
return {
|
|
18
|
+
__esModule: true,
|
|
19
|
+
default: class PasswordHashStub {},
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
|
|
9
23
|
import APIKeyAccessPermission from "../../../../Server/Utils/APIKey/AccessPermission";
|
|
10
|
-
import ApiKeyPermissionService
|
|
11
|
-
|
|
12
|
-
|
|
24
|
+
import ApiKeyPermissionService, {
|
|
25
|
+
ApiKeyPermissionRow,
|
|
26
|
+
} from "../../../../Server/Services/ApiKeyPermissionService";
|
|
13
27
|
import ObjectID from "../../../../Types/ObjectID";
|
|
14
28
|
import Permission, {
|
|
15
29
|
UserGlobalAccessPermission,
|
|
@@ -27,10 +41,11 @@ import { getJestSpyOn } from "../../../Spy";
|
|
|
27
41
|
* key full control of the project; one that dropped it from the master path
|
|
28
42
|
* would break trusted internal automation. Both directions are pinned below.
|
|
29
43
|
*
|
|
30
|
-
* getApiTenantAccessPermission also reshapes
|
|
31
|
-
* runtime UserPermission shape (
|
|
32
|
-
* mapping is where a dropped label would quietly widen a
|
|
33
|
-
* it is tested against a spied service rather than a
|
|
44
|
+
* getApiTenantAccessPermission also reshapes the (cached) permission rows into
|
|
45
|
+
* the runtime UserPermission shape (labelIds carried over, block flag
|
|
46
|
+
* preserved). That mapping is where a dropped label would quietly widen a
|
|
47
|
+
* scoped permission, so it is tested against a spied service rather than a
|
|
48
|
+
* live database.
|
|
34
49
|
*/
|
|
35
50
|
|
|
36
51
|
const projectId: ObjectID = ObjectID.generate();
|
|
@@ -118,9 +133,9 @@ describe("APIKeyAccessPermission.getMasterApiTenantAccessPermission", () => {
|
|
|
118
133
|
});
|
|
119
134
|
|
|
120
135
|
describe("APIKeyAccessPermission.getApiTenantAccessPermission", () => {
|
|
121
|
-
const
|
|
136
|
+
const spyFindPermissions: jest.SpyInstance = getJestSpyOn(
|
|
122
137
|
ApiKeyPermissionService,
|
|
123
|
-
"
|
|
138
|
+
"findPermissionsByApiKeyId",
|
|
124
139
|
);
|
|
125
140
|
|
|
126
141
|
beforeEach(() => {
|
|
@@ -135,40 +150,33 @@ describe("APIKeyAccessPermission.getApiTenantAccessPermission", () => {
|
|
|
135
150
|
permission: Permission;
|
|
136
151
|
labelIds?: Array<ObjectID>;
|
|
137
152
|
isBlockPermission?: boolean;
|
|
138
|
-
}) =>
|
|
153
|
+
}) => ApiKeyPermissionRow = (data: {
|
|
139
154
|
permission: Permission;
|
|
140
155
|
labelIds?: Array<ObjectID>;
|
|
141
156
|
isBlockPermission?: boolean;
|
|
142
|
-
}):
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
label.id = id;
|
|
149
|
-
return label;
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
row.isBlockPermission = data.isBlockPermission ?? false;
|
|
153
|
-
return row;
|
|
157
|
+
}): ApiKeyPermissionRow => {
|
|
158
|
+
return {
|
|
159
|
+
permission: data.permission,
|
|
160
|
+
labelIds: data.labelIds ?? [],
|
|
161
|
+
isBlockPermission: data.isBlockPermission ?? false,
|
|
162
|
+
};
|
|
154
163
|
};
|
|
155
164
|
|
|
156
165
|
it("queries the permissions for exactly this api key", async () => {
|
|
157
|
-
|
|
166
|
+
spyFindPermissions.mockResolvedValue([] as never);
|
|
158
167
|
|
|
159
168
|
await APIKeyAccessPermission.getApiTenantAccessPermission(
|
|
160
169
|
projectId,
|
|
161
170
|
apiKeyId,
|
|
162
171
|
);
|
|
163
172
|
|
|
164
|
-
expect(
|
|
165
|
-
const arg:
|
|
166
|
-
|
|
167
|
-
expect(arg.query.apiKeyId.toString()).toBe(apiKeyId.toString());
|
|
173
|
+
expect(spyFindPermissions).toHaveBeenCalledTimes(1);
|
|
174
|
+
const arg: ObjectID = spyFindPermissions.mock.calls[0]![0] as ObjectID;
|
|
175
|
+
expect(arg.toString()).toBe(apiKeyId.toString());
|
|
168
176
|
});
|
|
169
177
|
|
|
170
178
|
it("returns just the default baseline when the key has no permissions", async () => {
|
|
171
|
-
|
|
179
|
+
spyFindPermissions.mockResolvedValue([] as never);
|
|
172
180
|
|
|
173
181
|
const perm: UserTenantAccessPermission =
|
|
174
182
|
await APIKeyAccessPermission.getApiTenantAccessPermission(
|
|
@@ -187,7 +195,7 @@ describe("APIKeyAccessPermission.getApiTenantAccessPermission", () => {
|
|
|
187
195
|
|
|
188
196
|
it("maps each stored permission row onto the tenant permission", async () => {
|
|
189
197
|
const labelId: ObjectID = ObjectID.generate();
|
|
190
|
-
|
|
198
|
+
spyFindPermissions.mockResolvedValue([
|
|
191
199
|
makeRow({
|
|
192
200
|
permission: Permission.CreateProjectIncident,
|
|
193
201
|
labelIds: [labelId],
|
|
@@ -219,7 +227,7 @@ describe("APIKeyAccessPermission.getApiTenantAccessPermission", () => {
|
|
|
219
227
|
});
|
|
220
228
|
|
|
221
229
|
it("preserves the block flag so a deny row stays a deny row", async () => {
|
|
222
|
-
|
|
230
|
+
spyFindPermissions.mockResolvedValue([
|
|
223
231
|
makeRow({
|
|
224
232
|
permission: Permission.CreateProjectIncident,
|
|
225
233
|
labelIds: [],
|
|
@@ -243,11 +251,16 @@ describe("APIKeyAccessPermission.getApiTenantAccessPermission", () => {
|
|
|
243
251
|
});
|
|
244
252
|
|
|
245
253
|
it("treats a row with no labels as an empty (unscoped) label set", async () => {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
254
|
+
/*
|
|
255
|
+
* The service DTO normalizes a stored row's undefined labels to [] (pinned
|
|
256
|
+
* in ApiKeyPermissionService.test.ts); here the mapping must keep that
|
|
257
|
+
* empty set an array rather than dropping it to undefined.
|
|
258
|
+
*/
|
|
259
|
+
spyFindPermissions.mockResolvedValue([
|
|
260
|
+
makeRow({
|
|
261
|
+
permission: Permission.CreateProjectIncident,
|
|
262
|
+
}),
|
|
263
|
+
] as never);
|
|
251
264
|
|
|
252
265
|
const perm: UserTenantAccessPermission =
|
|
253
266
|
await APIKeyAccessPermission.getApiTenantAccessPermission(
|
|
@@ -261,7 +274,6 @@ describe("APIKeyAccessPermission.getApiTenantAccessPermission", () => {
|
|
|
261
274
|
},
|
|
262
275
|
);
|
|
263
276
|
expect(mapped).toBeDefined();
|
|
264
|
-
// No crash on undefined labels, and it becomes [] rather than undefined.
|
|
265
277
|
expect(mapped!.labelIds).toEqual([]);
|
|
266
278
|
});
|
|
267
279
|
});
|
|
@@ -956,6 +956,219 @@ describe("StatementGenerator", () => {
|
|
|
956
956
|
});
|
|
957
957
|
});
|
|
958
958
|
|
|
959
|
+
/*
|
|
960
|
+
* resourceEntityScopes: the compiled form of a resource-facet selection
|
|
961
|
+
* (a Kubernetes cluster, a host, ...). Unlike entityScope it carries an
|
|
962
|
+
* `entityIds` branch, because the same resource can be a row's PRIMARY
|
|
963
|
+
* entity (agent-ingested telemetry) or merely one of its memberships
|
|
964
|
+
* (OTLP telemetry primary-keyed on its Service). Matching only
|
|
965
|
+
* primaryEntityId is what made a cluster filter return zero rows for
|
|
966
|
+
* collector-ingested logs.
|
|
967
|
+
*/
|
|
968
|
+
describe("resourceEntityScopes synthetic key", () => {
|
|
969
|
+
class ResourceScopeModel extends AnalyticsBaseModel {
|
|
970
|
+
public constructor() {
|
|
971
|
+
super({
|
|
972
|
+
tableName: "<resource-scope-table>",
|
|
973
|
+
singularName: "<singular>",
|
|
974
|
+
pluralName: "<plural>",
|
|
975
|
+
tableColumns: [
|
|
976
|
+
new AnalyticsTableColumn({
|
|
977
|
+
key: "_id",
|
|
978
|
+
title: "<title>",
|
|
979
|
+
description: "<description>",
|
|
980
|
+
required: true,
|
|
981
|
+
type: TableColumnType.ObjectID,
|
|
982
|
+
}),
|
|
983
|
+
new AnalyticsTableColumn({
|
|
984
|
+
key: "primaryEntityId",
|
|
985
|
+
title: "<title>",
|
|
986
|
+
description: "<description>",
|
|
987
|
+
required: true,
|
|
988
|
+
type: TableColumnType.ObjectID,
|
|
989
|
+
}),
|
|
990
|
+
new AnalyticsTableColumn({
|
|
991
|
+
key: "entityKeys",
|
|
992
|
+
title: "<title>",
|
|
993
|
+
description: "<description>",
|
|
994
|
+
required: true,
|
|
995
|
+
defaultValue: [],
|
|
996
|
+
type: TableColumnType.ArrayText,
|
|
997
|
+
}),
|
|
998
|
+
new AnalyticsTableColumn({
|
|
999
|
+
key: "attributes",
|
|
1000
|
+
title: "<title>",
|
|
1001
|
+
description: "<description>",
|
|
1002
|
+
required: true,
|
|
1003
|
+
defaultValue: {},
|
|
1004
|
+
type: TableColumnType.MapStringString,
|
|
1005
|
+
}),
|
|
1006
|
+
],
|
|
1007
|
+
crudApiPath: new Route("route"),
|
|
1008
|
+
primaryKeys: ["_id"],
|
|
1009
|
+
sortKeys: ["_id"],
|
|
1010
|
+
partitionKey: "_id",
|
|
1011
|
+
tableEngine: AnalyticsTableEngine.MergeTree,
|
|
1012
|
+
});
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
const CLUSTER_ID: string = "8c0f2f1e-2e4f-4a8c-9a1a-2f5b6c7d8e9f";
|
|
1017
|
+
const HOST_ID: string = "5f4e3d2c-1b0a-4998-8776-655443322110";
|
|
1018
|
+
|
|
1019
|
+
let resourceGenerator: StatementGenerator<ResourceScopeModel>;
|
|
1020
|
+
beforeEach(() => {
|
|
1021
|
+
resourceGenerator = new StatementGenerator<ResourceScopeModel>({
|
|
1022
|
+
modelType: ResourceScopeModel,
|
|
1023
|
+
database: ClickhouseAppInstance,
|
|
1024
|
+
});
|
|
1025
|
+
});
|
|
1026
|
+
|
|
1027
|
+
test("ORs the three membership branches inside one scope", () => {
|
|
1028
|
+
const statement: Statement = resourceGenerator.toWhereStatement({
|
|
1029
|
+
resourceEntityScopes: [
|
|
1030
|
+
{
|
|
1031
|
+
entityIds: [CLUSTER_ID],
|
|
1032
|
+
entityKeys: ["210dac24142f1baa"],
|
|
1033
|
+
attributeKey: "resource.k8s.cluster.name",
|
|
1034
|
+
attributeValues: ["prod-eu"],
|
|
1035
|
+
},
|
|
1036
|
+
],
|
|
1037
|
+
} as any);
|
|
1038
|
+
|
|
1039
|
+
expect(statement.query).toBe(
|
|
1040
|
+
"AND ({p0:Identifier} IN {p1:Array(String)} OR hasAny({p2:Identifier}, {p3:Array(String)}) OR {p4:Identifier}[{p5:String}] IN {p6:Array(String)})",
|
|
1041
|
+
);
|
|
1042
|
+
expect(statement.query_params).toStrictEqual({
|
|
1043
|
+
p0: "primaryEntityId",
|
|
1044
|
+
p1: [CLUSTER_ID],
|
|
1045
|
+
p2: "entityKeys",
|
|
1046
|
+
p3: ["210dac24142f1baa"],
|
|
1047
|
+
p4: "attributes",
|
|
1048
|
+
p5: "resource.k8s.cluster.name",
|
|
1049
|
+
p6: ["prod-eu"],
|
|
1050
|
+
});
|
|
1051
|
+
});
|
|
1052
|
+
|
|
1053
|
+
test("ANDs separate scopes so two facets intersect", () => {
|
|
1054
|
+
const statement: Statement = resourceGenerator.toWhereStatement({
|
|
1055
|
+
resourceEntityScopes: [
|
|
1056
|
+
{ entityIds: [CLUSTER_ID], entityKeys: ["210dac24142f1baa"] },
|
|
1057
|
+
{ entityIds: [HOST_ID], entityKeys: ["9f8e7d6c5b4a3928"] },
|
|
1058
|
+
],
|
|
1059
|
+
} as any);
|
|
1060
|
+
|
|
1061
|
+
expect(statement.query).toBe(
|
|
1062
|
+
"AND ({p0:Identifier} IN {p1:Array(String)} OR hasAny({p2:Identifier}, {p3:Array(String)})) " +
|
|
1063
|
+
"AND ({p4:Identifier} IN {p5:Array(String)} OR hasAny({p6:Identifier}, {p7:Array(String)}))",
|
|
1064
|
+
);
|
|
1065
|
+
});
|
|
1066
|
+
|
|
1067
|
+
test("composes with a Services predicate — cluster AND service", () => {
|
|
1068
|
+
const statement: Statement = resourceGenerator.toWhereStatement({
|
|
1069
|
+
primaryEntityId: "<service-id>",
|
|
1070
|
+
resourceEntityScopes: [
|
|
1071
|
+
{ entityIds: [CLUSTER_ID], entityKeys: ["210dac24142f1baa"] },
|
|
1072
|
+
],
|
|
1073
|
+
} as any);
|
|
1074
|
+
|
|
1075
|
+
/*
|
|
1076
|
+
* The regression the issue reports: these two used to be coalesced
|
|
1077
|
+
* into ONE primaryEntityId IN (...) list, so adding a service made
|
|
1078
|
+
* results reappear while silently dropping the cluster.
|
|
1079
|
+
*/
|
|
1080
|
+
expect(statement.query).toBe(
|
|
1081
|
+
"AND {p0:Identifier} = {p1:String} " +
|
|
1082
|
+
"AND ({p2:Identifier} IN {p3:Array(String)} OR hasAny({p4:Identifier}, {p5:Array(String)}))",
|
|
1083
|
+
);
|
|
1084
|
+
});
|
|
1085
|
+
|
|
1086
|
+
test("a scope that resolved to ids only still narrows by primaryEntityId", () => {
|
|
1087
|
+
const statement: Statement = resourceGenerator.toWhereStatement({
|
|
1088
|
+
resourceEntityScopes: [{ entityIds: [CLUSTER_ID], entityKeys: [] }],
|
|
1089
|
+
} as any);
|
|
1090
|
+
|
|
1091
|
+
expect(statement.query).toBe(
|
|
1092
|
+
"AND ({p0:Identifier} IN {p1:Array(String)})",
|
|
1093
|
+
);
|
|
1094
|
+
});
|
|
1095
|
+
|
|
1096
|
+
test("an empty scope emits no predicate rather than an empty IN", () => {
|
|
1097
|
+
const statement: Statement = resourceGenerator.toWhereStatement({
|
|
1098
|
+
resourceEntityScopes: [{ entityIds: [], entityKeys: [] }],
|
|
1099
|
+
} as any);
|
|
1100
|
+
|
|
1101
|
+
expect(statement.query).toBe("");
|
|
1102
|
+
expect(statement.query_params).toStrictEqual({});
|
|
1103
|
+
});
|
|
1104
|
+
|
|
1105
|
+
test("an empty scope does not break separators for later predicates", () => {
|
|
1106
|
+
const statement: Statement = resourceGenerator.toWhereStatement({
|
|
1107
|
+
resourceEntityScopes: [{ entityIds: [], entityKeys: [] }],
|
|
1108
|
+
_id: "<value>",
|
|
1109
|
+
} as any);
|
|
1110
|
+
|
|
1111
|
+
expect(statement.query).toBe("AND {p0:Identifier} = {p1:String}");
|
|
1112
|
+
});
|
|
1113
|
+
|
|
1114
|
+
test("a non-array value carries no predicate", () => {
|
|
1115
|
+
const statement: Statement = resourceGenerator.toWhereStatement({
|
|
1116
|
+
resourceEntityScopes: { entityIds: [CLUSTER_ID] },
|
|
1117
|
+
} as any);
|
|
1118
|
+
|
|
1119
|
+
expect(statement.query).toBe("");
|
|
1120
|
+
});
|
|
1121
|
+
|
|
1122
|
+
test("blank ids and keys are filtered out of their branches", () => {
|
|
1123
|
+
const statement: Statement = resourceGenerator.toWhereStatement({
|
|
1124
|
+
resourceEntityScopes: [
|
|
1125
|
+
{ entityIds: ["", CLUSTER_ID], entityKeys: [""] },
|
|
1126
|
+
],
|
|
1127
|
+
} as any);
|
|
1128
|
+
|
|
1129
|
+
expect(statement.query).toBe(
|
|
1130
|
+
"AND ({p0:Identifier} IN {p1:Array(String)})",
|
|
1131
|
+
);
|
|
1132
|
+
expect(statement.query_params).toStrictEqual({
|
|
1133
|
+
p0: "primaryEntityId",
|
|
1134
|
+
p1: [CLUSTER_ID],
|
|
1135
|
+
});
|
|
1136
|
+
});
|
|
1137
|
+
|
|
1138
|
+
test("drops the branches whose backing column the model lacks", () => {
|
|
1139
|
+
// TestModel (outer generator) has neither primaryEntityId nor entityKeys.
|
|
1140
|
+
const statement: Statement = generator.toWhereStatement({
|
|
1141
|
+
resourceEntityScopes: [
|
|
1142
|
+
{ entityIds: [CLUSTER_ID], entityKeys: ["210dac24142f1baa"] },
|
|
1143
|
+
],
|
|
1144
|
+
} as any);
|
|
1145
|
+
|
|
1146
|
+
expect(statement.query).toBe("");
|
|
1147
|
+
});
|
|
1148
|
+
|
|
1149
|
+
test("qualifies every branch when a table alias is in play", () => {
|
|
1150
|
+
const statement: Statement = resourceGenerator.toWhereStatement(
|
|
1151
|
+
{
|
|
1152
|
+
resourceEntityScopes: [
|
|
1153
|
+
{
|
|
1154
|
+
entityIds: [CLUSTER_ID],
|
|
1155
|
+
entityKeys: ["210dac24142f1baa"],
|
|
1156
|
+
attributeKey: "resource.k8s.cluster.name",
|
|
1157
|
+
attributeValues: ["prod-eu"],
|
|
1158
|
+
},
|
|
1159
|
+
],
|
|
1160
|
+
} as any,
|
|
1161
|
+
{ tableAlias: "t" },
|
|
1162
|
+
);
|
|
1163
|
+
|
|
1164
|
+
expect(statement.query).toBe(
|
|
1165
|
+
"AND ({p0_t:Identifier}.{p0_c:Identifier} IN {p1:Array(String)} OR " +
|
|
1166
|
+
"hasAny({p2_t:Identifier}.{p2_c:Identifier}, {p3:Array(String)}) OR " +
|
|
1167
|
+
"{p4_t:Identifier}.{p4_c:Identifier}[{p5:String}] IN {p6:Array(String)})",
|
|
1168
|
+
);
|
|
1169
|
+
});
|
|
1170
|
+
});
|
|
1171
|
+
|
|
959
1172
|
/*
|
|
960
1173
|
* Table qualification (tableAlias option). Aggregate statements
|
|
961
1174
|
* alias expressions to real column names (`sum(col) as col`, and
|