oli*_*ren 6 permissions node.js docker
太棒了;使用 fs.readFileSync 的脚本在使用调用时抛出 EACCESS npm
,但不使用node
在一个古老的(2016)Docker 镜像上,我需要运行一个postinstall
涉及 Bower ( ) 的 NPM 脚本bower install --allow-root
,但每当我这样做时,我都会得到EACCES: permission denied, open '/root/.config/configstore/bower-github.json'
. 我发现这样做的npx bower
结果是一样的。npx bower
在 Docker之外运行效果很好。
通常,我很容易处理这些问题,因为每当有人在sudo
不应该执行的命令时使用命令时,这些问题通常就会出现。这些问题的解决方法通常是将所有者更改回当前用户,或者仅使用 sudo 和运行 Bower 命令--allow-root
(示例 1、示例 2)。
然而,这不是这些问题之一。 我已经是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'
Run Code Online (Sandbox Code Playgroud)
我无法进一步提升我的权利,添加也--allow-root
没有任何作用。我什至检查了有问题的模块,发现总是失败的调用就是这样:
readFileSync(this.path, 'utf8');
Run Code Online (Sandbox Code Playgroud)
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: {}
Run Code Online (Sandbox Code Playgroud)
一个谜!
oli*_*ren 16
太棒了;NPM 版本 7 和 8 将以根包目录的所有者身份运行。换句话说,如果您想以 root 身份运行,请chown root.root -R .
在项目的根目录上执行。早期和更高版本都没有这种行为,因此升级 NPM 也可以避免该问题。
更新NPM 9 将恢复更改,这意味着上述内容仅适用于 NPM 7 和 8。请参阅 PR。
让这个小火慢煮一段时间后,我只是想我可以检查一下代码运行的身份,所以我打开了有问题的模块(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' }));
Run Code Online (Sandbox Code Playgroud)
确实发生了一些可疑的事情,正如这些行所打印的那样:
exec `id`: uid=1000 gid=1000 groups=1000
ls: cannot open directory '/root': Permission denied
Run Code Online (Sandbox Code Playgroud)
那么不知何故,运行npx bower
为root
使得bower
以 uid=1000 的用户身份运行?运行npm run postinstall
结果相同。
好吧……让我们仔细看看这个。如果我bower
使用手动运行 CLI 模块会怎样node
?
$ 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
Run Code Online (Sandbox Code Playgroud)
它有效 - 我仍然是root!很明显,两者npx
都npm
在以某种方式在幕后做一些关于命令运行的有趣的事情!
root
和 CWD 的所有者深入挖掘寻找解决方案
在发现上述事实之后,我进行了一些谷歌搜索,并遇到了这个 NPM 问题,虽然实际上没有直接的解释,但我却发现了 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
Run Code Online (Sandbox Code Playgroud)
只是chown root.root -R node_modules
什么也没做,所以我继续寻找。然后我读了这篇文章,其中有这样的片段:
如果使用root权限调用npm,那么它将把uid更改为用户帐户或用户配置指定的uid,默认为nobody。设置 unsafe-perm 标志以使用 root 权限运行脚本。
好的,让我们尝试设置unsafe-perm
为 true。不行,我仍然以 uid=1000 运行。然后我冒险进入实际的 NPM 库来搜索相关的内容,uid
并在以下位置找到了答案:
/usr/local/lib/node_modules/npm/node_modules/@npmcli/promise-spawn/index.js
Run Code Online (Sandbox Code Playgroud)
对于 NPM 8,它使用这段代码来确定以谁身份运行:
const { uid, gid } = isRoot ? inferOwner.sync(cwd) : {}
Run Code Online (Sandbox Code Playgroud)
正如模块的文档infer-owner
所说:
根据最近的现有父路径的所有者推断路径的所有者
请注意该cwd
部分。它不查看node_modules
,而是查看当前工作目录!然后我chown root.root -R .
在项目的根目录上做了,你瞧,它成功了!
此行为仅适用于 NPM 版本 7 和 8。NPM 版本 < 7(随 Node 12-14 一起提供)在以 root 身份运行时工作得非常好。因此,最快的修复方法可能就是使用 Node 14。从 NPM 9 开始,旧的行为又回来了(可能随 Node 20 一起提供)。
归档时间: |
|
查看次数: |
5937 次 |
最近记录: |