ADR-0027: The configuration sandbox offers pure path and url modules
- Status: Accepted
- Date: 2026-09-22
- Derives from: ADR-0006 (the sandboxed QuickJS evaluator), design § The dependency-cruiser format, design § Test beds
- Constrains: architecture § Security posture,
crates/rb-config/src/js/ - Implemented by: Wave 1 plan, Step 2
- Requirements: FR-CFG-03, NFR-SEC-01
Context
ADR-0006 limits what a JavaScript configuration may require or import to JSON files, other configuration modules under the repository, and the bundled dependency-cruiser presets. Wave 1 measured that rule against the ten dependency-cruiser configurations the test-bed manifest names, fetched at their pinned commits:
| Configuration | Needs beyond ADR-0006 |
|---|---|
| eight of the ten | nothing |
sverweij/dependency-cruiser .dependency-cruiser.mjs |
node:url (fileURLToPath), new URL(..., import.meta.url) to name its own configs/recommended-strict.cjs |
invertase/react-native-firebase .dependency-cruiser.cjs |
fs (readdirSync, statSync, existsSync, and writeFileSync of a generated tsconfig) |
The first needs only string functions over paths: no file is opened and nothing leaves the process. The second genuinely reads and writes the filesystem.
Decision
- The sandbox provides
path(andnode:path,path/posix) andurl(andnode:url) as modules implemented in JavaScript inside the sandbox, plus a globalURLlimited tofile:URLs,import.meta.url,import.meta.dirname,import.meta.filename,__filenameand__dirname. They compute strings; none of them reads, writes or lists anything. - A no-op
consoleis present so a configuration that logs does not throw; it writes nothing. - Every other Node built-in (
fs,child_process,os,processand the rest) stays refused, with a message naming--config-via-node. The react-native-firebase configuration is the reference case for that flag. - Resolution still ends at the repository root, after symlinks are resolved.
Consequences
- The dependency-cruiser oracle loads in the sandbox, so layer 5 on dependency-cruiser's own repository does not need Node for its configuration.
- The sandbox's host surface is unchanged: two functions, resolve and read, both enforcing the repository root. The added modules are data transformations, so the escape tests of ADR-0006 still describe the boundary.
Alternatives considered
- Require
--config-via-nodefor dependency-cruiser's own configuration. Rejected: the drop-in would then need Node on the one repository whose maintainer the design names first in the adoption order. - Offer a read-only
fs. Rejected: it makes the configuration's output depend on the directory listing, which is the non-hermetic behaviour ADR-0006 exists to prevent.