From 2c3145c17c42fe3946c53a54ddd7603f3a2598e9 Mon Sep 17 00:00:00 2001 From: Adrian Moldovan <3854374+adimoldovan@users.noreply.github.com> Date: Wed, 12 Aug 2026 19:42:45 +0300 Subject: [PATCH] Build/Test Tools: Avoid npx when running build and test tooling. `npx` downloads a package and its dependencies from the registry when it cannot find that package locally, then runs the install scripts of everything it downloaded. Each call is a point where a compromised package can run code during a build. Replace every `npx` call in the repository with `npm exec --no`, which runs an installed binary and fails when the package is missing. `update-browserslist-db` is now a devDependency at 1.3.1. `browserslist` already required it as `^1.2.3`, so the lockfile hoists a package that was present and adds none. See #65864. --- .github/workflows/reusable-end-to-end-tests.yml | 2 +- .github/workflows/reusable-performance-test-v2.yml | 2 +- Gruntfile.js | 10 +++++----- package-lock.json | 7 ++++--- package.json | 1 + tests/qunit/playwright.config.js | 2 +- 6 files changed, 13 insertions(+), 11 deletions(-) diff --git a/.github/workflows/reusable-end-to-end-tests.yml b/.github/workflows/reusable-end-to-end-tests.yml index 36a71d1711d2f..9b5586973aacf 100644 --- a/.github/workflows/reusable-end-to-end-tests.yml +++ b/.github/workflows/reusable-end-to-end-tests.yml @@ -100,7 +100,7 @@ jobs: - name: Install Playwright browsers if: ${{ inputs.install-playwright }} - run: npx playwright install --with-deps chromium + run: npm exec --no -- playwright install --with-deps chromium - name: Build WordPress run: npm run build diff --git a/.github/workflows/reusable-performance-test-v2.yml b/.github/workflows/reusable-performance-test-v2.yml index a9b911e718cba..b92893f52f7f1 100644 --- a/.github/workflows/reusable-performance-test-v2.yml +++ b/.github/workflows/reusable-performance-test-v2.yml @@ -148,7 +148,7 @@ jobs: run: npm ci - name: Install Playwright browsers - run: npx playwright install --with-deps chromium + run: npm exec --no -- playwright install --with-deps chromium - name: Start Docker environment run: npm run env:start diff --git a/Gruntfile.js b/Gruntfile.js index 61f18481e23a8..ab40643d05a80 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -2279,8 +2279,8 @@ module.exports = function(grunt) { grunt.registerTask( 'qunit', 'Runs QUnit tests.', function() { var done = this.async(); grunt.util.spawn( { - cmd: 'npx', - args: [ 'playwright', 'test', '--config', 'tests/qunit/playwright.config.js' ], + cmd: 'npm', + args: [ 'exec', '--no', '--', 'playwright', 'test', '--config', 'tests/qunit/playwright.config.js' ], opts: { stdio: 'inherit' } }, function( error, result, code ) { if ( code !== 0 ) { @@ -2363,15 +2363,15 @@ module.exports = function(grunt) { grunt.registerTask( 'wp-packages:update', 'Update WordPress packages', function() { const distTag = grunt.option('dist-tag') || 'latest'; grunt.log.writeln( `Updating WordPress packages (--dist-tag=${distTag})` ); - spawn( 'npx', [ 'wp-scripts', 'packages-update', `--dist-tag=${distTag}` ], { + spawn( 'npm', [ 'exec', '--no', '--', 'wp-scripts', 'packages-update', `--dist-tag=${distTag}` ], { cwd: __dirname, stdio: 'inherit', } ); } ); grunt.registerTask( 'browserslist:update', 'Update the local database of browser supports', function() { - grunt.log.writeln( `Updating browsers list` ); - spawn( 'npx', [ 'update-browserslist-db@latest' ], { + grunt.log.writeln( 'Updating browsers list' ); + spawn( 'npm', [ 'exec', '--no', '--', 'update-browserslist-db' ], { cwd: __dirname, stdio: 'inherit', } ); diff --git a/package-lock.json b/package-lock.json index 78985e8f955c0..86c92eb71b93f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -89,6 +89,7 @@ "sinon-test": "~3.1.6", "source-map-loader": "5.0.0", "typescript": "6.0.3", + "update-browserslist-db": "1.3.1", "uuid": "14.0.1", "wait-on": "9.0.10", "webpack": "5.108.4" @@ -32266,9 +32267,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", - "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.1.tgz", + "integrity": "sha512-ZZ61DsRsOnakl74HAmp3oSN4aXUmEWXf+i/yv0h7tIBfICc3VdrFErQKUUKPgu3AMsTUMbcongALEN4l6GSUrQ==", "dev": true, "funding": [ { diff --git a/package.json b/package.json index d854406d50d7e..06afdaa363cec 100644 --- a/package.json +++ b/package.json @@ -77,6 +77,7 @@ "sinon-test": "~3.1.6", "source-map-loader": "5.0.0", "typescript": "6.0.3", + "update-browserslist-db": "1.3.1", "uuid": "14.0.1", "wait-on": "9.0.10", "webpack": "5.108.4" diff --git a/tests/qunit/playwright.config.js b/tests/qunit/playwright.config.js index fc6651e0917ac..9e49301727a6a 100644 --- a/tests/qunit/playwright.config.js +++ b/tests/qunit/playwright.config.js @@ -12,7 +12,7 @@ module.exports = defineConfig( { workers: 1, use: { headless: true, - /* This avoids the need to run `npx playwright install` in CI. */ + /* The system Chrome channel avoids a browser download in CI. */ channel: process.env.CI ? 'chrome' : undefined, }, reporter: process.env.CI ? 'github' : 'list',