diff --git a/docs/content/using-npm/config.md b/docs/content/using-npm/config.md index 200a2e401c7a6..ba79dd505a88e 100644 --- a/docs/content/using-npm/config.md +++ b/docs/content/using-npm/config.md @@ -138,6 +138,8 @@ npm ls --global --parseable --long --loglevel info * Type: null or String A basic-auth string to use when authenticating against the npm registry. +This will ONLY be used to authenticate against the npm registry. For other +registries you will need to scope it like "//other-registry.tld/:_auth" Warning: This should generally not be set via a command-line option. It is safer to use a registry-provided authentication bearer token stored in the diff --git a/lib/utils/config/definitions.js b/lib/utils/config/definitions.js index f4ffb821837b0..4a1f971d85436 100644 --- a/lib/utils/config/definitions.js +++ b/lib/utils/config/definitions.js @@ -147,6 +147,8 @@ define('_auth', { type: [null, String], description: ` A basic-auth string to use when authenticating against the npm registry. + This will ONLY be used to authenticate against the npm registry. For other + registries you will need to scope it like "//other-registry.tld/:_auth" Warning: This should generally not be set via a command-line option. It is safer to use a registry-provided authentication bearer token stored in diff --git a/tap-snapshots/test/lib/commands/publish.js.test.cjs b/tap-snapshots/test/lib/commands/publish.js.test.cjs index c6f757e8a9b2e..6a33b891e083d 100644 --- a/tap-snapshots/test/lib/commands/publish.js.test.cjs +++ b/tap-snapshots/test/lib/commands/publish.js.test.cjs @@ -5,6 +5,10 @@ * Make sure to inspect the output below. Do not ignore changes! */ 'use strict' +exports[`test/lib/commands/publish.js TAP _auth config default registry > new package version 1`] = ` ++ test-package@1.0.0 +` + exports[`test/lib/commands/publish.js TAP dry-run > must match snapshot 1`] = ` Array [ Array [ @@ -108,6 +112,10 @@ exports[`test/lib/commands/publish.js TAP respects publishConfig.registry, runs ` +exports[`test/lib/commands/publish.js TAP scoped _auth config scoped registry > new package version 1`] = ` ++ @npm/test-package@1.0.0 +` + exports[`test/lib/commands/publish.js TAP tarball > must match snapshot 1`] = ` Array [ Array [ diff --git a/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs b/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs index b190d7eb10ba6..ff00f9a0f9b3d 100644 --- a/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs +++ b/tap-snapshots/test/lib/utils/config/definitions.js.test.cjs @@ -169,6 +169,8 @@ exports[`test/lib/utils/config/definitions.js TAP > config description for _auth * Type: null or String A basic-auth string to use when authenticating against the npm registry. +This will ONLY be used to authenticate against the npm registry. For other +registries you will need to scope it like "//other-registry.tld/:_auth" Warning: This should generally not be set via a command-line option. It is safer to use a registry-provided authentication bearer token stored in the diff --git a/tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs b/tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs index a97b35d3acfe2..6740b94c772c8 100644 --- a/tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs +++ b/tap-snapshots/test/lib/utils/config/describe-all.js.test.cjs @@ -12,6 +12,8 @@ exports[`test/lib/utils/config/describe-all.js TAP > must match snapshot 1`] = ` * Type: null or String A basic-auth string to use when authenticating against the npm registry. +This will ONLY be used to authenticate against the npm registry. For other +registries you will need to scope it like "//other-registry.tld/:_auth" Warning: This should generally not be set via a command-line option. It is safer to use a registry-provided authentication bearer token stored in the diff --git a/test/fixtures/mock-registry.js b/test/fixtures/mock-registry.js index 5e39dcf48315a..5890fa7ee9366 100644 --- a/test/fixtures/mock-registry.js +++ b/test/fixtures/mock-registry.js @@ -11,6 +11,7 @@ class MockRegistry { #nock #registry #authorization + #basic constructor (opts) { if (!opts.registry) { @@ -18,6 +19,7 @@ class MockRegistry { } this.#registry = (new URL(opts.registry)).origin this.#authorization = opts.authorization + this.#basic = opts.basic // Required for this.package this.#tap = opts.tap } @@ -32,6 +34,9 @@ class MockRegistry { if (this.#authorization) { reqheaders.authorization = `Bearer ${this.#authorization}` } + if (this.#basic) { + reqheaders.authorization = `Basic ${this.#basic}` + } this.#nock = tnock(this.#tap, this.#registry, { reqheaders }) } return this.#nock diff --git a/test/lib/commands/publish.js b/test/lib/commands/publish.js index b17424b084461..885e820422ec0 100644 --- a/test/lib/commands/publish.js +++ b/test/lib/commands/publish.js @@ -10,6 +10,7 @@ const pkg = 'test-package' const token = 'test-auth-token' const auth = { '//registry.npmjs.org/:_authToken': token } const alternateRegistry = 'https://other.registry.npmjs.org' +const basic = Buffer.from('test-user:test-password').toString('base64') const pkgJson = { name: pkg, @@ -602,3 +603,74 @@ t.test('ignore-scripts', async t => { 'did not run postpublish' ) }) + +t.test('_auth config default registry', async t => { + const { npm, joinedOutput } = await loadMockNpm(t, { + config: { + _auth: basic, + }, + prefixDir: { + 'package.json': JSON.stringify(pkgJson), + }, + globals: ({ prefix }) => ({ + 'process.cwd': () => prefix, + }), + }) + const registry = new MockRegistry({ + tap: t, + registry: npm.config.get('registry'), + basic, + }) + registry.nock.put(`/${pkg}`).reply(200, {}) + await npm.exec('publish', []) + t.matchSnapshot(joinedOutput(), 'new package version') +}) + +t.test('bare _auth config scoped registry', async t => { + const { npm } = await loadMockNpm(t, { + config: { + '@npm:registry': alternateRegistry, + _auth: basic, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: '@npm/test-package', + version: '1.0.0', + }, null, 2), + }, + globals: ({ prefix }) => ({ + 'process.cwd': () => prefix, + }), + }) + await t.rejects( + npm.exec('publish', []), + { message: `This command requires you to be logged in to ${alternateRegistry}` } + ) +}) + +t.test('scoped _auth config scoped registry', async t => { + const spec = npa('@npm/test-package') + const { npm, joinedOutput } = await loadMockNpm(t, { + config: { + '@npm:registry': alternateRegistry, + [`${alternateRegistry.slice(6)}/:_auth`]: basic, + }, + prefixDir: { + 'package.json': JSON.stringify({ + name: '@npm/test-package', + version: '1.0.0', + }, null, 2), + }, + globals: ({ prefix }) => ({ + 'process.cwd': () => prefix, + }), + }) + const registry = new MockRegistry({ + tap: t, + registry: alternateRegistry, + basic, + }) + registry.nock.put(`/${spec.escapedName}`).reply(200, {}) + await npm.exec('publish', []) + t.matchSnapshot(joinedOutput(), 'new package version') +})