mirror of
https://github.com/usebruno/bruno.git
synced 2026-06-22 12:15:38 +00:00
* fix(node-vm): scripting context and module resolution issues Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(node-vm): use vm.createContext for true isolation and fix prototype mismatches - Replace vm.compileFunction with vm.createContext + runInContext for true isolation - Remove ECMAScript built-ins from safeGlobals (VM provides its own versions) - This fixes prototype chain mismatches that broke libraries like @faker-js/faker - Add sanitized process object (allows env, blocks exit/kill) - Add global/globalThis pointing to isolated context (not host) - Extract safe globals to constants.js for maintainability - Remove typed-arrays mixin (VM provides TypedArrays) - Add comprehensive isolation tests Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(node-vm): remove process, add Error types and TypedArrays mixin, add jose test - Remove process object from script context (security hardening) - Remove createSanitizedProcess function from constants.js - Add Error types to safeGlobals for instanceof checks with host errors - Add TypedArrays mixin for host API compatibility (TextEncoder, crypto, Buffer) - Add jose library and test for JWT sign/verify functionality - Update tests to reflect process removal Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(node-vm): handle circular dependencies and failed module caching - Pre-populate module cache before execution to support circular requires - Cache moduleObj instead of moduleObj.exports to handle module.exports reassignment - Remove failed modules from cache to allow retry - Add test for circular dependency handling Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(node-vm): spread all context properties in buildScriptContext Instead of explicitly listing each context property, spread all properties from the context input to support future additions. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(node-vm): add filtered process object to script context Expose a sanitized process object with only safe read-only properties (argv, version, arch, platform, pid, features) while keeping env empty for security. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * test(node-vm): add comprehensive tests for Node.js builtins Add 18 test files for Node.js builtin APIs in developer sandbox mode: - Buffer, URL, TextEncoder/TextDecoder, btoa/atob - Web Crypto API and node:crypto module - Timers (setTimeout, setInterval, setImmediate, queueMicrotask) - Fetch API (Request, Response, Headers, FormData, Blob) - Intl formatters, JSON, Events (Event, EventTarget, CustomEvent) - Node modules: fs, path, os, util, stream, zlib, querystring All tests skip in safe mode using bru.runner.skipRequest(). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(node-vm): address CodeRabbit review feedback - Block absolute paths from bypassing security by routing through loadLocalModule - Fix process tests to expect sanitized object instead of undefined - Fix cache test to verify module executes only once - Add tests for absolute path handling (block outside, allow within roots) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: lint issues * fix(node-vm): recontextualize host objects for cross-context deep equality Objects passed from the host context into the Node VM have different Object/Array constructors than objects created inside the VM. This breaks deep equality checks in libraries like AJV, where fast-deep-equal fails on `a.constructor !== b.constructor` for structurally identical objects. Add recontextualizeScript to utils.js that wraps getter methods (res.getBody, res.getHeaders, req.getBody, req.getHeaders, req.getPathParams, req.getTags, bru.getVar) to JSON round-trip returned objects inside the VM, giving them VM-native prototypes. Add external-lib-with-bru-req-res-objects package and tests to verify bru/req/res accessibility from npm modules. Update ajv.bru tests to validate res.getBody() against AJV schemas with enum on nested objects. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(node-vm): update spec to use saved mock refs after recontextualize The recontextualizeScript wraps res.getBody with a JSON round-trip function, replacing the jest mock on the context object. Save mock references before calling runScriptInNodeVm so assertions work. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(node-vm): shallow-copy mutable process properties in sandbox process.argv, process.versions, and process.features were passed by reference, allowing sandboxed scripts to mutate the host process. Shallow-copy these properties to prevent leaking mutable references. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(node-vm): use recursive clone in toVMNative instead of JSON round-trip JSON.stringify converts undefined to null in arrays, breaking tests like res.setBody([..., undefined, ...]). Replace with recursive clone that creates new VM-native objects/arrays while preserving undefined values. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor(node-vm): generalize recontextualize to wrap all bru/req/res methods Instead of hardcoding specific method names, walk the prototype chain with Object.getOwnPropertyNames to discover and wrap all methods that return Objects/Arrays. Async methods (sendRequest, runRequest) get their resolved values wrapped. The res callable and res.body/res.headers are also recontextualized for direct access and query usage. Adds integration tests for VM-native prototype checks across res, req, bru APIs, res() callable queries, and bru.sendRequest patterns. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * revert(node-vm): remove recontextualizeScript and related tests The recontextualize approach of wrapping all bru/req/res methods to return VM-native objects is being reverted in favor of a different solution to the cross-context prototype mismatch issue. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(node-vm): expose full process object in developer sandbox via safeGlobals * test(node-vm): update process tests for full process object in developer sandbox * test(node-vm): update spec to verify process.nextTick availability --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
84 lines
3.1 KiB
Plaintext
84 lines
3.1 KiB
Plaintext
meta {
|
|
name: additional context root
|
|
type: http
|
|
seq: 4
|
|
}
|
|
|
|
post {
|
|
url: {{host}}/api/echo/json
|
|
body: json
|
|
auth: none
|
|
}
|
|
|
|
body:json {
|
|
{
|
|
"test": "additionalContextRoot"
|
|
}
|
|
}
|
|
|
|
assert {
|
|
res.status: eq 200
|
|
}
|
|
|
|
script:pre-request {
|
|
// Load module from additionalContextRoot using relative path
|
|
// This tests that modules outside the collection can be loaded when configured in bruno.json
|
|
// The path "../additional-context-root-lib" is allowed because it's listed in additionalContextRoots
|
|
const additionalLib = require('../additional-context-root-lib');
|
|
|
|
// Verify all dependencies loaded correctly
|
|
const deps = additionalLib.verifyDependencies();
|
|
bru.setVar('fakerLoaded', deps.fakerLoaded);
|
|
bru.setVar('localModuleLoaded', deps.localModuleLoaded);
|
|
|
|
// Test the utility functions
|
|
const user = additionalLib.generateUser();
|
|
bru.setVar('hasFirstName', typeof user.firstName === 'string' && user.firstName.length > 0);
|
|
bru.setVar('hasLastName', typeof user.lastName === 'string' && user.lastName.length > 0);
|
|
bru.setVar('hasFullName', typeof user.fullName === 'string' && user.fullName.includes(' '));
|
|
bru.setVar('hasGreeting', typeof user.greeting === 'string' && user.greeting.startsWith('Hello, '));
|
|
bru.setVar('hasEmail', typeof user.email === 'string' && user.email.includes('@'));
|
|
|
|
// Test direct functions from local module
|
|
const formatted = additionalLib.formatName('John', 'Doe');
|
|
bru.setVar('formatNameResult', formatted);
|
|
|
|
const greeting = additionalLib.generateGreeting('Bruno');
|
|
bru.setVar('greetingResult', greeting);
|
|
|
|
// Test direct require of a specific file from additionalContextRoot
|
|
const libDirect = require('../additional-context-root-lib/lib.js');
|
|
bru.setVar('directRequireWorks', typeof libDirect.formatName === 'function');
|
|
bru.setVar('directFormatName', libDirect.formatName('Direct', 'Test'));
|
|
bru.setVar('directGreeting', libDirect.generateGreeting('World'));
|
|
}
|
|
|
|
tests {
|
|
test("should load module from additionalContextRoot", function() {
|
|
expect(bru.getVar('fakerLoaded')).to.equal(true);
|
|
expect(bru.getVar('localModuleLoaded')).to.equal(true);
|
|
});
|
|
|
|
test("should resolve npm module (@faker-js/faker) from collection node_modules", function() {
|
|
expect(bru.getVar('hasFirstName')).to.equal(true);
|
|
expect(bru.getVar('hasLastName')).to.equal(true);
|
|
expect(bru.getVar('hasEmail')).to.equal(true);
|
|
});
|
|
|
|
test("should resolve local module (./lib.js) relative to additionalContextRoot", function() {
|
|
expect(bru.getVar('hasFullName')).to.equal(true);
|
|
expect(bru.getVar('hasGreeting')).to.equal(true);
|
|
});
|
|
|
|
test("should correctly execute local module functions", function() {
|
|
expect(bru.getVar('formatNameResult')).to.equal('John Doe');
|
|
expect(bru.getVar('greetingResult')).to.equal('Hello, Bruno!');
|
|
});
|
|
|
|
test("should directly require specific file from additionalContextRoot", function() {
|
|
expect(bru.getVar('directRequireWorks')).to.equal(true);
|
|
expect(bru.getVar('directFormatName')).to.equal('Direct Test');
|
|
expect(bru.getVar('directGreeting')).to.equal('Hello, World!');
|
|
});
|
|
}
|