Skip to content

Commit 6b34ebf

Browse files
khendrikseKarinKarin
authored
fix: ensure extension api is always called with the right host (#6168)
* fix: ensure sdk api is always called with the right host * fix: tests and ensure it doesn't use the host when it should not --------- Co-authored-by: Karin <[email protected]> Co-authored-by: Karin <[email protected]>
1 parent d06d11d commit 6b34ebf

File tree

4 files changed

+75
-8
lines changed

4 files changed

+75
-8
lines changed

Diff for: packages/config/src/api/site_info.ts

+44-5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ import type { RequestInit } from 'node-fetch'
44

55
import { getEnvelope } from '../env/envelope.js'
66
import { throwUserError } from '../error.js'
7+
import {
8+
EXTENSION_API_BASE_URL,
9+
EXTENSION_API_STAGING_BASE_URL,
10+
NETLIFY_API_BASE_URL,
11+
NETLIFY_API_STAGING_BASE_URL,
12+
} from '../integrations.js'
713
import { ERROR_CALL_TO_ACTION } from '../log/messages.js'
814
import { IntegrationResponse } from '../types/api.js'
915
import { ModeOption, TestOptions } from '../types/options.js'
@@ -53,7 +59,16 @@ export const getSiteInfo = async function ({
5359

5460
const integrations =
5561
mode === 'buildbot' && !offline
56-
? await getIntegrations({ siteId, testOpts, offline, accountId, token, featureFlags, extensionApiBaseUrl })
62+
? await getIntegrations({
63+
siteId,
64+
testOpts,
65+
offline,
66+
accountId,
67+
token,
68+
featureFlags,
69+
extensionApiBaseUrl,
70+
mode,
71+
})
5772
: []
5873

5974
return { siteInfo, accounts: [], addons: [], integrations }
@@ -63,7 +78,7 @@ export const getSiteInfo = async function ({
6378
getSite(api, siteId, siteFeatureFlagPrefix),
6479
getAccounts(api),
6580
getAddons(api, siteId),
66-
getIntegrations({ siteId, testOpts, offline, accountId, token, featureFlags, extensionApiBaseUrl }),
81+
getIntegrations({ siteId, testOpts, offline, accountId, token, featureFlags, extensionApiBaseUrl, mode }),
6782
]
6883

6984
const [siteInfo, accounts, addons, integrations] = await Promise.all(promises)
@@ -120,6 +135,7 @@ type GetIntegrationsOpts = {
120135
token?: string
121136
featureFlags?: Record<string, boolean>
122137
extensionApiBaseUrl: string
138+
mode: ModeOption
123139
}
124140

125141
const getIntegrations = async function ({
@@ -130,19 +146,36 @@ const getIntegrations = async function ({
130146
token,
131147
featureFlags,
132148
extensionApiBaseUrl,
149+
mode,
133150
}: GetIntegrationsOpts): Promise<IntegrationResponse[]> {
134151
if (!siteId || offline) {
135152
return []
136153
}
137154
const sendBuildBotTokenToJigsaw = featureFlags?.send_build_bot_token_to_jigsaw
138-
const { host, setBaseUrl } = testOpts
155+
const { host: originalHost, setBaseUrl } = testOpts
156+
157+
// TODO(kh): I am adding this purely for local staging development.
158+
// We should remove this once we have fixed https://github.com/netlify/cli/blob/b5a5c7525edd28925c5c2e3e5f0f00c4261eaba5/src/lib/build.ts#L125
159+
let host = originalHost
160+
161+
// If there is a host, we use it to fetch the integrations
162+
// we check if the host is staging or production and set the host accordingly,
163+
// sadly necessary because of https://github.com/netlify/cli/blob/b5a5c7525edd28925c5c2e3e5f0f00c4261eaba5/src/lib/build.ts#L125
164+
if (originalHost) {
165+
if (originalHost?.includes(NETLIFY_API_STAGING_BASE_URL)) {
166+
host = EXTENSION_API_STAGING_BASE_URL
167+
} else if (originalHost?.includes(NETLIFY_API_BASE_URL)) {
168+
host = EXTENSION_API_BASE_URL
169+
} else {
170+
host = `http://${originalHost}`
171+
}
172+
}
139173

174+
const baseUrl = new URL(host ?? extensionApiBaseUrl)
140175
// We only use this for testing
141176
if (host && setBaseUrl) {
142177
setBaseUrl(extensionApiBaseUrl)
143178
}
144-
145-
const baseUrl = new URL(host ? `http://${host}` : extensionApiBaseUrl)
146179
// if accountId isn't present, use safe v1 endpoint
147180
const url = accountId
148181
? `${baseUrl}team/${accountId}/integrations/installations/meta/${siteId}`
@@ -151,8 +184,14 @@ const getIntegrations = async function ({
151184
try {
152185
const requestOptions = {} as RequestInit
153186

187+
// This is used to identify where the request is coming from
188+
requestOptions.headers = {
189+
'netlify-config-mode': mode,
190+
}
191+
154192
if (sendBuildBotTokenToJigsaw && token) {
155193
requestOptions.headers = {
194+
...requestOptions.headers,
156195
'netlify-sdk-build-bot-token': token,
157196
}
158197
}

Diff for: packages/config/src/integrations.ts

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Integration } from './types/integrations.js'
44
import { TestOptions } from './types/options.js'
55

66
export const NETLIFY_API_STAGING_BASE_URL = 'api-staging.netlify.com'
7+
export const NETLIFY_API_BASE_URL = 'api.netlify.com'
78
export const EXTENSION_API_BASE_URL = 'https://api.netlifysdk.com'
89
export const EXTENSION_API_STAGING_BASE_URL = 'https://api-staging.netlifysdk.com'
910

Diff for: packages/config/src/main.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,9 @@ export const resolveConfig = async function (opts) {
5555
}
5656

5757
// TODO(kh): remove this mapping and get the extensionApiHost from the opts
58-
const extensionApiBaseUrl =
59-
host === NETLIFY_API_STAGING_BASE_URL ? EXTENSION_API_STAGING_BASE_URL : EXTENSION_API_BASE_URL
58+
const extensionApiBaseUrl = host?.includes(NETLIFY_API_STAGING_BASE_URL)
59+
? EXTENSION_API_STAGING_BASE_URL
60+
: EXTENSION_API_BASE_URL
6061

6162
const {
6263
config: configOpt,

Diff for: packages/config/tests/api/tests.js

+27-1
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ test('Integrations are returned if accountId is present and mode is dev', async
425425
t.assert(config.integrations[0].has_build === true)
426426
})
427427

428-
test('Integrations are returned and called with a netlify-sdk-build-bot-token', async (t) => {
428+
test('Integrations are returned and called with a netlify-sdk-build-bot-token header', async (t) => {
429429
const { output, requests } = await new Fixture('./fixtures/base')
430430
.withFlags({
431431
siteId: 'test',
@@ -451,6 +451,32 @@ test('Integrations are returned and called with a netlify-sdk-build-bot-token',
451451
t.assert(config.integrations[0].has_build === true)
452452
})
453453

454+
test('Integrations are returned and called with a netlify-config-mode header', async (t) => {
455+
const { output, requests } = await new Fixture('./fixtures/base')
456+
.withFlags({
457+
siteId: 'test',
458+
mode: 'dev',
459+
token: 'test',
460+
accountId: 'account1',
461+
featureFlags: {
462+
send_build_bot_token_to_jigsaw: true,
463+
},
464+
})
465+
.runConfigServer([SITE_INFO_DATA, TEAM_INSTALLATIONS_META_RESPONSE, FETCH_INTEGRATIONS_EMPTY_RESPONSE])
466+
467+
const config = JSON.parse(output)
468+
const installationsHeaders = requests.find(
469+
(request) => request.url === TEAM_INSTALLATIONS_META_RESPONSE.path,
470+
)?.headers
471+
472+
t.assert(installationsHeaders.includes('netlify-config-mode'))
473+
t.assert(config.integrations)
474+
t.assert(config.integrations.length === 1)
475+
t.assert(config.integrations[0].slug === 'test')
476+
t.assert(config.integrations[0].version === 'so-cool-v2')
477+
t.assert(config.integrations[0].has_build === true)
478+
})
479+
454480
test('Integrations are not returned if failed to fetch integrations', async (t) => {
455481
const { output } = await new Fixture('./fixtures/base')
456482
.withFlags({

0 commit comments

Comments
 (0)