From d0488dd8bc28be32adb7e7a6c5eca758163ccae9 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Wed, 24 Jul 2024 10:06:44 -0400 Subject: [PATCH 1/6] Do not register tenancy app if disabled in yml Signed-off-by: Derek Ho --- public/plugin.ts | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/public/plugin.ts b/public/plugin.ts index fb71c9c8..2b31d411 100644 --- a/public/plugin.ts +++ b/public/plugin.ts @@ -224,16 +224,18 @@ export class SecurityPlugin return mountWrapper(params, '/permissions'); }, }); - core.application.register({ - id: `security-dashboards-plugin_tenants`, - title: 'Tenants', - order: 8040, - workspaceAvailability: WorkspaceAvailability.outsideWorkspace, - updater$: this.appStateUpdater, - mount: async (params: AppMountParameters) => { - return mountWrapper(params, '/tenants'); - }, - }); + if (config.multitenancy.enabled) { + core.application.register({ + id: `security-dashboards-plugin_tenants`, + title: 'Tenants', + order: 8040, + workspaceAvailability: WorkspaceAvailability.outsideWorkspace, + updater$: this.appStateUpdater, + mount: async (params: AppMountParameters) => { + return mountWrapper(params, '/tenants'); + }, + }); + } core.application.register({ id: `security-dashboards-plugin_auditlog`, title: 'Audit logs', From 80221713f3e382b894f9f3f3d26e0518682771c5 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Wed, 24 Jul 2024 17:27:53 -0400 Subject: [PATCH 2/6] Adds a test Signed-off-by: Derek Ho --- public/plugin.ts | 2 +- public/test/plugin.test.ts | 199 +++++++++++++++++++++++++++++++++++++ public/types.ts | 6 +- 3 files changed, 205 insertions(+), 2 deletions(-) create mode 100644 public/test/plugin.test.ts diff --git a/public/plugin.ts b/public/plugin.ts index 2b31d411..1603637c 100644 --- a/public/plugin.ts +++ b/public/plugin.ts @@ -60,7 +60,7 @@ import { getDataSourceFromUrl, } from './utils/datasource-utils'; -async function hasApiPermission(core: CoreSetup): Promise { +export async function hasApiPermission(core: CoreSetup): Promise { try { const permissions = await core.http.get(API_ENDPOINT_PERMISSIONS_INFO); return permissions.has_api_access || false; diff --git a/public/test/plugin.test.ts b/public/test/plugin.test.ts new file mode 100644 index 00000000..e56ad665 --- /dev/null +++ b/public/test/plugin.test.ts @@ -0,0 +1,199 @@ +/* + * Copyright OpenSearch Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +/* + * SPDX-License-Identifier: Apache-2.0 + * + * The OpenSearch Contributors require contributions made to + * this file be licensed under the Apache-2.0 license or a + * compatible open source license. + * + * Any modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { coreMock } from '../../../../src/core/public/mocks'; +import { SecurityPlugin } from '../plugin.ts'; +import * as pluginModule from '../plugin'; // Import the entire module to mock specific functions + +// Mock the hasApiPermission function +jest.mock('../plugin', () => { + const originalModule = jest.requireActual('../plugin'); + return { + ...originalModule, + hasApiPermission: jest.fn(), // Mock the function here + }; +}); + +describe('SecurityPlugin', () => { + let plugin; + let coreSetup; + let coreStart; + let initializerContext; + let deps; + + beforeEach(() => { + coreSetup = coreMock.createSetup(); + coreStart = coreMock.createStart(); + initializerContext = { + config: { + get: jest.fn().mockReturnValue({ + readonly_mode: { roles: [] }, + multitenancy: { enabled: true, enable_aggregation_view: false }, + clusterPermissions: { include: [] }, + indexPermissions: { include: [] }, + disabledTransportCategories: { exclude: [] }, + disabledRestCategories: { exclude: [] }, + ui: { autologout: false }, + }), + }, + }; + deps = { + dataSource: { dataSourceEnabled: true }, + savedObjectsManagement: { createSetup: jest.fn() }, + }; + }); + + it('does not call register function for certain applications when getNavGroupEnabled is off', async () => { + // Mock hasApiPermission to return false + pluginModule.hasApiPermission.mockResolvedValue(false); // Access the mock via the imported module + + // Instantiate the plugin after mocking + plugin = new SecurityPlugin(initializerContext); + + // Override getNavGroupEnabled to return false + coreSetup.chrome.navGroup = { + ...coreSetup.chrome.navGroup, + getNavGroupEnabled: () => false, + }; + // Mock the core.application.register function + const registerSpy = jest.spyOn(coreSetup.application, 'register'); + + // Execute the setup function + await plugin.setup(coreSetup, deps); + + // Assert that the register function was not called for specific applications + const registeredApps = registerSpy.mock.calls.map((call) => call[0].id); + const expectedApps = [ + 'security-dashboards-plugin_getstarted', + 'security-dashboards-plugin_auth', + 'security-dashboards-plugin_roles', + 'security-dashboards-plugin_users', + 'security-dashboards-plugin_permissions', + 'security-dashboards-plugin_tenants', + 'security-dashboards-plugin_auditlog', + ]; + + expectedApps.forEach((app) => { + expect(registeredApps).not.toContain(app); + }); + }); + + it('calls register function for certain applications when getNavGroupEnabled is on', async () => { + // Mock hasApiPermission to return true + pluginModule.hasApiPermission.mockResolvedValue(true); // Access the mock via the imported module + + // Instantiate the plugin after mocking + plugin = new SecurityPlugin(initializerContext); + + // Override getNavGroupEnabled to return true + coreSetup.chrome.navGroup = { + ...coreSetup.chrome.navGroup, + getNavGroupEnabled: () => true, + }; + // Mock the core.application.register function + const registerSpy = jest.spyOn(coreSetup.application, 'register'); + + // Execute the setup function + await plugin.setup(coreSetup, deps); + + // Assert that the register function was called for specific applications + const registeredApps = registerSpy.mock.calls.map((call) => call[0].id); + const expectedApps = [ + 'security-dashboards-plugin_getstarted', + 'security-dashboards-plugin_auth', + 'security-dashboards-plugin_roles', + 'security-dashboards-plugin_users', + 'security-dashboards-plugin_permissions', + 'security-dashboards-plugin_tenants', + 'security-dashboards-plugin_auditlog', + ]; + + expectedApps.forEach((app) => { + expect(registeredApps).toContain(app); + }); + }); + + it('does not call register function for tenant app when multitenancy is off', async () => { + // Mock hasApiPermission to return true + pluginModule.hasApiPermission.mockResolvedValue(true); + + // InitializerContext with multitenancy disabled + initializerContext = { + config: { + get: jest.fn().mockReturnValue({ + readonly_mode: { roles: [] }, + multitenancy: { enabled: false, enable_aggregation_view: false }, + clusterPermissions: { include: [] }, + indexPermissions: { include: [] }, + disabledTransportCategories: { exclude: [] }, + disabledRestCategories: { exclude: [] }, + ui: { autologout: false }, + }), + }, + }; + + // Instantiate the plugin after mocking + plugin = new SecurityPlugin(initializerContext); + + // Override getNavGroupEnabled to return true + coreSetup.chrome.navGroup = { + ...coreSetup.chrome.navGroup, + getNavGroupEnabled: () => true, + }; + // Mock the core.application.register function + const registerSpy = jest.spyOn(coreSetup.application, 'register'); + + // Execute the setup function + await plugin.setup(coreSetup, deps); + + // Assert that the register function was not called for tenancy app + const registeredApps = registerSpy.mock.calls.map((call) => call[0].id); + const expectedApps = ['security-dashboards-plugin_tenants']; + + expectedApps.forEach((app) => { + expect(registeredApps).not.toContain(app); + }); + }); +}); diff --git a/public/types.ts b/public/types.ts index 96e58735..70e16872 100644 --- a/public/types.ts +++ b/public/types.ts @@ -19,7 +19,10 @@ import { SavedObjectsManagementPluginStart, } from '../../../src/plugins/saved_objects_management/public'; import { ManagementOverViewPluginSetup } from '../../../src/plugins/management_overview/public'; -import { DataSourcePluginStart } from '../../../src/plugins/data_source/public/types'; +import { + DataSourcePluginSetup, + DataSourcePluginStart, +} from '../../../src/plugins/data_source/public/types'; import { DataSourceManagementPluginSetup } from '../../../src/plugins/data_source_management/public'; // eslint-disable-next-line @typescript-eslint/no-empty-interface @@ -31,6 +34,7 @@ export interface SecurityPluginSetupDependencies { savedObjectsManagement: SavedObjectsManagementPluginSetup; managementOverview?: ManagementOverViewPluginSetup; dataSourceManagement?: DataSourceManagementPluginSetup; + dataSource?: DataSourcePluginSetup; } export interface Cluster { From 5aa4ba2dbf3204149e7ad6e37f997cdbbe1c6931 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Thu, 25 Jul 2024 09:52:20 -0400 Subject: [PATCH 3/6] Revert type and export Signed-off-by: Derek Ho --- public/plugin.ts | 2 +- public/types.ts | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/public/plugin.ts b/public/plugin.ts index 1603637c..2b31d411 100644 --- a/public/plugin.ts +++ b/public/plugin.ts @@ -60,7 +60,7 @@ import { getDataSourceFromUrl, } from './utils/datasource-utils'; -export async function hasApiPermission(core: CoreSetup): Promise { +async function hasApiPermission(core: CoreSetup): Promise { try { const permissions = await core.http.get(API_ENDPOINT_PERMISSIONS_INFO); return permissions.has_api_access || false; diff --git a/public/types.ts b/public/types.ts index 70e16872..96e58735 100644 --- a/public/types.ts +++ b/public/types.ts @@ -19,10 +19,7 @@ import { SavedObjectsManagementPluginStart, } from '../../../src/plugins/saved_objects_management/public'; import { ManagementOverViewPluginSetup } from '../../../src/plugins/management_overview/public'; -import { - DataSourcePluginSetup, - DataSourcePluginStart, -} from '../../../src/plugins/data_source/public/types'; +import { DataSourcePluginStart } from '../../../src/plugins/data_source/public/types'; import { DataSourceManagementPluginSetup } from '../../../src/plugins/data_source_management/public'; // eslint-disable-next-line @typescript-eslint/no-empty-interface @@ -34,7 +31,6 @@ export interface SecurityPluginSetupDependencies { savedObjectsManagement: SavedObjectsManagementPluginSetup; managementOverview?: ManagementOverViewPluginSetup; dataSourceManagement?: DataSourceManagementPluginSetup; - dataSource?: DataSourcePluginSetup; } export interface Cluster { From 900816b6fcbe1801ad6b5550b9daea697c43eed5 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Thu, 25 Jul 2024 10:14:13 -0400 Subject: [PATCH 4/6] Use constants Signed-off-by: Derek Ho --- common/index.ts | 7 ++++++ public/plugin.ts | 42 ++++++++++++++++++++++------------- public/test/plugin.test.ts | 45 +++++++++++++++++++++++--------------- 3 files changed, 61 insertions(+), 33 deletions(-) diff --git a/common/index.ts b/common/index.ts index 23ad3e1b..bb61c2e5 100644 --- a/common/index.ts +++ b/common/index.ts @@ -15,6 +15,13 @@ export const PLUGIN_ID = 'opensearchDashboardsSecurity'; export const PLUGIN_NAME = 'security-dashboards-plugin'; +export const PLUGIN_GET_STARTED_APP_ID = 'security-dashboards-plugin_getstarted'; +export const PLUGIN_AUTH_APP_ID = 'security-dashboards-plugin_auth'; +export const PLUGIN_ROLES_APP_ID = 'security-dashboards-plugin_roles'; +export const PLUGIN_USERS_APP_ID = 'security-dashboards-plugin_users'; +export const PLUGIN_PERMISSIONS_APP_ID = 'security-dashboards-plugin_permissions'; +export const PLUGIN_TENANTS_APP_ID = 'security-dashboards-plugin_tenants'; +export const PLUGIN_AUDITLOG_APP_ID = 'security-dashboards-plugin_auditlog'; export const APP_ID_LOGIN = 'login'; export const APP_ID_CUSTOMERROR = 'customerror'; diff --git a/public/plugin.ts b/public/plugin.ts index 2b31d411..5eec1a03 100644 --- a/public/plugin.ts +++ b/public/plugin.ts @@ -30,7 +30,19 @@ import { PluginInitializerContext, WorkspaceAvailability, } from '../../../src/core/public'; -import { APP_ID_LOGIN, CUSTOM_ERROR_PAGE_URI, LOGIN_PAGE_URI, PLUGIN_NAME } from '../common'; +import { + APP_ID_LOGIN, + CUSTOM_ERROR_PAGE_URI, + LOGIN_PAGE_URI, + PLUGIN_AUDITLOG_APP_ID, + PLUGIN_AUTH_APP_ID, + PLUGIN_GET_STARTED_APP_ID, + PLUGIN_NAME, + PLUGIN_PERMISSIONS_APP_ID, + PLUGIN_ROLES_APP_ID, + PLUGIN_TENANTS_APP_ID, + PLUGIN_USERS_APP_ID, +} from '../common'; import { APP_ID_CUSTOMERROR } from '../common'; import { setupTopNavButton } from './apps/account/account-app'; import { fetchAccountInfoSafe } from './apps/account/utils'; @@ -175,7 +187,7 @@ export class SecurityPlugin if (core.chrome.navGroup.getNavGroupEnabled()) { core.application.register({ - id: `security-dashboards-plugin_getstarted`, + id: PLUGIN_GET_STARTED_APP_ID, title: 'Get Started', order: 8040, workspaceAvailability: WorkspaceAvailability.outsideWorkspace, @@ -185,7 +197,7 @@ export class SecurityPlugin }, }); core.application.register({ - id: `security-dashboards-plugin_auth`, + id: PLUGIN_AUTH_APP_ID, title: 'Authentication', order: 8040, workspaceAvailability: WorkspaceAvailability.outsideWorkspace, @@ -195,7 +207,7 @@ export class SecurityPlugin }, }); core.application.register({ - id: `security-dashboards-plugin_roles`, + id: PLUGIN_ROLES_APP_ID, title: 'Roles', order: 8040, workspaceAvailability: WorkspaceAvailability.outsideWorkspace, @@ -205,7 +217,7 @@ export class SecurityPlugin }, }); core.application.register({ - id: `security-dashboards-plugin_users`, + id: PLUGIN_USERS_APP_ID, title: 'Internal users', order: 8040, workspaceAvailability: WorkspaceAvailability.outsideWorkspace, @@ -215,7 +227,7 @@ export class SecurityPlugin }, }); core.application.register({ - id: `security-dashboards-plugin_permissions`, + id: PLUGIN_PERMISSIONS_APP_ID, title: 'Permissions', order: 8040, workspaceAvailability: WorkspaceAvailability.outsideWorkspace, @@ -226,7 +238,7 @@ export class SecurityPlugin }); if (config.multitenancy.enabled) { core.application.register({ - id: `security-dashboards-plugin_tenants`, + id: PLUGIN_TENANTS_APP_ID, title: 'Tenants', order: 8040, workspaceAvailability: WorkspaceAvailability.outsideWorkspace, @@ -237,7 +249,7 @@ export class SecurityPlugin }); } core.application.register({ - id: `security-dashboards-plugin_auditlog`, + id: PLUGIN_AUDITLOG_APP_ID, title: 'Audit logs', order: 8040, workspaceAvailability: WorkspaceAvailability.outsideWorkspace, @@ -250,31 +262,31 @@ export class SecurityPlugin core.chrome.navGroup.addNavLinksToGroup(DEFAULT_NAV_GROUPS.dataAdministration, [ { - id: `security-dashboards-plugin_getstarted`, + id: PLUGIN_GET_STARTED_APP_ID, category: dataAccessUsersCategory, }, { - id: `security-dashboards-plugin_auth`, + id: PLUGIN_AUTH_APP_ID, category: dataAccessUsersCategory, }, { - id: `security-dashboards-plugin_roles`, + id: PLUGIN_ROLES_APP_ID, category: dataAccessUsersCategory, }, { - id: `security-dashboards-plugin_users`, + id: PLUGIN_USERS_APP_ID, category: dataAccessUsersCategory, }, { - id: `security-dashboards-plugin_permissions`, + id: PLUGIN_PERMISSIONS_APP_ID, category: dataAccessUsersCategory, }, { - id: `security-dashboards-plugin_tenants`, + id: PLUGIN_TENANTS_APP_ID, category: dataAccessUsersCategory, }, { - id: `security-dashboards-plugin_auditlog`, + id: PLUGIN_AUDITLOG_APP_ID, category: dataAccessUsersCategory, }, ]); diff --git a/public/test/plugin.test.ts b/public/test/plugin.test.ts index e56ad665..e07be77c 100644 --- a/public/test/plugin.test.ts +++ b/public/test/plugin.test.ts @@ -46,6 +46,15 @@ import { coreMock } from '../../../../src/core/public/mocks'; import { SecurityPlugin } from '../plugin.ts'; import * as pluginModule from '../plugin'; // Import the entire module to mock specific functions +import { + PLUGIN_AUDITLOG_APP_ID, + PLUGIN_AUTH_APP_ID, + PLUGIN_GET_STARTED_APP_ID, + PLUGIN_PERMISSIONS_APP_ID, + PLUGIN_ROLES_APP_ID, + PLUGIN_TENANTS_APP_ID, + PLUGIN_USERS_APP_ID, +} from '../../common/index.ts'; // Mock the hasApiPermission function jest.mock('../plugin', () => { @@ -106,13 +115,13 @@ describe('SecurityPlugin', () => { // Assert that the register function was not called for specific applications const registeredApps = registerSpy.mock.calls.map((call) => call[0].id); const expectedApps = [ - 'security-dashboards-plugin_getstarted', - 'security-dashboards-plugin_auth', - 'security-dashboards-plugin_roles', - 'security-dashboards-plugin_users', - 'security-dashboards-plugin_permissions', - 'security-dashboards-plugin_tenants', - 'security-dashboards-plugin_auditlog', + PLUGIN_GET_STARTED_APP_ID, + PLUGIN_AUTH_APP_ID, + PLUGIN_ROLES_APP_ID, + PLUGIN_USERS_APP_ID, + PLUGIN_PERMISSIONS_APP_ID, + PLUGIN_TENANTS_APP_ID, + PLUGIN_AUDITLOG_APP_ID, ]; expectedApps.forEach((app) => { @@ -141,13 +150,13 @@ describe('SecurityPlugin', () => { // Assert that the register function was called for specific applications const registeredApps = registerSpy.mock.calls.map((call) => call[0].id); const expectedApps = [ - 'security-dashboards-plugin_getstarted', - 'security-dashboards-plugin_auth', - 'security-dashboards-plugin_roles', - 'security-dashboards-plugin_users', - 'security-dashboards-plugin_permissions', - 'security-dashboards-plugin_tenants', - 'security-dashboards-plugin_auditlog', + PLUGIN_GET_STARTED_APP_ID, + PLUGIN_AUTH_APP_ID, + PLUGIN_ROLES_APP_ID, + PLUGIN_USERS_APP_ID, + PLUGIN_PERMISSIONS_APP_ID, + PLUGIN_TENANTS_APP_ID, + PLUGIN_AUDITLOG_APP_ID, ]; expectedApps.forEach((app) => { @@ -190,10 +199,10 @@ describe('SecurityPlugin', () => { // Assert that the register function was not called for tenancy app const registeredApps = registerSpy.mock.calls.map((call) => call[0].id); - const expectedApps = ['security-dashboards-plugin_tenants']; - expectedApps.forEach((app) => { - expect(registeredApps).not.toContain(app); - }); + expect(registeredApps).not.toContain(PLUGIN_TENANTS_APP_ID); + + // Assert that other apps are registered because the feature flag is on + expect(registeredApps).toContain(PLUGIN_GET_STARTED_APP_ID); }); }); From 9fc2991ab491f3d99d2a28ec9d2af4bebb525d97 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Thu, 25 Jul 2024 10:21:15 -0400 Subject: [PATCH 5/6] Remove extra license field Signed-off-by: Derek Ho --- public/test/plugin.test.ts | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/public/test/plugin.test.ts b/public/test/plugin.test.ts index e07be77c..e33c83d0 100644 --- a/public/test/plugin.test.ts +++ b/public/test/plugin.test.ts @@ -13,36 +13,6 @@ * permissions and limitations under the License. */ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - * - * Any modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - import { coreMock } from '../../../../src/core/public/mocks'; import { SecurityPlugin } from '../plugin.ts'; import * as pluginModule from '../plugin'; // Import the entire module to mock specific functions From 6c37aca0e796ed17ebd67cea53114bc0531e3722 Mon Sep 17 00:00:00 2001 From: Derek Ho Date: Thu, 25 Jul 2024 14:26:17 -0400 Subject: [PATCH 6/6] Refactor with constants Signed-off-by: Derek Ho --- common/index.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/common/index.ts b/common/index.ts index bb61c2e5..b33c099a 100644 --- a/common/index.ts +++ b/common/index.ts @@ -15,13 +15,13 @@ export const PLUGIN_ID = 'opensearchDashboardsSecurity'; export const PLUGIN_NAME = 'security-dashboards-plugin'; -export const PLUGIN_GET_STARTED_APP_ID = 'security-dashboards-plugin_getstarted'; -export const PLUGIN_AUTH_APP_ID = 'security-dashboards-plugin_auth'; -export const PLUGIN_ROLES_APP_ID = 'security-dashboards-plugin_roles'; -export const PLUGIN_USERS_APP_ID = 'security-dashboards-plugin_users'; -export const PLUGIN_PERMISSIONS_APP_ID = 'security-dashboards-plugin_permissions'; -export const PLUGIN_TENANTS_APP_ID = 'security-dashboards-plugin_tenants'; -export const PLUGIN_AUDITLOG_APP_ID = 'security-dashboards-plugin_auditlog'; +export const PLUGIN_GET_STARTED_APP_ID = `${PLUGIN_NAME}_getstarted`; +export const PLUGIN_AUTH_APP_ID = `${PLUGIN_NAME}_auth`; +export const PLUGIN_ROLES_APP_ID = `${PLUGIN_NAME}_roles`; +export const PLUGIN_USERS_APP_ID = `${PLUGIN_NAME}_users`; +export const PLUGIN_PERMISSIONS_APP_ID = `${PLUGIN_NAME}_permissions`; +export const PLUGIN_TENANTS_APP_ID = `${PLUGIN_NAME}_tenants`; +export const PLUGIN_AUDITLOG_APP_ID = `${PLUGIN_NAME}_auditlog`; export const APP_ID_LOGIN = 'login'; export const APP_ID_CUSTOMERROR = 'customerror';