From a18e5e5b9456b4e21b0bc37b157e4757a063edaf Mon Sep 17 00:00:00 2001 From: Anoop M D Date: Tue, 13 Aug 2024 19:06:17 +0530 Subject: [PATCH] Feat/safe mode quickjs (#2825) * feat: testing quickjs sanbox * feat: testing quickjs sanbox * feat: testing quickjs sanbox --- contributing.md | 3 + .../src/runner/run-single-request.js | 2 +- .../bruno-electron/src/ipc/network/index.js | 2 +- packages/bruno-js/.gitignore | 2 +- packages/bruno-js/package.json | 7 +- packages/bruno-js/src/runtime/test-runtime.js | 94 ++++---- .../utils => }/bundle-libraries.js | 18 +- .../bruno-js/src/sandbox/isolatedvm/index.js | 2 +- .../bruno-js/src/sandbox/quickjs/index.js | 203 ++++++++++++++++++ .../bruno-js/src/sandbox/quickjs/shims/bru.js | 65 ++++++ .../sandbox/quickjs/shims/bruno-request.js | 107 +++++++++ .../sandbox/quickjs/shims/bruno-response.js | 51 +++++ .../src/sandbox/quickjs/shims/test.js | 17 ++ .../src/sandbox/quickjs/utils/index.js | 35 +++ .../collection/environments/Prod.bru | 3 - packages/bruno-tests/collection/ping.bru | 49 ----- .../scripting/api/bru/getEnvName.bru | 3 +- .../collection/scripting/api/bru/setVar.bru | 3 +- .../collection/scripting/api/req/getUrl.bru | 3 +- 19 files changed, 546 insertions(+), 123 deletions(-) rename packages/bruno-js/src/sandbox/{isolatedvm/utils => }/bundle-libraries.js (84%) create mode 100644 packages/bruno-js/src/sandbox/quickjs/index.js create mode 100644 packages/bruno-js/src/sandbox/quickjs/shims/bru.js create mode 100644 packages/bruno-js/src/sandbox/quickjs/shims/bruno-request.js create mode 100644 packages/bruno-js/src/sandbox/quickjs/shims/bruno-response.js create mode 100644 packages/bruno-js/src/sandbox/quickjs/shims/test.js create mode 100644 packages/bruno-js/src/sandbox/quickjs/utils/index.js diff --git a/contributing.md b/contributing.md index 6575e36ea..cc788db23 100644 --- a/contributing.md +++ b/contributing.md @@ -57,6 +57,9 @@ npm run build:graphql-docs npm run build:bruno-query npm run build:bruno-common +# bundle js sandbox libraries +npm run sandbox:bundle-libraries --workspace=packages/bruno-js + # run next app (terminal 1) npm run dev:web diff --git a/packages/bruno-cli/src/runner/run-single-request.js b/packages/bruno-cli/src/runner/run-single-request.js index 23db67a0a..7ebad6b2f 100644 --- a/packages/bruno-cli/src/runner/run-single-request.js +++ b/packages/bruno-cli/src/runner/run-single-request.js @@ -42,7 +42,7 @@ const runSingleRequest = async function ( // todo: allow to override from cli args // we will default to vm2 (developer-mode) for 1.x version for backward compatibility // 2.x will default to isolated-vm (safe mode) - scriptingConfig.runtime = 'vm2'; + scriptingConfig.runtime = 'isolated-vm'; // make axios work in node using form data // reference: https://github.com/axios/axios/issues/1006#issuecomment-320165427 diff --git a/packages/bruno-electron/src/ipc/network/index.js b/packages/bruno-electron/src/ipc/network/index.js index 53d3a6afd..8ee39c199 100644 --- a/packages/bruno-electron/src/ipc/network/index.js +++ b/packages/bruno-electron/src/ipc/network/index.js @@ -83,7 +83,7 @@ const getEnvVars = (environment = {}) => { const getJsSandboxRuntime = (collection) => { const securityConfig = get(collection, 'securityConfig', {}); - return securityConfig.jsSandboxMode === 'safe' ? 'isolated-vm' : 'vm2'; + return securityConfig.jsSandboxMode === 'safe' ? 'quickjs' : 'vm2'; }; const protocolRegex = /^([-+\w]{1,25})(:?\/\/|:)/; diff --git a/packages/bruno-js/.gitignore b/packages/bruno-js/.gitignore index c7c43f854..22322eb1b 100644 --- a/packages/bruno-js/.gitignore +++ b/packages/bruno-js/.gitignore @@ -1 +1 @@ -src/bundle-browser-rollup.js \ No newline at end of file +src/sandbox/bundle-browser-rollup.js \ No newline at end of file diff --git a/packages/bruno-js/package.json b/packages/bruno-js/package.json index b9c519b00..a0dd1546d 100644 --- a/packages/bruno-js/package.json +++ b/packages/bruno-js/package.json @@ -12,12 +12,10 @@ }, "scripts": { "test": "jest --testPathIgnorePatterns test.js", - "rebuild:electron": "cd ./node_modules/isolated-vm && npx electron-rebuild", - "postinstall": "npm run isolated-vm:install && npm run isolated-vm:prebuild:dev && npm run isolated-vm:bundle-libraries", + "sandbox:bundle-libraries": "node ./src/sandbox/bundle-libraries.js", "isolated-vm:install": "cd ./node_modules/isolated-vm && npm install", "isolated-vm:prebuild:dev": "node ./scripts/prebuild-isolated-vm-for-dev.js", - "isolated-vm:prebuild:prod": "node ./scripts/prebuild-isolated-vm-for-prod-builds.js", - "isolated-vm:bundle-libraries": "node ./src/sandbox/isolatedvm/utils/bundle-libraries.js" + "isolated-vm:prebuild:prod": "node ./scripts/prebuild-isolated-vm-for-prod-builds.js" }, "dependencies": { "@usebruno/common": "0.1.0", @@ -37,6 +35,7 @@ "nanoid": "3.3.4", "node-fetch": "2.*", "node-vault": "^0.10.2", + "quickjs-emscripten": "^0.29.2", "uuid": "^9.0.0" }, "devDependencies": { diff --git a/packages/bruno-js/src/runtime/test-runtime.js b/packages/bruno-js/src/runtime/test-runtime.js index c13890e0a..01b85a972 100644 --- a/packages/bruno-js/src/runtime/test-runtime.js +++ b/packages/bruno-js/src/runtime/test-runtime.js @@ -31,6 +31,7 @@ const fetch = require('node-fetch'); const CryptoJS = require('crypto-js'); const NodeVault = require('node-vault'); const { executeInIsolatedVMAsync } = require('../sandbox/isolatedvm'); +const { executeQuickJsVmAsync } = require('../sandbox/quickjs'); class TestRuntime { constructor(props) { @@ -108,61 +109,58 @@ class TestRuntime { }; } - if (this.mode == 'safe') { + if (this.runtime === 'isolated-vm') { await executeInIsolatedVMAsync({ script: testsFile, context: context, modules: {}, scriptType: 'jsScript' }); - - return { - request, - envVariables: cleanJson(envVariables), - runtimeVariables: cleanJson(runtimeVariables), - results: cleanJson(__brunoTestResults.getResults()), - nextRequestName: bru.nextRequest - }; - } - - // default runtime is vm2 - const vm = new NodeVM({ - sandbox: context, - require: { - context: 'sandbox', - external: true, - root: [collectionPath, ...additionalContextRootsAbsolute], - mock: { - // node libs - path, - stream, - util, - url, - http, - https, - punycode, - zlib, - // 3rd party libs - ajv, - 'ajv-formats': addFormats, - btoa, - atob, - lodash, - moment, - uuid, - nanoid, - axios, - chai, - 'node-fetch': fetch, - 'crypto-js': CryptoJS, - ...whitelistedModules, - fs: allowScriptFilesystemAccess ? fs : undefined, - 'node-vault': NodeVault + } else if(this.runtime === 'quickjs') { + await executeQuickJsVmAsync({ + script: testsFile, + context: context + }); + } else { + // default runtime is vm2 + const vm = new NodeVM({ + sandbox: context, + require: { + context: 'sandbox', + external: true, + root: [collectionPath, ...additionalContextRootsAbsolute], + mock: { + // node libs + path, + stream, + util, + url, + http, + https, + punycode, + zlib, + // 3rd party libs + ajv, + 'ajv-formats': addFormats, + btoa, + atob, + lodash, + moment, + uuid, + nanoid, + axios, + chai, + 'node-fetch': fetch, + 'crypto-js': CryptoJS, + ...whitelistedModules, + fs: allowScriptFilesystemAccess ? fs : undefined, + 'node-vault': NodeVault + } } - } - }); - const asyncVM = vm.run(`module.exports = async () => { ${testsFile}}`, path.join(collectionPath, 'vm.js')); - await asyncVM(); + }); + const asyncVM = vm.run(`module.exports = async () => { ${testsFile}}`, path.join(collectionPath, 'vm.js')); + await asyncVM(); + } return { request, diff --git a/packages/bruno-js/src/sandbox/isolatedvm/utils/bundle-libraries.js b/packages/bruno-js/src/sandbox/bundle-libraries.js similarity index 84% rename from packages/bruno-js/src/sandbox/isolatedvm/utils/bundle-libraries.js rename to packages/bruno-js/src/sandbox/bundle-libraries.js index f909ec405..23c11c426 100644 --- a/packages/bruno-js/src/sandbox/isolatedvm/utils/bundle-libraries.js +++ b/packages/bruno-js/src/sandbox/bundle-libraries.js @@ -11,13 +11,13 @@ const bundleLibraries = async () => { import moment from "moment"; import btoa from "btoa"; import atob from "atob"; - global.expect = expect; - global.assert = assert; - global.moment = moment; - global.btoa = btoa; - global.atob = atob; - global.Buffer = Buffer; - global.requireObject = { + globalThis.expect = expect; + globalThis.assert = assert; + globalThis.moment = moment; + globalThis.btoa = btoa; + globalThis.atob = atob; + globalThis.Buffer = Buffer; + globalThis.requireObject = { 'chai': { expect, assert }, 'moment': moment, 'buffer': { Buffer }, @@ -54,7 +54,7 @@ const bundleLibraries = async () => { ] }, output: { - file: './src/bundle-browser-rollup.js', + file: './src/sandbox/bundle-browser-rollup.js', format: 'iife', name: 'MyBundle' } @@ -64,7 +64,7 @@ const bundleLibraries = async () => { const bundle = await rollup.rollup(config.input); const { output } = await bundle.generate(config.output); fs.writeFileSync( - './src/bundle-browser-rollup.js', + './src/sandbox/bundle-browser-rollup.js', ` const getBundledCode = () => { return function(){ diff --git a/packages/bruno-js/src/sandbox/isolatedvm/index.js b/packages/bruno-js/src/sandbox/isolatedvm/index.js index cb35a3024..db410d5d1 100644 --- a/packages/bruno-js/src/sandbox/isolatedvm/index.js +++ b/packages/bruno-js/src/sandbox/isolatedvm/index.js @@ -7,7 +7,7 @@ const addTestShimToContext = require('./shims/test'); const addLibraryShimsToContext = require('./shims/lib'); // execute `npm run build:isolated-vm:inbuilt-modules` if the below file doesn't exist -const getBundledCode = require('../../bundle-browser-rollup'); +const getBundledCode = require('../bundle-browser-rollup'); const addSleepShimToContext = require('./shims/sleep'); const toNumber = (value) => { diff --git a/packages/bruno-js/src/sandbox/quickjs/index.js b/packages/bruno-js/src/sandbox/quickjs/index.js new file mode 100644 index 000000000..dea71d525 --- /dev/null +++ b/packages/bruno-js/src/sandbox/quickjs/index.js @@ -0,0 +1,203 @@ +const ivm = require('isolated-vm'); +const addBruShimToContext = require('./shims/bru'); +const addBrunoRequestShimToContext = require('./shims/bruno-request'); +const addBrunoResponseShimToContext = require('./shims/bruno-response'); +const addTestShimToContext = require('./shims/test'); +const { newQuickJSAsyncWASMModule } = require('quickjs-emscripten'); + +// execute `npm run build:isolated-vm:inbuilt-modules` if the below file doesn't exist +const getBundledCode = require('../bundle-browser-rollup'); + +const toNumber = (value) => { + const num = Number(value); + return Number.isInteger(num) ? parseInt(value, 10) : parseFloat(value); +}; + +const executeQuickJsVm = ({ script: externalScript, context: externalContext }) => { + if (!isNaN(Number(externalScript))) { + return Number(externalScript); + } + let result; + const isolate = new ivm.Isolate(); + try { + const context = isolate.createContextSync(); + context.global.setSync('global', context.global.derefInto()); + + const { bru, req, res } = externalContext; + + context.evalSync(` + let bru = {}; + let req = {}; + let res = {}; + `); + + bru && addBruShimToContext(context, bru); + req && addBrunoRequestShimToContext(context, req); + res && addBrunoResponseShimToContext(context, res); + + context.global.setSync('setResult', function (arg) { + result = arg; + }); + + const templateLiteralText = ` + let value = \`${externalScript}\`; + setResult(value); + `; + + const jsExpressionText = ` + let value = ${externalScript}; + setResult(value); + `; + + let scriptText = scriptType === 'template-literal' ? templateLiteralText : jsExpressionText; + + const script = isolate.compileScriptSync(scriptText); + script.runSync(context); + return result; + } catch (error) { + console.error('Error executing the script!', error); + } + isolate.dispose(); +}; + +const executeQuickJsVmAsync = async ({ + script: externalScript, + context: externalContext +}) => { + if (!isNaN(Number(externalScript))) { + return toNumber(externalScript); + } + try { + const module = await newQuickJSAsyncWASMModule() + const runtime = module.newRuntime() + const vm = runtime.newContext() + + const bundledCode = getBundledCode?.toString() || ''; + let bundledScript = `(${bundledCode})()`; + + bundledScript += ` + globalThis.require = (module) => { + return globalThis.requireObject[module]; + } + `; + + bundledScript += ` + let bru = { + cwd: __bruno__cwd, + getEnvName: __bruno__getEnvName, + getProcessEnv: __bruno__getProcessEnv, + getEnvVar: __bruno__getEnvVar, + setEnvVar: __bruno__setEnvVar, + getVar: __bruno__getVar, + setVar: __bruno__setVar, + setNextRequest: __bruno__setNextRequest, + visualize: __bruno__visualize, + getSecretVar: __bruno__getSecretVar + }; + let req = { + url: __bruno__req__url, + method: __bruno__req__method, + headers: __bruno__req__headers, + body: __bruno__req__body, + timeout: __bruno__req__timeout, + getUrl: __bruno__req__getUrl, + setUrl: __bruno__req__setUrl, + getMethod: __bruno__req__getMethod, + setMethod: __bruno__req__setMethod, + getAuthMode: __bruno__req__getAuthMode, + getHeaders: __bruno__req__getHeaders, + setHeaders: __bruno__req__setHeaders, + getHeader: __bruno__req__getHeader, + setHeader: __bruno__req__setHeader, + getBody: __bruno__req__getBody, + setBody: __bruno__req__setBody, + setMaxRedirects: __bruno__req__setMaxRedirects, + getTimeout: __bruno__req__getTimeout, + setTimeout: __bruno__req__setTimeout + }; + let res = { + status: globalThis.__bruno__res__status, + headers: globalThis.__bruno__res__headers, + body: globalThis.__bruno__res__body, + responseTime: globalThis.__bruno__res__responseTime, + getStatus: globalThis.__bruno__res__getStatus, + getHeader: globalThis.__bruno__res__getHeader, + getHeaders: globalThis.__bruno__res__getHeaders, + getBody: globalThis.__bruno__res__getBody, + getResponseTime: globalThis.__bruno__res__getResponseTime + }; + `; + + const { bru, req, res, test, __brunoTestResults, console: consoleFn } = externalContext; + + bru && addBruShimToContext(vm, bru); + req && addBrunoRequestShimToContext(vm, req); + res && addBrunoResponseShimToContext(vm, res); + + test && __brunoTestResults && addTestShimToContext(vm, __brunoTestResults); + + bundledScript += ` + globalThis.expect = require('chai').expect; + globalThis.assert = require('chai').assert; + + globalThis.__brunoTestResults = { + addResult: globalThis.__bruno__addResult, + getResults: globalThis.__bruno__getResults, + } + + globalThis.DummyChaiAssertionError = class DummyChaiAssertionError extends Error { + constructor(message, props, ssf) { + super(message); + this.name = "AssertionError"; + Object.assign(this, props); + } + } + + globalThis.Test = (__brunoTestResults) => (description, callback) => { + try { + callback(); + __brunoTestResults.addResult({ description, status: "pass" }); + } catch (error) { + if (error instanceof DummyChaiAssertionError) { + const { message, actual, expected } = error; + __brunoTestResults.addResult({ + description, + status: "fail", + error: message, + actual, + expected, + }); + } else { + __brunoTestResults.addResult({ + description, + status: "fail", + error: error.message || "An unexpected error occurred.", + }); + } + // console.log(error); + } + }; + + globalThis.test = Test(__brunoTestResults); + `; + + bundledScript += externalScript; + + const result = await vm.evalCodeAsync(bundledScript); + if (result.error) { + console.log("Execution failed:", vm.dump(result.error)) + result.error.dispose() + } else { + result.value.dispose(); + } + vm.dispose(); + return result; + } catch (error) { + console.error('Error executing the script!', error); + } +}; + +module.exports = { + executeQuickJsVm, + executeQuickJsVmAsync +}; diff --git a/packages/bruno-js/src/sandbox/quickjs/shims/bru.js b/packages/bruno-js/src/sandbox/quickjs/shims/bru.js new file mode 100644 index 000000000..dd29c8435 --- /dev/null +++ b/packages/bruno-js/src/sandbox/quickjs/shims/bru.js @@ -0,0 +1,65 @@ +const { marshallToVm } = require('../utils'); + +const addBruShimToContext = (vm, bru) => { + let cwd = vm.newFunction('cwd', function () { + return marshallToVm(bru.cwd(), vm); + }); + vm.setProp(vm.global, "__bruno__cwd", cwd) + cwd.dispose(); + + let getEnvName = vm.newFunction('getEnvName', function () { + return marshallToVm(bru.getEnvName(), vm); + }); + vm.setProp(vm.global, "__bruno__getEnvName", getEnvName); + getEnvName.dispose(); + + let getProcessEnv = vm.newFunction('getProcessEnv', function (key) { + return marshallToVm(bru.getProcessEnv(vm.dump(key)), vm); + }); + vm.setProp(vm.global, "__bruno__getProcessEnv", getProcessEnv); + getProcessEnv.dispose(); + + let getEnvVar = vm.newFunction('getEnvVar', function (key) { + return marshallToVm(bru.getEnvVar(vm.dump(key)), vm); + }); + vm.setProp(vm.global, "__bruno__getEnvVar", getEnvVar); + getEnvVar.dispose(); + + let setEnvVar = vm.newFunction('setEnvVar', function (key, value) { + bru.setEnvVar(vm.dump(key), vm.dump(value)); + }); + vm.setProp(vm.global, "__bruno__setEnvVar", setEnvVar); + setEnvVar.dispose(); + + let getVar = vm.newFunction('getVar', function (key) { + return marshallToVm(bru.getVar(vm.dump(key)), vm); + }); + vm.setProp(vm.global, "__bruno__getVar", getVar); + getVar.dispose(); + + let setVar = vm.newFunction('setVar', function (key, value) { + bru.setVar(vm.dump(key), vm.dump(value)); + }); + vm.setProp(vm.global, "__bruno__setVar", setVar); + setVar.dispose(); + + let setNextRequest = vm.newFunction('setNextRequest', function (nextRequest) { + bru.setNextRequest(vm.dump(nextRequest)); + }); + vm.setProp(vm.global, "__bruno__setNextRequest", setNextRequest); + setNextRequest.dispose(); + + let visualize = vm.newFunction('visualize', function (htmlString) { + bru.visualize(vm.dump(htmlString)); + }); + vm.setProp(vm.global, "__bruno__visualize", visualize); + visualize.dispose(); + + let getSecretVar = vm.newFunction('getSecretVar', function (key) { + return marshallToVm(bru.getSecretVar(vm.dump(key)), vm); + }); + vm.setProp(vm.global, "__bruno__getSecretVar", getSecretVar); + getSecretVar.dispose(); +}; + +module.exports = addBruShimToContext; diff --git a/packages/bruno-js/src/sandbox/quickjs/shims/bruno-request.js b/packages/bruno-js/src/sandbox/quickjs/shims/bruno-request.js new file mode 100644 index 000000000..509097a25 --- /dev/null +++ b/packages/bruno-js/src/sandbox/quickjs/shims/bruno-request.js @@ -0,0 +1,107 @@ +const { marshallToVm } = require('../utils'); + +const addBrunoRequestShimToContext = (vm, req) => { + const url = marshallToVm(req.getUrl(), vm); + const method = marshallToVm(req.getMethod(), vm); + const headers = marshallToVm(req.getHeaders(), vm); + const body = marshallToVm(req.getBody(), vm); + const timeout = marshallToVm(req.getTimeout(), vm); + + vm.setProp(vm.global, '__bruno__req__url', url); + vm.setProp(vm.global, '__bruno__req__method', method); + vm.setProp(vm.global, '__bruno__req__headers', headers); + vm.setProp(vm.global, '__bruno__req__body', body); + vm.setProp(vm.global, '__bruno__req__timeout', timeout); + + url.dispose(); + method.dispose(); + headers.dispose(); + body.dispose(); + timeout.dispose(); + + let getUrl = vm.newFunction('getUrl', function () { + return marshallToVm(req.getUrl(), vm); + }); + vm.setProp(vm.global, '__bruno__req__getUrl', getUrl); + getUrl.dispose(); + + let setUrl = vm.newFunction('setUrl', function (url) { + req.setUrl(vm.dump(url)); + }); + vm.setProp(vm.global, '__bruno__req__setUrl', setUrl); + setUrl.dispose(); + + let getMethod = vm.newFunction('getMethod', function () { + return marshallToVm(req.getMethod(), vm); + }); + vm.setProp(vm.global, '__bruno__req__getMethod', getMethod); + getMethod.dispose(); + + let getAuthMode = vm.newFunction('getAuthMode', function () { + return marshallToVm(req.getAuthMode(), vm); + }); + vm.setProp(vm.global, '__bruno__req__getAuthMode', getAuthMode); + getAuthMode.dispose(); + + let setMethod = vm.newFunction('setMethod', function (method) { + req.setMethod(vm.dump(method)); + }); + vm.setProp(vm.global, '__bruno__req__setMethod', setMethod); + setMethod.dispose(); + + let getHeaders = vm.newFunction('getHeaders', function () { + return marshallToVm(req.getHeaders(), vm); + }); + vm.setProp(vm.global, '__bruno__req__getHeaders', getHeaders); + getHeaders.dispose(); + + let setHeaders = vm.newFunction('setHeaders', function (headers) { + req.setHeaders(vm.dump(headers)); + }); + vm.setProp(vm.global, '__bruno__req__setHeaders', setHeaders); + setHeaders.dispose(); + + let getHeader = vm.newFunction('getHeader', function (name) { + return marshallToVm(req.getHeader(vm.dump(name)), vm); + }); + vm.setProp(vm.global, '__bruno__req__getHeader', getHeader); + getHeader.dispose(); + + let setHeader = vm.newFunction('setHeader', function (name, value) { + req.setHeader(vm.dump(name), vm.dump(value)); + }); + vm.setProp(vm.global, '__bruno__req__setHeader', setHeader); + setHeader.dispose(); + + let getBody = vm.newFunction('getBody', function () { + return marshallToVm(req.getBody(), vm); + }); + vm.setProp(vm.global, '__bruno__req__getBody', getBody); + getBody.dispose(); + + let setBody = vm.newFunction('setBody', function (data) { + req.setBody(vm.dump(data)); + }); + vm.setProp(vm.global, '__bruno__req__setBody', setBody); + setBody.dispose(); + + let setMaxRedirects = vm.newFunction('setMaxRedirects', function (maxRedirects) { + req.setMaxRedirects(vm.dump(maxRedirects)); + }); + vm.setProp(vm.global, '__bruno__req__setMaxRedirects', setMaxRedirects); + setMaxRedirects.dispose(); + + let getTimeout = vm.newFunction('getTimeout', function () { + return marshallToVm(req.getTimeout(), vm); + }); + vm.setProp(vm.global, '__bruno__req__getTimeout', getTimeout); + getTimeout.dispose(); + + let setTimeout = vm.newFunction('setTimeout', function (timeout) { + req.setTimeout(vm.dump(timeout)); + }); + vm.setProp(vm.global, '__bruno__req__setTimeout', setTimeout); + setTimeout.dispose(); +}; + +module.exports = addBrunoRequestShimToContext; diff --git a/packages/bruno-js/src/sandbox/quickjs/shims/bruno-response.js b/packages/bruno-js/src/sandbox/quickjs/shims/bruno-response.js new file mode 100644 index 000000000..c7909b2c6 --- /dev/null +++ b/packages/bruno-js/src/sandbox/quickjs/shims/bruno-response.js @@ -0,0 +1,51 @@ + +const { marshallToVm } = require('../utils'); + +const addBrunoResponseShimToContext = (vm, res) => { + const status = marshallToVm(res?.status, vm); + const headers = marshallToVm(res?.headers, vm); + const body = marshallToVm(res?.body, vm); + const responseTime = marshallToVm(res?.responseTime, vm); + + vm.setProp(vm.global, '__bruno__res__status', status); + vm.setProp(vm.global, '__bruno__res__headers', headers); + vm.setProp(vm.global, '__bruno__res__body', body); + vm.setProp(vm.global, '__bruno__res__responseTime', responseTime); + + status.dispose(); + headers.dispose(); + body.dispose(); + responseTime.dispose(); + + let getStatus = vm.newFunction('getStatus', function () { + return marshallToVm(res.getStatus(), vm); + }); + vm.setProp(vm.global, '__bruno__res__getStatus', getStatus); + getStatus.dispose(); + + let getHeader = vm.newFunction('getHeader', function (name) { + return marshallToVm(res.getHeader(vm.dump(name)), vm); + }); + vm.setProp(vm.global, '__bruno__res__getHeader', getHeader); + getHeader.dispose(); + + let getHeaders = vm.newFunction('getHeaders', function () { + return marshallToVm(res.getHeaders(), vm); + }); + vm.setProp(vm.global, '__bruno__res__getHeaders', getHeaders); + getHeaders.dispose(); + + let getBody = vm.newFunction('getBody', function () { + return marshallToVm(res.getBody(), vm); + }); + vm.setProp(vm.global, '__bruno__res__getBody', getBody); + getBody.dispose(); + + let getResponseTime = vm.newFunction('getResponseTime', function () { + return marshallToVm(res.getResponseTime(), vm); + }); + vm.setProp(vm.global, '__bruno__res__getResponseTime', getResponseTime); + getResponseTime.dispose(); +}; + +module.exports = addBrunoResponseShimToContext; diff --git a/packages/bruno-js/src/sandbox/quickjs/shims/test.js b/packages/bruno-js/src/sandbox/quickjs/shims/test.js new file mode 100644 index 000000000..38d2971a6 --- /dev/null +++ b/packages/bruno-js/src/sandbox/quickjs/shims/test.js @@ -0,0 +1,17 @@ +const { marshallToVm } = require('../utils'); + +const addBruShimToContext = (vm, __brunoTestResults) => { + let addResult = vm.newFunction('addResult', function (v) { + __brunoTestResults.addResult(vm.dump(v)); + }); + vm.setProp(vm.global, "__bruno__addResult", addResult); + addResult.dispose(); + + let getResults = vm.newFunction('getResults', function () { + return marshallToVm(__brunoTestResults.getResults(), vm); + }); + vm.setProp(vm.global, "__bruno__getResults", getResults); + getResults.dispose(); +}; + +module.exports = addBruShimToContext; diff --git a/packages/bruno-js/src/sandbox/quickjs/utils/index.js b/packages/bruno-js/src/sandbox/quickjs/utils/index.js new file mode 100644 index 000000000..22ea7d922 --- /dev/null +++ b/packages/bruno-js/src/sandbox/quickjs/utils/index.js @@ -0,0 +1,35 @@ +const marshallToVm = (value, vm) => { + if (value === undefined) { + return vm.undefined; + } + + if (value === null) { + return vm.null; + } + + if (typeof value === "string") { + return vm.newString(value); + } else if (typeof value === "number") { + return vm.newNumber(value); + } else if (typeof value === "boolean") { + return vm.newBoolean(value); + } else if (typeof value === "object") { + if (Array.isArray(value)) { + const arr = vm.newArray(); + for (let i = 0; i < value.length; i++) { + vm.setProp(arr, i, marshallToVm(value[i], vm)); + } + return arr; + } else { + const obj = vm.newObject(); + for (const key in value) { + vm.setProp(obj, key, marshallToVm(value[key], vm)); + } + return obj; + } + } +}; + +module.exports = { + marshallToVm +}; diff --git a/packages/bruno-tests/collection/environments/Prod.bru b/packages/bruno-tests/collection/environments/Prod.bru index 7f4bf5d5f..4bea1e77a 100644 --- a/packages/bruno-tests/collection/environments/Prod.bru +++ b/packages/bruno-tests/collection/environments/Prod.bru @@ -8,6 +8,3 @@ vars { foo: bar testSetEnvVar: bruno-29653 } -vars:secret [ - bruno -] diff --git a/packages/bruno-tests/collection/ping.bru b/packages/bruno-tests/collection/ping.bru index bbefac464..3abc7a2d4 100644 --- a/packages/bruno-tests/collection/ping.bru +++ b/packages/bruno-tests/collection/ping.bru @@ -9,52 +9,3 @@ get { body: none auth: none } - -auth:awsv4 { - accessKeyId: a - secretAccessKey: b - sessionToken: c - service: d - region: e - profileName: f -} - -vars:pre-request { - m4: true - pong: pong -} - -assert { - res.status: eq 200 - res.responseTime: lte 2000 - res.body: eq {{pong}} -} - -tests { - test("should ping pong", function() { - const data = res.getBody(); - expect(data).to.equal(bru.getRequestVar("pong")); - }); -} - -docs { - # API Documentation - - ## Introduction - - Welcome to the API documentation for [Your API Name]. This document provides instructions on how to make requests to the API and covers available authentication methods. - - ## Authentication - - Before making requests to the API, you need to authenticate your application. [Your API Name] supports the following authentication methods: - - ### API Key - - To use API key authentication, include your API key in the request headers as follows: - - ```http - GET /api/endpoint - Host: api.example.com - Authorization: Bearer YOUR_API_KEY - -} diff --git a/packages/bruno-tests/collection/scripting/api/bru/getEnvName.bru b/packages/bruno-tests/collection/scripting/api/bru/getEnvName.bru index f05052508..4e7c37ec3 100644 --- a/packages/bruno-tests/collection/scripting/api/bru/getEnvName.bru +++ b/packages/bruno-tests/collection/scripting/api/bru/getEnvName.bru @@ -10,7 +10,6 @@ get { auth: none } - script:pre-request { const envName = bru.getEnvName(); bru.setVar("testEnvName", envName); @@ -21,4 +20,4 @@ tests { const testEnvName = bru.getVar("testEnvName"); expect(testEnvName).to.equal("Prod"); }); -} \ No newline at end of file +} diff --git a/packages/bruno-tests/collection/scripting/api/bru/setVar.bru b/packages/bruno-tests/collection/scripting/api/bru/setVar.bru index cfd701dcd..a155117c9 100644 --- a/packages/bruno-tests/collection/scripting/api/bru/setVar.bru +++ b/packages/bruno-tests/collection/scripting/api/bru/setVar.bru @@ -10,7 +10,6 @@ get { auth: none } - script:post-response { bru.setVar("testSetVar", "bruno-test-87267") } @@ -20,4 +19,4 @@ tests { const testSetVar = bru.getVar("testSetVar"); expect(testSetVar).to.equal("bruno-test-87267"); }); -} \ No newline at end of file +} diff --git a/packages/bruno-tests/collection/scripting/api/req/getUrl.bru b/packages/bruno-tests/collection/scripting/api/req/getUrl.bru index 3b044b85b..155a40b7a 100644 --- a/packages/bruno-tests/collection/scripting/api/req/getUrl.bru +++ b/packages/bruno-tests/collection/scripting/api/req/getUrl.bru @@ -10,7 +10,6 @@ get { auth: none } - assert { res.status: eq 200 res.body: eq pong @@ -21,4 +20,4 @@ tests { const url = req.getUrl(); expect(url).to.equal("https://testbench-sanity.usebruno.com/ping"); }); -} \ No newline at end of file +}