diff --git a/packages/core/http/core-http-server-internal/src/http_server.ts b/packages/core/http/core-http-server-internal/src/http_server.ts index c0ca940ea3d615..4c7570ac63ec94 100644 --- a/packages/core/http/core-http-server-internal/src/http_server.ts +++ b/packages/core/http/core-http-server-internal/src/http_server.ts @@ -58,7 +58,7 @@ import { AuthStateStorage } from './auth_state_storage'; import { AuthHeadersStorage } from './auth_headers_storage'; import { BasePath } from './base_path_service'; import { getEcsResponseLog } from './logging'; -import { StaticAssets } from './static_assets'; +import { StaticAssets, type IStaticAssets } from './static_assets'; /** * Adds ELU timings for the executed function to the current's context transaction @@ -136,7 +136,7 @@ export interface HttpServerSetup { * @note Static assets may be served over CDN */ registerStaticDir: (path: string, dirPath: string) => void; - staticAssets: StaticAssets; + staticAssets: IStaticAssets; basePath: HttpServiceSetup['basePath']; csp: HttpServiceSetup['csp']; createCookieSessionStorageFactory: HttpServiceSetup['createCookieSessionStorageFactory']; diff --git a/packages/core/http/core-http-server-internal/src/static_assets.ts b/packages/core/http/core-http-server-internal/src/static_assets.ts index 7de55958f8c4a6..d5d6eeee725260 100644 --- a/packages/core/http/core-http-server-internal/src/static_assets.ts +++ b/packages/core/http/core-http-server-internal/src/static_assets.ts @@ -10,7 +10,11 @@ import type { KibanaRequest } from '@kbn/core-http-server/src/router'; import type { BasePath } from './base_path_service'; import { CdnConfig } from './cdn'; -export class StaticAssets { +export interface IStaticAssets { + getHrefBase(request?: KibanaRequest): string; +} + +export class StaticAssets implements IStaticAssets { constructor(private readonly basePath: BasePath, private readonly cdnConfig: CdnConfig) {} /** * Returns a href (hypertext reference) intended to be used as the base for constructing diff --git a/packages/core/http/core-http-server-mocks/src/http_service.mock.ts b/packages/core/http/core-http-server-mocks/src/http_service.mock.ts index 433560c9104565..ad7e310f5a2d8a 100644 --- a/packages/core/http/core-http-server-mocks/src/http_service.mock.ts +++ b/packages/core/http/core-http-server-mocks/src/http_service.mock.ts @@ -34,12 +34,13 @@ import type { import { sessionStorageMock } from './cookie_session_storage.mocks'; type BasePathMocked = jest.Mocked; +type StaticAssetsMocked = jest.Mocked; type AuthMocked = jest.Mocked; export type HttpServicePrebootMock = jest.Mocked; export type InternalHttpServicePrebootMock = jest.Mocked< - Omit -> & { basePath: BasePathMocked }; + Omit +> & { basePath: BasePathMocked; staticAssets: StaticAssetsMocked }; export type HttpServiceSetupMock< ContextType extends RequestHandlerContextBase = RequestHandlerContextBase > = jest.Mocked, 'basePath' | 'createRouter'>> & { @@ -47,10 +48,14 @@ export type HttpServiceSetupMock< createRouter: jest.MockedFunction<() => RouterMock>; }; export type InternalHttpServiceSetupMock = jest.Mocked< - Omit + Omit< + InternalHttpServiceSetup, + 'basePath' | 'staticAssets' | 'createRouter' | 'authRequestHeaders' | 'auth' + > > & { auth: AuthMocked; basePath: BasePathMocked; + staticAssets: StaticAssetsMocked; createRouter: jest.MockedFunction<(path: string) => RouterMock>; authRequestHeaders: jest.Mocked; }; @@ -73,6 +78,13 @@ const createBasePathMock = ( remove: jest.fn(), }); +const createStaticAssetsMock = ( + basePath: BasePathMocked, + cdnUrl: undefined | string = undefined +): StaticAssetsMocked => ({ + getHrefBase: jest.fn(() => cdnUrl ?? basePath.serverBasePath), +}); + const createAuthMock = () => { const mock: AuthMocked = { get: jest.fn(), @@ -91,12 +103,17 @@ const createAuthHeaderStorageMock = () => { return mock; }; -const createInternalPrebootContractMock = () => { +interface CreateMockArgs { + cdnUrl?: string; +} +const createInternalPrebootContractMock = (args: CreateMockArgs = {}) => { + const basePath = createBasePathMock(); const mock: InternalHttpServicePrebootMock = { registerRoutes: jest.fn(), registerRouteHandlerContext: jest.fn(), registerStaticDir: jest.fn(), - basePath: createBasePathMock(), + basePath, + staticAssets: createStaticAssetsMock(basePath, args.cdnUrl), csp: CspConfig.DEFAULT, externalUrl: ExternalUrlConfig.DEFAULT, auth: createAuthMock(), @@ -149,6 +166,7 @@ const createInternalSetupContractMock = () => { registerStaticDir: jest.fn(), basePath: createBasePathMock(), csp: CspConfig.DEFAULT, + staticAssets: { getHrefBase: jest.fn(() => mock.basePath.serverBasePath) }, externalUrl: ExternalUrlConfig.DEFAULT, auth: createAuthMock(), authRequestHeaders: createAuthHeaderStorageMock(), diff --git a/packages/core/rendering/core-rendering-server-internal/src/__snapshots__/rendering_service.test.ts.snap b/packages/core/rendering/core-rendering-server-internal/src/__snapshots__/rendering_service.test.ts.snap index 6316dc056563cc..d444959de3c9e8 100644 --- a/packages/core/rendering/core-rendering-server-internal/src/__snapshots__/rendering_service.test.ts.snap +++ b/packages/core/rendering/core-rendering-server-internal/src/__snapshots__/rendering_service.test.ts.snap @@ -1,5 +1,72 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`RenderingService preboot() render() renders "core" CDN url injected 1`] = ` +Object { + "anonymousStatusPage": false, + "basePath": "/mock-server-basepath", + "branch": Any, + "buildNumber": Any, + "clusterInfo": Object {}, + "csp": Object { + "warnLegacyBrowsers": true, + }, + "customBranding": Object {}, + "env": Object { + "mode": Object { + "dev": Any, + "name": Any, + "prod": Any, + }, + "packageInfo": Object { + "branch": Any, + "buildDate": "2023-05-15T23:12:09.000Z", + "buildFlavor": Any, + "buildNum": Any, + "buildSha": Any, + "dist": Any, + "version": Any, + }, + }, + "externalUrl": Object { + "policy": Array [ + Object { + "allow": true, + }, + ], + }, + "i18n": Object { + "translationsUrl": "/mock-server-basepath/translations/en.json", + }, + "legacyMetadata": Object { + "globalUiSettings": Object { + "defaults": Object {}, + "user": Object {}, + }, + "uiSettings": Object { + "defaults": Object { + "registered": Object { + "name": "title", + }, + }, + "user": Object { + "theme:darkMode": Object { + "userValue": true, + }, + }, + }, + }, + "publicBaseUrl": "http://myhost.com/mock-server-basepath", + "serverBasePath": "/mock-server-basepath", + "theme": Object { + "darkMode": "theme:darkMode", + "version": "v8", + }, + "uiPlugins": Array [], + "vars": Object {}, + "version": Any, +} +`; + exports[`RenderingService preboot() render() renders "core" page 1`] = ` Object { "anonymousStatusPage": false, @@ -449,6 +516,78 @@ Object { } `; +exports[`RenderingService setup() render() renders "core" CDN url injected 1`] = ` +Object { + "anonymousStatusPage": false, + "basePath": "/mock-server-basepath", + "branch": Any, + "buildNumber": Any, + "clusterInfo": Object { + "cluster_build_flavor": "default", + "cluster_name": "cluster-name", + "cluster_uuid": "cluster-uuid", + "cluster_version": "8.0.0", + }, + "csp": Object { + "warnLegacyBrowsers": true, + }, + "customBranding": Object {}, + "env": Object { + "mode": Object { + "dev": Any, + "name": Any, + "prod": Any, + }, + "packageInfo": Object { + "branch": Any, + "buildDate": "2023-05-15T23:12:09.000Z", + "buildFlavor": Any, + "buildNum": Any, + "buildSha": Any, + "dist": Any, + "version": Any, + }, + }, + "externalUrl": Object { + "policy": Array [ + Object { + "allow": true, + }, + ], + }, + "i18n": Object { + "translationsUrl": "/mock-server-basepath/translations/en.json", + }, + "legacyMetadata": Object { + "globalUiSettings": Object { + "defaults": Object {}, + "user": Object {}, + }, + "uiSettings": Object { + "defaults": Object { + "registered": Object { + "name": "title", + }, + }, + "user": Object { + "theme:darkMode": Object { + "userValue": true, + }, + }, + }, + }, + "publicBaseUrl": "http://myhost.com/mock-server-basepath", + "serverBasePath": "/mock-server-basepath", + "theme": Object { + "darkMode": "theme:darkMode", + "version": "v8", + }, + "uiPlugins": Array [], + "vars": Object {}, + "version": Any, +} +`; + exports[`RenderingService setup() render() renders "core" page 1`] = ` Object { "anonymousStatusPage": false, diff --git a/packages/core/rendering/core-rendering-server-internal/src/bootstrap/bootstrap_renderer.test.ts b/packages/core/rendering/core-rendering-server-internal/src/bootstrap/bootstrap_renderer.test.ts index b4d6a6a882d1d4..5c699e905e9cd9 100644 --- a/packages/core/rendering/core-rendering-server-internal/src/bootstrap/bootstrap_renderer.test.ts +++ b/packages/core/rendering/core-rendering-server-internal/src/bootstrap/bootstrap_renderer.test.ts @@ -319,7 +319,7 @@ describe('bootstrapRenderer', () => { expect(getPluginsBundlePathsMock).toHaveBeenCalledWith({ isAnonymousPage, uiPlugins, - regularBundlePath: '/base-path/42/bundles', + bundlesHref: '/base-path/42/bundles', }); }); }); diff --git a/packages/core/rendering/core-rendering-server-internal/src/rendering_service.test.ts b/packages/core/rendering/core-rendering-server-internal/src/rendering_service.test.ts index 193ad54918d9f6..521e697f29a400 100644 --- a/packages/core/rendering/core-rendering-server-internal/src/rendering_service.test.ts +++ b/packages/core/rendering/core-rendering-server-internal/src/rendering_service.test.ts @@ -180,10 +180,25 @@ function renderTestCases( expect(getStylesheetPathsMock).toHaveBeenCalledWith({ darkMode: true, themeVersion: 'v8', - basePath: '/mock-server-basepath', + baseHref: '/mock-server-basepath', buildNum: expect.any(Number), }); }); + + it('renders "core" CDN url injected', async () => { + const userSettings = { 'theme:darkMode': { userValue: true } }; + uiSettings.client.getUserProvided.mockResolvedValue(userSettings); + (mockRenderingPrebootDeps.http.staticAssets.getHrefBase as jest.Mock).mockImplementation( + () => 'http://foo.bar:1773' + ); + const [render] = await getRender(); + const content = await render(createKibanaRequest(), uiSettings, { + isAnonymousPage: false, + }); + const dom = load(content); + const data = JSON.parse(dom('kbn-injected-metadata').attr('data') ?? '""'); + expect(data).toMatchSnapshot(INJECTED_METADATA); + }); }); } @@ -233,7 +248,7 @@ function renderDarkModeTestCases( expect(getStylesheetPathsMock).toHaveBeenCalledWith({ darkMode: true, themeVersion: 'v8', - basePath: '/mock-server-basepath', + baseHref: '/mock-server-basepath', buildNum: expect.any(Number), }); }); @@ -259,7 +274,7 @@ function renderDarkModeTestCases( expect(getStylesheetPathsMock).toHaveBeenCalledWith({ darkMode: false, themeVersion: 'v8', - basePath: '/mock-server-basepath', + baseHref: '/mock-server-basepath', buildNum: expect.any(Number), }); }); @@ -283,7 +298,7 @@ function renderDarkModeTestCases( expect(getStylesheetPathsMock).toHaveBeenCalledWith({ darkMode: false, themeVersion: 'v8', - basePath: '/mock-server-basepath', + baseHref: '/mock-server-basepath', buildNum: expect.any(Number), }); }); @@ -307,7 +322,7 @@ function renderDarkModeTestCases( expect(getStylesheetPathsMock).toHaveBeenCalledWith({ darkMode: true, themeVersion: 'v8', - basePath: '/mock-server-basepath', + baseHref: '/mock-server-basepath', buildNum: expect.any(Number), }); }); @@ -331,7 +346,7 @@ function renderDarkModeTestCases( expect(getStylesheetPathsMock).toHaveBeenCalledWith({ darkMode: false, themeVersion: 'v8', - basePath: '/mock-server-basepath', + baseHref: '/mock-server-basepath', buildNum: expect.any(Number), }); }); @@ -355,7 +370,7 @@ function renderDarkModeTestCases( expect(getStylesheetPathsMock).toHaveBeenCalledWith({ darkMode: false, themeVersion: 'v8', - basePath: '/mock-server-basepath', + baseHref: '/mock-server-basepath', buildNum: expect.any(Number), }); }); @@ -379,7 +394,7 @@ function renderDarkModeTestCases( expect(getStylesheetPathsMock).toHaveBeenCalledWith({ darkMode: true, themeVersion: 'v8', - basePath: '/mock-server-basepath', + baseHref: '/mock-server-basepath', buildNum: expect.any(Number), }); }); diff --git a/packages/core/rendering/core-rendering-server-internal/src/rendering_service.tsx b/packages/core/rendering/core-rendering-server-internal/src/rendering_service.tsx index b9252e1df52cc4..4300cfb0d69f81 100644 --- a/packages/core/rendering/core-rendering-server-internal/src/rendering_service.tsx +++ b/packages/core/rendering/core-rendering-server-internal/src/rendering_service.tsx @@ -190,7 +190,7 @@ export class RenderingService { const metadata: RenderingMetadata = { strictCsp: http.csp.strict, uiPublicUrl: `${staticAssetsHrefBase}/ui`, - bootstrapScriptUrl: `${serverBasePath}/${bootstrapScript}`, + bootstrapScriptUrl: `${basePath}/${bootstrapScript}`, i18n: i18n.translate, locale: i18n.getLocale(), darkMode, @@ -214,7 +214,7 @@ export class RenderingService { anonymousStatusPage: status?.isStatusPageAnonymous() ?? false, i18n: { // TODO: Make this load as part of static assets! - translationsUrl: `${serverBasePath}/translations/${i18n.getLocale()}.json`, + translationsUrl: `${basePath}/translations/${i18n.getLocale()}.json`, }, theme: { darkMode,