Skip to content

Feature/upgrade runtime with http2#3347

Open
saecula wants to merge 4 commits intodevelopfrom
feature/upgrade-runtime-with-http2
Open

Feature/upgrade runtime with http2#3347
saecula wants to merge 4 commits intodevelopfrom
feature/upgrade-runtime-with-http2

Conversation

@saecula
Copy link
Collaborator

@saecula saecula commented Feb 6, 2026

Removes remaining major production vulnerabilities (currently addressed via "overrides") primarily by upgrading postman-runtime 7.39.1 → 7.51.1. and postman-collection 4.4.0 -> 5.2.0, which also necessitates dropping Node 16 support.

Related issue: #3336

The current version of this PR also re-adds HTTP/2 support.

changes

tests

  • Add integration tests covering HTTP/2
  • re-add timeout test fixes
  • filter Node.js deprecation warnings in CLI stderr tests
  • fix secure-fs output-check tests

Note: The major upgrade of postman-collections from v4-> v5 includes a breaking change w/r/t PropertyBase.parent: https://github.com/postmanlabs/postman-collection/blob/develop/CHANGELOG.yaml#L40 This seems safe since tests for nested collection items are coming clean for related functionality in Newman eg lib/util.js:getFullName()

// override exec for it to become silent by default and filter deprecation warnings
global.exec = function (cmd, done) {
return exec(cmd, { silent: true }, done);
return exec(cmd, { silent: true }, function (code, stdout, stderr) {

Check warning

Code scanning / CodeQL

Shell command built from environment values Medium test

This shell command depends on an uncontrolled
absolute path
.
This shell command depends on an uncontrolled
absolute path
.

Copilot Autofix

AI about 1 month ago

In general, the problem is that shelljs.exec is called with a single string cmd that was built by interpolating a path. The shell then parses cmd, so spaces or metacharacters in the path can alter the command. The standard fix is to avoid the shell for argument parsing: either (a) change callers to pass arguments separately and use an API that does not invoke a shell, or (b) at least escape or quote the interpolated values. Since we cannot touch the callers other than the shown test file, the best approach here is to (1) refactor the tests to use child_process.spawn/execFile directly with an argument array instead of global.exec, and (2) make global.exec in npm/test-cli.js reject multi-word shell commands and only allow a single binary path, effectively preventing unsafe templates from being used.

Concretely:

  • In test/cli/working-directory.test.js, stop calling global.exec with a template literal. Instead, require Node’s child_process and use spawn (or execFile) with:

    • command: 'node'
    • args: ['./bin/newman.js', 'run', 'test/fixtures/run/single-file-....json', '--working-dir', workingDir, ...]
      This passes workingDir as a separate argument and bypasses shell parsing entirely.
  • In npm/test-cli.js, harden the overridden global.exec so it only accepts a command that is a simple binary path with no spaces (or is already an array), and throws if the caller passes something that looks like a shell command line. This addresses the CodeQL sink at line 35 by ensuring we never pass an arbitrary space-containing string to shelljs.exec. For compatibility with existing tests that legitimately use a string binary path, we allow a single word (no whitespace) or, optionally, an object/array form; for now we’ll implement the strict single-token check. This keeps existing functionality for legitimate usages while blocking unsafe patterns like those in working-directory.test.js which we are refactoring away.

No new external packages are needed: child_process is built-in. The required changes are limited to the shown snippets in npm/test-cli.js and test/cli/working-directory.test.js.

Suggested changeset 2
npm/test-cli.js

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/npm/test-cli.js b/npm/test-cli.js
--- a/npm/test-cli.js
+++ b/npm/test-cli.js
@@ -32,6 +32,14 @@
 
         // override exec for it to become silent by default and filter deprecation warnings
         global.exec = function (cmd, done) {
+            // For safety, only allow simple commands without whitespace so that shell parsing
+            // cannot be influenced by untrusted or environment-derived values embedded in `cmd`.
+            // More complex invocations should use child_process.spawn/execFile with an args array.
+            if (typeof cmd === 'string' && /\s/.test(cmd)) {
+                throw new Error('Unsafe use of global.exec with a shell command string containing whitespace. ' +
+                    'Use child_process.spawn/execFile with argument arrays instead.');
+            }
+
             return exec(cmd, { silent: true }, function (code, stdout, stderr) {
                 // Filter out Node.js deprecation warnings from stderr (e.g., DEP0040 punycode warning in Node 22)
                 // This prevents test failures when Node emits deprecation warnings
EOF
@@ -32,6 +32,14 @@

// override exec for it to become silent by default and filter deprecation warnings
global.exec = function (cmd, done) {
// For safety, only allow simple commands without whitespace so that shell parsing
// cannot be influenced by untrusted or environment-derived values embedded in `cmd`.
// More complex invocations should use child_process.spawn/execFile with an args array.
if (typeof cmd === 'string' && /\s/.test(cmd)) {
throw new Error('Unsafe use of global.exec with a shell command string containing whitespace. ' +
'Use child_process.spawn/execFile with argument arrays instead.');
}

return exec(cmd, { silent: true }, function (code, stdout, stderr) {
// Filter out Node.js deprecation warnings from stderr (e.g., DEP0040 punycode warning in Node 22)
// This prevents test failures when Node emits deprecation warnings
test/cli/working-directory.test.js
Outside changed files

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/test/cli/working-directory.test.js b/test/cli/working-directory.test.js
--- a/test/cli/working-directory.test.js
+++ b/test/cli/working-directory.test.js
@@ -1,20 +1,42 @@
 const path = require('path'),
     expect = require('chai').expect,
+    spawn = require('child_process').spawn,
 
     workingDir = path.resolve(__dirname, '../fixtures/files/work-dir');
 
 describe('newman run --working-dir --no-insecure-file-read', function () {
     it('should resolve file present inside working directory', function (done) {
-        // eslint-disable-next-line max-len
-        exec(`node ./bin/newman.js run test/fixtures/run/single-file-inside.json --working-dir ${workingDir}`, function (code) {
+        const child = spawn('node', [
+            './bin/newman.js',
+            'run',
+            'test/fixtures/run/single-file-inside.json',
+            '--working-dir',
+            workingDir
+        ], { shell: false });
+
+        child.on('close', function (code) {
             expect(code, 'should have exit code of 0').to.equal(0);
             done();
         });
     });
 
     it('should not resolve file present outside working directory with --no-insecure-file-read', function (done) {
-        // eslint-disable-next-line max-len
-        exec(`node ./bin/newman.js run test/fixtures/run/single-file-outside.json --working-dir ${workingDir} --no-insecure-file-read`, function (code, stdout) {
+        let stdout = '';
+
+        const child = spawn('node', [
+            './bin/newman.js',
+            'run',
+            'test/fixtures/run/single-file-outside.json',
+            '--working-dir',
+            workingDir,
+            '--no-insecure-file-read'
+        ], { shell: false });
+
+        child.stdout.on('data', function (data) {
+            stdout += data;
+        });
+
+        child.on('close', function (code) {
             expect(code, 'should have exit code of 1').to.equal(1);
             expect(stdout).to.have.string('AssertionError');
             done();
@@ -22,8 +33,21 @@
     });
 
     it('should resolve file present outside working directory by default', function (done) {
-        // eslint-disable-next-line max-len
-        exec(`node ./bin/newman.js run test/fixtures/run/single-file-outside.json --working-dir ${workingDir}`, function (code, stdout) {
+        let stdout = '';
+
+        const child = spawn('node', [
+            './bin/newman.js',
+            'run',
+            'test/fixtures/run/single-file-outside.json',
+            '--working-dir',
+            workingDir
+        ], { shell: false });
+
+        child.stdout.on('data', function (data) {
+            stdout += data;
+        });
+
+        child.on('close', function (code) {
             expect(code, 'should have exit code of 0').to.equal(0);
             expect(stdout).to.not.have.string('AssertionError');
             done();
EOF
Copilot is powered by AI and may make mistakes. Always verify output.
@saecula saecula committed this autofix suggestion about 1 month ago.
Copy link
Collaborator Author

@saecula saecula Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this was already here, but added check for allowed prefixes to make it happier

@codecov-commenter
Copy link

codecov-commenter commented Feb 6, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 82.16%. Comparing base (942d139) to head (e250918).

❌ Your project status has failed because the head coverage (52.12%) is below the target coverage (65.00%). You can increase the head coverage or adjust the target coverage.

Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #3347      +/-   ##
===========================================
+ Coverage    81.85%   82.16%   +0.30%     
===========================================
  Files           21       21              
  Lines         1152     1155       +3     
  Branches       352      354       +2     
===========================================
+ Hits           943      949       +6     
+ Misses         114      111       -3     
  Partials        95       95              
Flag Coverage Δ
cli 70.99% <75.00%> (-0.19%) ⬇️
integration 35.58% <100.00%> (+0.16%) ⬆️
library 52.12% <75.00%> (+0.29%) ⬆️
unit 66.06% <75.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@saecula saecula force-pushed the feature/upgrade-runtime-with-http2 branch from ad38fd8 to 641d45a Compare February 6, 2026 17:40
@saecula saecula force-pushed the feature/upgrade-runtime-with-http2 branch from 641d45a to 5ed273b Compare February 6, 2026 18:07
@saecula saecula force-pushed the feature/upgrade-runtime-with-http2 branch from 55d7a0b to e250918 Compare February 6, 2026 23:21
@saecula saecula marked this pull request as ready for review February 6, 2026 23:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants