Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion lib/git.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,13 +191,24 @@ class GitFetcher extends Fetcher {
}
noPrepare.push(this.resolved)

// npm exports user config into lifecycle environments, but a nested npm
// treats allow-scripts there as a CLI/env override and rejects it for
// project-scoped installs. Let it reload the policy from .npmrc instead.
const env = { ...process.env }
for (const key of Object.keys(env)) {
if (key.toLowerCase() === 'npm_config_allow_scripts') {
delete env[key]
}
}
env._PACOTE_NO_PREPARE_ = noPrepare.join('\n')

// the DirFetcher will do its own preparation to run the prepare scripts
// All we have to do is put the deps in place so that it can succeed.
return npm(
this.npmBin,
[].concat(this.npmInstallCmd).concat(this.npmCliConfig),
dir,
{ ...process.env, _PACOTE_NO_PREPARE_: noPrepare.join('\n') },
env,
{ message: 'git dep preparation failed' }
)
})
Expand Down
4 changes: 4 additions & 0 deletions test/fixtures/npm-mock.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ const data = {
argv,
noPrepare: pnp ? pnp.split('\\n') : [],
cwd: process.cwd(),
allowScriptsEnv: Object.fromEntries(Object.entries(env).filter(([key]) =>
key.toLowerCase() === 'npm_config_allow_scripts')),
preservedEnv: env._PACOTE_TEST_ENV_,
userConfig: env.npm_config_userconfig,
}

if (data.noPrepare.length > 5) {
Expand Down
14 changes: 14 additions & 0 deletions test/git.js
Original file line number Diff line number Diff line change
Expand Up @@ -746,9 +746,17 @@ t.test('handle it when prepared git deps depend on each other', { skip: isWindow

process.env._PACOTE_TEST_PATH_ = dirname(__dirname)
process.env._PACOTE_TEST_OPTS_ = JSON.stringify(opts)
process.env._PACOTE_TEST_ENV_ = 'preserved'
process.env.npm_config_allow_scripts = 'lowercase'
process.env.npm_config_userconfig = '/tmp/user.npmrc'
process.env.NPM_CONFIG_ALLOW_SCRIPTS = 'uppercase'
t.teardown(() => {
delete process.env._PACOTE_TEST_PATH_
delete process.env._PACOTE_TEST_OPTS_
delete process.env._PACOTE_TEST_ENV_
delete process.env.npm_config_allow_scripts
delete process.env.npm_config_userconfig
delete process.env.NPM_CONFIG_ALLOW_SCRIPTS
})

for (const project of ['cycle-a', 'cycle-b']) {
Expand Down Expand Up @@ -778,6 +786,12 @@ t.test('handle it when prepared git deps depend on each other', { skip: isWindow
log.argv.includes('--global=false'),
'inner npm install is invoked with --global=false'
)
t.strictSame(log.allowScriptsEnv, {},
'allow-scripts config is not forwarded as an environment override')
t.equal(log.preservedEnv, 'preserved',
'unrelated environment variables are preserved')
t.equal(log.userConfig, '/tmp/user.npmrc',
'the user config remains available to the inner install')
// our rudimentary package manager dumps the deps into the pkg root
// but it doesn't get installed once the loop is detected.
const base = basename(local)
Expand Down