tldr; script using fs.readFileSync throws EACCESS when called using npm
, but not using node
On an ancient (2016) Docker image, I need to run a postinstall
NPM script involving Bower (bower install --allow-root
), but whenever I do, I get EACCES: permission denied, open '/root/.config/configstore/bower-github.json'
. I found out that doing npx bower
results in the same. Running npx bower
outside of Docker works fine.
Usually, I would easily have dealt with these issues, as they normally arise whenever someone has been executing a command using sudo
when they should not have. The fix for those issues is usually to either change the owner back to the current user or just run the bower command with sudo and --allow-root
(example 1, example 2).
This, however, is not one of these issues. I am already root!
The full error is like any of the similar issues:
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'
I cannot elevate my rights any further and adding --allow-root
does not do anything. I even inspected the module in question, seeing that the call that always failed was simply this:
readFileSync(this.path, 'utf8');
where this.path
was of course '/root/.config/configstore/bower-github.json'
.
I then wrote this small test module that does the same, and it ran without issues:
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: {}
A mystery!