diff --git a/test/lib/commands/exec.js b/test/lib/commands/exec.js index db2a8641708d3..2a6d3f6b8e0af 100644 --- a/test/lib/commands/exec.js +++ b/test/lib/commands/exec.js @@ -275,6 +275,31 @@ t.test('packs from git spec', async t => { const exists = await fs.stat(path.join(npm.prefix, 'npm-exec-test-success')) t.ok(exists.isFile(), 'bin ran, creating file') } catch (err) { - t.fail(err, "shouldn't throw") + t.fail(err, 'should not throw') + } +}) + +t.test('can run packages with keywords', async t => { + const { npm } = await loadMockNpm(t, { + prefixDir: { + 'package.json': JSON.stringify({ + name: '@npmcli/npx-package-test', + bin: { select: 'index.js' }, + }), + 'index.js': `#!/usr/bin/env node + require('fs').writeFileSync('npm-exec-test-success', (process.argv.length).toString())`, + }, + }) + + try { + await npm.exec('exec', ['select']) + + const testFilePath = path.join(npm.prefix, 'npm-exec-test-success') + const exists = await fs.stat(testFilePath) + t.ok(exists.isFile(), 'bin ran, creating file') + const noExtraArgumentCount = await fs.readFile(testFilePath, 'utf8') + t.equal(+noExtraArgumentCount, 2, 'should have no extra arguments') + } catch (err) { + t.fail(err, 'should not throw') } }) diff --git a/workspaces/libnpmexec/lib/run-script.js b/workspaces/libnpmexec/lib/run-script.js index 1f621edcbc9aa..aa4f0525e9d2f 100644 --- a/workspaces/libnpmexec/lib/run-script.js +++ b/workspaces/libnpmexec/lib/run-script.js @@ -3,6 +3,7 @@ const runScript = require('@npmcli/run-script') const readPackageJson = require('read-package-json-fast') const { log, output } = require('proc-log') const noTTY = require('./no-tty.js') +const isWindowsShell = require('./is-windows.js') const run = async ({ args, @@ -14,6 +15,14 @@ const run = async ({ runPath, scriptShell, }) => { + // escape executable path + // necessary for preventing bash/cmd keywords from overriding + if (!isWindowsShell) { + if (args.length > 0) { + args[0] = '"' + args[0] + '"' + } + } + // turn list of args into command string const script = call || args.shift() || scriptShell diff --git a/workspaces/libnpmexec/test/run-script.js b/workspaces/libnpmexec/test/run-script.js index 01e3f35594906..61937098b7e83 100644 --- a/workspaces/libnpmexec/test/run-script.js +++ b/workspaces/libnpmexec/test/run-script.js @@ -115,3 +115,31 @@ t.test('ci env', async t => { t.equal(logs[0], 'warn exec Interactive mode disabled in CI environment') }) + +t.test('isWindows', async t => { + const { runScript } = await mockRunScript(t, { + 'ci-info': { isCI: true }, + '@npmcli/run-script': async () => { + t.ok('should call run-script') + }, + '../lib/is-windows.js': true, + }) + + await runScript({ args: ['test'] }) + // need both arguments and no arguments for code coverage + await runScript() +}) + +t.test('isNotWindows', async t => { + const { runScript } = await mockRunScript(t, { + 'ci-info': { isCI: true }, + '@npmcli/run-script': async () => { + t.ok('should call run-script') + }, + '../lib/is-windows.js': false, + }) + + await runScript({ args: ['test'] }) + // need both arguments and no arguments for code coverage + await runScript() +})