[Bug]: When using --allow-fs-write to execute a non-existent folder, creating subdirectories of that folder will fail
Version
v22.3.0
Platform
Darwin mac-studio.local 23.5.0 Darwin Kernel Version 23.5.0: Wed May 1 20:12:58 PDT 2024; root:xnu-10063.121.3~5/RELEASE_ARM64_T6000 arm64
Subsystem
No response
What steps will reproduce the bug?
- Create new file
test.js
// /Users/skypesky/workSpaces/javascript/github/test.js
const { mkdir } = require('node:fs/promises');
(async () => {
await mkdir('/Users/skypesky/workSpaces/javascript/github/temp/a/b/c/d', { recursive: true });
})();
- Execute the following command
➜ node --experimental-permission --allow-fs-write=/Users/skypesky/workSpaces/javascript/github/temp --allow-fs-read=/Users/skypesky/workSpaces/javascript/github/test.js test.js
(node:9132) ExperimentalWarning: Permission is an experimental feature
(Use `node --trace-warnings ...` to show where the warning was created)
node:internal/fs/promises:864
binding.mkdir(pathModule.toNamespacedPath(path),
^
Error: Access to this API has been restricted
at mkdir (node:internal/fs/promises:864:13)
at /Users/skypesky/workSpaces/javascript/github/test.js:4:9
at Object.<anonymous> (/Users/skypesky/workSpaces/javascript/github/test.js:5:3)
at Module._compile (node:internal/modules/cjs/loader:1460:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1544:10)
at Module.load (node:internal/modules/cjs/loader:1275:32)
at Module._load (node:internal/modules/cjs/loader:1091:12)
at wrapModuleLoad (node:internal/modules/cjs/loader:212:19)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:158:5)
at node:internal/main/run_main_module:30:49 {
code: 'ERR_ACCESS_DENIED',
permission: 'FileSystemWrite',
resource: '/Users/skypesky/workSpaces/javascript/github/temp/a/b/c/d'
}
Node.js v22.3.0
How often does it reproduce? Is there a required condition?
No response
What is the expected behavior? Why is that the expected behavior?
- I want to create the folder successfully without throwing any errors
- node.js cannot make everyone pre-create folders for these scripts
What do you see instead?
➜ node --experimental-permission --allow-fs-write=/Users/skypesky/workSpaces/javascript/github/temp --allow-fs-read=/Users/skypesky/workSpaces/javascript/github/test.js test.js
(node:9132) ExperimentalWarning: Permission is an experimental feature
(Use `node --trace-warnings ...` to show where the warning was created)
node:internal/fs/promises:864
binding.mkdir(pathModule.toNamespacedPath(path),
^
Error: Access to this API has been restricted
at mkdir (node:internal/fs/promises:864:13)
at /Users/skypesky/workSpaces/javascript/github/test.js:4:9
at Object.<anonymous> (/Users/skypesky/workSpaces/javascript/github/test.js:5:3)
at Module._compile (node:internal/modules/cjs/loader:1460:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1544:10)
at Module.load (node:internal/modules/cjs/loader:1275:32)
at Module._load (node:internal/modules/cjs/loader:1091:12)
at wrapModuleLoad (node:internal/modules/cjs/loader:212:19)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:158:5)
at node:internal/main/run_main_module:30:49 {
code: 'ERR_ACCESS_DENIED',
permission: 'FileSystemWrite',
resource: '/Users/skypesky/workSpaces/javascript/github/temp/a/b/c/d'
}
Node.js v22.3.0
Additional information
- I managed to create temp successfully, but I couldn't create a subfolder for temp.
const { mkdir } = require('node:fs/promises');
(async () => {
await mkdir('/Users/skypesky/workSpaces/javascript/github/temp', { recursive: true }); // exec ok!
await mkdir('/Users/skypesky/workSpaces/javascript/github/temp/a/b/c/d', { recursive: true }); // failed
})();
You have set allow-write to /Users/skypesky/workSpaces/javascript/github/temp and trying to write on
/Users/skypesky/workSpaces/javascript/github/tmp/ it's working as supposed, you need set write-permission to /Users/skypesky/workSpaces/javascript/github/tmp
@marco-ippolito
please ignore my spelling mistakes, this is indeed a bug, here is a screenshot.
does the folder temp exists?
- The temp folder does not exist! Specifically, I can actually create temp successfully, but I cannot create subfolders of temp.
const { mkdir } = require('node:fs/promises');
(async () => {
await mkdir('/Users/skypesky/workSpaces/javascript/github/temp', { recursive: true }); // exec ok!
await mkdir('/Users/skypesky/workSpaces/javascript/github/temp/a/b/c/d', { recursive: true }); // exec failed!!!
})();
does the folder
tempexists? if not it wont work To create the foldertempyou need to have write access in the parent directory for example:/Users/skypesky/workSpaces/javascript/github/
I do not want it to have the permission to write data in this folder on github, this is not what we intended.
I can reproduce, I confirm its a bug @RafaelGSS
node --experimental-permission --allow-fs-write=$PWD/foo --allow-fs-read=$PWD/test.js test.js
const { mkdir } = require('node:fs/promises');
(async () => {
await mkdir('./foo/', { recursive: true });
await mkdir('./foo/tmp/a/b/c/d', { recursive: true });
})();
Meanwhile, can you try adding a * after temp? --allow-fs-write=/Users/skypesky/workSpaces/javascript/github/temp/*
Anyway, I'll fix it.
Just tested it this as well, if adding * after temp it will say no matches found: --allow-fs-write=/file path/
Sometimes it's related to your terminal (such as zsh). Try wrapping it into quotes: --allow-fs-write="/Users/skypesky/workSpaces/javascript/github/temp/*"
Thanks, it was my terminal (zsh), after adding * it works, it can create the folders recursively.
Actually, thinking more about it... It's not a bug, temp never existed, so the system cannot identify if temp is supposed to be a folder or just a file temp.
I'm pretty sure if you try to create a file /Users/skypesky/workSpaces/javascript/github/temp it will work with success.
Hence, for non-existent folders you must add the wildcard: *.
Actually, thinking more about it... It's not a bug,
tempnever existed, so the system cannot identify iftempis supposed to be a folder or just a filetemp.I'm pretty sure if you try to create a file
/Users/skypesky/workSpaces/javascript/github/tempit will work with success.Hence, for non-existent folders you must add the wildcard: *.
But give then case:
node --experimental-permission --allow-fs-write=$PWD/foo --allow-fs-read=$PWD/test.js test.js
const { mkdir } = require('node:fs/promises');
(async () => {
await mkdir('./foo/', { recursive: true });
await mkdir('./foo/tmp/a/b/c/d', { recursive: true });
})();
The folder is created succesfully so it should word PS: Accidentally closed
IIRC, when the permission model is being initialized, it implicitly adds wildcards to the end of paths that are (existing) directories. If $PWD/foo does not exist, no wildcard is implicitly added, so the permission model only allows access to the exact path $PWD/foo.
IIRC, when the permission model is being initialized, it implicitly adds wildcards to the end of paths that are (existing) directories. If
$PWD/foodoes not exist, no wildcard is implicitly added, so the permission model only allows access to the exact path$PWD/foo.
That's correct. If you created $PWD/foo folder during runtime, the permission model won't be able to identify if that's a folder and add the wildcard.
I'm going to close it as this is expected behaviour. Feel free to re-open if something is misleading.
Thanks for the explanation @tniessen @RafaelGSS I traced to is_granted method in fs_permission.cc and found out it was cached. I am thinking this probably should be documented in the Limitations and Known Issues section of the api/permissions doc? (👍 or 👎)
It's not a limitation as it's designed to work in that way. We could mention it on https://nodejs.org/api/permissions.html#file-system-permissions specifically on wildcard mention.