Skip to content

fix: handle additional context root paths for node-vm#6491

Merged
bijin-bruno merged 3 commits intousebruno:mainfrom
lohit-bruno:node_vm_paths_fix
Dec 23, 2025
Merged

fix: handle additional context root paths for node-vm#6491
bijin-bruno merged 3 commits intousebruno:mainfrom
lohit-bruno:node_vm_paths_fix

Conversation

@lohit-bruno
Copy link
Collaborator

@lohit-bruno lohit-bruno commented Dec 23, 2025

Description

Contribution Checklist:

  • I've used AI significantly to create this pull request
  • The pull request only addresses one issue or adds one feature.
  • The pull request does not introduce any breaking changes
  • I have added screenshots or gifs to help explain the change if applicable.
  • I have read the contribution guidelines.
  • Create an issue and link to the pull request.

Note: Keeping the PR small and focused helps make it easier to review and merge. If you have multiple changes you want to make, please consider submitting them as separate pull requests.

Publishing to New Package Managers

Please see here for more information.

Summary by CodeRabbit

  • New Features

    • Support for additional context roots and Windows-style path formats when resolving local modules.
  • Bug Fixes

    • Strengthened validation of allowed context roots to prevent out-of-root access.
    • Improved, actionable error messages that list permitted roots and suggest configuration options.
  • Tests

    • New tests covering local module resolution, cross-platform paths, access control, caching, and failure cases.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 23, 2025

Walkthrough

Compute and normalize absolute additional context roots (always include collectionPath), normalize module names for Windows separators, pass normalized roots through the custom require/load flow, validate resolved local-module paths against all allowed roots and throw detailed errors when outside, and add Jest tests covering these behaviors.

Changes

Cohort / File(s) Summary
Security-Enhanced Module Resolution
packages/bruno-js/src/sandbox/node-vm/index.js
Normalize scriptingConfig.additionalContextRoots into additionalContextRootsAbsolute (absolute paths including collectionPath); normalize module names (convert backslashes to forward slashes) for local-module detection; pass additionalContextRootsAbsolute into loadLocalModule and createCustomRequire; verify resolved local paths are within any allowed root and throw errors listing allowed roots when access is outside. JSDoc updated to reflect new parameter.
Comprehensive Test Suite
packages/bruno-js/src/sandbox/node-vm/index.spec.js
New Jest tests: require via ./ and ../, Windows backslash handling, blocking access outside collectionPath, loading from additionalContextRoots (relative & absolute), npm resolution (lodash), and module caching behavior. Test setup/teardown uses temporary directories.

Sequence Diagram(s)

sequenceDiagram
    actor Script
    participant VM as node-vm Sandbox
    participant Resolver as Module Resolver
    participant Validator as Context Validator
    participant FS as Filesystem

    Script->>VM: execute script / call require('name')
    VM->>Resolver: resolveModule(name, requesterPath, additionalContextRootsAbsolute)
    Resolver->>Resolver: normalize name (backslashes → forward slashes)
    alt local path (./, ../, or backslash form)
        Resolver->>Validator: toAbsolutePath(normalized, requesterPath)
        rect rgb(235,245,255)
            Note over Validator: Check absolute path against allowed roots
            Validator->>Validator: compare against collectionPath + additionalContextRootsAbsolute
        end
        alt allowed
            Validator->>FS: read file / load module
            FS-->>Resolver: module exports
        else blocked
            Validator-->>Resolver: throw Error(listAllowedRoots + hint about additionalContextRoots)
        end
    else non-local (npm or builtin)
        Resolver->>FS: standard node resolution (node_modules)
        FS-->>Resolver: module exports
    end
    Resolver-->>VM: module exports or error
    VM-->>Script: return value or throw
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested labels

size/XS

Suggested reviewers

  • helloanoop
  • naman-bruno
  • bijin-bruno

