11import test from "ava" ;
22import * as td from "testdouble" ;
3+ import AggregateError from "aggregate-error" ;
34import { OFFICIAL_REGISTRY } from "../lib/definitions/constants.js" ;
45
5- let execa , verifyAuth , getRegistry , setNpmrcAuth ;
6+ let execa , verifyAuth , getRegistry , setNpmrcAuth , oidcContextEstablished ;
67const DEFAULT_NPM_REGISTRY = OFFICIAL_REGISTRY ;
78const npmrc = "npmrc contents" ;
89const pkg = { } ;
@@ -15,6 +16,8 @@ test.beforeEach(async (t) => {
1516 ( { execa } = await td . replaceEsm ( "execa" ) ) ;
1617 ( { default : getRegistry } = await td . replaceEsm ( "../lib/get-registry.js" ) ) ;
1718 ( { default : setNpmrcAuth } = await td . replaceEsm ( "../lib/set-npmrc-auth.js" ) ) ;
19+ ( { default : oidcContextEstablished } = await td . replaceEsm ( "../lib/trusted-publishing/oidc-context.js" ) ) ;
20+ td . when ( oidcContextEstablished ( ) ) . thenReturn ( false ) ;
1821
1922 ( { default : verifyAuth } = await import ( "../lib/verify-auth.js" ) ) ;
2023} ) ;
@@ -23,10 +26,21 @@ test.afterEach.always((t) => {
2326 td . reset ( ) ;
2427} ) ;
2528
29+ test . serial (
30+ "that the auth context for the official registry is considered valid when trusted publishing is established" ,
31+ async ( t ) => {
32+ td . when ( getRegistry ( pkg , context ) ) . thenReturn ( DEFAULT_NPM_REGISTRY ) ;
33+ td . when ( oidcContextEstablished ( DEFAULT_NPM_REGISTRY ) ) . thenReturn ( true ) ;
34+
35+ await t . notThrowsAsync ( verifyAuth ( npmrc , pkg , context ) ) ;
36+ }
37+ ) ;
38+
2639test . serial (
2740 "that the provided token is verified with `npm whoami` when trusted publishing is not established for the official registry" ,
2841 async ( t ) => {
2942 td . when ( getRegistry ( pkg , context ) ) . thenReturn ( DEFAULT_NPM_REGISTRY ) ;
43+ td . when ( oidcContextEstablished ( DEFAULT_NPM_REGISTRY ) ) . thenReturn ( false ) ;
3044 td . when (
3145 execa ( "npm" , [ "whoami" , "--userconfig" , npmrc , "--registry" , DEFAULT_NPM_REGISTRY ] , {
3246 cwd,
@@ -46,6 +60,7 @@ test.serial(
4660 "that the auth context for the official registry is considered invalid when no token is provided and trusted publishing is not established" ,
4761 async ( t ) => {
4862 td . when ( getRegistry ( pkg , context ) ) . thenReturn ( DEFAULT_NPM_REGISTRY ) ;
63+ td . when ( oidcContextEstablished ( DEFAULT_NPM_REGISTRY ) ) . thenReturn ( false ) ;
4964 td . when (
5065 execa ( "npm" , [ "whoami" , "--userconfig" , npmrc , "--registry" , DEFAULT_NPM_REGISTRY ] , {
5166 cwd,
@@ -64,10 +79,89 @@ test.serial(
6479 }
6580) ;
6681
82+ test . serial (
83+ "that a publish dry run is performed to validate token presence when publishing to a custom registry" ,
84+ async ( t ) => {
85+ const otherRegistry = "https://other.registry.org" ;
86+ td . when ( getRegistry ( pkg , context ) ) . thenReturn ( otherRegistry ) ;
87+ td . when ( oidcContextEstablished ( otherRegistry ) ) . thenReturn ( false ) ;
88+ td . when (
89+ execa (
90+ "npm" ,
91+ [
92+ "publish" ,
93+ "--dry-run" ,
94+ "--tag=semantic-release-auth-check" ,
95+ "--userconfig" ,
96+ npmrc ,
97+ "--registry" ,
98+ otherRegistry ,
99+ ] ,
100+ {
101+ cwd,
102+ env : otherEnvVars ,
103+ preferLocal : true ,
104+ lines : true ,
105+ }
106+ )
107+ ) . thenResolve ( {
108+ stderr : [ "foo" , "bar" , "baz" ] ,
109+ } ) ;
110+
111+ await t . notThrowsAsync ( verifyAuth ( npmrc , pkg , context ) ) ;
112+ }
113+ ) ;
114+
67115// since alternative registries are not consistent in implementing `npm whoami`,
68116// we do not attempt to verify the provided token when publishing to them
69- test . serial ( "that `npm whoami` is not invoked when publishing to a custom registry" , async ( t ) => {
70- td . when ( getRegistry ( pkg , context ) ) . thenReturn ( "https://other.registry.org" ) ;
117+ test . serial (
118+ "that the token is considered invalid when the publish dry run fails when publishing to a custom registry" ,
119+ async ( t ) => {
120+ const otherRegistry = "https://other.registry.org" ;
121+ td . when ( getRegistry ( pkg , context ) ) . thenReturn ( otherRegistry ) ;
122+ td . when ( oidcContextEstablished ( otherRegistry ) ) . thenReturn ( false ) ;
123+ td . when (
124+ execa (
125+ "npm" ,
126+ [
127+ "publish" ,
128+ "--dry-run" ,
129+ "--tag=semantic-release-auth-check" ,
130+ "--userconfig" ,
131+ npmrc ,
132+ "--registry" ,
133+ otherRegistry ,
134+ ] ,
135+ {
136+ cwd,
137+ env : otherEnvVars ,
138+ preferLocal : true ,
139+ lines : true ,
140+ }
141+ )
142+ ) . thenResolve ( {
143+ stderr : [ "foo" , "bar" , "baz" , `This command requires you to be logged in to ${ otherRegistry } ` , "qux" ] ,
144+ } ) ;
145+
146+ const {
147+ errors : [ error ] ,
148+ } = await t . throwsAsync ( verifyAuth ( npmrc , pkg , context ) ) ;
149+
150+ t . is ( error . name , "SemanticReleaseError" ) ;
151+ t . is ( error . code , "EINVALIDNPMAUTH" ) ;
152+ t . is ( error . message , "Invalid npm authentication." ) ;
153+ }
154+ ) ;
155+
156+ test . serial ( "that errors from setting up auth bubble through this function" , async ( t ) => {
157+ const registry = DEFAULT_NPM_REGISTRY ;
158+ const thrownError = new Error ( ) ;
159+ td . when ( getRegistry ( pkg , context ) ) . thenReturn ( registry ) ;
160+ td . when ( setNpmrcAuth ( npmrc , registry , context ) ) . thenThrow ( new AggregateError ( [ thrownError ] ) ) ;
161+
162+ const {
163+ errors : [ error ] ,
164+ } = await t . throwsAsync ( verifyAuth ( npmrc , pkg , context ) ) ;
71165
72- await t . notThrowsAsync ( verifyAuth ( npmrc , pkg , context ) ) ;
166+ t . is ( error , thrownError ) ;
73167} ) ;
0 commit comments