Skip to content
This repository has been archived by the owner on Aug 11, 2021. It is now read-only.

postinstall "cannot run in wd" when working directory does not match the package name (in docker) #49

Open
amadsen opened this issue Jul 2, 2020 · 3 comments

Comments

@amadsen
Copy link

amadsen commented Jul 2, 2020

What / Why

It is common for a Dockerfile to install an app in a /app directory. If the app is a node app and it has a "postinstall" script (and possibly other lifecycle hooks) it will fail with an error that looks like:

npm WARN lifecycle [email protected]~postinstall: cannot run in wd [email protected] npm run exit 0 (wd=/app)

Most of the issues found using a search engine will indicate that this is a permissions issue caused by running as root and npm downgrading permissions to nobody. However, this issue will still occur if the "postinstall" script is "exit 0", which should require no permissions. On the other hand, the suggested workaround of setting --unsafe-perm works. The relevant lines of code are:

        if ((wd.indexOf(opts.dir) !== 0 || _incorrectWorkingDirectory(wd, pkg)) &&
            !opts.unsafePerm && pkg.scripts[stage]) {
          opts.log.warn('lifecycle', logid(pkg, stage), 'cannot run in wd', pkg._id, pkg.scripts[stage], `(wd=${wd})`)
          return resolve()
        }

(from index.js, lines 86-90)

Note that employing --unsafe-perm specifically serves as an escape hatch, though it does not appear to have much to do with permissions on the directory. _incorrectWorkingDirectory() checks to see if the working directory matches the name of the package in package.json.

I do not know if this is a bug or intended behavior - it makes sense as a swift heuristic to ensure you are in the expected package - but it is not well documented and conflicts subtly with nodejs.org's recommendations for a Dockerfile.

@Seb35
Copy link

Seb35 commented Jul 20, 2020

I also observed this (in action prepare for me, but whatever), in a Docker in a CI pipeline. Like @amadsen I’m not sure what ckeck the conditions around wd, opts.dir, and pkg.name: I observe they are always true, but possibly it is for a specific use case we don’t use.

Note that it is very common in Docker and specifically in CI to execute as root. I think it is a bad practice, but it is very common, even in the official Docker image for node (see this issue).

About npm-lifecycle, I wonder if there is not a logic bug around unsafe-perm+user+group:

  • if unsafe-perm is false (as a root user with default unsafe-perm = false), there is no chance we execute the program because of the condition mentionned above lines 86-90,
  • if unsafe-perm is true (as a non-root user or a root user with explicit unsafe-perm=true), we continue through the functions lifecycle_ then runPackageLifecycle/runHookLifecycle then runCmd and here we use the config values user and group only if unsafe-perm is false, but it is true in this branch, hence we always run the program as root and user/group are never used (at least in this branch path, perhaps it is used elsewhere).

@Seb35
Copy link

Seb35 commented Jul 20, 2020

PS: if like me the action is in a child npm process (like in a dependency defined by a Git repo), the --unsafe-perm in the main npm was not enough (=not transmitted to the child npm), so it can be used an environment variable npm_config_unsafe_perm="true".

@lydell
Copy link

lydell commented Sep 6, 2020

@amadsen Thank you so much for digging into this! I’m adding this weird workaround to my package.json:

+  "__comment": "'name' must match the WORKDIR in Dockerfile used when executing `RUN npm ci`.",
+  "name": "app",

Also, if I understand _incorrectWorkingDirectory correctly it just does a convoluted “ends with” check. I guess the intention is to check that for example my-package matches /some/path/my-package but /some/path/foobar-my-package will match as well?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants