diff --git a/configure.py b/configure.py index 57177b969bb523..714639bf03bf07 100755 --- a/configure.py +++ b/configure.py @@ -1965,18 +1965,29 @@ def configure_node(o): msvc_dir = target_arch # 'x64' or 'arm64' vc_tools_dir = os.environ.get('VCToolsInstallDir', '') - if vc_tools_dir: - clang_profile_lib = os.path.join(vc_tools_dir, 'lib', msvc_dir, lib_name) - if os.path.isfile(clang_profile_lib): - o['variables']['clang_profile_lib'] = clang_profile_lib - else: - raise Exception( - f'PGO profile runtime library not found at {clang_profile_lib}. ' - 'Ensure the ClangCL toolset is installed.') - else: + if not vc_tools_dir: raise Exception( 'VCToolsInstallDir not set. Run from a Visual Studio command prompt.') + # Primary location: VS2026 and VS2022 x64 + candidates = [os.path.join(vc_tools_dir, 'lib', msvc_dir, lib_name)] + + # Secondary location: VS2022 arm64 fallback + clang_major = options.clang_cl.split('.', 1)[0] + candidates.append(os.path.normpath(os.path.join( + vc_tools_dir, '..', '..', 'Llvm', msvc_dir, + 'lib', 'clang', clang_major, 'lib', 'windows', lib_name))) + + clang_profile_lib = next( + (p for p in candidates if os.path.isfile(p)), None) + if clang_profile_lib: + o['variables']['clang_profile_lib'] = clang_profile_lib + else: + raise Exception( + f'PGO profile runtime library {lib_name} not found. Searched:\n ' + + '\n '.join(candidates) + + '\nEnsure the ClangCL toolset is installed.') + if flavor != 'win' and options.enable_thin_lto: raise Exception( 'Use --enable-lto instead.') diff --git a/doc/api/permissions.md b/doc/api/permissions.md index 5af6fbb398f53a..3f2a6411d3f678 100644 --- a/doc/api/permissions.md +++ b/doc/api/permissions.md @@ -78,7 +78,7 @@ flag. For WASI, use the [`--allow-wasi`][] flag. For FFI, use the When enabling the Permission Model through the [`--permission`][] flag a new property `permission` is added to the `process` object. -This property contains one function: +This property contains the following functions: ##### `permission.has(scope[, reference])` @@ -92,6 +92,41 @@ process.permission.has('fs.read'); // true process.permission.has('fs.read', '/home/rafaelgss/protected-folder'); // false ``` +##### `permission.drop(scope[, reference])` + +API call to drop permissions at runtime. This operation is **irreversible**. + +When called without a reference, the entire scope is dropped. When called +with a reference, only the permission for that specific resource is revoked. +Dropping a permission only affects future access checks. It does not close or +revoke access to resources that are already open, such as file descriptors, +network sockets, child processes, or worker threads. Applications are +responsible for closing or terminating those resources when they are no longer +needed. + +You can only drop the exact resource that was explicitly granted. The +reference passed to `drop()` must match the original grant. If a permission +was granted using a wildcard (`*`), only the entire scope can be dropped +(by calling `drop()` without a reference). If a directory was granted +(e.g. `--allow-fs-read=/my/folder`), you cannot drop individual files +inside it - you must drop the same directory that was originally granted. + +```js +const fs = require('node:fs'); + +// Read config at startup while we still have permission +const config = fs.readFileSync('/etc/myapp/config.json', 'utf8'); + +// Drop read access to /etc/myapp after initialization +process.permission.drop('fs.read', '/etc/myapp'); + +// This will now throw ERR_ACCESS_DENIED +process.permission.has('fs.read', '/etc/myapp/config.json'); // false + +// Drop child process permission entirely +process.permission.drop('child'); +``` + #### File System Permissions The Permission Model, by default, restricts access to the file system through the `node:fs` module. diff --git a/doc/api/process.md b/doc/api/process.md index 28b60d93836429..c054b7336a5cb6 100644 --- a/doc/api/process.md +++ b/doc/api/process.md @@ -3168,6 +3168,65 @@ process.permission.has('fs.read', './README.md'); process.permission.has('fs.read'); ``` +### `process.permission.drop(scope[, reference])` + + + +> Stability: 1.1 - Active Development + +* `scope` {string} +* `reference` {string} + +Drops the specified permission from the current process. This operation is +**irreversible** — once a permission is dropped, it cannot be restored through +any Node.js API. + +If no reference is provided, the entire scope is dropped. For example, +`process.permission.drop('fs.read')` will revoke ALL file system read +permissions. + +When a reference is provided, only the permission for that specific resource +is dropped. For example, `process.permission.drop('fs.read', '/etc/myapp')` +will revoke read access to that directory while keeping other read +permissions intact. + +**Important:** You can only drop the exact resource that was explicitly +granted. The reference passed to `drop()` must match the original grant: + +* If a permission was granted using a wildcard (`*`), such as + `--allow-fs-read=*`, individual paths cannot be dropped - only the entire + scope can be dropped (by calling `drop()` without a reference). +* If a directory was granted (e.g. `--allow-fs-read=/my/folder`), you cannot + drop access to individual files inside it. You must drop the same directory + that was granted. Any remaining grants continue to apply. + +The available scopes are the same as [`process.permission.has()`][]: + +* `fs` - All File System (drops both read and write) +* `fs.read` - File System read operations +* `fs.write` - File System write operations +* `child` - Child process spawning operations +* `worker` - Worker thread spawning operation +* `net` - Network operations +* `inspector` - Inspector operations +* `wasi` - WASI operations +* `addon` - Native addon operations + +```js +const fs = require('node:fs'); + +// Read configuration during startup +const config = fs.readFileSync('/etc/myapp/config.json', 'utf8'); + +// Drop read access to the config directory after initialization +process.permission.drop('fs.read', '/etc/myapp'); + +// This will now throw ERR_ACCESS_DENIED +fs.readFileSync('/etc/myapp/config.json'); +``` + ## `process.pid`