Add directory traversal to .npmrc lookup algorithm

Frustrations

Multi-user authentication across multiple scopes in the same registry

See this idea for a similar request.

I have two separate logins to publish packages in different orgs (i.e., “scopes”) to https://registry.npmjs.org/. For security reasons, user A shouldn’t have access to publish to scope B and vice versa. This wouldn’t be an issue if both scopes were in different registries, but because both scopes are in the same registry (public NPM registry), I have to manage different .npmrc files for both users and remember to provide a --userconfig option every time I need to authenticate with the registry. This increases the potential for simple mistakes that occur as a result of human error.

I could set up project-specific .npmrc files, but then I’d have to manage numerous .npmrc files across all of @a/* scoped and @b/* scoped packages, duplicating my authentication credentials and increasing the surface area for an accidental commit of an .npmrc file to a public service. Should that happen, then I’d have to go update credentials across every single project using the same credentials.

Scope/org-specific settings

  • Scope @a packages should all be licensed under MIT (init-license=MIT).
  • Scope @b packages should all be licensed under Apache 2.0 (init-license=Apache-2.0).

Once again, I’m forced to use yet another set of .npmrc files to load with npm init --userconfig=scope/a/.npmrc. For similar reasons mentions above, this is undesirable.

I don’t know about other devs, but it makes sense to organize all @a/* scoped projects in the same directory parent directory (e.g., @a/**/). As such, it’d be extremely helpful to define all of my @a default configs at ~/@a/.npmrc and automatically recognized if I run npm init from within ~/@a/bar/.

Proposal

Add directory traversal to the .npmrc lookup algorithm

Example Directory Structure

~/.npmrc
  # init-version=0.0.1

~/@foo/.npmrc # scope configuration
  # (inherits "init-version" from ../.npmrc)
  # scope=foo
  # init-license=MIT
  # //registry.npmjs.org/:_authToken=AAAA-AAAA-AAAA-AAAA-AAAA

~/@foo/bar/.npmrc # project configuration
  # (inherits "init-version", "init-license", "scope", and auth creds from ../.npmrc)

~/@bar/.npmrc
  # init-version=1.0.0 (overrides ../.npmrc)
  # init-license=Apache-2.0
  # scope=bar
  # //registry.npmjs.org/:_authToken=BBBB-BBBB-BBBB-BBBB-BBBB

Configuration Option Resolution

Config options resolve in the following order (earlier definitions trump later ones):

  1. CLI options (e.g., --userconfig)
  2. Project-level config (~/@foo/bar/.npmrc)
  3. Scope-level config (~/**/@foo/.npmrc)
  4. User-level config (~/.npmrc)
  5. Global config file ($PREFIX/etc/npmrc)
  6. npm builtin config file (/path/to/npm/npmrc)

(Note: I’m not sure where environment variables fit into this hierarchy.)

Advantages

  1. Scope-specific auth is isolated to a single .npmrc file.
    • If you’re not using a monorepo, this keeps authToken away from accidental exposure via version control.
    • If you are using a monorepo, this is already possible today, with a project-level config.
  2. Project-level configs inherit scope-level configs, so there’s no need to add the scope-level authToken to every project in the same scope.
  3. npm automatically knows how to resolve config settings without the need to manually include --userconfig every time you need to override a default setting
    • npm init can pull init-version, init-license, etc. automatically when I initialize a new scoped directory
    • npm publish can pull registry, authentication, and scope configs in order to publish to the right place as the right user, every time
  4. Because nested .npmrc files can inherit the config of its parent directory, you can override as little or as much as needed, no matter how deep your directories are nested.
    • Any configuration can be overridden at any level.
    • May no longer need @scoped registry config(just change registry=... at any level)

Disadvantages

  1. Can be somewhat daunting to new package developers. Will need more robust and user-friendly output from npm config list command.
  2. I’m not sure where environment variables fit into the config resolution hierarchy.

Hopefully, I’ve explained this clear enough.