node icon indicating copy to clipboard operation
node copied to clipboard

[Bug]: When using --allow-fs-write to execute a non-existent folder, creating subdirectories of that folder will fail

Open skypesky opened this issue 1 year ago • 13 comments

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?

  1. 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 });
})();

  1. 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?

  1. I want to create the folder successfully without throwing any errors
  2. 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
})();

skypesky avatar Jun 28 '24 11:06 skypesky

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 avatar Jun 28 '24 11:06 marco-ippolito

@marco-ippolito please ignore my spelling mistakes, this is indeed a bug, here is a screenshot. image

image

skypesky avatar Jun 28 '24 12:06 skypesky

does the folder temp exists?

marco-ippolito avatar Jun 28 '24 12:06 marco-ippolito

  • 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!!!
})();

skypesky avatar Jun 28 '24 12:06 skypesky

does the folder temp exists? if not it wont work To create the folder temp you 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.

skypesky avatar Jun 28 '24 12:06 skypesky

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 });
})();

marco-ippolito avatar Jun 28 '24 12:06 marco-ippolito

Meanwhile, can you try adding a * after temp? --allow-fs-write=/Users/skypesky/workSpaces/javascript/github/temp/*

Anyway, I'll fix it.

RafaelGSS avatar Jun 28 '24 13:06 RafaelGSS

Just tested it this as well, if adding * after temp it will say no matches found: --allow-fs-write=/file path/

jakecastelli avatar Jun 28 '24 13:06 jakecastelli

Sometimes it's related to your terminal (such as zsh). Try wrapping it into quotes: --allow-fs-write="/Users/skypesky/workSpaces/javascript/github/temp/*"

RafaelGSS avatar Jun 28 '24 13:06 RafaelGSS

Thanks, it was my terminal (zsh), after adding * it works, it can create the folders recursively.

jakecastelli avatar Jun 28 '24 13:06 jakecastelli

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: *.

RafaelGSS avatar Jun 28 '24 13:06 RafaelGSS

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: *.

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

marco-ippolito avatar Jun 28 '24 13:06 marco-ippolito

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.

tniessen avatar Jun 30 '24 09:06 tniessen

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.

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.

RafaelGSS avatar Jun 30 '24 20:06 RafaelGSS

I'm going to close it as this is expected behaviour. Feel free to re-open if something is misleading.

RafaelGSS avatar Jul 01 '24 01:07 RafaelGSS

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 👎)

jakecastelli avatar Jul 01 '24 01:07 jakecastelli

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.

RafaelGSS avatar Jul 01 '24 02:07 RafaelGSS