以root身份运行NPM 8时获取eAccess [英] Getting EACCESS when running NPM 8 as root

查看:40
本文介绍了以root身份运行NPM 8时获取eAccess的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

tldr;使用fs.readFileSync的脚本在使用npm而不是使用node调用时引发eAccess

在一个古老的(2016)Docker镜像上,我需要运行一个涉及Bower(bower install --allow-root)的postinstallnpm脚本,但是每当我这样做时,我都会得到EACCES: permission denied, open '/root/.config/configstore/bower-github.json'。我发现做npx bower的结果是一样的。在Docker的npx bower外部运行正常。

通常,我可以很容易地处理这些问题,因为每当有人使用sudo执行命令时,通常会出现这些问题,而他们不应该使用sudo。解决这些问题的方法通常是将所有者改回当前用户,或者只使用sudo和--allow-root(example 1example 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手动运行bowerCLI模块怎么办?

$ 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!因此,很明显,npxnpm都在暗地里做了一些关于命令以谁身份运行的怪事!

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