Skip to content

Commit 2ffc2ea

Browse files
reggihashtagchris
andauthored
fix: change to the oidc flow for more granular control over log levels (#8399)
Co-authored-by: Chris Sidi <hashtagchris@github.com>
1 parent 9021253 commit 2ffc2ea

File tree

3 files changed

+70
-32
lines changed

3 files changed

+70
-32
lines changed

lib/utils/oidc.js

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ async function oidc ({ packageName, registry, opts, config }) {
3030
/** @see https://github.com/watson/ci-info/blob/v4.2.0/vendors.json#L161C13-L161C22 */
3131
ciInfo.GITLAB
3232
)) {
33+
log.silly('oidc', 'Not running OIDC, not in a supported CI environment')
3334
return undefined
3435
}
3536

@@ -67,14 +68,11 @@ async function oidc ({ packageName, registry, opts, config }) {
6768
process.env.ACTIONS_ID_TOKEN_REQUEST_URL &&
6869
process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN
6970
) {
70-
log.silly('oidc', '"GITHUB_ACTIONS" detected with "ACTIONS_ID_" envs, fetching id_token')
71-
7271
/**
7372
* The specification for an audience is `npm:registry.npmjs.org`,
7473
* where "registry.npmjs.org" can be any supported registry.
7574
*/
7675
const audience = `npm:${new URL(registry).hostname}`
77-
log.silly('oidc', `Using audience: ${audience}`)
7876
const url = new URL(process.env.ACTIONS_ID_TOKEN_REQUEST_URL)
7977
url.searchParams.append('audience', audience)
8078
const startTime = Date.now()
@@ -96,17 +94,19 @@ async function oidc ({ packageName, registry, opts, config }) {
9694
const json = await response.json()
9795

9896
if (!response.ok) {
99-
throw new Error(`Failed to fetch id_token from GitHub: received an invalid response`)
97+
log.verbose('oidc', `Failed to fetch id_token from GitHub: received an invalid response`)
98+
return undefined
10099
}
101100

102101
if (!json.value) {
103-
throw new Error(`Failed to fetch id_token from GitHub: missing value`)
102+
log.verbose('oidc', `Failed to fetch id_token from GitHub: missing value`)
103+
return undefined
104104
}
105105

106-
log.silly('oidc', 'GITHUB_ACTIONS valid fetch response for id_token')
107106
idToken = json.value
108107
} else {
109-
throw new Error('GITHUB_ACTIONS detected. If you intend to publish using OIDC, please set workflow permissions for `id-token: write`')
108+
log.silly('oidc', 'GITHUB_ACTIONS detected. If you intend to publish using OIDC, please set workflow permissions for `id-token: write`')
109+
return undefined
110110
}
111111
}
112112
}
@@ -130,22 +130,31 @@ async function oidc ({ packageName, registry, opts, config }) {
130130
}
131131

132132
const escapedPackageName = npa(packageName).escapedName
133-
const response = await npmFetch.json(new URL(`/-/npm/v1/oidc/token/exchange/package/${escapedPackageName}`, registry), {
134-
...{
135-
...opts,
136-
[authTokenKey]: idToken, // Use the idToken as the auth token for the request
137-
},
138-
method: 'POST',
139-
headers: {
140-
...opts.headers,
141-
'Content-Type': 'application/json',
142-
// this will not work because the existing auth token will replace it.
143-
// authorization: `Bearer ${idToken}`,
144-
},
145-
})
133+
let response
134+
try {
135+
response = await npmFetch.json(new URL(`/-/npm/v1/oidc/token/exchange/package/${escapedPackageName}`, registry), {
136+
...{
137+
...opts,
138+
[authTokenKey]: idToken, // Use the idToken as the auth token for the request
139+
},
140+
method: 'POST',
141+
headers: {
142+
...opts.headers,
143+
'Content-Type': 'application/json',
144+
// this will not work because the existing auth token will replace it.
145+
// authorization: `Bearer ${idToken}`,
146+
},
147+
})
148+
} catch (error) {
149+
if (error?.body?.message) {
150+
log.verbose('oidc', `Registry body response error message "${error.body.message}"`)
151+
}
152+
return undefined
153+
}
146154

147155
if (!response?.token) {
148-
throw new Error('OIDC token exchange failure: missing token in response body')
156+
log.verbose('oidc', 'OIDC token exchange failure: missing token in response body')
157+
return undefined
149158
}
150159
/*
151160
* The "opts" object is a clone of npm.flatOptions and is passed through the `publish` command,
@@ -157,10 +166,8 @@ async function oidc ({ packageName, registry, opts, config }) {
157166
config.set(authTokenKey, response.token, 'user')
158167
log.silly('oidc', `OIDC token successfully retrieved`)
159168
} catch (error) {
160-
log.verbose('oidc', error.message)
161-
if (error?.body?.message) {
162-
log.verbose('oidc', `Registry body response error message "${error.body.message}"`)
163-
}
169+
/* istanbul ignore next */
170+
log.verbose('oidc', 'Failure checking OIDC config', error)
164171
}
165172
return undefined
166173
}

mock-registry/lib/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -631,11 +631,11 @@ class MockRegistry {
631631
}
632632
}
633633

634-
mockOidcTokenExchange ({ packageName, idToken, token, statusCode = 200 } = {}) {
634+
mockOidcTokenExchange ({ packageName, idToken, statusCode = 200, body } = {}) {
635635
const encodedPackageName = npa(packageName).escapedName
636636
this.nock.post(this.fullPath(`/-/npm/v1/oidc/token/exchange/package/${encodedPackageName}`))
637637
.matchHeader('authorization', `Bearer ${idToken}`)
638-
.reply(statusCode, statusCode !== 500 ? { token } : { message: 'Internal Server Error' })
638+
.reply(statusCode, body || {})
639639
}
640640
}
641641

test/lib/commands/publish.js

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,6 +1060,27 @@ t.test('oidc token exchange', t => {
10601060
}))
10611061

10621062
t.test('token exchange 500 with fallback', oidcPublishTest({
1063+
oidcOptions: { github: true },
1064+
config: {
1065+
'//registry.npmjs.org/:_authToken': 'existing-fallback-token',
1066+
},
1067+
mockGithubOidcOptions: {
1068+
audience: 'npm:registry.npmjs.org',
1069+
idToken: 'github-jwt-id-token',
1070+
},
1071+
mockOidcTokenExchangeOptions: {
1072+
statusCode: 500,
1073+
idToken: 'github-jwt-id-token',
1074+
body: {
1075+
message: 'oidc token exchange failed',
1076+
},
1077+
},
1078+
publishOptions: {
1079+
token: 'existing-fallback-token',
1080+
},
1081+
}))
1082+
1083+
t.test('token exchange 500 (with no body message) with fallback', oidcPublishTest({
10631084
oidcOptions: { github: true },
10641085
config: {
10651086
'//registry.npmjs.org/:_authToken': 'existing-fallback-token',
@@ -1138,7 +1159,9 @@ t.test('oidc token exchange', t => {
11381159
},
11391160
mockOidcTokenExchangeOptions: {
11401161
idToken: 'github-jwt-id-token',
1141-
token: 'exchange-token',
1162+
body: {
1163+
token: 'exchange-token',
1164+
},
11421165
},
11431166
publishOptions: {
11441167
token: 'exchange-token',
@@ -1152,7 +1175,9 @@ t.test('oidc token exchange', t => {
11521175
},
11531176
mockOidcTokenExchangeOptions: {
11541177
idToken: 'gitlab-jwt-id-token',
1155-
token: 'exchange-token',
1178+
body: {
1179+
token: 'exchange-token',
1180+
},
11561181
},
11571182
publishOptions: {
11581183
token: 'exchange-token',
@@ -1172,7 +1197,9 @@ t.test('oidc token exchange', t => {
11721197
},
11731198
mockOidcTokenExchangeOptions: {
11741199
idToken: 'github-jwt-id-token',
1175-
token: 'exchange-token',
1200+
body: {
1201+
token: 'exchange-token',
1202+
},
11761203
},
11771204
publishOptions: {
11781205
token: 'exchange-token',
@@ -1190,7 +1217,9 @@ t.test('oidc token exchange', t => {
11901217
},
11911218
mockOidcTokenExchangeOptions: {
11921219
idToken: 'github-jwt-id-token',
1193-
token: 'exchange-token',
1220+
body: {
1221+
token: 'exchange-token',
1222+
},
11941223
},
11951224
publishOptions: {
11961225
token: 'exchange-token',
@@ -1213,7 +1242,9 @@ t.test('oidc token exchange', t => {
12131242
},
12141243
mockOidcTokenExchangeOptions: {
12151244
idToken: 'github-jwt-id-token',
1216-
token: 'exchange-token',
1245+
body: {
1246+
token: 'exchange-token',
1247+
},
12171248
},
12181249
publishOptions: {
12191250
token: 'exchange-token',

0 commit comments

Comments
 (0)