From 369c423e5b1dfc777270e5807300e744a211a807 Mon Sep 17 00:00:00 2001 From: Joe Clark Date: Tue, 27 Jun 2023 10:04:37 -0400 Subject: [PATCH 1/3] runtime: allow globals to be injected --- packages/runtime/src/execute/context.ts | 5 +++- packages/runtime/src/runtime.ts | 5 ++++ packages/runtime/test/runtime.test.ts | 12 ++++++++++ pnpm-lock.yaml | 31 +++++++------------------ 4 files changed, 29 insertions(+), 24 deletions(-) diff --git a/packages/runtime/src/execute/context.ts b/packages/runtime/src/execute/context.ts index 10bfeb624..585567199 100644 --- a/packages/runtime/src/execute/context.ts +++ b/packages/runtime/src/execute/context.ts @@ -15,11 +15,14 @@ const freezeAll = ( // Build a safe and helpful execution context // This will be shared by all jobs -export default (state: State, options: Pick) => { +export default (state: State, options: Pick) => { const logger = options.jobLogger ?? console; + const globals = options.globals || {}; const context = vm.createContext( freezeAll( { + ...globals, + // Note that these globals will be overridden console: logger, clearInterval, clearTimeout, diff --git a/packages/runtime/src/runtime.ts b/packages/runtime/src/runtime.ts index d00010901..5830e7e33 100644 --- a/packages/runtime/src/runtime.ts +++ b/packages/runtime/src/runtime.ts @@ -27,6 +27,11 @@ export type Options = { forceSandbox?: boolean; linker?: LinkerOptions; + + // inject stuff into the environment + // aka globals + // Used by unit tests. any security concerns? + globals?: any; }; const defaultState = { data: {}, configuration: {} }; diff --git a/packages/runtime/test/runtime.test.ts b/packages/runtime/test/runtime.test.ts index 73fd6477d..6db890e09 100644 --- a/packages/runtime/test/runtime.test.ts +++ b/packages/runtime/test/runtime.test.ts @@ -269,3 +269,15 @@ test('stuff written to state before an error is preserved', async (t) => { t.is(result.x, 1); }); + +test('inject globals', async (t) => { + const expression = 'export default [(s) => Object.assign(s, { data: { x } })]'; + + const result: any = await run(expression, {}, { + globals: { + x: 90210 + } + }); + t.is(result.data.x, 90210); +}); + diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5b3e0e7e6..c9696925c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -59,14 +59,6 @@ importers: tslib: 2.4.0 typescript: 4.8.3 - integration-tests/cli/repo: - specifiers: - '@openfn/language-common_1.7.7': npm:@openfn/language-common@^1.7.7 - is-array_1.0.1: npm:is-array@^1.0.1 - dependencies: - '@openfn/language-common_1.7.7': /@openfn/language-common/1.7.7 - is-array_1.0.1: /is-array/1.0.1 - packages/cli: specifiers: '@openfn/compiler': workspace:* @@ -618,17 +610,6 @@ packages: - debug dev: true - /@openfn/language-common/1.7.7: - resolution: {integrity: sha512-GSoAbo6oL0b8jHufhLKvIzHJ271aE2AKv/ibeuiWU3CqN1gRmaHArlA/omlCs/rsfcieSp2VWAvWeGuFY8buZw==} - dependencies: - axios: 1.1.3 - date-fns: 2.29.3 - jsonpath-plus: 4.0.0 - lodash: 4.17.21 - transitivePeerDependencies: - - debug - dev: false - /@openfn/language-common/2.0.0-rc3: resolution: {integrity: sha512-7kwhBnCd1idyTB3MD9dXmUqROAhoaUIkz2AGDKuv9vn/cbZh7egEv9/PzKkRcDJYFV9qyyS+cVT3Xbgsg2ii5g==} bundledDependencies: [] @@ -1072,6 +1053,7 @@ packages: /asynckit/0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + dev: true /atob/2.1.2: resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==} @@ -1145,6 +1127,7 @@ packages: proxy-from-env: 1.1.0 transitivePeerDependencies: - debug + dev: true /b4a/1.6.1: resolution: {integrity: sha512-AsKjNhz72yxteo/0EtQEiwkMUgk/tGmycXlbG4g3Ard2/ULtNLUykGOkeK0egmN27h0xMAhb76jYccW+XTBExA==} @@ -1540,6 +1523,7 @@ packages: engines: {node: '>= 0.8'} dependencies: delayed-stream: 1.0.0 + dev: true /commander/4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} @@ -1810,6 +1794,7 @@ packages: /delayed-stream/1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} + dev: true /delegates/1.0.0: resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} @@ -2849,6 +2834,7 @@ packages: peerDependenciesMeta: debug: optional: true + dev: true /for-in/1.0.2: resolution: {integrity: sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==} @@ -2862,6 +2848,7 @@ packages: asynckit: 0.4.0 combined-stream: 1.0.8 mime-types: 2.1.35 + dev: true /fragment-cache/0.2.1: resolution: {integrity: sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==} @@ -3264,10 +3251,6 @@ packages: kind-of: 6.0.3 dev: true - /is-array/1.0.1: - resolution: {integrity: sha512-gxiZ+y/u67AzpeFmAmo4CbtME/bs7J2C++su5zQzvQyaxUqVzkh69DI+jN+KZuSO6JaH6TIIU6M6LhqxMjxEpw==} - dev: false - /is-arrayish/0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} dev: true @@ -3584,6 +3567,7 @@ packages: /jsonpath-plus/4.0.0: resolution: {integrity: sha512-e0Jtg4KAzDJKKwzbLaUtinCn0RZseWBVRTRGihSpvFlM3wTR7ExSp+PTdeTsDrLNJUe7L7JYJe8mblHX5SCT6A==} engines: {node: '>=10.0'} + dev: true /keygrip/1.1.0: resolution: {integrity: sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==} @@ -4533,6 +4517,7 @@ packages: /proxy-from-env/1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + dev: true /proxy-middleware/0.15.0: resolution: {integrity: sha512-EGCG8SeoIRVMhsqHQUdDigB2i7qU7fCsWASwn54+nPutYO8n4q6EiwMzyfWlC+dzRFExP+kvcnDFdBDHoZBU7Q==} From 6002a0f58a45315d0fc88daab0baf521e212d110 Mon Sep 17 00:00:00 2001 From: Joe Clark Date: Tue, 27 Jun 2023 10:13:30 -0400 Subject: [PATCH 2/3] runtime: extra test on global injection --- packages/runtime/test/runtime.test.ts | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/packages/runtime/test/runtime.test.ts b/packages/runtime/test/runtime.test.ts index 6db890e09..0ce9226c3 100644 --- a/packages/runtime/test/runtime.test.ts +++ b/packages/runtime/test/runtime.test.ts @@ -281,3 +281,28 @@ test('inject globals', async (t) => { t.is(result.data.x, 90210); }); +test('injected globals can\'t override special functions', async (t) => { + const panic = () => { throw new Error('illegal override') } + + const globals = { + console: panic, + clearInterval: panic, + clearTimeout: panic, + parseFloat: panic, + parseInt: panic, + setInterval: panic, + setTimeout: panic, + } + const expression = `export default [(s) => { + parseFloat(); + parseInt(); + const i = setInterval(() => {}, 1000); + clearInterval(i); + const t = setTimeout(() => {}, 1000); + clearTimeout(t); + return s; + }]`; + + const result: any = await run(expression, {}, { globals }); + t.falsy(result.errors); +}); From a520e7b7aa7ed65119902efd877300ee62687f32 Mon Sep 17 00:00:00 2001 From: Joe Clark Date: Tue, 27 Jun 2023 10:46:41 -0400 Subject: [PATCH 3/3] runtime: use global execute from injection if it exists --- packages/runtime/src/execute/expression.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime/src/execute/expression.ts b/packages/runtime/src/execute/expression.ts index 7ac7a49e1..d03d0a978 100644 --- a/packages/runtime/src/execute/expression.ts +++ b/packages/runtime/src/execute/expression.ts @@ -23,7 +23,7 @@ export default ( const { operations, execute } = await prepareJob(expression, context, opts); // Create the main reducer function - const reducer = (execute || defaultExecute)( + const reducer = (execute || opts.globals?.execute || defaultExecute)( ...operations.map((op, idx) => wrapOperation(op, logger, `${idx + 1}`, opts.immutableState) )