From dd2fda271187f718def78002516861736dc48cf7 Mon Sep 17 00:00:00 2001 From: Kyle Pollich Date: Fri, 10 Nov 2023 11:01:36 -0500 Subject: [PATCH] [Fleet] Append space ID to security solution tag (#170789) ## Summary Fixes https://github.com/elastic/kibana/issues/166798 Appends the current space ID to the ID of the security solution tag. Note: If there are integrations suffering from the above bug (might be "stuck" in `installing` status, showing concurrent installation errors, etc), they should be reinstalled via the API in their corresponding space, e.g. ``` # In Kibana dev tools for the space in which the integration is installed POST kbn:/api/fleet/epm/packages/cisco_asa/2.27.1 { "force": true } ``` --------- Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../epm/kibana/assets/tag_assets.test.ts | 149 ++++++++++++------ .../services/epm/kibana/assets/tag_assets.ts | 8 +- 2 files changed, 106 insertions(+), 51 deletions(-) diff --git a/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.test.ts b/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.test.ts index 113866017f24b..f3d59c9607a38 100644 --- a/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.test.ts +++ b/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.test.ts @@ -688,55 +688,108 @@ describe('tagKibanaAssets', () => { ); }); - it('should respect SecuritySolution tags', async () => { - savedObjectTagClient.get.mockRejectedValue(new Error('not found')); - savedObjectTagClient.create.mockImplementation(({ name }: { name: string }) => - Promise.resolve({ id: name.toLowerCase(), name }) - ); - const kibanaAssets = { - dashboard: [ - { id: 'dashboard1', type: 'dashboard' }, - { id: 'dashboard2', type: 'dashboard' }, - { id: 'search_id1', type: 'search' }, - { id: 'search_id2', type: 'search' }, - ], - } as any; - const assetTags = [ - { - text: 'Security Solution', - asset_types: ['dashboard'], - }, - ]; - await tagKibanaAssets({ - savedObjectTagAssignmentService, - savedObjectTagClient, - kibanaAssets, - pkgTitle: 'TestPackage', - pkgName: 'test-pkg', - spaceId: 'default', - importedAssets: [], - assetTags, + describe('Security Solution tag', () => { + it('creates tag in default space', async () => { + savedObjectTagClient.get.mockRejectedValue(new Error('not found')); + savedObjectTagClient.create.mockImplementation(({ name }: { name: string }) => + Promise.resolve({ id: name.toLowerCase(), name }) + ); + const kibanaAssets = { + dashboard: [ + { id: 'dashboard1', type: 'dashboard' }, + { id: 'dashboard2', type: 'dashboard' }, + { id: 'search_id1', type: 'search' }, + { id: 'search_id2', type: 'search' }, + ], + } as any; + const assetTags = [ + { + text: 'Security Solution', + asset_types: ['dashboard'], + }, + ]; + await tagKibanaAssets({ + savedObjectTagAssignmentService, + savedObjectTagClient, + kibanaAssets, + pkgTitle: 'TestPackage', + pkgName: 'test-pkg', + spaceId: 'default', + importedAssets: [], + assetTags, + }); + expect(savedObjectTagClient.create).toHaveBeenCalledWith( + managedTagPayloadArg1, + managedTagPayloadArg2 + ); + expect(savedObjectTagClient.create).toHaveBeenCalledWith( + { + color: '#4DD2CA', + description: '', + name: 'TestPackage', + }, + { id: 'fleet-pkg-test-pkg-default', overwrite: true, refresh: false } + ); + expect(savedObjectTagClient.create).toHaveBeenCalledWith( + { + color: expect.any(String), + description: 'Tag defined in package-spec', + name: 'Security Solution', + }, + { id: 'security-solution-default', overwrite: true, refresh: false } + ); + }); + + it('creates tag in non-default space', async () => { + savedObjectTagClient.get.mockRejectedValue(new Error('not found')); + savedObjectTagClient.create.mockImplementation(({ name }: { name: string }) => + Promise.resolve({ id: name.toLowerCase(), name }) + ); + const kibanaAssets = { + dashboard: [ + { id: 'dashboard1', type: 'dashboard' }, + { id: 'dashboard2', type: 'dashboard' }, + { id: 'search_id1', type: 'search' }, + { id: 'search_id2', type: 'search' }, + ], + } as any; + const assetTags = [ + { + text: 'Security Solution', + asset_types: ['dashboard'], + }, + ]; + await tagKibanaAssets({ + savedObjectTagAssignmentService, + savedObjectTagClient, + kibanaAssets, + pkgTitle: 'TestPackage', + pkgName: 'test-pkg', + spaceId: 'my-secondary-space', + importedAssets: [], + assetTags, + }); + expect(savedObjectTagClient.create).toHaveBeenCalledWith(managedTagPayloadArg1, { + ...managedTagPayloadArg2, + id: 'fleet-managed-my-secondary-space', + }); + expect(savedObjectTagClient.create).toHaveBeenCalledWith( + { + color: expect.any(String), + description: '', + name: 'TestPackage', + }, + { id: 'fleet-pkg-test-pkg-my-secondary-space', overwrite: true, refresh: false } + ); + expect(savedObjectTagClient.create).toHaveBeenCalledWith( + { + color: expect.anything(), + description: 'Tag defined in package-spec', + name: 'Security Solution', + }, + { id: 'security-solution-my-secondary-space', overwrite: true, refresh: false } + ); }); - expect(savedObjectTagClient.create).toHaveBeenCalledWith( - managedTagPayloadArg1, - managedTagPayloadArg2 - ); - expect(savedObjectTagClient.create).toHaveBeenCalledWith( - { - color: '#4DD2CA', - description: '', - name: 'TestPackage', - }, - { id: 'fleet-pkg-test-pkg-default', overwrite: true, refresh: false } - ); - expect(savedObjectTagClient.create).toHaveBeenCalledWith( - { - color: expect.any(String), - description: 'Tag defined in package-spec', - name: 'Security Solution', - }, - { id: 'security-solution-default', overwrite: true, refresh: false } - ); }); it('should only call savedObjectTagClient.create for basic tags if there are no assetTags to assign', async () => { diff --git a/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.ts b/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.ts index 86d39a5582607..5e7d4477bbbd3 100644 --- a/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.ts +++ b/x-pack/plugins/fleet/server/services/epm/kibana/assets/tag_assets.ts @@ -37,7 +37,7 @@ const PACKAGE_TAG_COLOR = '#4DD2CA'; const MANAGED_TAG_NAME = 'Managed'; const LEGACY_MANAGED_TAG_ID = 'managed'; const SECURITY_SOLUTION_TAG_NAME = 'Security Solution'; -const SECURITY_SOLUTION_TAG_ID = 'security-solution-default'; +const SECURITY_SOLUTION_TAG_ID_BASE = 'security-solution'; // the tag service only accepts 6-digits hex colors const TAG_COLORS = [ @@ -65,8 +65,10 @@ const getLegacyPackageTagId = (pkgName: string) => pkgName; In that case return id `security-solution-default` */ export const getPackageSpecTagId = (spaceId: string, pkgName: string, tagName: string) => { - if (tagName.toLowerCase() === SECURITY_SOLUTION_TAG_NAME.toLowerCase()) - return SECURITY_SOLUTION_TAG_ID; + if (tagName.toLowerCase() === SECURITY_SOLUTION_TAG_NAME.toLowerCase()) { + return `${SECURITY_SOLUTION_TAG_ID_BASE}-${spaceId}`; + } + // UUID v5 needs a namespace (uuid.DNS) to generate a predictable uuid const uniqueId = uuidv5(`${tagName.toLowerCase()}`, uuidv5.DNS); return `fleet-shared-tag-${pkgName}-${uniqueId}-${spaceId}`;