"Paths are folded into absolute light,
Slashes tamed for Windows' night,
Roots declared and checks applied,
Errors list the bounds they hide,
Tests applaud the sandboxed rite."

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: handling additional context root paths for node-vm, which aligns with the core modifications to security checks, module loading, and path normalization in the implementation.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@lohit-bruno lohit-bruno changed the title fix: handle additional context root paths for node vm fix: handle additional context root paths for node-vm Dec 23, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (4)
packages/bruno-js/src/sandbox/node-vm/index.js (3)

203-215: Redundant normalization on line 204.

additionalContextRootsAbsolute entries are already normalized at lines 123-126. The path.normalize(allowedRoot) call on line 204 is redundant.

🔎 Proposed simplification
  const isWithinAllowedRoot = additionalContextRootsAbsolute.some((allowedRoot) => {
-   const normalizedAllowedRoot = path.normalize(allowedRoot);
-   const relativePath = path.relative(normalizedAllowedRoot, normalizedFilePath);
+   const relativePath = path.relative(allowedRoot, normalizedFilePath);
    return !relativePath.startsWith('..') && !path.isAbsolute(relativePath);
  });

187-194: JSDoc incomplete: missing @throws for out-of-root access.

The JSDoc at line 185 mentions throwing when "module is outside collection path," but the actual error message now references "allowed context roots." Consider updating the JSDoc to reflect this.

🔎 Proposed JSDoc update
- * @throws {Error} When module is outside collection path or cannot be loaded
+ * @throws {Error} When module is outside allowed context roots or cannot be loaded

243-250: Nested createCustomRequire recomputes additionalContextRootsAbsolute on each local module load.

This is inefficient for deeply nested local imports. Consider passing the already-computed additionalContextRootsAbsolute array to avoid redundant path resolution and normalization on every nested require.

🔎 Proposed fix

