以root身份运行NPM 8时获取eAccess [英] Getting EACCESS when running NPM 8 as root
问题描述
tldr;使用fs.readFileSync的脚本在使用npm
而不是使用node
调用时引发eAccess
在一个古老的(2016)Docker镜像上,我需要运行一个涉及Bower(bower install --allow-root
)的postinstall
npm脚本,但是每当我这样做时,我都会得到EACCES: permission denied, open '/root/.config/configstore/bower-github.json'
。我发现做npx bower
的结果是一样的。在Docker的npx bower
外部运行正常。
通常,我可以很容易地处理这些问题,因为每当有人使用sudo
执行命令时,通常会出现这些问题,而他们不应该使用sudo
。解决这些问题的方法通常是将所有者改回当前用户,或者只使用sudo和--allow-root
(example 1,example 2)运行Bower命令。
但是,这不是这些问题之一。我已经是root用户了!
完整错误与任何类似问题类似:
root@eaa32456c249:/var/www/myproj# npx bower --allow-root
/var/www/myproj/node_modules/bower/lib/node_modules/configstore/index.js:54
throw err;
^
Error: EACCES: permission denied, open '/root/.config/configstore/bower-github.json'
You don't have access to this file.
at Object.openSync (node:fs:585:3)
at Object.readFileSync (node:fs:453:35)
at Configstore.get (/var/www/myproj/node_modules/bower/lib/node_modules/configstore/index.js:35:38)
at new Configstore (/var/www/myproj/node_modules/bower/lib/node_modules/configstore/index.js:28:48)
at readCachedConfig (/var/www/myproj/node_modules/bower/lib/config.js:19:23)
at defaultConfig (/var/www/myproj/node_modules/bower/lib/config.js:11:12)
at Object.<anonymous> (/var/www/myproj/node_modules/bower/lib/index.js:16:32)
at Module._compile (node:internal/modules/cjs/loader:1101:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
at Module.load (node:internal/modules/cjs/loader:981:32) {
errno: -13,
syscall: 'open',
code: 'EACCES',
path: '/root/.config/configstore/bower-github.json'
我不能进一步提升我的权限,添加--allow-root
不会有任何作用。我甚至检查了有问题的模块,发现总是失败的调用很简单:
readFileSync(this.path, 'utf8');
其中this.path
当然是'/root/.config/configstore/bower-github.json'
。
然后我编写了这个执行相同操作的小测试模块,它运行时没有任何问题:
root@eaa32456c249:/var/www/myproj# cat test.js
const execSync = require('child_process').execSync;
const fs = require('fs');
const path = '/root/.config/configstore/bower-github.json';
console.log('exec whoami: ', execSync('whoami').toString());
try {
const result = execSync('ls -l ' + path, { encoding: 'utf8' });
console.log('exec ls -l: ', result);
} catch (err) {}
try {
const parsed = JSON.parse(fs.readFileSync(path, 'utf8', { encoding: 'utf8' }));
console.log('parsed: ', parsed);
} catch (err) {
console.error(err.message);
}
root@eaa32456c249:/var/www/myproj# node test.js
exec whoami: root
exec ls -l: -rw-r--r-- 1 root root 3 Dec 8 22:55 /root/.config/configstore/bower-github.json
parsed: {}
神秘!
推荐答案
让它酝酿一段时间后,我想我可以检查一下代码是以谁的身份运行的,所以我打开了有问题的模块(node_modules/configstore/index.js
),并将以下代码添加到失败的调用之前的行中:
const execSync = require('child_process').execSync;
console.log('exec `id`: ', execSync('id', { encoding: 'utf8' }));
console.log('exec `ls`: ', execSync('ls -l /root', { encoding: 'utf8' }));
确实发生了一些可疑的事情,因为打印了这些行:
exec `id`: uid=1000 gid=1000 groups=1000
ls: cannot open directory '/root': Permission denied
那么,以root
身份运行npx bower
会使bower
以uid=1000的用户身份运行吗?运行npm run postinstall
会导致相同的问题。
好的.让我们仔细看看这个。如果我使用node
手动运行bower
CLI模块怎么办?
$ node node_modules/.bin/bower --allow-root
root@eaa32456c249:/var/www/myproj# node node_modules/.bin/bower --allow-root
exec `id`: uid=0(root) gid=0(root) groups=0(root)
exec `ls`: total 0
它起作用了-我仍然是root!因此,很明显,npx
和npm
都在暗地里做了一些关于命令以谁身份运行的怪事!
npm,root
和CWD的所有者
深入挖掘寻找解决方案
在我发现上述事实后,我做了一些谷歌搜索,发现了this NPM issue,而实际上没有得到直接的解释,这让我找到了Node试图以文件所有者的身份执行的踪迹。我第一次真正检查了文件的所有者是谁:
root@eaa32456c249:/var/www/myproj# ls -lh node_modules/bower/
total 72K
-rw-r--r-- 1 1000 1000 40K Oct 20 08:50 CHANGELOG.md
-rw-r--r-- 1 1000 1000 1.1K Oct 20 08:50 LICENSE
-rw-r--r-- 1 1000 1000 14K Oct 20 08:50 README.md
drwxr-xr-x 2 1000 1000 4.0K Oct 20 08:50 bin
drwxr-xr-x 9 1000 1000 4.0K Oct 20 08:50 lib
-rw-r--r-- 1 1000 1000 460 Oct 20 08:50 package.json
简单地执行chown root.root -R node_modules
没有任何作用,因此我继续搜索。然后我阅读了this article,其中包含以下代码片段:
如果npm是使用root权限调用的,则它会将uid更改为用户配置指定的用户帐户或uid,默认情况下为noboone。设置unsafe-perm标志以使用root权限运行脚本。好的,让我们尝试将
unsafe-perm
设置为true。不行,我还在以uid=1000的身份运行。然后,我冒险进入实际的NPM库,搜索与uid
相关的内容,并在以下位置找到了答案:
/usr/local/lib/node_modules/npm/node_modules/@npmcli/promise-spawn/index.js
对于NPM 8,它使用以下代码来确定以谁的身份运行:
const { uid, gid } = isRoot ? inferOwner.sync(cwd) : {}
和infer-owner
模块的the docs表示:
请注意根据最接近的现有父级的所有者推断路径的所有者
cwd
部分。它不查看node_modules
,而是查看当前工作目录!所以我随后在根目录和loo上执行了chown root.root -R .
,看哪,它起作用了!
附录
此行为仅适用于npm版本>;=7。npm版本<;7是随Node12-14一起提供的版本,以root身份运行时工作正常。因此,最快的解决方法可能是简单地使用节点14。
这篇关于以root身份运行NPM 8时获取eAccess的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!