diff --git a/src/__tests__/getMtlsFetch.test.js b/src/__tests__/getMtlsFetch.test.js new file mode 100644 index 0000000..dcce88d --- /dev/null +++ b/src/__tests__/getMtlsFetch.test.js @@ -0,0 +1,59 @@ +/* +Copyright 2025 Adobe. All rights reserved. +This file is licensed 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 REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import getMtlsFetch from '../getMtlsFetch.js'; +import { MTLS_BINDING } from '../constants.js'; + +describe('getMtlsFetch', () => { + let mockEnv; + let mockFetch; + + beforeEach(() => { + mockFetch = vi.fn(); + mockEnv = {}; + }); + + it('should return the MTLS fetch function when the binding exists', () => { + // Arrange + mockEnv[MTLS_BINDING] = { fetch: mockFetch }; + + // Act + const result = getMtlsFetch(mockEnv); + + // Assert + expect(result).toBe(mockFetch); + }); + + it('should return a function that throws an error when the binding does not exist', () => { + // Arrange + mockEnv = {}; // Empty env without MTLS binding + + // Act + const result = getMtlsFetch(mockEnv); + + // Assert + expect(() => result()).toThrowError( + 'MTLS certificate not found on the worker' + ); + }); + + it('should handle undefined env gracefully', () => { + // Act + const result = getMtlsFetch(undefined); + + // Assert + expect(result).toBeInstanceOf(Function); + expect(() => result()).toThrowError( + 'MTLS certificate not found on the worker' + ); + }); +}); diff --git a/src/__tests__/index.test.js b/src/__tests__/index.test.js index 7ce2634..86ad8a6 100644 --- a/src/__tests__/index.test.js +++ b/src/__tests__/index.test.js @@ -33,13 +33,16 @@ describe('index', () => { request: { header: {}, body: { xdm: {}, data: {} } } }; - const execute = index.initialize(containerInitFunction, { - fetch: globalFetch - }); + const execute = index.initialize(containerInitFunction); - return execute(callData, { - headersForSubrequests: {} - }).then((result) => { + return execute( + callData, + {}, + { + headersForSubrequests: {}, + fetch: globalFetch + } + ).then((result) => { expect(result).toStrictEqual([ { ruleId: 'RLbb1d94c79fee4733a510564a86ba3c59', diff --git a/src/constants.js b/src/constants.js index 3669e77..9ab6022 100644 --- a/src/constants.js +++ b/src/constants.js @@ -11,3 +11,4 @@ governing permissions and limitations under the License. export const CORE = 'core'; export const PROMISE_TIMEOUT = 30000; +export const MTLS_BINDING = 'ADOBE_MTLS_CERTIFICATE'; diff --git a/src/executeRules.js b/src/executeRules.js index 40022e9..f860e80 100644 --- a/src/executeRules.js +++ b/src/executeRules.js @@ -17,14 +17,14 @@ import logRuleStarting from './rules/logRuleStarting.js'; import logRuleEnding from './rules/logRuleEnding.js'; import returnRuleResult from './rules/returnRuleResult.js'; import createPromiseChain from './rules/createPromiseChain.js'; +import getMtlsFetch from './getMtlsFetch.js'; export default ( moduleProvider, container, - globalFetch, requestData, env, - { headersForSubrequests } = {} + { headersForSubrequests, fetch: globalFetch } = {} ) => { const rulePromises = []; @@ -53,11 +53,19 @@ export default ( logger ); + const mtlsFetch = getRuleFetchFn( + getMtlsFetch(env), + getHeaderOverrides(env), + headersForSubrequests, + logger + ); + const utils = { getRule: () => ({ id, name }), getBuildInfo: () => buildInfo, logger, - fetch + fetch, + mtlsFetch }; const initialContext = { diff --git a/src/getMtlsFetch.js b/src/getMtlsFetch.js new file mode 100644 index 0000000..b60ccee --- /dev/null +++ b/src/getMtlsFetch.js @@ -0,0 +1,22 @@ +/* +Copyright 2025 Adobe. All rights reserved. +This file is licensed 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 REPRESENTATIONS +OF ANY KIND, either express or implied. See the License for the specific language +governing permissions and limitations under the License. +*/ + +import { MTLS_BINDING } from './constants.js'; + +export default (env) => { + if (env && env[MTLS_BINDING]) { + return env[MTLS_BINDING].fetch; + } + + return () => { + throw new Error('MTLS certificate not found on the worker'); + }; +}; diff --git a/src/getRuleFetchFn.js b/src/getRuleFetchFn.js index d200048..c676ebc 100644 --- a/src/getRuleFetchFn.js +++ b/src/getRuleFetchFn.js @@ -12,12 +12,7 @@ governing permissions and limitations under the License. const byteArrayToString = (buf) => new TextDecoder('utf-8').decode(new Uint8Array(buf)); -export default ( - globalFetch, - headerOverrides, - headersForSubrequests, - logger -) => { +export default (fetch, headerOverrides, headersForSubrequests, logger) => { return (resource, init = {}) => { // If resource is not a string then it must be a Request object and we // need to read it's headers. Otherwise the Request headers will be @@ -50,7 +45,7 @@ export default ( } }); - return globalFetch(resource, init).then( + return fetch(resource, init).then( (r) => { // Below we will read the body of the response. The body can be read only once. // We are cloning the response and sending it down to the actions so in case diff --git a/src/index.js b/src/index.js index 3d5f5ff..737503c 100644 --- a/src/index.js +++ b/src/index.js @@ -29,14 +29,14 @@ const getDataElementValue = createGetDataElementValue( const getDataElementValues = createGetDataElementValues(getDataElementValue); -const initialize = (containerInitFunction, { fetch }) => { +const initialize = (containerInitFunction) => { const container = containerInitFunction(getDataElementValues); if (container.dataElements) { dataElements = container.dataElements; } moduleProvider.registerModules(container.modules, container.extensions); - return executeRules.bind(null, moduleProvider, container, fetch); + return executeRules.bind(null, moduleProvider, container); }; export default {