Skip to content

Conversation

@frontegg-david
Copy link
Contributor

@frontegg-david frontegg-david commented Jan 5, 2026

Summary by CodeRabbit

  • New Features

    • Memory tracking and enforcement with peak usage stats and structured limit errors
    • Exposed memory-tracking utilities and expanded sandbox globals
    • Optional strict proxy behavior to throw on blocked property access
  • Bug Fixes

    • Corrected JavaScript + semantics for addition/concatenation and template literals
    • Improved worker queue and memory recycling behavior
  • Tests

    • Extensive unit/integration suites for memory, worker pools, double-VM, and security
  • Chores

    • ESLint ignores expanded to skip test/spec files and dist

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

@frontegg-david
Copy link
Contributor Author

frontegg-david commented Jan 5, 2026

Snyk checks have passed. No issues have been found so far.

Status Scanner Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Code Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@coderabbitai
Copy link

coderabbitai bot commented Jan 5, 2026

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

Adds end-to-end memory tracking and enforcement across Enclave: new MemoryTracker and sizing helpers, tracked String/Array proxies and AST transforms, runtime integrations in safe runtime, single/worker/double-VM adapters, worker-slot/script adjustments, secure-proxy throw-on-blocked behavior, and extensive test updates.

Changes

Cohort / File(s) Summary
Config & Exports
eslint.config.mjs, libs/enclave-vm/src/index.ts
ESLint ignores expanded to exclude spec/test paths; memory-tracker APIs exported publicly.
Memory Tracking Core
libs/enclave-vm/src/memory-tracker.ts, libs/enclave-vm/src/memory-proxy.ts
New MemoryTracker, MemoryLimitError, sizing helpers, and tracked String/Array factories/method wrappers that account allocations and can throw on limit breach. Review size estimators and error semantics.
AST Transforms
libs/ast-guard/src/transforms/concat.transform.ts
Two-pass transform to avoid rewriting TemplateLiterals used by tag functions (collect+skip set). Check tag-safety and location preservation.
Safe Runtime Integration
libs/enclave-vm/src/safe-runtime.ts, libs/enclave-vm/src/memory-proxy.ts
safe runtime accepts optional memoryTracker; __safe_concat/__safe_template and provided globals use tracked constructors when enabled. Verify constructor wrapping and concatenation semantics.
Enclave Codepath
libs/enclave-vm/src/enclave.ts
New applyMemoryTrackingTransforms(code) and conditional transform application when memoryLimit>0 and no sidecar. Validate transform insertion point.
VM Adapters & Double-VM
libs/enclave-vm/src/adapters/vm-adapter.ts, libs/enclave-vm/src/double-vm/double-vm-wrapper.ts, libs/enclave-vm/src/double-vm/parent-vm-bootstrap.ts
MemoryTracker created/passed into runtimes, peak memory recorded in stats, MemoryLimitError special-cased in responses; parent bootstrap gains memoryLimit/throwOnBlocked options and inner concat semantics updated. Inspect error shaping and stats wiring.
Worker Pool & Worker Script
libs/enclave-vm/src/adapters/worker-pool/* (e.g., worker-slot.ts,worker-script.ts,worker-pool-adapter.ts,memory-monitor.ts,execution-queue.ts)
Worker init only adds --max-old-space-size when limit>0; worker script path resolution improved for test envs; sandbox globals expanded (prefixed + unprefixed), awaiting optional __ag_main; markForRecycle() signature simplified and call sites updated; memory-monitor recycling signaling adjusted. Check worker lifecycle and compatibility.
Secure Proxy & Types
libs/enclave-vm/src/secure-proxy.ts, libs/enclave-vm/src/types.ts
Added throwOnBlocked option (defaults true in config); proxy traps may now throw Security errors instead of returning undefined for blocked accesses; SECURITY_LEVEL_CONFIGS updated. Review throwing semantics and cache-key variation.
Tests
libs/enclave-vm/src/__tests__/* (notable: memory-limit.spec.ts, worker-pool-adapter.spec.ts, safe-runtime-reference.spec.ts, many security specs)
Large test additions/updates: memory-tracking tests, worker/double-VM memory scenarios, and many security tests updated to expect thrown "Security violation" errors or adjusted concatenation semantics. Review skipped/conditional tests and Node-version notes.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant U as User Code
    participant E as Enclave
    participant T as MemoryTracker
    participant R as SafeRuntime
    participant V as VM (worker/double)

    U->>E: execute(code, options{memoryLimit})
    E->>T: create/start (if memoryLimit>0)
    E->>E: applyMemoryTrackingTransforms(code) (if no sidecar)
    E->>R: createSafeRuntime({memoryTracker: T})
    R->>V: run(user code in VM)
    V->>T: report allocations (strings/arrays) during execution
    alt limit exceeded
        T-->>V: throw MemoryLimitError
        V-->>E: propagate structured MEMORY_LIMIT_EXCEEDED error
    else within limit
        V-->>E: return result
    end
    E->>T: getSnapshot()
    T-->>E: peakTrackedBytes
    E-->>U: {result, stats: {memoryUsage}}
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 I nibble bytes with careful paws,

I count each string and heed the laws.
When arrays grow and limits call,
I hop and halt to save them all.
Safe enclosures—springtime for code!

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 accurately describes the main change: implementing memory tracking and limit enforcement for VM execution, which is the primary focus of the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

📜 Recent 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 c1bdf38 and e975c21.

📒 Files selected for processing (2)
  • libs/enclave-vm/src/secure-proxy.ts
  • libs/enclave-vm/src/types.ts

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

Copy link

@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

Fix all issues with AI Agents 🤖
In @libs/enclave-vm/src/enclave.ts:
- Line 98: Update the JSDoc for the memoryLimit property in types.ts to reflect
the new default of 1MB (1 * 1024 * 1024) instead of 128MB, explicitly note that
this change was intentional and is a breaking change for users upgrading from
prior versions, and add a short entry to the project release notes or migration
guide documenting the change and pointing out that memoryLimitPerWorker in the
worker pool still defaults to 128MB (so users should adjust that separately if
needed); locate the memoryLimit JSDoc near the memoryLimit property declaration
in types.ts and update the default value text and add a one-line breaking-change
note, then add the release-notes entry referencing the tests (e.g.,
memory-limit.spec.ts) that confirm the 1MB default.

In @libs/enclave-vm/src/index.ts:
- Around line 105-114: Add a dedicated API section for the Memory Tracker
exports (MemoryTracker, MemoryLimitError, MemoryTrackerConfig,
MemoryUsageSnapshot, estimateStringSize, estimateArraySize, estimateObjectSize)
in the docs: document each symbol’s purpose and TypeScript signature, list
configuration options available on MemoryTrackerConfig, show concise examples
for instantiating MemoryTracker, recording/tracking objects, requesting
snapshots (MemoryUsageSnapshot) and handling MemoryLimitError, and include short
usage snippets demonstrating the size estimator helpers and common patterns
(start/stop, snapshot comparison, and error handling).

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
libs/enclave-vm/src/adapters/worker-pool/worker-slot.ts (1)

242-248: Public API breaking change: markForRecycle parameter removal requires documentation update.

WorkerSlot is exported as public API, and removing the reason parameter from markForRecycle() is a breaking change for external consumers. Per the coding guidelines for libs/**, public API changes must include matching documentation updates in docs/draft/docs/**, which are currently missing. All internal call sites are compatible with the new signature.

🧹 Nitpick comments (8)
eslint.config.mjs (1)

8-8: Consider linting test files with relaxed rules instead of excluding them entirely.

Excluding all test and spec files from linting may miss legitimate issues (e.g., incorrect assertions, unused variables in tests). A common alternative is to keep tests linted but with relaxed rules for test-specific patterns.

If this is intentional to reduce noise from test-specific patterns, this is acceptable.

libs/enclave-vm/src/adapters/worker-pool/worker-slot.ts (1)

175-191: Path detection may match unintended directories.

The check __dirname.includes('/src/') could match paths containing /src/ in other locations (e.g., /some-src/ or nested paths like /node_modules/@scope/src/). Consider using a more precise pattern.

🔎 Proposed fix for more precise path matching
-    // Check if we're running from src (ts-jest tests)
-    if (__dirname.includes('/src/')) {
-      // Replace /src/ with /dist/src/ to find compiled JS
-      const distPath = __dirname.replace('/src/', '/dist/src/');
+    // Check if we're running from src (ts-jest tests)
+    // Match /src/ only when it's followed by adapters/worker-pool (our expected path)
+    if (__dirname.includes('/src/adapters/worker-pool')) {
+      // Replace /src/ with /dist/src/ to find compiled JS
+      const distPath = __dirname.replace('/src/', '/dist/src/');
       return path.join(distPath, 'worker-script.js');
     }
libs/enclave-vm/src/__tests__/worker-pool-adapter.spec.ts (3)

79-95: Missing cleanup in async test.

This test creates an enclave but doesn't dispose it in a finally block. If the test fails, the worker pool won't be cleaned up, potentially causing resource leaks or interference with other tests.

🔎 Proposed fix to add cleanup
     it('should execute async code with await', async () => {
       const toolHandler: ToolHandler = async () => {
         await new Promise((r) => setTimeout(r, 10));
         return { done: true };
       };

       const enclave = createWorkerEnclave({ toolHandler });
-      const result = await enclave.run(`
-        async function __ag_main() {
-          const response = await callTool('asyncOp', {});
-          return response.done ? 'async complete' : 'failed';
-        }
-      `);
-
-      expect(result.success).toBe(true);
-      expect(result.value).toBe('async complete');
+      try {
+        const result = await enclave.run(`
+          async function __ag_main() {
+            const response = await callTool('asyncOp', {});
+            return response.done ? 'async complete' : 'failed';
+          }
+        `);
+
+        expect(result.success).toBe(true);
+        expect(result.value).toBe('async complete');
+      } finally {
+        enclave.dispose();
+      }
     });

97-109: Missing cleanup in error handling test.

Same issue - enclave not disposed in finally block.


111-133: Missing cleanup in multiple tests.

Several tests in this block (should return primitives correctly) don't dispose the enclave. Consider extracting a shared enclave instance with beforeEach/afterEach or wrapping each test in try/finally.

libs/enclave-vm/src/__tests__/memory-limit.spec.ts (1)

344-346: Fragile Node.js version detection.

Parsing the version string with slice(1).split('.')[0] works but could fail with unexpected version formats. Consider using process.versions.node or a more robust parser.

🔎 Proposed fix for more robust version parsing
-  const nodeVersion = parseInt(process.version.slice(1).split('.')[0], 10);
-  const skipDueToNodeVersion = nodeVersion >= 24;
+  // Parse major version more robustly
+  const nodeVersion = parseInt(process.versions.node.split('.')[0], 10);
+  const skipDueToNodeVersion = Number.isNaN(nodeVersion) || nodeVersion >= 24;
libs/enclave-vm/src/memory-proxy.ts (1)

176-185: Pre-check in repeat() uses incorrect size estimation.

The pre-check calculates estimateStringSize(this) * count, but estimateStringSize already includes the 40-byte overhead per string. The actual result is one string with this.length * count characters, so the size should be this.length * count * 2 + 40, not (this.length * 2 + 40) * count.

This causes the pre-check to over-estimate, which is conservative (may reject valid operations) but not a correctness issue.

🔎 Proposed fix for accurate size estimation
     repeat: function (this: string, count: number) {
       // Pre-check to avoid allocating before tracking
-      const estimatedSize = estimateStringSize(this) * count;
+      // Result is one string with (this.length * count) characters
+      const estimatedSize = this.length * count * 2 + 40;
       if (tracker.getLimit() > 0 && estimatedSize > tracker.getLimit()) {
         tracker.track(estimatedSize); // This will throw
       }
       const result = originalRepeat.call(this, count);
       tracker.trackString(result);
       return result;
     },
libs/enclave-vm/src/memory-tracker.ts (1)

258-263: formatBytes doesn't handle edge cases.

Negative values would display incorrectly (e.g., -1024 would show as -1024B instead of being formatted). This is likely fine since trackedBytes should never be negative, but consider adding a guard.

📜 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 6b58618 and 64df806.

📒 Files selected for processing (19)
  • eslint.config.mjs
  • libs/ast-guard/src/transforms/concat.transform.ts
  • libs/enclave-vm/src/__tests__/memory-limit.spec.ts
  • libs/enclave-vm/src/__tests__/safe-runtime-reference.spec.ts
  • libs/enclave-vm/src/__tests__/worker-pool-adapter.spec.ts
  • libs/enclave-vm/src/adapters/vm-adapter.ts
  • libs/enclave-vm/src/adapters/worker-pool/execution-queue.ts
  • libs/enclave-vm/src/adapters/worker-pool/memory-monitor.ts
  • libs/enclave-vm/src/adapters/worker-pool/worker-pool-adapter.ts
  • libs/enclave-vm/src/adapters/worker-pool/worker-script.ts
  • libs/enclave-vm/src/adapters/worker-pool/worker-slot.ts
  • libs/enclave-vm/src/double-vm/double-vm-wrapper.ts
  • libs/enclave-vm/src/double-vm/parent-vm-bootstrap.ts
  • libs/enclave-vm/src/enclave.ts
  • libs/enclave-vm/src/index.ts
  • libs/enclave-vm/src/memory-proxy.ts
  • libs/enclave-vm/src/memory-tracker.ts
  • libs/enclave-vm/src/safe-runtime.ts
  • libs/enclave-vm/src/types.ts
🧰 Additional context used
📓 Path-based instructions (1)
libs/**

⚙️ CodeRabbit configuration file

libs/**: Contains publishable SDK libraries. Review for API correctness, breaking changes, and consistency with docs. When public APIs change, ensure there is a matching docs/draft/docs/** update (not direct edits under docs/docs/**).

Files:

  • libs/ast-guard/src/transforms/concat.transform.ts
  • libs/enclave-vm/src/adapters/vm-adapter.ts
  • libs/enclave-vm/src/safe-runtime.ts
  • libs/enclave-vm/src/index.ts
  • libs/enclave-vm/src/types.ts
  • libs/enclave-vm/src/enclave.ts
  • libs/enclave-vm/src/__tests__/memory-limit.spec.ts
  • libs/enclave-vm/src/memory-tracker.ts
  • libs/enclave-vm/src/__tests__/worker-pool-adapter.spec.ts
  • libs/enclave-vm/src/__tests__/safe-runtime-reference.spec.ts
  • libs/enclave-vm/src/memory-proxy.ts
  • libs/enclave-vm/src/adapters/worker-pool/memory-monitor.ts
  • libs/enclave-vm/src/double-vm/double-vm-wrapper.ts
  • libs/enclave-vm/src/adapters/worker-pool/worker-pool-adapter.ts
  • libs/enclave-vm/src/double-vm/parent-vm-bootstrap.ts
  • libs/enclave-vm/src/adapters/worker-pool/execution-queue.ts
  • libs/enclave-vm/src/adapters/worker-pool/worker-slot.ts
  • libs/enclave-vm/src/adapters/worker-pool/worker-script.ts
🧬 Code graph analysis (3)
libs/enclave-vm/src/enclave.ts (1)
libs/ast-guard/src/transforms/concat.transform.ts (2)
  • transformConcatenation (65-116)
  • transformTemplateLiterals (131-200)
libs/enclave-vm/src/__tests__/memory-limit.spec.ts (2)
libs/enclave-vm/src/index.ts (4)
  • MemoryTracker (107-107)
  • estimateStringSize (111-111)
  • estimateArraySize (112-112)
  • MemoryLimitError (108-108)
libs/enclave-vm/src/memory-tracker.ts (4)
  • MemoryTracker (126-264)
  • estimateStringSize (70-75)
  • estimateArraySize (87-91)
  • MemoryLimitError (40-58)
libs/enclave-vm/src/memory-proxy.ts (2)
libs/enclave-vm/src/index.ts (2)
  • MemoryTracker (107-107)
  • estimateStringSize (111-111)
libs/enclave-vm/src/memory-tracker.ts (3)
  • MemoryTracker (126-264)
  • start (144-148)
  • estimateStringSize (70-75)
🔇 Additional comments (42)
libs/ast-guard/src/transforms/concat.transform.ts (1)

137-153: LGTM! Correctly preserves tagged template expressions.

The two-pass approach properly identifies and skips tagged templates (e.g., html`...`), which must pass the raw template to the tag function rather than be transformed into __safe_template__ calls. Using a Set with direct node references is efficient and correct since acorn-walk traverses the same AST objects.

libs/enclave-vm/src/adapters/worker-pool/memory-monitor.ts (2)

10-11: LGTM!

Import cleanup is consistent with the simplified markForRecycle() signature.


156-162: LGTM!

The simplified markForRecycle() call aligns with the updated signature in worker-slot.ts. The memory-exceeded event is still emitted (Line 158) before marking for recycle, so the reason is communicated through the event system rather than the method parameter.

libs/enclave-vm/src/adapters/worker-pool/worker-script.ts (4)

141-147: LGTM!

The wrapped code correctly calls __ag_main() if defined, aligning with the Enclave's AST transformation that wraps user code in an async __ag_main function. The fallback to undefined when __ag_main is not defined is appropriate.


292-296: LGTM!

Exposing console under both __safe_console and console provides backward compatibility while supporting the AST transformer's prefixed naming convention.


311-316: LGTM!

Adding __safe_ prefixed error types enables the AST transformer to rewrite error constructor references while still allowing the sandbox to resolve them correctly.


298-334: Memory tracking is handled differently in the worker pool adapter and does not require memory-tracked constructors.

The worker pool uses OS-level memory limiting via the --max-old-space-size Node.js flag (set in worker-slot.ts:155) combined with external RSS-based monitoring in MemoryMonitor, rather than the memory-tracked proxy approach used in the VM adapter. The memoryLimit configuration is intentionally not serialized and passed to workers—it controls the worker process heap limit instead. This architectural choice differs from the VM adapter but is appropriate for the worker pool's OS-level isolation model.

libs/enclave-vm/src/double-vm/parent-vm-bootstrap.ts (4)

47-49: LGTM!

Adding memoryLimit to ParentVmBootstrapOptions enables memory-aware code generation for the double-VM path.


196-198: LGTM!

The memoryLimit constant is correctly emitted into the generated bootstrap code, making it available at runtime for memory tracking decisions.


508-527: LGTM! Numeric addition fast path and incremental memory tracking.

The numeric addition fast path (Lines 509-512) correctly follows JavaScript + semantics. For string concatenation, tracking only rightLen * 2 bytes is correct for incremental tracking since the left operand's memory was already accounted for in prior operations.


574-584: __host_memory_track__ is properly injected into parent VM context.

The function is defined in double-vm-wrapper.ts via Object.defineProperty() on the parent context, with appropriate handling for both enabled and disabled memory tracking scenarios.

libs/enclave-vm/src/adapters/worker-pool/execution-queue.ts (1)

152-155: LGTM!

Replacing the length pre-check with a direct shift() followed by an undefined guard is safer and eliminates the non-null assertion (!). The behavior remains identical while being more defensive.

libs/enclave-vm/src/types.ts (2)

391-399: Documentation clearly explains memory tracking semantics.

The expanded documentation for memoryUsage effectively communicates that this is an estimation based on allocation tracking (String/Array), not actual V8 heap usage. The guidance about using worker_threads for precise isolation is helpful.


434-443: Documentation clearly explains memoryLimit enforcement.

The documentation properly describes that memoryLimit enables allocation tracking rather than V8 heap limits, notes the overhead (~5-10%), and provides appropriate guidance for precise isolation via worker_threads.

libs/enclave-vm/src/adapters/vm-adapter.ts (4)

361-374: Memory tracker initialization is correct.

The conditional creation of MemoryTracker when memoryLimit > 0 is appropriate. The configuration disables object tracking (line 369) which is a reasonable optimization given the noted overhead. The call to start() on line 374 properly initiates tracking before execution.


382-382: Memory tracker correctly passed to safe runtime.

Passing the memoryTracker to createSafeRuntime enables allocation monitoring within the sandbox, which is the correct integration point for memory tracking.


475-479: Memory usage captured in both success and error paths.

The implementation correctly captures peak tracked memory in both success (lines 475-479) and error (lines 493-497) paths, ensuring stats are complete regardless of execution outcome.

Also applies to: 493-497


499-514: MemoryLimitError handling provides good error context.

The special-case handling for MemoryLimitError returns a structured error with:

  • Descriptive name and message
  • Error code MEMORY_LIMIT_EXCEEDED
  • Data with usedBytes and limitBytes

This provides clear actionable information for debugging memory limit issues.

libs/enclave-vm/src/__tests__/safe-runtime-reference.spec.ts (1)

53-66: Tests correctly validate JavaScript + operator semantics.

The updated test cases properly verify that __safe_concat follows JavaScript's + operator behavior when no sidecar is configured:

  • Numeric addition: 1 + 2 === 3
  • Boolean coercion: true + false === 1
  • Null/undefined: null + undefined === NaN
  • String concatenation with numbers ✓

This aligns with the implementation described in the relevant code snippets from safe-runtime.ts.

libs/enclave-vm/src/enclave.ts (2)

323-327: Memory tracking transform logic is correct.

The conditional application of memory tracking transforms is well-structured:

  • Applied only when memoryLimit > 0 (line 323)
  • Applied only when no sidecar is configured (avoids duplicate transforms)
  • Follows the same pattern as sidecar transforms (lines 321-322)

460-486: Memory tracking transform implementation is sound.

The applyMemoryTrackingTransforms method correctly:

  • Parses code into AST (lines 471-474)
  • Applies concatenation transform (line 478)
  • Applies template literal transform (line 482)
  • Regenerates code (line 485)

The implementation pattern mirrors applySidecarTransforms (lines 497-522), ensuring consistency.

libs/enclave-vm/src/adapters/worker-pool/worker-pool-adapter.ts (3)

188-192: State change handler correctly updated for new signature.

The handler now receives only newState (line 188), matching the updated event signature described in the AI summary. The recycling check on line 189 works correctly with the single parameter.


243-243: markForRecycle() called with simplified signature.

The call to markForRecycle() without a reason parameter aligns with the simplified API mentioned in the AI summary. This removes unused metadata while preserving the recycling trigger functionality.


276-299: handleMemoryExceeded simplified appropriately.

The method signature now takes only slotId (line 276), removing unused usage and limit parameters. The implementation correctly:

  • Retrieves the slot (line 277)
  • Checks if executing (line 281)
  • Increments termination counter (line 282)
  • Terminates and cleans up (lines 283-297)
libs/enclave-vm/src/adapters/worker-pool/worker-slot.ts (1)

153-159: LGTM - Conditional memory flag for Node.js 24+ compatibility.

Good fix for handling Node.js 24+ stricter worker permissions. The conditional check ensures backward compatibility with earlier versions while avoiding failures on newer runtimes.

libs/enclave-vm/src/__tests__/worker-pool-adapter.spec.ts (1)

463-478: Good test for preserving JavaScript numeric semantics.

This test verifies that the memory tracking transforms don't inadvertently break numeric addition (e.g., by coercing numbers to strings). Important regression test.

libs/enclave-vm/src/double-vm/double-vm-wrapper.ts (3)

70-82: Memory tracker configuration disables object tracking.

The tracker is created with trackObjects: false, which means object allocations won't be tracked. This may be intentional for performance, but large object graphs could still exhaust memory without triggering limits. Consider documenting this limitation.


136-148: Good structured error handling for MemoryLimitError.

The error includes useful diagnostic data (usedBytes, limitBytes) and a consistent error code. This enables callers to programmatically handle memory limit violations.


227-245: No-op callback pattern for disabled tracking.

Good approach to always define __host_memory_track__ (even as no-op) to avoid conditional checks in parent VM code. This simplifies the parent VM bootstrap logic.

libs/enclave-vm/src/__tests__/memory-limit.spec.ts (3)

10-57: Comprehensive unit tests for MemoryTracker.

Good coverage of basic tracking, string/array size tracking, and reset behavior. The tests verify both accumulation and peak tracking correctly.


60-96: Good limit enforcement tests with edge cases.

Tests cover the limit exceeded case, error details verification, and the unlimited (0) case. The fail() pattern in the try-catch ensures the error is actually thrown.


529-549: Good regression test for numeric addition semantics.

This test ensures that the memory tracking transforms don't break JavaScript's + operator semantics for numbers. Important for correctness validation.

libs/enclave-vm/src/safe-runtime.ts (3)

271-275: Critical numeric fast path for performance.

Good optimization - checking both operands are numbers before any string operations ensures numeric addition isn't penalized by memory tracking overhead.


326-337: Potential over-tracking for mixed-type concatenation.

For cases like "hello" + 123, the entire result string is tracked (result.length * 2), not just the growth. This could over-count memory if the left operand was already tracked. However, this is a conservative approach that ensures no allocations are missed.


530-547: Memory-tracked constructors correctly integrated.

When memoryTracker is provided, the String and Array constructors are wrapped with tracking proxies. This ensures all allocations through these constructors are monitored.

libs/enclave-vm/src/memory-proxy.ts (3)

21-34: String constructor proxy tracks allocations correctly.

Both apply (calling String(value)) and construct (new String(value)) are handled. The valueOf() call on line 30 correctly gets the primitive string from the String object.


118-126: Splice tracking may over-count allocations.

The splice wrapper tracks both the removed items array (line 121) and the net growth (lines 122-124). However, if deleteCount is provided but items are not added, this still works correctly. The logic looks sound.


187-201: padStart/padEnd only track when string grows.

Good optimization - only tracking when the result is longer than the original avoids unnecessary overhead for no-op padding operations.

libs/enclave-vm/src/memory-tracker.ts (4)

40-58: Well-implemented custom Error class.

Proper inheritance from Error with Error.captureStackTrace for V8 stack traces. The code property is readonly and set directly, making it easy to check programmatically. Good pattern for custom errors.


70-75: String size estimation follows V8 memory model.

The 2-bytes-per-character (UTF-16) plus 40-byte overhead is a reasonable approximation for V8's string storage. The comment explains the short-string optimization that's not accounted for.


156-176: Correct limit enforcement with peak tracking.

The implementation correctly:

  1. Ignores non-positive allocations
  2. Updates peak before checking limit (so peak reflects the violating allocation)
  3. Only checks limit when limit > 0

217-219: Release correctly floors at zero.

Using Math.max(0, ...) ensures tracked bytes never go negative, which could cause incorrect limit checks. This aligns with the test at lines 111-120 in the spec file.

Copy link

@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: 1

🧹 Nitpick comments (1)
libs/enclave-vm/src/double-vm/parent-vm-bootstrap.ts (1)

577-603: Minor: Variable shadowing may cause confusion.

leftIsRef and rightIsRef are declared twice with var (lines 550-551 and 580-581). While this works due to var hoisting, it can be confusing. Consider using different variable names in the second block for clarity.

🔎 Suggested rename for clarity
     // For mixed types (one string, one non-string), check for references first
     // then use native + for proper ToPrimitive handling
     if (typeof left === 'string' || typeof right === 'string') {
       // Check if the string operand(s) are references BEFORE coercion
-      var leftIsRef = typeof left === 'string' && refIdPattern.test(left);
-      var rightIsRef = typeof right === 'string' && refIdPattern.test(right);
+      var leftHasRef = typeof left === 'string' && refIdPattern.test(left);
+      var rightHasRef = typeof right === 'string' && refIdPattern.test(right);

-      if (leftIsRef || rightIsRef) {
+      if (leftHasRef || rightHasRef) {
         // Reference detected - check if composites are allowed
📜 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 64df806 and c1bdf38.

📒 Files selected for processing (13)
  • libs/enclave-vm/src/__tests__/constructor-obfuscation-attacks.spec.ts
  • libs/enclave-vm/src/__tests__/double-vm.security.spec.ts
  • libs/enclave-vm/src/__tests__/enclave.constructor-attack.spec.ts
  • libs/enclave-vm/src/__tests__/enclave.nodejs24-security.spec.ts
  • libs/enclave-vm/src/__tests__/enclave.security.spec.ts
  • libs/enclave-vm/src/__tests__/enclave.serialization.spec.ts
  • libs/enclave-vm/src/__tests__/function-gadget-attacks.spec.ts
  • libs/enclave-vm/src/__tests__/runtime-attack-vectors.spec.ts
  • libs/enclave-vm/src/__tests__/secure-proxy.spec.ts
  • libs/enclave-vm/src/double-vm/double-vm-wrapper.ts
  • libs/enclave-vm/src/double-vm/parent-vm-bootstrap.ts
  • libs/enclave-vm/src/secure-proxy.ts
  • libs/enclave-vm/src/types.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • libs/enclave-vm/src/double-vm/double-vm-wrapper.ts
🧰 Additional context used
📓 Path-based instructions (1)
libs/**

⚙️ CodeRabbit configuration file

libs/**: Contains publishable SDK libraries. Review for API correctness, breaking changes, and consistency with docs. When public APIs change, ensure there is a matching docs/draft/docs/** update (not direct edits under docs/docs/**).

Files:

  • libs/enclave-vm/src/__tests__/enclave.constructor-attack.spec.ts
  • libs/enclave-vm/src/__tests__/function-gadget-attacks.spec.ts
  • libs/enclave-vm/src/__tests__/enclave.nodejs24-security.spec.ts
  • libs/enclave-vm/src/types.ts
  • libs/enclave-vm/src/__tests__/secure-proxy.spec.ts
  • libs/enclave-vm/src/double-vm/parent-vm-bootstrap.ts
  • libs/enclave-vm/src/secure-proxy.ts
  • libs/enclave-vm/src/__tests__/enclave.security.spec.ts
  • libs/enclave-vm/src/__tests__/runtime-attack-vectors.spec.ts
  • libs/enclave-vm/src/__tests__/double-vm.security.spec.ts
  • libs/enclave-vm/src/__tests__/enclave.serialization.spec.ts
  • libs/enclave-vm/src/__tests__/constructor-obfuscation-attacks.spec.ts
🔇 Additional comments (38)
libs/enclave-vm/src/__tests__/enclave.serialization.spec.ts (3)

21-44: LGTM - Test correctly updated for new security model.

The test appropriately verifies that non-blocked properties (like data) remain accessible while confirming the host environment is not polluted. The explicit assertions on result.success and result.value improve test clarity.


71-92: LGTM - Consistent with updated security model.

The test correctly verifies that nested non-blocked properties remain accessible. The approach is consistent with the other updated tests in this file.


119-146: Verify documentation and error message implementation for breaking behavior change.

The test validates throwing an error when accessing blocked constructor properties, which changes from previous silent filtering. Before proceeding:

  1. Confirm the 'Security violation' error message is actually implemented in the proxy handler (could not be located in codebase)
  2. Ensure a changelog or migration guide documents this breaking change, particularly since changes to libs/** public APIs require a matching docs/draft/docs/** update per coding guidelines
  3. Verify the error message will appear in developer-facing documentation

The test logic itself is sound, but the implementation claims require verification.

libs/enclave-vm/src/__tests__/double-vm.security.spec.ts (5)

1006-1018: LGTM: Test correctly validates throwing behavior on constructor access.

The test has been properly updated to expect a thrown security violation error when accessing constructor via computed properties on tool results, replacing the previous successful-but-blocked behavior. The updated comment accurately describes the secure proxy's new throwing semantics.


1041-1042: LGTM: Consistent error handling for proto access.

Test expectations correctly updated to match the new security violation throwing behavior.


1064-1065: LGTM: Promise constructor blocking correctly enforced.

Test properly validates that accessing Promise constructor via computed properties now throws a security violation.


1080-1092: LGTM: Test correctly reflects immediate throw on first violation.

The test and comments properly document that accessing blocked properties throws immediately, preventing subsequent attack steps. The updated code correctly expects the first computed property access to fail with a security violation.


1136-1137: LGTM: Chained escape prevention validated.

Test correctly expects security violation when attempting to access constructor through chained tool call results.

libs/enclave-vm/src/__tests__/enclave.nodejs24-security.spec.ts (3)

128-129: LGTM: Runtime proxy protection correctly enforced.

Test properly validates that constructor access via computed properties on wrapped globals now throws a security violation.


193-201: LGTM: PERMISSIVE mode behavior correctly documented.

The updated comment clearly explains that PERMISSIVE mode has throwOnBlocked: false, so it returns undefined instead of throwing. This is an important distinction from other security levels and is properly tested.


301-302: LGTM: Combined attack vectors correctly blocked.

Tests properly validate that multiple obfuscation techniques and prototype pollution attempts all fail with security violations.

Also applies to: 312-316

libs/enclave-vm/src/__tests__/function-gadget-attacks.spec.ts (3)

748-756: LGTM: String constructor access correctly blocked.

Test properly validates that the String global is wrapped by SecureProxy and throws when constructor is accessed via computed properties. The comment clearly explains the expected behavior.


1255-1268: LGTM: Object global properly distinguished from sandbox objects.

The updated test clearly validates that the Object global (wrapped by SecureProxy) throws a security violation when constructor is accessed, improving clarity over the previous undefined-check approach.


1270-1284: LGTM: Important distinction between wrapped globals and sandbox objects.

This new test correctly validates a critical security model distinction:

  • Wrapped globals (Object, Array, etc.) block constructor access to prevent host escape
  • Sandbox-created objects ({}) allow constructor access, which leads to the sandbox's isolated Function constructor

This is the correct defense-in-depth approach.

libs/enclave-vm/src/secure-proxy.ts (5)

336-339: LGTM: Cache key correctly includes throwOnBlocked.

The cache key generation correctly includes throwOnBlocked state to ensure different proxies are created for different throwing behaviors. The optimization to only include when true is reasonable.


444-445: LGTM: Correct precedence for throwOnBlocked resolution.

The option resolution correctly prioritizes explicit options.throwOnBlocked over levelConfig, with a safe default of false.


492-497: LGTM: get handler correctly implements throwing behavior.

The implementation properly:

  • Respects JavaScript proxy invariants for non-configurable properties
  • Calls onBlocked callback before throwing
  • Throws clear, descriptive error messages
  • Falls back to undefined when throwOnBlocked is false

Also applies to: 512-517


555-560: LGTM: set handler consistently implements throwing behavior.

The set handler correctly throws when attempting to set blocked properties, maintaining consistency with the get handler implementation.


575-580: LGTM: Comprehensive throwing behavior across all relevant proxy traps.

Both defineProperty and getOwnPropertyDescriptor handlers correctly implement the throwing behavior, ensuring blocked properties are protected across all access patterns.

Also applies to: 618-628

libs/enclave-vm/src/__tests__/constructor-obfuscation-attacks.spec.ts (2)

39-40: LGTM: Comprehensive and systematic test updates for throwing behavior.

All constructor obfuscation attack tests have been correctly updated to expect security violation errors instead of silent blocking. The updates are consistent across various obfuscation techniques (string concatenation, character codes, escapes, type coercion, etc.) and correctly validate that the SecureProxy now throws on blocked property access.

The test coverage remains comprehensive, testing all documented attack vectors against wrapped globals.

Also applies to: 53-54, 65-66, 78-79, 90-91, 110-111, 125-126, 138-139, 177-178, 194-195, 247-248, 281-282, 299-300, 312-313, 324-325, 339-340, 352-353, 386-387, 421-422, 439-440


527-545: LGTM: PERMISSIVE mode behavior correctly validated.

The PERMISSIVE mode tests correctly demonstrate the nuanced behavior:

  • blockConstructor: false - constructor is accessible
  • blockPrototype: true - __proto__ is still blocked
  • throwOnBlocked: false - returns undefined instead of throwing

This validates that PERMISSIVE mode provides a less restrictive but still somewhat protected environment.

libs/enclave-vm/src/__tests__/secure-proxy.spec.ts (1)

443-486: LGTM!

The test configurations are correctly updated to include the new throwOnBlocked: true flag, aligning with the updated SecureProxyLevelConfig interface. The tests properly exercise the buildBlockedPropertiesFromConfig function with complete configuration objects.

libs/enclave-vm/src/__tests__/enclave.constructor-attack.spec.ts (2)

27-31: LGTM!

The test expectations are correctly updated to verify that constructor access via computed properties now throws a security violation error instead of returning undefined. This aligns with the new throwOnBlocked: true default behavior.


134-137: LGTM!

The __proto__ access test correctly expects the security violation error message to contain both "Security violation" and "proto", ensuring proper error identification.

libs/enclave-vm/src/__tests__/runtime-attack-vectors.spec.ts (2)

68-71: LGTM!

Test expectations are correctly updated to verify that computed property attacks now result in explicit security violation errors.


1181-1184: LGTM!

Tool result attack tests correctly expect security violations when attempting to access constructor on proxied tool results.

libs/enclave-vm/src/types.ts (5)

80-92: LGTM!

The throwOnBlocked field is well-documented with clear explanation of its purpose, default value, and security implications. The documentation correctly notes that setting it to false is for backward compatibility.


197-217: LGTM!

STRICT security level appropriately sets throwOnBlocked: true to make security violations explicit and detectable.


314-334: LGTM!

PERMISSIVE level correctly sets throwOnBlocked: false for development/debugging purposes, consistent with its documented use case. The comment accurately explains this is for returning undefined instead of throwing.


406-416: LGTM!

The enhanced documentation for memoryUsage clearly explains that this is an estimate based on allocation tracking (String and Array), not actual V8 heap usage, and appropriately recommends worker_threads for precise isolation.


449-459: LGTM!

The memoryLimit documentation correctly explains the enforcement mechanism (allocation tracking with ~5-10% overhead) and sets appropriate expectations about precision.

libs/enclave-vm/src/__tests__/enclave.security.spec.ts (2)

881-895: LGTM!

Object introspection attack tests are correctly updated to expect security violation errors. The added comments clearly explain that SecureProxy blocks constructor access at runtime by throwing an error.


1308-1327: LGTM!

Sandbox escape prevention tests correctly verify that __proto__ access via string concatenation throws a security violation error, both with Double VM enabled and disabled. This provides good coverage for the defense-in-depth strategy.

libs/enclave-vm/src/double-vm/parent-vm-bootstrap.ts (5)

47-53: LGTM!

New options memoryLimit and throwOnBlocked are clearly documented and appropriately optional with sensible defaults (0 for unlimited memory, true for throwing on blocked properties).


197-205: LGTM!

The constants are correctly injected into the generated bootstrap code, making them available for the proxy traps and concatenation logic.


249-256: LGTM!

The get trap correctly implements the throw-on-blocked pattern with a descriptive error message that explains why the property is blocked.


605-615: LGTM on the default path logic.

The fallback to JavaScript's native + operator correctly handles all edge cases (objects with ToPrimitive, booleans, null, undefined) and appropriately tracks memory only for string results.


539-575: Remove the suggested defensive check—__host_memory_track__ is always injected.

The code does not need the typeof __host_memory_track__ === 'function' guard. The double-vm-wrapper.ts initialization (lines 230 and 239) always injects __host_memory_track__ into the context: either as an actual tracking function or as a no-op function when memory tracking is disabled. Since it's guaranteed to exist, the current guard if (memoryLimit > 0) is sufficient and safe.

Likely an incorrect or invalid review comment.

…curity violation handling and document breaking changes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants