denoland / deno

A modern runtime for JavaScript and TypeScript.
https://deno.com
MIT License
93.98k stars 5.23k forks source link

deno run - Uncaught PermissionDenied: Permission denied (os error 13) #5816 #17222

Open jimisaacs opened 1 year ago

jimisaacs commented 1 year ago

deno 1.29.1 (release, x86_64-unknown-linux-gnu) v8 10.9.194.5 typescript 4.9.4

Originally commented the following here https://github.com/denoland/deno/issues/5816#issuecomment-1367713864, but then I realized this seems to be a different error and doesn't appear to have anything to do with TSL.

I was fighting and fighting with this error:

error: Permission denied (os error 13)

during this command:

setuidgid $MY_USER deno cache --import-map ./import_map.json --lock ./deno.lock main.ts

What fixed it was simply one of these:

chown $MY_USER deno.lock

or

chmod 666 deno.lock

Keep in mind 664 did NOT work. So something is requiring write permissions on the lock file.

jimisaacs commented 1 year ago

I should also mention I get the same error:

error: Permission denied (os error 13)

with the following command:

setuidgid $MY_USER exec deno run \
    --allow-env --allow-net --allow-read \
    --import-map ./import_map.json \
    --lock ./deno.lock \
    --cached-only main.ts

and the previously mentioned fixes for deno cache also fixes this.

bartlomieju commented 1 year ago

If you're using deno cache then the lockfile might get updated - it's expected that a write permissions is required in such case.

jimisaacs commented 1 year ago

@bartlomieju that's not really clear and actually questionable. I'd commit the lock file, but not the cache. So to hydrate the cache consistently I'd use deno cache with the lock file, and I'd want to do that without a write.

This, and there's an option for deno cache -h that has this:

  --lock-write
            Force overwriting the lock file.

This sounds like by default, it wouldn't write the lock file.

jimisaacs commented 1 year ago

keep in mind this is all to work with --cache-only while in production.

bartlomieju commented 1 year ago

Starting with v1.28 lockfile is automatically discovered and created if there's a deno.json file: https://deno.com/blog/v1.28#auto-discovery-of-the-lock-file. Since then --lock-write is a way to force writing of lockfile is something gets broken.

If all entries are present in the lockfile then it shouldn't be updated and thus nothing would be written to disk. Can you provide a reproduction code?

jimisaacs commented 1 year ago

I missed the simple command didn't I? Whoops! So all of the above in the original message applies to after running deno cache ./main.ts from the directory where a deno.json and deno.lock file exists.

jimisaacs commented 1 year ago

Though the user that runs deno cache is different from the owner of deno.lock

jimisaacs commented 1 year ago

So I don't expect the deno.lock file to be written, but the process asks for write access, hence the os error

jimisaacs commented 1 year ago

@bartlomieju I found the reduced case!!!

Here is a working import_map.json that does not cause a error: Permission denied (os error 13) on deno task start of a fresh new fresh demo app:

{
    "imports": {
        "@preact/signals-core": "https://esm.sh/*@preact/signals-core@1.0.1",
        "@preact/signals": "https://esm.sh/*@preact/signals@1.0.3",
        "$fresh/": "https://deno.land/x/fresh@1.1.2/",
        "asserts": "https://deno.land/std@0.168.0/testing/asserts.ts",
        "preact-render-to-string": "https://esm.sh/*preact-render-to-string@5.2.4",
        "preact": "https://esm.sh/preact@10.11.0",
        "preact/": "https://esm.sh/preact@10.11.0/",
        "twind": "https://esm.sh/twind@0.16.17",
        "twind/": "https://esm.sh/twind@0.16.17/",
    }
}

Here is an example that does cause error: Permission denied (os error 13) on deno task start:

{
    "imports": {
        "@preact/signals-core": "https://esm.sh/*@preact/signals-core@1.0.1",
        "@preact/signals": "https://esm.sh/*@preact/signals@1.0.3",
        "$fresh/": "https://deno.land/x/fresh@1.1.2/",
        "asserts": "https://deno.land/std@0.168.0/testing/asserts.ts",
        "preact-render-to-string": "https://esm.sh/*preact-render-to-string@5.2.4",
        "preact": "https://esm.sh/preact@10.11.0",
        "preact/": "https://esm.sh/preact@10.11.0/",
        "twind": "https://esm.sh/twind@0.16.17",
        "twind/": "https://esm.sh/twind@0.16.17/",
        "example-typescript-package": "npm:example-typescript-package@0.2.2"
    }
}

Keep in mind that I added this to main.ts to ensure it got exercised:

import { Num } from 'example-typescript-package';
console.log(new Num(5));

Also, to reiterate. This only happens when the deno.lock file is owned by a different user than whom executed deno run.


You'll notice the only thing that is different, is that one has no npm: specifier, and one arbitrarily does. I think the npm: specifier is causing a write to deno.lock unexpectedly.

jimisaacs commented 1 year ago

I'm going to retitle this issue to deno run since that is more descriptive of the reduced case. Also funny thing to mention is that in that reduced case, the entire $DENO_DIR is fine in both scenarios being owned by another user than the user that executed deno run. It seems to only be the deno.lock file that causes the permission denied error.

For specificity. This case is running an enterprise deno application, which is executed by a user specific to running that application. While the source files, that include the cache in $DENO_DIR, and the deno.lock file, are owned by the root user. Then when launching the application on deploy with deno task start is when the permission issue occurs.

So imagine it is launched like this, even though all sources are owned by the root user:

exec setuidgid "${MY_APP_USER}" deno task start