Skip to content

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

Description

@skypesky

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

Activity

  1. added
    fsIssues and PRs related to file-system APIs and the fs module.
    securityIssues and PRs related to security.
    experimentalIssues and PRs related to experimental features.
    permissionIssues and PRs related to the Permission Model.
    on Jun 28, 2024
  2. marco-ippolito commented on Jun 28, 2024

    @marco-ippolito
    Member

    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

  3. skypesky commented on Jun 28, 2024

    @skypesky
    Author

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

    image
  4. marco-ippolito commented on Jun 28, 2024

    @marco-ippolito
    Member

    does the folder temp exists?

  5. skypesky commented on Jun 28, 2024

    @skypesky
    Author
    • 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!!!
    })();
  6. skypesky commented on Jun 28, 2024

    @skypesky
    Author

    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.

  7. marco-ippolito commented on Jun 28, 2024

    @marco-ippolito
    Member

    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 });
    })();
  8. RafaelGSS commented on Jun 28, 2024

    @RafaelGSS
    Member

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

    Anyway, I'll fix it.

  9. jakecastelli commented on Jun 28, 2024

    @jakecastelli
    Member

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

  10. 1 remaining item

  11. jakecastelli commented on Jun 28, 2024

    @jakecastelli
    Member

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

  12. RafaelGSS commented on Jun 28, 2024

    @RafaelGSS
    Member

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

  13. marco-ippolito commented on Jun 28, 2024

    @marco-ippolito
    Member

    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

  14. tniessen commented on Jun 30, 2024

    @tniessen
    Member

    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.

  15. RafaelGSS commented on Jun 30, 2024

    @RafaelGSS
    Member

    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.

  16. RafaelGSS commented on Jul 1, 2024

    @RafaelGSS
    Member

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

  17. jakecastelli commented on Jul 1, 2024

    @jakecastelli
    Member

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

  18. RafaelGSS commented on Jul 1, 2024

    @RafaelGSS
    Member

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    experimentalIssues and PRs related to experimental features.fsIssues and PRs related to file-system APIs and the fs module.permissionIssues and PRs related to the Permission Model.securityIssues and PRs related to security.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions