yarnpkg / berry

📦🐈 Active development trunk for Yarn ⚒
https://yarnpkg.com
BSD 2-Clause "Simplified" License
7.37k stars 1.1k forks source link

publish/whoami authorisation with Workspaces + Scoped packages + Custom Registry seems broken. #1998

Open xenobytezero opened 3 years ago

xenobytezero commented 3 years ago

It's difficult to provide a reproduction for this issue, considering that it requires a custom NPM registry, but I have described as much as possible.

Describe the bug

I have a Yarn 2 Workspaces projects, under the scope 'obsidian' set up like the following

.
├── .yarn
│   └── **
├── packages
│   ├── a
│   │   ├── src
│   │   └── package.json
│   └── b
│       ├── src
│       └── package.json
├── package.json
└── .yarnrc.yaml

My .yarnrc.yaml looks like the following (with redactions)

enableGlobalCache: true

npmScopes:
  obsidian:
    npmPublishRegistry: "https://my.custom.publish.repo/"
    npmRegistryServer: "https://my.custom.repo/"

plugins:
  - path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
    spec: "@yarnpkg/plugin-workspace-tools"

pnpMode: loose

yarnPath: .yarn/releases/yarn-2.3.3.cjs

I am at the point where I'm ready to publish, and started going through the yarn npm login flow, and cannot seem to successfully login to a custom registry with a scope and successfully publish.

To Reproduce

C:\Projects\__\tool>yarn npm login --publish --scope obsidian
➤ YN0000: Logging in to https://my.custom.repo/publish

√ Username: · me
√ Password: · ***********

➤ YN0000: Successfully logged in
➤ YN0000: Done in 4s 710ms

I now have the following in my user .yarnrc.yaml

npmScopes:
  obsidian:
    npmAuthToken: <AUTH_TOKEN>

All seems good at this point. Lets try and do a whoami to confirm the login

C:\Projects\__\tool>yarn npm whoami --scope obsidian --publish
➤ YN0033: No authentication configured for request
➤ YN0000: Failed with errors in 0s 3ms

From the subpackages?

C:\Projects\__\tool\packages\a>yarn npm whoami --scope obsidian --publish
➤ YN0033: No authentication configured for request
➤ YN0000: Failed with errors in 0s 4ms

Lets look at the yarn config that combines the project and the user settings

C:\Projects\Personal\CPITAutoDeploy\AutoDeploy\tool>yarn config --why
***
***
➤ YN0000: npmAlwaysAuth                 <default>                                                                                                 false
➤ YN0000: npmAuthIdent                  <default>                                                                                                 null
➤ YN0000: npmAuthToken                  <default>                                                                                                 null
➤ YN0000: npmPublishAccess              <default>                                                                                                 null
➤ YN0000: npmPublishRegistry            <default>                                                                                                 null
➤ YN0000: npmRegistries                 <default>                                                                                                 Map {}
➤ YN0000: npmRegistryServer             <default>                                                                                                 'https://registry.yarnpkg.com'
➤ YN0000: npmScopes                     undefined, /C:/Projects/__/tool/.yarnrc.yml, /C:/Users/me/.yarnrc.yml   Map { 'obsidian' => Map { 'npmAlwaysAuth' => false, 'npmAuthIdent' => null, 'npmAuthToken' => null, 'npmPublishRegistry' => 'https://my.custom.publish.repo/', 'npmRegistryServer' => 'https://my.custom.repo/' } }
***
***
➤ YN0000: Done in 0s 130ms

Looks like it's not picking up the scoped npmAuthToken from the user .yarnrc? Normally the auth token shows up as ********* in the list.

We are now in non-useful debug territory, but lets try dumping the npmAuthToken in the project .yarnrc for this scope

enableGlobalCache: true

npmScopes:
  obsidian:
    npmPublishRegistry: "https://my.custom.publish.repo/"
    npmRegistryServer: "https://my.custom.repo/"
    npmAuthToken: <AUTH_TOKEN>

plugins:
  - path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
    spec: "@yarnpkg/plugin-workspace-tools"

pnpMode: loose

yarnPath: .yarn/releases/yarn-2.3.3.cjs

Try again?

C:\Projects\__\tool>yarn npm whoami --scope obsidian --publish
➤ YN0033: No authentication configured for request
➤ YN0000: Failed with errors in 0s 3ms

Config list?


➤ YN0000: npmScopes                     undefined, /C:/Projects/Personal/CPITAutoDeploy/AutoDeploy/tool/.yarnrc.yml, /C:/Users/euro/.yarnrc.yml   Map { 'obsidian' => Map { 'npmAlwaysAuth' => false, 'npmAuthIdent' => null, 'npmAuthToken' => '********', 'npmPublishRegistry' => 'https://my.custom.publish.repo/', 'npmRegistryServer' => 'https://my.custom.repo/' } }

So it's picking up the npmAuthToken now but not using it?

Finally what if we just add the auth token to the top level of the .yarnrc?

enableGlobalCache: true

npmAuthToken: <AUTH_TOKEN>

npmScopes:
  obsidian:
    npmPublishRegistry: "https://my.custom.publish.repo/"
    npmRegistryServer: "https://my.custom.repo/"

plugins:
  - path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
    spec: "@yarnpkg/plugin-workspace-tools"

pnpMode: loose

yarnPath: .yarn/releases/yarn-2.3.3.cjs

Try again

C:\Projects\__\tool>yarn npm whoami --scope obsidian --publish
➤ YN0000: me
➤ YN0000: Done in 0s 292ms

Looks like thats the only way to get this to work?

I can confirm that trying to yarn npm publish produces the same results as using yarn npm whoami, can only get it to work with putting the npmAuthToken at the root of the project .yarnrc

Environment if relevant (please complete the following information):

merceyz commented 3 years ago

yarn npm whoami --scope not picking up the correct login was fixed in https://github.com/yarnpkg/berry/pull/1943 but it hasn't been released yet, you can test out the version from master using yarn set version from sources

xenobytezero commented 3 years ago

@merceyz Does #1943 only fix whoami issues or for all authentication with scoped packages? I'm just using whoami as an example rather than using yarn npm publish which is producing the same errors?

xenobytezero commented 3 years ago

@merceyz I've just run yarn set version from sources and I'm getting the same behaviour with a scope where the auth token is in my user .yarnrc

C:\Projects\__\tool>yarn npm whoami --scope obsidian --publish
➤ YN0033: No authentication configured for request
➤ YN0000: Failed with errors in 0s 3ms
yarnbot commented 3 years ago

Hi! 👋

This issue looks stale, and doesn't feature the reproducible label - which implies that you didn't provide a working reproduction using Sherlock. As a result, it'll be closed in a few days unless a maintainer explicitly vouches for it or you edit your first post to include a formal reproduction (you can use the playground for that).

Note that we require Sherlock reproductions for long-lived issues (rather than standalone git repositories or similar) because we're a small team. Sherlock gives us the ability to check which bugs are still affecting the master branch at any given point, and decreases the amount of code we need to run on our own machines (thus leading to faster bug resolutions). It helps us help you! 😃

If you absolutely cannot reproduce a bug on Sherlock (for example because it's a Windows-only issue), a maintainer will have to manually add the upholded label. Thanks for helping us triaging our repository! 🌟

xenobytezero commented 3 years ago

This issue is difficult to reproduce considering the nature of it.

Can anyone provide pointers for how to keep this issue open? I'm still seeing the issue, and have had to move back to NPM7 to continue working.

merceyz commented 3 years ago

https://github.com/yarnpkg/berry/issues/1998#issuecomment-712084046 the auth token is in my user .yarnrc

Do you mean .yarnrc.yml? .yarnrc isn't used by V2

Anyways, I can't reproduce this

IlyaM commented 3 years ago

Do you mean .yarnrc.yml? .yarnrc isn't used by V2

I'm not the original reporter but I'm almost sure that he meant .yarnrc.yml. I'm just tired to set up the publishing of scoped packages to a private repository and I've hit the exact same problem, as the original requestor described.

yarn npm login --scope XXX where XXX is my scope, which is configured via npmScopes, logins successfully and adds npmAuthToken into .yarnrc.yml in $HOME but yarn npm whoami --scope XXX fails to authorize unless I copy npmAuthToken from .yarnrc.yml in $HOME into .yarnrc.yml in the project directory. Likewise publish doesn't work as well unless npmAuthToken is copied into .yarnrc.yml in the project directory. Basically, I've done exactly the same steps as @xenobytezero described and I've got the exact same results.

This is reproducible with the latest version yarn 2.4.1

xenobytezero commented 3 years ago

Can confirm I meant .yarnrc.yml

acusti commented 3 years ago

i am not using a custom registry, though i am using scoped packages inside a yarn 2 workspace. as described above, when i run yarn npm login --scope acusti, the resulting npmAuthToken is written to ~/.yarnrc.yml, but when i then try to run yarn npm publish, i get YN0033 (which doesn’t have an entry in the error codes page):

YN0033: No authentication configured for request

however, if i copy the npmAuthToken and add it as a top-level item in the workspaces’ top-level .yarnrc.yml file, npm publish works without error.

note that i had to yarn set version from sources to resolve #2232, so my yarn version is the following:

$ yarn --version
2.4.0-git.20210324.hash-a307bddb
kasperisager commented 3 years ago

I'm hitting the same issue with GitHub Packages. The following is specified in <project>/.yarnrc.yml:

npmScopes:
  myorg:
    npmRegistryServer: "https://npm.pkg.github.com"

To install the dependencies of the project, I first do the following in <project>:

yarn npm login --scope myorg

This puts the following in ~/.yarnrc.yml:

npmScopes:
  myorg:
    npmAuthToken: ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

After logging in, if I do the following in <project>...

yarn config get npmScopes

...I see this:

{
  myorg: {
    npmAlwaysAuth: false,
    npmAuthIdent: null,
    npmAuthToken: null,
    npmPublishRegistry: null,
    npmRegistryServer: 'https://npm.pkg.github.com'
  }
}

If I remove npmScopes from <project>/.yarnrc.yml, I instead see this:

{
  myorg: {
    npmAlwaysAuth: false,
    npmAuthIdent: null,
    npmAuthToken: '********',
    npmPublishRegistry: null,
    npmRegistryServer: 'https://registry.yarnpkg.com'
  }
}

This leads me to believe that the configuration merging is not working for npmScopes for some reason. What I'd expect to see is this:

{
  myorg: {
    npmAlwaysAuth: false,
    npmAuthIdent: null,
    npmAuthToken: '********',
    npmPublishRegistry: null,
    npmRegistryServer: 'https://npm.pkg.github.com'
  }
}

That is, npmRegistryServer should be sourced from <project>/.yarnrc.yml and npmAuthToken should be sourced from ~/.yarnrc.yml. Is that what the maintainers believe should happen as well or am I holding this thing wrong?

rachel-church commented 3 years ago

Looking into the unit tests for the Configuration class it looks like the nested values of npmScopes are expected to be overridden: https://github.com/yarnpkg/berry/blob/%40yarnpkg/core%2F2.4.0/packages/yarnpkg-core/tests/Configuration.test.ts#L160-L189

From the "should overwrite map properties" unit test the following two config files:

// global config
{
  npmRegistryServer: `https://foo.server`,
  npmScopes: {
    foo: {
      npmAuthToken: `token for foo`,
    },
  },
}
// project config
{
  npmRegistryServer: `http://bar.server`,
  npmScopes: {
    foo: {
      npmAlwaysAuth: true,
    },
    bar: {
      npmAlwaysAuth: true,
    },
  },
}

Will result in configuration.get('npmScopes').get('foo').get('npmAuthToken') === null even though npmAuthToken is defined in the global config.

The merge logic was added in #1859 and the description mentions this exact case:

I've opted for only merging maps because merging maps makes sense. For shape configuration types it doesn't really make sense. What would the expected result be when merging

npmScopes:
  foo:
    npmAuthIdent: someIdent==

into

npmScopes:
  foo:
    npmAuthToken: a-token

? The object would have both ident and token, so how do we decide which one to take? What if the configs were turned around?

We could add a function on the ShapeSettingsDefinition type to perform this merge, but I'm not sure that's worth it. Wouldn't that always come down to not merging anyway? I mean: why would you want to replace the npmRegistryServer for a scope but keep the npmPublishRegistry and the configured authentication? If you want to configure auth and registry separately for a scope we already provide a way to do so via npmRegistries.

This behavior is unexpected to users and does not match how the documentation describes how to utilize yarn npm login --scope myorg. A deep merge should be added for these nested properties

rachel-church commented 3 years ago

Workaround

Run yarn config set --home "npmRegistries['<npmRegistryServer>'].npmAuthToken" "<npmAuthToken>" with the vales of your npmRegistryServer and npmAuthToken

This will add the auth token associated with the NPM registry URL to the global ~/.yarnrc.yml file.

npmRegistries:
  "https://npm.pkg.github.com":
    npmAuthToken: ffffffff-ffff-ffff-ffff-ffffffffffff
bhishp commented 3 years ago

+1 for experiencing this issue on my end. If its not technically a bug it is certainly not the behaviour I expected - in yarnv1 or npm the authToken for scope gets merged as expected and installs/publishes work fine.

Workaround

Run yarn config set --home "npmRegistries['<npmRegistryServer>'].npmAuthToken" "<npmAuthToken>" with the vales of your npmRegistryServer and npmAuthToken

This will add the auth token associated with the NPM registry URL to the global ~/.yarnrc.yml file.

npmRegistries:
  "https://npm.pkg.github.com":
    npmAuthToken: ffffffff-ffff-ffff-ffff-ffffffffffff

@rachel-church your workaround works a charm in the meantime, thank you