First, update loadLocalModule to receive the computed roots:

  function loadLocalModule({
    moduleName,
    collectionPath,
    scriptContext,
    localModuleCache,
    currentModuleDir,
-   additionalContextRootsAbsolute = []
+   additionalContextRootsAbsolute = [],
+   scriptingConfig
  }) {

Then update the nested createCustomRequire:

    require: createCustomRequire({
-     scriptingConfig: scriptContext.scriptingConfig || {},
+     scriptingConfig: scriptingConfig,
      collectionPath,
      scriptContext,
      currentModuleDir: moduleDir,
      localModuleCache,
-     allowScriptFilesystemAccess: get(scriptContext.scriptingConfig, 'filesystemAccess.allow', false)
+     allowScriptFilesystemAccess: get(scriptingConfig, 'filesystemAccess.allow', false)
    })

And pass scriptingConfig from loadLocalModule call site at line 132.

packages/bruno-js/src/sandbox/node-vm/index.spec.js (1)

186-209: Caching test doesn't truly verify caching behavior.

The test writes a static module with count: 1 and checks mod1.count === mod2.count. This will always be true since the file content is fixed. The test doesn't verify that the module code executed only once.

A more robust test would use a side-effect (e.g., incrementing a counter in context) to prove the module wasn't re-executed.

🔎 Suggested improvement
it('should cache loaded modules', async () => {
  fs.writeFileSync(
    path.join(collectionPath, 'cached.js'),
    `
    bru.incrementCount();
    module.exports = { loaded: true };
    `
  );

  let loadCount = 0;
  const context = {
    bru: {
      setVar: jest.fn(),
      incrementCount: () => { loadCount++; }
    },
    console: console
  };

  const script = `
    const mod1 = require('./cached');
    const mod2 = require('./cached');
    bru.setVar('same', mod1 === mod2);
  `;

  await runScriptInNodeVm({ script, context, collectionPath, scriptingConfig: {} });

  expect(loadCount).toBe(1); // Module executed only once
  expect(context.bru.setVar).toHaveBeenCalledWith('same', true);
});
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4831434 and 80d7c5e.

📒 Files selected for processing (2)
  • packages/bruno-js/src/sandbox/node-vm/index.js
  • packages/bruno-js/src/sandbox/node-vm/index.spec.js
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (CODING_STANDARDS.md)

**/*.{js,jsx,ts,tsx}: Use 2 spaces for indentation. No tabs, just spaces
Stick to single quotes for strings. For JSX/TSX attributes, use double quotes (e.g., )
Always add semicolons at the end of statements
No trailing commas
Always use parentheses around parameters in arrow functions, even for single params
For multiline constructs, put opening braces on the same line, and ensure consistency. Minimum 2 elements for multiline
No newlines inside function parentheses
Space before and after the arrow in arrow functions. () => {} is good
No space between function name and parentheses. func() not func ()
Semicolons go at the end of the line, not on a new line
Names for functions need to be concise and descriptive
Add in JSDoc comments to add more details to the abstractions if needed
Add in meaningful comments instead of obvious ones where complex code flow is explained properly

Files:

  • packages/bruno-js/src/sandbox/node-vm/index.spec.js
  • packages/bruno-js/src/sandbox/node-vm/index.js
🧠 Learnings (3)
📚 Learning: 2025-12-05T20:31:33.005Z
Learnt from: CR
Repo: usebruno/bruno PR: 0
File: CODING_STANDARDS.md:0-0
Timestamp: 2025-12-05T20:31:33.005Z
Learning: Applies to **/*.test.{js,jsx,ts,tsx} : Add tests for any new functionality or meaningful changes. If code is added, removed, or significantly modified, corresponding tests should be updated or created

Applied to files:

  • packages/bruno-js/src/sandbox/node-vm/index.spec.js
📚 Learning: 2025-12-16T07:16:23.647Z
Learnt from: sanish-bruno
Repo: usebruno/bruno PR: 6090
File: tests/scripting/hooks/init-user-data/ui-state-snapshot.json:1-8
Timestamp: 2025-12-16T07:16:23.647Z
Learning: For e2e tests in the bruno repository: Collections that are shared between CLI and UI tests (comprehensive test suites testing core functionality) should be placed in `packages/bruno-tests/` to avoid duplication. The `tests/**/fixtures/collection` pattern should be used for test-specific collections that test particular UI behaviors or are specific to a single test file.

Applied to files:

  • packages/bruno-js/src/sandbox/node-vm/index.spec.js
📚 Learning: 2025-12-17T21:41:24.730Z
Learnt from: naman-bruno
Repo: usebruno/bruno PR: 6407
File: packages/bruno-app/src/components/Environments/ConfirmCloseEnvironment/index.js:5-41
Timestamp: 2025-12-17T21:41:24.730Z
Learning: Do not suggest PropTypes validation for React components in the Bruno codebase. The project does not use PropTypes, so reviews should avoid proposing PropTypes and rely on the existing typing/validation approach (e.g., TypeScript or alternative runtime checks) if applicable. This guideline applies broadly to all JavaScript/JSX components in the repo.

Applied to files:

  • packages/bruno-js/src/sandbox/node-vm/index.spec.js
  • packages/bruno-js/src/sandbox/node-vm/index.js
🧬 Code graph analysis (1)
packages/bruno-js/src/sandbox/node-vm/index.js (4)
packages/bruno-js/src/sandbox/node-vm/index.spec.js (2)
  • path (3-3)
  • collectionPath (9-9)
packages/bruno-cli/src/runner/run-single-request.js (1)
  • path (19-19)
packages/bruno-electron/src/ipc/network/index.js (2)
  • path (3-3)
  • collectionPath (338-338)
packages/bruno-cli/src/commands/run.js (2)
  • path (3-3)
  • collectionPath (295-295)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Playwright E2E Tests
  • GitHub Check: Unit Tests
  • GitHub Check: CLI Tests
  • GitHub Check: SSL Tests - macOS
  • GitHub Check: SSL Tests - Windows
  • GitHub Check: SSL Tests - Linux
🔇 Additional comments (5)
packages/bruno-js/src/sandbox/node-vm/index.js (1)

129-133: LGTM - Windows path normalization is correct.

The normalization to forward slashes before checking for ./ and ../ prefixes properly handles cross-platform path separators. This ensures local module detection works on Windows.

packages/bruno-js/src/sandbox/node-vm/index.spec.js (4)

11-21: LGTM - Good test isolation with temp directories.

Proper setup and teardown using mkdtempSync and rmSync ensures tests don't pollute each other or leave artifacts. Clean pattern for filesystem-based testing.


74-94: LGTM - Windows backslash test is well-designed.

The double-escaped backslash in the script string ('.\\\\module') correctly simulates how a Windows path would appear in a JavaScript string. Good cross-platform coverage.


167-183: LGTM - npm module loading test is appropriate.

Testing that lodash.get is a function confirms the require resolution through module.paths works correctly.


96-106: Add test for symlink-based path traversal escapes.

The path validation uses path.normalize() and path.relative() but does not resolve symlinks with fs.realpathSync(). A symlink created inside the collection directory pointing outside can bypass the boundary check. For example, a symlink at collection/link → /outside/file would pass validation (appears to be within collection) but the actual loaded module is outside the sandbox.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
packages/bruno-js/src/sandbox/node-vm/index.js (1)

121-126: Security gap: nested createCustomRequire recomputes allowed roots instead of inheriting them.

The nested createCustomRequire call at line 244 derives additionalContextRootsAbsolute from scriptContext.scriptingConfig || {} rather than accepting the already-computed and validated array. If scriptContext.scriptingConfig differs or is manipulated, nested modules could load from unexpected paths.

Pass additionalContextRootsAbsolute as an explicit parameter to createCustomRequire and propagate it to nested calls.

🔎 Proposed fix

Update createCustomRequire signature to accept pre-computed roots:

 function createCustomRequire({
   scriptingConfig,
   collectionPath,
   scriptContext,
   currentModuleDir = collectionPath,
   localModuleCache = new Map(),
-  allowScriptFilesystemAccess = false
+  allowScriptFilesystemAccess = false,
+  additionalContextRootsAbsolute = null
 }) {
-  const additionalContextRoots = get(scriptingConfig, 'additionalContextRoots', []);
-  const additionalContextRootsAbsolute = lodash
-    .chain(additionalContextRoots)
-    .map((acr) => (path.isAbsolute(acr) ? acr : path.join(collectionPath, acr)))
-    .map((acr) => path.normalize(acr))
-    .value();
-  additionalContextRootsAbsolute.push(path.normalize(collectionPath));
+  if (additionalContextRootsAbsolute === null) {
+    const additionalContextRoots = get(scriptingConfig, 'additionalContextRoots', []);
+    additionalContextRootsAbsolute = lodash
+      .chain(additionalContextRoots)
+      .map((acr) => (path.isAbsolute(acr) ? acr : path.join(collectionPath, acr)))
+      .map((acr) => path.normalize(acr))
+      .value();
+    additionalContextRootsAbsolute.push(path.normalize(collectionPath));
+  }

Then pass it through in nested call at line 244:

     require: createCustomRequire({
       scriptingConfig: scriptContext.scriptingConfig || {},
       collectionPath,
       scriptContext,
       currentModuleDir: moduleDir,
       localModuleCache,
-      allowScriptFilesystemAccess: get(scriptContext.scriptingConfig, 'filesystemAccess.allow', false)
+      allowScriptFilesystemAccess: get(scriptContext.scriptingConfig, 'filesystemAccess.allow', false),
+      additionalContextRootsAbsolute
     })

Also applies to: 244-251

🧹 Nitpick comments (1)
packages/bruno-js/src/sandbox/node-vm/index.js (1)

204-216: Solid security check with clear error messaging.

The containment check using path.relative correctly identifies when a file path escapes allowed roots. The !path.isAbsolute(relativePath) guard handles Windows cross-drive scenarios.

Minor note: Line 205 re-normalizes allowedRoot, but these are already normalized at line 124. You could remove the redundant normalization, but it's harmless.

🔎 Optional: Remove redundant normalization
   const isWithinAllowedRoot = additionalContextRootsAbsolute.some((allowedRoot) => {
-    const normalizedAllowedRoot = path.normalize(allowedRoot);
-    const relativePath = path.relative(normalizedAllowedRoot, normalizedFilePath);
+    const relativePath = path.relative(allowedRoot, normalizedFilePath);
     return !relativePath.startsWith('..') && !path.isAbsolute(relativePath);
   });
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 80d7c5e and 5623c1b.

📒 Files selected for processing (2)
  • packages/bruno-js/src/sandbox/node-vm/index.js
  • packages/bruno-js/src/sandbox/node-vm/index.spec.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/bruno-js/src/sandbox/node-vm/index.spec.js
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (CODING_STANDARDS.md)

**/*.{js,jsx,ts,tsx}: Use 2 spaces for indentation. No tabs, just spaces
Stick to single quotes for strings. For JSX/TSX attributes, use double quotes (e.g., )
Always add semicolons at the end of statements
No trailing commas
Always use parentheses around parameters in arrow functions, even for single params
For multiline constructs, put opening braces on the same line, and ensure consistency. Minimum 2 elements for multiline
No newlines inside function parentheses
Space before and after the arrow in arrow functions. () => {} is good
No space between function name and parentheses. func() not func ()
Semicolons go at the end of the line, not on a new line
Names for functions need to be concise and descriptive
Add in JSDoc comments to add more details to the abstractions if needed
Add in meaningful comments instead of obvious ones where complex code flow is explained properly

Files:

  • packages/bruno-js/src/sandbox/node-vm/index.js
🧠 Learnings (1)
📚 Learning: 2025-12-17T21:41:24.730Z
Learnt from: naman-bruno
Repo: usebruno/bruno PR: 6407
File: packages/bruno-app/src/components/Environments/ConfirmCloseEnvironment/index.js:5-41
Timestamp: 2025-12-17T21:41:24.730Z
Learning: Do not suggest PropTypes validation for React components in the Bruno codebase. The project does not use PropTypes, so reviews should avoid proposing PropTypes and rely on the existing typing/validation approach (e.g., TypeScript or alternative runtime checks) if applicable. This guideline applies broadly to all JavaScript/JSX components in the repo.

Applied to files:

  • packages/bruno-js/src/sandbox/node-vm/index.js
🧬 Code graph analysis (1)
packages/bruno-js/src/sandbox/node-vm/index.js (4)
packages/bruno-js/src/sandbox/node-vm/index.spec.js (2)
  • path (3-3)
  • collectionPath (9-9)
packages/bruno-cli/src/runner/run-single-request.js (1)
  • path (19-19)
packages/bruno-electron/src/ipc/network/index.js (2)
  • path (3-3)
  • collectionPath (338-338)
packages/bruno-cli/src/commands/run.js (2)
  • path (3-3)
  • collectionPath (295-295)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Unit Tests
  • GitHub Check: Playwright E2E Tests
  • GitHub Check: CLI Tests
  • GitHub Check: SSL Tests - macOS
  • GitHub Check: SSL Tests - Windows
  • GitHub Check: SSL Tests - Linux
🔇 Additional comments (2)
packages/bruno-js/src/sandbox/node-vm/index.js (2)

129-133: Good cross-platform path handling.

Normalizing backslashes to forward slashes before the local module check ensures Windows-style paths (.\foo or ..\bar) are correctly identified as local modules. The normalized name is then passed through to loadLocalModule.


188-195: LGTM - parameter addition is well documented.

The additionalContextRootsAbsolute parameter with [] default ensures deny-by-default behavior when no roots are provided. This is a safe default.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
packages/bruno-js/src/sandbox/node-vm/index.spec.js (1)

226-251: Test validates caching but setup has a subtle issue.

The callCount increment happens at test setup time (when writeFileSync is called), not at module execution time. The test still validates caching correctly (same object reference via mod1.count === mod2.count), but the intent seems to be testing that the module code is executed only once. The current test logic works, but the callCount variable is unused after the initial assignment.

🔎 Consider simplifying the test
  describe('createCustomRequire - module caching', () => {
    it('should cache loaded modules', async () => {
-     let callCount = 0;
      fs.writeFileSync(
        path.join(collectionPath, 'cached.js'),
-       `
-       module.exports = { count: ${++callCount} };
-       `
+       'module.exports = { count: 1 };'
      );

      const script = `
        const mod1 = require('./cached');
        const mod2 = require('./cached');
-       bru.setVar('same', mod1.count === mod2.count);
+       bru.setVar('same', mod1 === mod2);
      `;
packages/bruno-js/src/sandbox/node-vm/index.js (1)

168-176: Consider handling the case where additionalContextRootsAbsolute is empty.

The error message template handles the empty case with || ' - No "additionalContextRoots" defined', but since collectionPath is always pushed (line 48), the array should never be empty in practice. The fallback text is misleading because it suggests no roots are defined when collectionPath is always included.

🔎 Consider updating fallback message
-      throw new Error(`Could not resolve module "${moduleName}": ${requireError.message}\n\nThis most likely means you did not install the module under the collection or the "additionalContextRoots" using a package manager like npm.\n\nThese are your current "additionalContextRoots":\n${additionalContextRootsAbsolute.map((root) => `  - ${root}`).join('\n') || '  - No "additionalContextRoots" defined'}`);
+      throw new Error(`Could not resolve module "${moduleName}": ${requireError.message}\n\nThis most likely means you did not install the module under the collection or the "additionalContextRoots" using a package manager like npm.\n\nThese are your current allowed context roots:\n${additionalContextRootsAbsolute.map((root) => `  - ${root}`).join('\n')}`);
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5623c1b and 1f9b104.

📒 Files selected for processing (2)
  • packages/bruno-js/src/sandbox/node-vm/index.js
  • packages/bruno-js/src/sandbox/node-vm/index.spec.js
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (CODING_STANDARDS.md)

**/*.{js,jsx,ts,tsx}: Use 2 spaces for indentation. No tabs, just spaces
Stick to single quotes for strings. For JSX/TSX attributes, use double quotes (e.g., )
Always add semicolons at the end of statements
No trailing commas
Always use parentheses around parameters in arrow functions, even for single params
For multiline constructs, put opening braces on the same line, and ensure consistency. Minimum 2 elements for multiline
No newlines inside function parentheses
Space before and after the arrow in arrow functions. () => {} is good
No space between function name and parentheses. func() not func ()
Semicolons go at the end of the line, not on a new line
Names for functions need to be concise and descriptive
Add in JSDoc comments to add more details to the abstractions if needed
Add in meaningful comments instead of obvious ones where complex code flow is explained properly

Files:

  • packages/bruno-js/src/sandbox/node-vm/index.spec.js
  • packages/bruno-js/src/sandbox/node-vm/index.js
🧠 Learnings (3)
📚 Learning: 2025-12-05T20:31:33.005Z
Learnt from: CR
Repo: usebruno/bruno PR: 0
File: CODING_STANDARDS.md:0-0
Timestamp: 2025-12-05T20:31:33.005Z
Learning: Applies to **/*.test.{js,jsx,ts,tsx} : Add tests for any new functionality or meaningful changes. If code is added, removed, or significantly modified, corresponding tests should be updated or created

Applied to files:

  • packages/bruno-js/src/sandbox/node-vm/index.spec.js
📚 Learning: 2025-12-16T07:16:23.647Z
Learnt from: sanish-bruno
Repo: usebruno/bruno PR: 6090
File: tests/scripting/hooks/init-user-data/ui-state-snapshot.json:1-8
Timestamp: 2025-12-16T07:16:23.647Z
Learning: For e2e tests in the bruno repository: Collections that are shared between CLI and UI tests (comprehensive test suites testing core functionality) should be placed in `packages/bruno-tests/` to avoid duplication. The `tests/**/fixtures/collection` pattern should be used for test-specific collections that test particular UI behaviors or are specific to a single test file.

Applied to files:

  • packages/bruno-js/src/sandbox/node-vm/index.spec.js
📚 Learning: 2025-12-17T21:41:24.730Z
Learnt from: naman-bruno
Repo: usebruno/bruno PR: 6407
File: packages/bruno-app/src/components/Environments/ConfirmCloseEnvironment/index.js:5-41
Timestamp: 2025-12-17T21:41:24.730Z
Learning: Do not suggest PropTypes validation for React components in the Bruno codebase. The project does not use PropTypes, so reviews should avoid proposing PropTypes and rely on the existing typing/validation approach (e.g., TypeScript or alternative runtime checks) if applicable. This guideline applies broadly to all JavaScript/JSX components in the repo.

Applied to files:

  • packages/bruno-js/src/sandbox/node-vm/index.spec.js
  • packages/bruno-js/src/sandbox/node-vm/index.js
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: SSL Tests - Windows
  • GitHub Check: SSL Tests - Linux
  • GitHub Check: SSL Tests - macOS
  • GitHub Check: Playwright E2E Tests
  • GitHub Check: CLI Tests
  • GitHub Check: Unit Tests
🔇 Additional comments (16)
packages/bruno-js/src/sandbox/node-vm/index.spec.js (10)

1-6: LGTM!

Imports are clean and appropriate for the test file. Using node:fs would be more consistent with the implementation file, but this is a minor nit.


11-21: LGTM!

Good test hygiene with proper setup/teardown using temporary directories. The fs.rmSync with recursive: true, force: true ensures clean teardown even if tests fail.


24-44: LGTM!

Well-structured test for basic local module loading via ./ path. The test correctly validates that the custom require function resolves and loads local modules.


46-72: LGTM!

Good test for nested module resolution with ../ paths. This validates the parent directory traversal and nested require chains work correctly.


74-96: LGTM!

Important cross-platform test for Windows-style backslash handling. The double-escaped backslashes in the script string are correct for testing backslash normalization.


98-108: LGTM!

Critical security test ensuring access outside allowed context roots is properly blocked. The error message assertion matches the implementation.


111-139: LGTM!

This test addresses the previous review concern. The test now correctly uses ../shared/shared to traverse from collection to testDir then into the shared directory, which is properly allowed via additionalContextRoots.


141-167: LGTM!

Good test validating that relative paths in additionalContextRoots are resolved correctly against collectionPath.


169-205: LGTM!

Important test for nested module chains accessing additional context roots. This validates that the additionalContextRootsAbsolute is correctly propagated through nested createCustomRequire calls.


208-224: LGTM!

Good coverage for npm module loading. Using lodash (already a project dependency) is pragmatic.

packages/bruno-js/src/sandbox/node-vm/index.js (6)

41-48: LGTM!

Clean computation of absolute context roots. The lodash chain normalizes relative paths against collectionPath and always includes collectionPath itself. This ensures consistent root handling.


85-93: LGTM!

The pre-computed additionalContextRootsAbsolute is now passed directly to createCustomRequire, addressing the previous review concern about recomputation.


123-138: LGTM!

Good cross-platform handling. Normalizing backslashes to forward slashes before the local module check ensures Windows paths work correctly. The additionalContextRootsAbsolute parameter is properly passed through.


192-220: LGTM!

The security check correctly validates that the resolved file path is within at least one of the allowed roots. Using path.relative and checking for .. prefix is a robust approach. The error message is informative, listing all allowed roots.


248-256: Previous review concern addressed.

The nested createCustomRequire now receives additionalContextRootsAbsolute directly as a parameter instead of recomputing it from scriptContext.scriptingConfig. This ensures consistent allowed roots across nested module loads.

Note: Line 254 still reads allowScriptFilesystemAccess from scriptContext.scriptingConfig, which is slightly inconsistent with passing additionalContextRootsAbsolute directly. However, this is acceptable since filesystemAccess.allow is a simple boolean that doesn't require the same normalization logic.


159-159: Module resolution priority is intentional for sandboxed context.

The path order [...additionalContextRootsAbsolute, ...module.paths] at line 159 is deliberate design for Bruno's sandboxed scripting environment. The collection path and additional context roots are explicitly prioritized to support isolated script execution within collections. This behavior is tested, documented in error messages, and aligns with the sandboxed VM context (line 80: vm.runInNewContext). Local module shadowing of npm packages is expected and supports collection-scoped dependencies.

Likely an incorrect or invalid review comment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants