fix(ext/node): vm dynamic import without callback throws ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING (#34427)
## Summary
`vm.runInThisContext` (and friends) currently allow dynamic `import()`
to fall through to the main module loader even when no
`importModuleDynamically` callback was provided. This lets sandboxed
code reach modules like `node:fs`. Node throws
`ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING` in this situation.
Fix: tag the host-defined options of every script/function/module
compiled by `node:vm` with a `VM_DYNAMIC_IMPORT_MISSING` kind, and check
that kind inside the runtime's dynamic-import host callback. If the
marker is present, reject the import promise with a Node-compatible
`TypeError` carrying `code = "ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING"`
and message `"A dynamic import callback was not specified."`.
Covered entry points:
- `vm.Script(...).runInThisContext()`
- `vm.runInContext` / `vm.createContext` + `runInContext`
- `vm.runInNewContext`
- `vm.compileFunction`
- `vm.SourceTextModule`
Before:
```
$ deno run -A repro.mjs
fsModule type inside VM: object
```
After:
```
$ deno run -A repro.mjs
VM error code: ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING
VM error name: TypeError
VM error message: A dynamic import callback was not specified.
```
Implementation notes:
- New `libs/core/runtime/host_defined_options.rs` defines a small
kind-tag layout for the `PrimitiveArray` Deno already attaches as
`host_defined_options`. The existing npm marker (`[Boolean(true)]`) is
left alone — it doesn't collide with the new `[Uint32]` kind.
- `host_import_module_with_phase_dynamically_callback` reads the tag up
front and short-circuits with the Node error when the script was
compiled by `node:vm` without a callback. All other host_defined_options
shapes (including the npm marker and the V8 default empty array) flow
through unchanged.
Future work: actually wiring the `importModuleDynamically` callback
through to the user-provided function. That's a larger feature; this PR
closes the immediate sandbox-escape gap to match Node.
Fixes #33385.
Closes denoland/orchid#245
## Test plan
- [x] `tests/specs/node/vm_dynamic_import_no_callback/` covers all six
vm entry points; passes via `cargo test --test specs
node::vm_dynamic_import_no_callback`.
- [x] Updated `tests/unit_node/vm_test.ts` "vm runInNewContext module
loader" (#22441) to assert the new (Node-matching) behavior.
- [x] `cargo clippy -p deno_core -p deno_node --all-targets` clean.
- [x] Verified normal Deno module imports (including npm packages) still
work unchanged.
---------
Co-authored-by: divybot <divybot@users.noreply.github.com>
Co-authored-by: Divy Srivastava <me@littledivy.com>