@@ -61,6 +61,48 @@ def _normalize_path(path: Union[Path, str]) -> str:
6161 return re .sub ("/cygdrive/(.*?)(/)" , r"\1://" , path , count = 1 )
6262
6363
64+ _MR_VERSION = "6.7.1"
65+
66+
67+ def _install_mongodb_runner () -> Path :
68+ """Install mongodb-runner via npm with overrides to pin @mongodb-js/oidc-mock-provider.
69+
70+ npx does not support npm overrides, so we manage the install manually.
71+ @mongodb-js/oidc-mock-provider 0.13.8+ switched to yargs@18 (ESM-only), which
72+ cannot be require()'d on Node 16. Pinning to 0.13.7 keeps it on yargs@17.
73+ """
74+ install_dir = TMPDIR / f"mongodb-runner-{ _MR_VERSION } "
75+ ext = ".cmd" if PLATFORM == "win32" else ""
76+ runner_bin = install_dir / "node_modules" / ".bin" / f"mongodb-runner{ ext } "
77+ if not runner_bin .exists ():
78+ pkg = {
79+ "name" : "mongodb-runner-wrapper" ,
80+ "version" : "1.0.0" ,
81+ "dependencies" : {"mongodb-runner" : _MR_VERSION },
82+ "overrides" : {"@mongodb-js/oidc-mock-provider" : "0.13.7" },
83+ }
84+ install_dir .mkdir (parents = True , exist_ok = True )
85+ (install_dir / "package.json" ).write_text (json .dumps (pkg , indent = 2 ))
86+ npm = shutil .which ("npm" )
87+ if npm is None :
88+ raise RuntimeError (
89+ "npm not found. Source init-node-and-npm-env.sh or install Node before running this script."
90+ )
91+ if PLATFORM == "win32" :
92+ # .cmd files require shell=True on Windows; pass as string to avoid quoting issues.
93+ subprocess .run (
94+ f'"{ npm } " install --silent' ,
95+ cwd = str (install_dir ),
96+ check = True ,
97+ shell = True ,
98+ )
99+ else :
100+ subprocess .run (
101+ [npm , "install" , "--silent" ], cwd = str (install_dir ), check = True
102+ )
103+ return runner_bin
104+
105+
64106def start_mongodb_runner (opts , data ):
65107 mo_home = Path (opts .mongo_orchestration_home )
66108 server_log = mo_home / "server.log"
@@ -80,20 +122,39 @@ def start_mongodb_runner(opts, data):
80122 binary = shutil .which ("node" )
81123 target = HERE / "devtools-shared/packages/mongodb-runner/bin/runner.js"
82124 target = _normalize_path (target )
125+ binary = _normalize_path (binary )
126+ cmd = f"{ binary } { target } start --debug --config { config_file } "
83127 else :
84- binary = shutil .which ("npx" )
85- target = "-y mongodb-runner@^6.7.1"
86- binary = _normalize_path (binary )
87- cmd = f"{ binary } { target } start --debug --config { config_file } "
88- LOGGER .info (f"Running mongodb-runner using { binary } { target } ..." )
128+ binary = _normalize_path (_install_mongodb_runner ())
129+ cmd = f"{ binary } start --debug --config { config_file } "
130+ LOGGER .info (f"Running mongodb-runner using { binary } ..." )
131+ env = os .environ .copy ()
132+ node_bin = shutil .which ("node" )
133+ if node_bin :
134+ try :
135+ node_ver = subprocess .check_output (
136+ [node_bin , "--version" ], encoding = "utf-8"
137+ ).strip ()
138+ node_major = int (node_ver .lstrip ("v" ).split ("." )[0 ])
139+ # Node < 19 doesn't expose WebCrypto as a global; mongodb driver needs it.
140+ # The flag was removed in Node 22, so only add it for Node 16-18.
141+ if node_major < 19 :
142+ existing = env .get ("NODE_OPTIONS" , "" )
143+ env ["NODE_OPTIONS" ] = (
144+ f"{ existing } --experimental-global-webcrypto" .strip ()
145+ )
146+ except (subprocess .CalledProcessError , ValueError ):
147+ pass
89148 try :
90149 with server_log .open ("w" ) as fid :
91150 # Capture output while still streaming it to the file
92151 proc = subprocess .Popen (
93- shlex .split (cmd ),
152+ cmd if PLATFORM == "win32" else shlex .split (cmd ),
94153 stdout = subprocess .PIPE ,
95154 stderr = subprocess .STDOUT ,
96155 text = True ,
156+ env = env ,
157+ shell = (PLATFORM == "win32" ),
97158 )
98159 output_lines = []
99160 for line in proc .stdout :
@@ -109,7 +170,7 @@ def start_mongodb_runner(opts, data):
109170 LOGGER .error ("server.log: %s" , server_log .read_text ())
110171 LOGGER .error (str (e ))
111172 raise e
112- LOGGER .info (f"Running mongodb-runner using { binary } { target } ... done." )
173+ LOGGER .info (f"Running mongodb-runner using { binary } ... done." )
113174 cluster_file = Path (config ["runnerDir" ]) / f"m-{ config ['id' ]} .json"
114175 server_info = json .loads (cluster_file .read_text ())
115176 cluster_file .unlink ()
0 commit comments