diff --git a/packages/core/http/core-http-server-internal/src/csp/csp_directives.test.ts b/packages/core/http/core-http-server-internal/src/csp/csp_directives.test.ts index e250a6b1fea44..d430962053ceb 100644 --- a/packages/core/http/core-http-server-internal/src/csp/csp_directives.test.ts +++ b/packages/core/http/core-http-server-internal/src/csp/csp_directives.test.ts @@ -121,5 +121,28 @@ describe('CspDirectives', () => { `"script-src 'report-sample' 'self' 'unsafe-hashes'; worker-src 'report-sample' 'self' blob:; style-src 'report-sample' 'self' 'unsafe-inline'"` ); }); + + it('merges additional CSP configs as expected', () => { + const config = cspConfig.schema.validate({ + connect_src: ['*.foo.bar'], // should de-dupe these + }); + const additionalConfig1 = { + connect_src: ['*.foo.bar'], + img_src: ['*.foo.bar'], + }; + const additionalConfig2 = { + connect_src: [`cdn.host.test`], + font_src: [`cdn.host.test`], + frame_src: [`cdn.host.test`], + img_src: [`cdn.host.test`], + worker_src: [`cdn.host.test`], + script_src: [`cdn.host.test`], + style_src: [`cdn.host.test`], + }; + const directives = CspDirectives.fromConfig(config, additionalConfig1, additionalConfig2); + expect(directives.getCspHeader()).toEqual( + `script-src 'report-sample' 'self' cdn.host.test; worker-src 'report-sample' 'self' blob: cdn.host.test; style-src 'report-sample' 'self' 'unsafe-inline' cdn.host.test; connect-src 'self' *.foo.bar cdn.host.test; font-src 'self' cdn.host.test; frame-src 'self' cdn.host.test; img-src 'self' *.foo.bar cdn.host.test` + ); + }); }); }); diff --git a/packages/core/http/core-http-server-internal/src/csp/csp_directives.ts b/packages/core/http/core-http-server-internal/src/csp/csp_directives.ts index d7495e4c09bfc..21b2f7c573e33 100644 --- a/packages/core/http/core-http-server-internal/src/csp/csp_directives.ts +++ b/packages/core/http/core-http-server-internal/src/csp/csp_directives.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import { merge } from 'lodash'; +import deepmerge from 'deepmerge'; import { CspConfigType } from './config'; export type CspDirectiveName = @@ -70,7 +70,10 @@ export class CspDirectives { firstConfig: CspConfigType, ...otherConfigs: Array> ): CspDirectives { - const config = otherConfigs.length ? merge(firstConfig, ...otherConfigs) : firstConfig; + const config = otherConfigs.reduce( + (acc, conf) => deepmerge(acc, conf), + firstConfig + ); const cspDirectives = new CspDirectives(); // combining `default` directive configurations