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>
92 lines
2.6 KiB
Plaintext
92 lines
2.6 KiB
Plaintext
meta {
|
|
name: node-crypto
|
|
type: http
|
|
seq: 12
|
|
}
|
|
|
|
get {
|
|
url: {{host}}/ping
|
|
body: none
|
|
auth: none
|
|
}
|
|
|
|
script:pre-request {
|
|
// Skip in safe mode - these tests require developer sandbox
|
|
if (bru.isSafeMode()) {
|
|
bru.runner.skipRequest();
|
|
return;
|
|
}
|
|
}
|
|
|
|
tests {
|
|
const crypto = require('node:crypto');
|
|
|
|
test("crypto.randomBytes", function() {
|
|
const bytes = crypto.randomBytes(16);
|
|
expect(Buffer.isBuffer(bytes)).to.equal(true);
|
|
expect(bytes.length).to.equal(16);
|
|
});
|
|
|
|
test("crypto.randomUUID", function() {
|
|
const uuid = crypto.randomUUID();
|
|
expect(uuid).to.match(/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/);
|
|
});
|
|
|
|
test("crypto.createHash", function() {
|
|
const md5 = crypto.createHash('md5').update('hello').digest('hex');
|
|
expect(md5).to.have.lengthOf(32);
|
|
|
|
const sha256 = crypto.createHash('sha256').update('hello').digest('hex');
|
|
expect(sha256).to.have.lengthOf(64);
|
|
|
|
const sha512 = crypto.createHash('sha512').update('hello').digest('hex');
|
|
expect(sha512).to.have.lengthOf(128);
|
|
});
|
|
|
|
test("crypto.createHmac", function() {
|
|
const hmac = crypto.createHmac('sha256', 'secret').update('hello').digest('hex');
|
|
expect(hmac).to.have.lengthOf(64);
|
|
});
|
|
|
|
test("crypto.getHashes and crypto.getCiphers", function() {
|
|
const hashes = crypto.getHashes();
|
|
expect(hashes).to.be.an('array').that.includes('sha256');
|
|
|
|
const ciphers = crypto.getCiphers();
|
|
expect(ciphers).to.be.an('array');
|
|
expect(ciphers.some(c => c.includes('aes'))).to.equal(true);
|
|
});
|
|
|
|
test("crypto.pbkdf2Sync", function() {
|
|
const key = crypto.pbkdf2Sync('password', 'salt', 1000, 32, 'sha256');
|
|
expect(key.length).to.equal(32);
|
|
});
|
|
|
|
test("crypto.scryptSync", function() {
|
|
const key = crypto.scryptSync('password', 'salt', 32);
|
|
expect(key.length).to.equal(32);
|
|
});
|
|
|
|
test("crypto.timingSafeEqual", function() {
|
|
const a = Buffer.from('hello');
|
|
const b = Buffer.from('hello');
|
|
const c = Buffer.from('world');
|
|
expect(crypto.timingSafeEqual(a, b)).to.equal(true);
|
|
expect(crypto.timingSafeEqual(a, c)).to.equal(false);
|
|
});
|
|
|
|
test("AES encryption/decryption", function() {
|
|
const key = crypto.randomBytes(32);
|
|
const iv = crypto.randomBytes(16);
|
|
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
|
|
let encrypted = cipher.update('secret message', 'utf8', 'hex');
|
|
encrypted += cipher.final('hex');
|
|
|
|
const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
|
|
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
|
|
decrypted += decipher.final('utf8');
|
|
|
|
expect(decrypted).to.equal('secret message');
|
|
});
|
|
}
|