diff --git a/doc/api/cli.md b/doc/api/cli.md index 1f5136ce69442f..f7fad4add5755f 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -432,6 +432,12 @@ added: v12.0.0 Specify the file name of the CPU profile generated by `--cpu-prof`. +### `--deprecated-process-binding` + +Ensure that the deprecated `process.binding(...)` API is available. This +is currently the default. A runtime deprecation warning, however, will be +emitted when `process.binding(...)` is accessed. + ### `--diagnostic-dir=directory` Set the directory to which all diagnostic output files are written. @@ -1172,6 +1178,10 @@ Disable the `node-addons` exports condition as well as disable loading native addons. When `--no-addons` is specified, calling `process.dlopen` or requiring a native C++ addon will fail and throw an exception. +### `--no-deprecated-process-binding` + +Makes the deprecated `process.binding(...)` API unavailable in the process. + ### `--no-deprecation` -Type: Documentation-only (supports [`--pending-deprecation`][]) +Type: Runtime `process.binding()` is for use by Node.js internal code only. @@ -2604,12 +2607,15 @@ Prefer [`response.socket`][] over [`response.connection`][] and -Type: Documentation-only (supports [`--pending-deprecation`][]) +Type: Runtime The `process._tickCallback` property was never documented as an officially supported API. diff --git a/lib/internal/bootstrap/realm.js b/lib/internal/bootstrap/realm.js index c6935c6f7775fc..2aeab2e37d0191 100644 --- a/lib/internal/bootstrap/realm.js +++ b/lib/internal/bootstrap/realm.js @@ -77,7 +77,6 @@ ObjectDefineProperty(process, 'moduleLoadList', { writable: false, }); - // processBindingAllowList contains the name of bindings that are allowed // for access via process.binding(). This is used to provide a transition // path for modules that are being moved over to internalBinding. @@ -144,6 +143,9 @@ const experimentalModuleList = new SafeSet(); { const bindingObj = { __proto__: null }; + // TODO(@jasnell): If the --deprecated-process-binding option is false we really + // ought to skip setting this here. However, we cannot require internal/options or + // use internalBinding here so we'll have to pull it back out later. process.binding = function binding(module) { module = String(module); // Deprecated specific process.binding() modules, but not all, allow diff --git a/lib/internal/process/policy.js b/lib/internal/process/policy.js index 8e07cb92118c84..1886d47c0c65b4 100644 --- a/lib/internal/process/policy.js +++ b/lib/internal/process/policy.js @@ -11,6 +11,10 @@ const { ERR_MANIFEST_TDZ, } = require('internal/errors').codes; const { Manifest } = require('internal/policy/manifest'); + +const { getOptionValue } = require('internal/options'); +const deprecatedProcessBinding = getOptionValue('--deprecated-process-binding'); + let manifest; let manifestSrc; let manifestURL; @@ -36,9 +40,11 @@ module.exports = ObjectFreeze({ // process.binding() is deprecated (DEP0111) and trivially allows bypassing // policies, so if policies are enabled, make this API unavailable. - process.binding = function binding(_module) { - throw new ERR_ACCESS_DENIED('process.binding'); - }; + if (deprecatedProcessBinding) { + process.binding = function binding(_module) { + throw new ERR_ACCESS_DENIED('process.binding'); + }; + } process._linkedBinding = function _linkedBinding(_module) { throw new ERR_ACCESS_DENIED('process._linkedBinding'); }; diff --git a/lib/internal/process/pre_execution.js b/lib/internal/process/pre_execution.js index c535f8e8ed8a5d..a053f467cfc8ea 100644 --- a/lib/internal/process/pre_execution.js +++ b/lib/internal/process/pre_execution.js @@ -545,15 +545,20 @@ function initializeDeprecations() { }); } - if (pendingDeprecation) { + if (getOptionValue('--deprecated-process-binding')) { process.binding = deprecate(process.binding, 'process.binding() is deprecated. ' + 'Please use public APIs instead.', 'DEP0111'); - - process._tickCallback = deprecate(process._tickCallback, - 'process._tickCallback() is deprecated', - 'DEP0134'); + } else { + // Ideally it wouldn't be defined at all already but realm.js does not + // provide a means of checking to see if the option is enabled or not, + // so we do it here. + delete process.binding; } + + process._tickCallback = deprecate(process._tickCallback, + 'process._tickCallback() is deprecated', + 'DEP0134'); } function setupChildProcessIpcChannel() { @@ -587,9 +592,11 @@ function initializeClusterIPC() { function initializePermission() { const experimentalPermission = getOptionValue('--experimental-permission'); if (experimentalPermission) { - process.binding = function binding(_module) { - throw new ERR_ACCESS_DENIED('process.binding'); - }; + if (getOptionValue('--deprecated-process-binding') && process.binding !== undefined) { + process.binding = function binding(_module) { + throw new ERR_ACCESS_DENIED('process.binding'); + }; + } process.emitWarning('Permission is an experimental feature', 'ExperimentalWarning'); const { has, deny } = require('internal/process/permission'); diff --git a/src/node_options.cc b/src/node_options.cc index 417d4679e84ec3..ac1a8cc6a99808 100644 --- a/src/node_options.cc +++ b/src/node_options.cc @@ -535,6 +535,11 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() { "emit pending deprecation warnings", &EnvironmentOptions::pending_deprecation, kAllowedInEnvvar); + AddOption("--deprecated-process-binding", + "enable the deprecated process.binding(...) api", + &EnvironmentOptions::deprecated_process_binding, + kAllowedInEnvvar, + true); AddOption("--preserve-symlinks", "preserve symbolic links when resolving", &EnvironmentOptions::preserve_symlinks, diff --git a/src/node_options.h b/src/node_options.h index 04c8a9e438dcfb..da3838647fbd56 100644 --- a/src/node_options.h +++ b/src/node_options.h @@ -188,6 +188,16 @@ class EnvironmentOptions : public Options { false; #endif // DEBUG + // TODO(@jasnell): In preparation for the eventual complete removal of + // the deprecated process.binding, this option controls whether or not + // process.binding is available. Currently the default is true, making + // the deprecated API available, albeit with a runtime deprecation message. + // Then, later, we can change the default to false, giving folks the option + // to re-enable if they really need it. Then, as the final step, we would + // remove the deprecated api entirely, in which case this option becomes + // a non-op. + bool deprecated_process_binding = true; + bool watch_mode = false; bool watch_mode_report_to_parent = false; bool watch_mode_preserve_output = false; diff --git a/test/parallel/test-no-deprecated-process-binding.js b/test/parallel/test-no-deprecated-process-binding.js new file mode 100644 index 00000000000000..71cc3c058fb623 --- /dev/null +++ b/test/parallel/test-no-deprecated-process-binding.js @@ -0,0 +1,5 @@ +'use strict'; +// Flags: --no-deprecated-process-binding +require('../common'); +const { strictEqual } = require('node:assert'); +strictEqual(process.binding, undefined);