复现
- 使用root用户进行
npm install
操作 - 然后执行
npm run postinstall:"bower install"
报错:
npm WARN lifecycle ****~postinstall: cannot run in wd (wd=/app)
- 首先wd是当前的工作目录
- 说明npm run postinstall不能在当前的目录下运行
我的执行过程:使用npm install 安装bower, 然后在postscript中使用bower install
(使用bower安装bower中的依赖)
使用Docker启动一个node container 作为运行环境。
// Dockerfile
FROM node:8.12.0
RUN mkdir /app
WORKDIR /app
COPY . .
ENTRYPOINT ["/bin/bash", "-c"]
// docker-compose.yml
version: '2'
services:
dev:
build: .
volumes:
- ~/.ssh:/home/node/.ssh:ro
// package.json
"scripts": {
"postinstall": "bower install --allow-root"
}
// auto/test
docker-compose run --rm dev "npm ci && ${@-bash}"
解决过程
- 直接运行
auto/auto/test
报错
npm WARN lifecycle ***~postinstall: cannot run in wd *** bower install --allow-root (wd=/app)
根据以上错误翻译:npm warn 生命周期script postinstall: 不能在当前的work dir中运行bower install --allow-root
- 是否是因为
postinstall
中执行了一些不能运行的command,于是尝试替换
// package.json
"scripts": {
"postinstall": "whoami"
}
发现报错一样,说明:
不论postinstall里执行任何命令都会导致以上的错误
原因:
如果使用root调用npm的时候,npm会将
uid
修改成user account
或者是在npm的config文件中找到user config
然后用此时的user修改uid
,如果这些值都没有,user的默认值是nobody
.你可以通过设置--unsafe-perm=true
使用root权限运行npm script命令
.
- 是否是所有的
npm script
都不能执行呢?
试验:移除postinstall脚本,然后定义新的script bowerInstall: bower install --allow-root
, 在npm ci
之后执行npm ci && npm run bowerInstall
结果: bower install成功
结论: 当你使用root用户执行npm的指令,会导致npm相关lifecycle方法(之后npm lifecycle中的方法,比如postinstall)的运行出现以上的问题
当你使用root调用npm,只有在running package lifecycle script,npm才会将uid设置成nobody
。对于其他的script,npm不会强制设置你的uid
npm 中的每一个script都会运行三个独立的脚本。prescript、script本身以及postscript。正如它们的名称所暗示的,这两个附加脚本在主脚本之前和之后运行。pre以及post脚本通常被用来setup以及clean up工作。
pre<script-name>
和post<script-name>
in the same scripts object as before.
- root 权限执行
npm
会有什么问题?
如果使用root执行npm install
, 当你安装postinstall一个package,npm还会是用当前这个权限去运行这个package中的postinstall
, 因此如果脚本中写了一些不利于操作系统的脚本,会直接broke
你的电脑。
当你使用root执行npm install的时候,npm为了安全性考虑,将你的uid设置成nobody
, nobody
权限非常的低,因此postinstall里写的很多脚本nobody都没有权限执行,因此不会造成安全问题
Issue link
- 那么如果必须使用root用户调用npm,如何解决上面的问题呢?
虽然npm可以自动的帮助你在执行lifecycle script的时候降低权限到nobody
, 但是如果你自己希望npm不要强制修改你的uid,你可以使用npm install --unsafe-perm
:
强制npm运行所有lifecycle script的时候都使用root,不要自动帮你改变权限。但是请注意这是一项很危险的动作。
- 那么有没有什么安全的fix方法呢?
那么你可以选择不要使用root用户调用npm的各种执行,在Docker image中使用USER node
,将用户从root改成node。
或者不要把你想要执行的脚本写在postinstall(lifecycle)
脚本中,而是写在其他npm script
中
bower install --allow-root: 这条指令允许你运行使用root权限运行
bower install
,但是事实上,根本没有必要使用root权限运行, 但是如果你还是强行想使用root权限那么可以使用all-root