diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index c7d39e8bb5099..ea4f544dab000 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -496,6 +496,7 @@ src/platform/packages/shared/kbn-connector-schemas @elastic/response-ops src/platform/packages/shared/kbn-connector-specs @elastic/response-ops src/platform/packages/shared/kbn-content-management-utils @elastic/kibana-data-discovery src/platform/packages/shared/kbn-core-server-benchmarks @elastic/kibana-core +src/platform/packages/shared/kbn-cps-server-utils @elastic/kibana-core src/platform/packages/shared/kbn-cps-utils @elastic/kibana-presentation src/platform/packages/shared/kbn-crypto @elastic/kibana-security src/platform/packages/shared/kbn-crypto-browser @elastic/kibana-core diff --git a/package.json b/package.json index cc7c2c5cbe3f9..585cb944c57e2 100644 --- a/package.json +++ b/package.json @@ -498,6 +498,7 @@ "@kbn/core-user-settings-server-internal": "link:src/core/packages/user-settings/server-internal", "@kbn/core-user-settings-server-mocks": "link:src/core/packages/user-settings/server-mocks", "@kbn/cps": "link:src/platform/plugins/shared/cps", + "@kbn/cps-server-utils": "link:src/platform/packages/shared/kbn-cps-server-utils", "@kbn/cps-utils": "link:src/platform/packages/shared/kbn-cps-utils", "@kbn/cross-cluster-replication-plugin": "link:x-pack/platform/plugins/private/cross_cluster_replication", "@kbn/crypto": "link:src/platform/packages/shared/kbn-crypto", diff --git a/src/platform/packages/shared/kbn-cps-server-utils/README.md b/src/platform/packages/shared/kbn-cps-server-utils/README.md new file mode 100644 index 0000000000000..4d0f97cc21775 --- /dev/null +++ b/src/platform/packages/shared/kbn-cps-server-utils/README.md @@ -0,0 +1,20 @@ +# @kbn/cps-server-utils + +Server-side Cross-Project Search (CPS) utilities. + +## `getSpaceNPRE` + +Returns the Named Project Routing Expression (NPRE) for a given space, using the convention `kibana_space_${spaceId}_default`. + +Accepts either a `spaceId` string or a `KibanaRequest` (from which the space is derived via the request URL path, without a dependency on the `spaces` plugin). + +```ts +import { getSpaceNPRE } from '@kbn/cps-server-utils'; + +// From a space ID string +getSpaceNPRE('my-space'); // 'kibana_space_my-space_default' +getSpaceNPRE(''); // 'kibana_space_default_default' + +// From a KibanaRequest (extracts space from the URL path) +getSpaceNPRE(request); // e.g. 'kibana_space_my-space_default' +``` diff --git a/src/platform/packages/shared/kbn-cps-server-utils/index.ts b/src/platform/packages/shared/kbn-cps-server-utils/index.ts new file mode 100644 index 0000000000000..8b287ce8cfc30 --- /dev/null +++ b/src/platform/packages/shared/kbn-cps-server-utils/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +export { getSpaceNPRE } from './src/get_space_npre'; diff --git a/src/platform/packages/shared/kbn-cps-server-utils/jest.config.js b/src/platform/packages/shared/kbn-cps-server-utils/jest.config.js new file mode 100644 index 0000000000000..3b58292c01e3f --- /dev/null +++ b/src/platform/packages/shared/kbn-cps-server-utils/jest.config.js @@ -0,0 +1,14 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +module.exports = { + preset: '@kbn/test/jest_node', + rootDir: '../../../../..', + roots: ['/src/platform/packages/shared/kbn-cps-server-utils'], +}; diff --git a/src/platform/packages/shared/kbn-cps-server-utils/kibana.jsonc b/src/platform/packages/shared/kbn-cps-server-utils/kibana.jsonc new file mode 100644 index 0000000000000..7f78db4117572 --- /dev/null +++ b/src/platform/packages/shared/kbn-cps-server-utils/kibana.jsonc @@ -0,0 +1,9 @@ +{ + "type": "shared-server", + "id": "@kbn/cps-server-utils", + "owner": [ + "@elastic/kibana-core" + ], + "group": "platform", + "visibility": "shared" +} diff --git a/src/platform/packages/shared/kbn-cps-server-utils/moon.yml b/src/platform/packages/shared/kbn-cps-server-utils/moon.yml new file mode 100644 index 0000000000000..d7016eb59962a --- /dev/null +++ b/src/platform/packages/shared/kbn-cps-server-utils/moon.yml @@ -0,0 +1,46 @@ +# This file is generated by the @kbn/moon package. Any manual edits will be erased! +# To extend this, write your extensions/overrides to 'moon.extend.yml' +# then regenerate this file with: 'node scripts/regenerate_moon_projects.js --update --filter @kbn/cps-server-utils' + +$schema: https://moonrepo.dev/schemas/project.json +id: '@kbn/cps-server-utils' +type: unknown +owners: + defaultOwner: '@elastic/kibana-core' +toolchain: + default: node +language: typescript +project: + name: '@kbn/cps-server-utils' + description: Moon project for @kbn/cps-server-utils + channel: '' + owner: '@elastic/kibana-core' + metadata: + sourceRoot: src/platform/packages/shared/kbn-cps-server-utils +dependsOn: + - '@kbn/core-http-server' + - '@kbn/spaces-utils' +tags: + - shared-server + - package + - prod + - group-platform + - shared + - jest-unit-tests +fileGroups: + src: + - '**/*' + - '!target/**/*' +tasks: + jest: + args: + - '--config' + - $projectRoot/jest.config.js + inputs: + - '@group(src)' + jestCI: + args: + - '--config' + - $projectRoot/jest.config.js + inputs: + - '@group(src)' diff --git a/src/platform/packages/shared/kbn-cps-server-utils/package.json b/src/platform/packages/shared/kbn-cps-server-utils/package.json new file mode 100644 index 0000000000000..194ec935c35cc --- /dev/null +++ b/src/platform/packages/shared/kbn-cps-server-utils/package.json @@ -0,0 +1,7 @@ +{ + "name": "@kbn/cps-server-utils", + "version": "1.0.0", + "private": true, + "license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0", + "sideEffects": false +} diff --git a/src/platform/packages/shared/kbn-cps-server-utils/src/get_space_npre.test.ts b/src/platform/packages/shared/kbn-cps-server-utils/src/get_space_npre.test.ts new file mode 100644 index 0000000000000..de76db5f56742 --- /dev/null +++ b/src/platform/packages/shared/kbn-cps-server-utils/src/get_space_npre.test.ts @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import type { KibanaRequest } from '@kbn/core-http-server'; +import { getSpaceNPRE } from './get_space_npre'; + +const mockRequest = (pathname: string) => + ({ url: new URL(`http://localhost:5601${pathname}`) } as unknown as KibanaRequest); + +describe('getSpaceNPRE', () => { + describe('when called with a spaceId string', () => { + it('returns the NPRE for the given space', () => { + expect(getSpaceNPRE('my-space')).toBe('kibana_space_my-space_default'); + }); + + it('uses "default" when spaceId is an empty string', () => { + expect(getSpaceNPRE('')).toBe('kibana_space_default_default'); + }); + + it('returns the NPRE for the default space when spaceId is "default"', () => { + expect(getSpaceNPRE('default')).toBe('kibana_space_default_default'); + }); + }); + + describe('when called with a KibanaRequest', () => { + it('extracts the space from the request URL and returns the NPRE', () => { + expect(getSpaceNPRE(mockRequest('/s/my-space/api/foo'))).toBe( + 'kibana_space_my-space_default' + ); + }); + + it('returns the default space NPRE when the request URL has no space segment', () => { + expect(getSpaceNPRE(mockRequest('/api/foo'))).toBe('kibana_space_default_default'); + }); + }); +}); diff --git a/src/platform/packages/shared/kbn-cps-server-utils/src/get_space_npre.ts b/src/platform/packages/shared/kbn-cps-server-utils/src/get_space_npre.ts new file mode 100644 index 0000000000000..35fcb8781a04a --- /dev/null +++ b/src/platform/packages/shared/kbn-cps-server-utils/src/get_space_npre.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import type { KibanaRequest } from '@kbn/core-http-server'; +import { DEFAULT_SPACE_ID, getSpaceIdFromPath } from '@kbn/spaces-utils'; + +export function getSpaceNPRE(spaceIdOrRequest: string | KibanaRequest): string { + const spaceId = + typeof spaceIdOrRequest === 'string' + ? spaceIdOrRequest || DEFAULT_SPACE_ID + : getSpaceIdFromPath(spaceIdOrRequest.url.pathname).spaceId; + + return `kibana_space_${spaceId}_default`; +} diff --git a/src/platform/packages/shared/kbn-cps-server-utils/tsconfig.json b/src/platform/packages/shared/kbn-cps-server-utils/tsconfig.json new file mode 100644 index 0000000000000..7cf571130aa4e --- /dev/null +++ b/src/platform/packages/shared/kbn-cps-server-utils/tsconfig.json @@ -0,0 +1,17 @@ +{ + "extends": "@kbn/tsconfig-base/tsconfig.json", + "compilerOptions": { + "outDir": "target/types", + }, + "include": [ + "**/*", + "../../../../../typings/**/*", + ], + "kbn_references": [ + "@kbn/core-http-server", + "@kbn/spaces-utils", + ], + "exclude": [ + "target/**/*" + ] +} diff --git a/tsconfig.base.json b/tsconfig.base.json index e924e2c5b7a44..2fc4aa54147e8 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -840,6 +840,8 @@ "@kbn/core-user-settings-server-mocks/*": ["src/core/packages/user-settings/server-mocks/*"], "@kbn/cps": ["src/platform/plugins/shared/cps"], "@kbn/cps/*": ["src/platform/plugins/shared/cps/*"], + "@kbn/cps-server-utils": ["src/platform/packages/shared/kbn-cps-server-utils"], + "@kbn/cps-server-utils/*": ["src/platform/packages/shared/kbn-cps-server-utils/*"], "@kbn/cps-utils": ["src/platform/packages/shared/kbn-cps-utils"], "@kbn/cps-utils/*": ["src/platform/packages/shared/kbn-cps-utils/*"], "@kbn/cross-cluster-replication-plugin": ["x-pack/platform/plugins/private/cross_cluster_replication"], diff --git a/yarn.lock b/yarn.lock index d01d17b2a8776..284677d61ad48 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2705,7 +2705,7 @@ resolved "https://registry.yarnpkg.com/@elastic/filesaver/-/filesaver-1.1.2.tgz#1998ffb3cd89c9da4ec12a7793bfcae10e30c77a" integrity sha512-YZbSufYFBhAj+S2cJgiKALoxIJevqXN2MSr6Yqr42rJdaPuM31cj6pUDwflkql1oDjupqD9la+MfxPFjXI1JFQ== -"@elastic/kibana-d3-color@npm:@elastic/kibana-d3-color@2.0.1", "d3-color@1 - 2", "d3-color@npm:@elastic/kibana-d3-color@2.0.1": +"@elastic/kibana-d3-color@npm:@elastic/kibana-d3-color@2.0.1": version "2.0.1" resolved "https://registry.yarnpkg.com/@elastic/kibana-d3-color/-/kibana-d3-color-2.0.1.tgz#f83b9c2fea09273a918659de04d5e8098c82f65c" integrity sha512-YZ8hV2bWNyYi833Yj3UWczmTxdHzmo/Xc2IVkNXr/ZqtkrTDlTLysCyJm7SfAt9iBy6EVRGWTn8cPz8QOY6Ixw== @@ -6357,6 +6357,10 @@ version "0.0.0" uid "" +"@kbn/cps-server-utils@link:src/platform/packages/shared/kbn-cps-server-utils": + version "0.0.0" + uid "" + "@kbn/cps-utils@link:src/platform/packages/shared/kbn-cps-utils": version "0.0.0" uid "" @@ -19053,6 +19057,11 @@ d3-collection@^1.0.7: resolved "https://registry.yarnpkg.com/d3-collection/-/d3-collection-1.0.7.tgz#349bd2aa9977db071091c13144d5e4f16b5b310e" integrity sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A== +"d3-color@1 - 2", "d3-color@npm:@elastic/kibana-d3-color@2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@elastic/kibana-d3-color/-/kibana-d3-color-2.0.1.tgz#f83b9c2fea09273a918659de04d5e8098c82f65c" + integrity sha512-YZ8hV2bWNyYi833Yj3UWczmTxdHzmo/Xc2IVkNXr/ZqtkrTDlTLysCyJm7SfAt9iBy6EVRGWTn8cPz8QOY6Ixw== + "d3-color@1 - 3", d3-color@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-3.1.0.tgz#395b2833dfac71507f12ac2f7af23bf819de24e2" @@ -32379,7 +32388,7 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" -"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -32397,6 +32406,15 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" @@ -32489,7 +32507,14 @@ stringify-object@^3.2.1: is-obj "^1.0.1" is-regexp "^1.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -35301,7 +35326,7 @@ workerpool@^6.5.1: resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544" integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -35327,6 +35352,15 @@ wrap-ansi@^6.0.1, wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"