diff --git a/.changeset/heavy-adults-walk.md b/.changeset/heavy-adults-walk.md new file mode 100644 index 0000000000..b9b353fdf3 --- /dev/null +++ b/.changeset/heavy-adults-walk.md @@ -0,0 +1,6 @@ +--- +'@shopify/cli-kit': minor +'@shopify/app': minor +--- + +Add support for SHOPIFY_CLI_TOKEN env var as a new name for SHOPIFY_CLI_PARTNERS_TOKEN diff --git a/packages/app/src/cli/utilities/developer-platform-client/app-management-client.ts b/packages/app/src/cli/utilities/developer-platform-client/app-management-client.ts index 33cf9e5771..0a7493164a 100644 --- a/packages/app/src/cli/utilities/developer-platform-client/app-management-client.ts +++ b/packages/app/src/cli/utilities/developer-platform-client/app-management-client.ts @@ -142,7 +142,7 @@ import { AppLogsSubscribeMutationVariables, } from '../../api/graphql/app-management/generated/app-logs-subscribe.js' import {SourceExtension} from '../../api/graphql/app-management/generated/types.js' -import {getPartnersToken} from '@shopify/cli-kit/node/environment' +import {getCliToken} from '@shopify/cli-kit/node/environment' import {ensureAuthenticatedAppManagementAndBusinessPlatform, Session} from '@shopify/cli-kit/node/session' import {isUnitTest} from '@shopify/cli-kit/node/context/local' import {AbortError, BugError} from '@shopify/cli-kit/node/error' @@ -294,7 +294,7 @@ export class AppManagementClient implements DeveloperPlatformClient { unauthorizedHandler: this.createUnauthorizedHandler('businessPlatform'), }) - if (getPartnersToken() && userInfoResult.currentUserAccount) { + if (getCliToken() && userInfoResult.currentUserAccount) { const organizations = userInfoResult.currentUserAccount.organizations.nodes.map((org) => ({ name: org.name, })) diff --git a/packages/cli-kit/src/private/node/constants.ts b/packages/cli-kit/src/private/node/constants.ts index 3672b8b4c2..4a6a94f0be 100644 --- a/packages/cli-kit/src/private/node/constants.ts +++ b/packages/cli-kit/src/private/node/constants.ts @@ -21,6 +21,7 @@ export const environmentVariables = { env: 'SHOPIFY_CLI_ENV', firstPartyDev: 'SHOPIFY_CLI_1P_DEV', noAnalytics: 'SHOPIFY_CLI_NO_ANALYTICS', + cliToken: 'SHOPIFY_CLI_TOKEN', partnersToken: 'SHOPIFY_CLI_PARTNERS_TOKEN', runAsUser: 'SHOPIFY_RUN_AS_USER', serviceEnv: 'SHOPIFY_SERVICE_ENV', diff --git a/packages/cli-kit/src/private/node/session.test.ts b/packages/cli-kit/src/private/node/session.test.ts index 08eda6acff..2c9d7a12a1 100644 --- a/packages/cli-kit/src/private/node/session.test.ts +++ b/packages/cli-kit/src/private/node/session.test.ts @@ -24,7 +24,7 @@ import * as fqdnModule from '../../public/node/context/fqdn.js' import {themeToken} from '../../public/node/context/local.js' import {partnersRequest} from '../../public/node/api/partners.js' import {businessPlatformRequest} from '../../public/node/api/business-platform.js' -import {getPartnersToken} from '../../public/node/environment.js' +import {getCliToken} from '../../public/node/environment.js' import {nonRandomUUID} from '../../public/node/crypto.js' import {terminalSupportsPrompting} from '../../public/node/system.js' @@ -319,7 +319,7 @@ describe('when existing session is valid', () => { // Given vi.mocked(validateSession).mockResolvedValueOnce('ok') vi.mocked(fetchSessions).mockResolvedValue(validSessions) - vi.mocked(getPartnersToken).mockReturnValue('custom_cli_token') + vi.mocked(getCliToken).mockReturnValue('custom_cli_token') const expected = {...validTokens, partners: 'custom_partners_token'} // When @@ -450,7 +450,7 @@ describe('getLastSeenUserIdAfterAuth', () => { test('returns UUID based on partners token if present in environment', async () => { // Given vi.mocked(getCurrentSessionId).mockReturnValue(undefined) - vi.mocked(getPartnersToken).mockReturnValue('partners-token-456') + vi.mocked(getCliToken).mockReturnValue('partners-token-456') // When const userId = await getLastSeenUserIdAfterAuth() @@ -540,7 +540,7 @@ describe('setLastSeenUserIdAfterAuth', () => { describe('getLastSeenAuthMethod', () => { beforeEach(() => { vi.mocked(getCurrentSessionId).mockReturnValue(undefined) - vi.mocked(getPartnersToken).mockReturnValue(undefined) + vi.mocked(getCliToken).mockReturnValue(undefined) vi.mocked(themeToken).mockReturnValue(undefined) setLastSeenAuthMethod('none') }) @@ -571,7 +571,7 @@ describe('getLastSeenAuthMethod', () => { test('returns partners_token if there is a partners token in the environment', async () => { // Given - vi.mocked(getPartnersToken).mockReturnValue('partners-token-456') + vi.mocked(getCliToken).mockReturnValue('partners-token-456') // When const method = await getLastSeenAuthMethod() diff --git a/packages/cli-kit/src/private/node/session.ts b/packages/cli-kit/src/private/node/session.ts index 6f87d00c66..91cd578c5b 100644 --- a/packages/cli-kit/src/private/node/session.ts +++ b/packages/cli-kit/src/private/node/session.ts @@ -19,7 +19,7 @@ import {outputContent, outputToken, outputDebug, outputCompleted} from '../../pu import {firstPartyDev, themeToken} from '../../public/node/context/local.js' import {AbortError} from '../../public/node/error.js' import {normalizeStoreFqdn, identityFqdn} from '../../public/node/context/fqdn.js' -import {getIdentityTokenInformation, getPartnersToken} from '../../public/node/environment.js' +import {getIdentityTokenInformation, getCliToken} from '../../public/node/environment.js' import {AdminSession, logout} from '../../public/node/session.js' import {nonRandomUUID} from '../../public/node/crypto.js' import {isEmpty} from '../../public/common/object.js' @@ -137,7 +137,7 @@ export async function getLastSeenUserIdAfterAuth(): Promise { const currentSessionId = getCurrentSessionId() if (currentSessionId) return currentSessionId - const customToken = getPartnersToken() ?? themeToken() + const customToken = getCliToken() ?? themeToken() return customToken ? nonRandomUUID(customToken) : 'unknown' } @@ -162,7 +162,7 @@ export async function getLastSeenAuthMethod(): Promise { if (getCurrentSessionId()) return 'device_auth' - const partnersToken = getPartnersToken() + const partnersToken = getCliToken() if (partnersToken) return 'partners_token' const themePassword = themeToken() @@ -264,7 +264,7 @@ ${outputToken.json(applications)} const tokens = await tokensFor(applications, completeSession) // Overwrite partners token if using a custom CLI Token - const envToken = getPartnersToken() + const envToken = getCliToken() if (envToken && applications.partnersApi) { tokens.partners = (await exchangeCustomPartnerToken(envToken)).accessToken } diff --git a/packages/cli-kit/src/private/node/session/exchange.ts b/packages/cli-kit/src/private/node/session/exchange.ts index ebf49f3d6a..7b09d611af 100644 --- a/packages/cli-kit/src/private/node/session/exchange.ts +++ b/packages/cli-kit/src/private/node/session/exchange.ts @@ -70,8 +70,8 @@ export async function refreshAccessToken(currentToken: IdentityToken): Promise { @@ -110,8 +110,8 @@ export async function exchangeCustomPartnerToken(token: string): Promise<{access } /** - * Given a custom CLI token passed as ENV variable, request a valid App Management API token - * @param token - The CLI token passed as ENV variable `SHOPIFY_CLI_PARTNERS_TOKEN` + * Given a custom CLI token passed as ENV variable, request a valid App Management API token. + * @param token - The CLI token passed as ENV variable `SHOPIFY_CLI_TOKEN` * @returns An instance with the application access tokens. */ export async function exchangeCliTokenForAppManagementAccessToken( @@ -121,8 +121,8 @@ export async function exchangeCliTokenForAppManagementAccessToken( } /** - * Given a custom CLI token passed as ENV variable, request a valid Business Platform API token - * @param token - The CLI token passed as ENV variable `SHOPIFY_CLI_PARTNERS_TOKEN` + * Given a custom CLI token passed as ENV variable, request a valid Business Platform API token. + * @param token - The CLI token passed as ENV variable `SHOPIFY_CLI_TOKEN` * @returns An instance with the application access tokens. */ export async function exchangeCliTokenForBusinessPlatformAccessToken( diff --git a/packages/cli-kit/src/public/node/environment.test.ts b/packages/cli-kit/src/public/node/environment.test.ts new file mode 100644 index 0000000000..fb5239b5d4 --- /dev/null +++ b/packages/cli-kit/src/public/node/environment.test.ts @@ -0,0 +1,33 @@ +import {getCliToken} from './environment.js' +import {environmentVariables} from '../../private/node/constants.js' +import {describe, expect, test, beforeEach} from 'vitest' + +beforeEach(() => { + delete process.env[environmentVariables.cliToken] + delete process.env[environmentVariables.partnersToken] +}) + +describe('getCliToken', () => { + test('returns SHOPIFY_CLI_TOKEN when set', () => { + process.env[environmentVariables.cliToken] = 'new-token' + + expect(getCliToken()).toBe('new-token') + }) + + test('returns SHOPIFY_CLI_PARTNERS_TOKEN when SHOPIFY_CLI_TOKEN is not set', () => { + process.env[environmentVariables.partnersToken] = 'old-token' + + expect(getCliToken()).toBe('old-token') + }) + + test('prefers SHOPIFY_CLI_TOKEN over SHOPIFY_CLI_PARTNERS_TOKEN', () => { + process.env[environmentVariables.cliToken] = 'new-token' + process.env[environmentVariables.partnersToken] = 'old-token' + + expect(getCliToken()).toBe('new-token') + }) + + test('returns undefined when neither env var is set', () => { + expect(getCliToken()).toBeUndefined() + }) +}) diff --git a/packages/cli-kit/src/public/node/environment.ts b/packages/cli-kit/src/public/node/environment.ts index 653b4895d7..5044a732c9 100644 --- a/packages/cli-kit/src/public/node/environment.ts +++ b/packages/cli-kit/src/public/node/environment.ts @@ -18,21 +18,14 @@ export function getEnvironmentVariables(): NodeJS.ProcessEnv { } /** - * Returns the value of the SHOPIFY_CLI_PARTNERS_TOKEN environment variable. + * Returns the value of the SHOPIFY_CLI_TOKEN environment variable, + * falling back to the deprecated SHOPIFY_CLI_PARTNERS_TOKEN. * - * @returns Current process environment variables. - */ -export function getPartnersToken(): string | undefined { - return getEnvironmentVariables()[environmentVariables.partnersToken] -} - -/** - * Check if the current proccess is running using the partners token. - * - * @returns True if the current proccess is running using the partners token. + * @returns The CLI token value, or undefined if neither env var is set. */ -export function usePartnersToken(): boolean { - return getPartnersToken() !== undefined +export function getCliToken(): string | undefined { + const env = getEnvironmentVariables() + return env[environmentVariables.cliToken] ?? env[environmentVariables.partnersToken] } /** diff --git a/packages/cli-kit/src/public/node/session.test.ts b/packages/cli-kit/src/public/node/session.test.ts index c391dea79a..a032326c81 100644 --- a/packages/cli-kit/src/public/node/session.test.ts +++ b/packages/cli-kit/src/public/node/session.test.ts @@ -8,7 +8,7 @@ import { ensureAuthenticatedThemes, } from './session.js' -import {getPartnersToken} from './environment.js' +import {getCliToken} from './environment.js' import {shopifyFetch} from './http.js' import {ApplicationToken} from '../../private/node/session/schema.js' import {ensureAuthenticated, setLastSeenAuthMethod, setLastSeenUserIdAfterAuth} from '../../private/node/session.js' @@ -136,7 +136,7 @@ describe('ensureAuthenticatedPartners', () => { accessToken: partnersToken.accessToken, userId: '575e2102-cb13-7bea-4631-ce3469eac491cdcba07d', }) - vi.mocked(getPartnersToken).mockReturnValue('custom_cli_token') + vi.mocked(getCliToken).mockReturnValue('custom_cli_token') // When const got = await ensureAuthenticatedPartners([]) @@ -253,7 +253,7 @@ describe('ensureAuthenticatedAppManagementAndBusinessPlatform', () => { test('returns app managment and business platform tokens if CLI token envvar is defined', async () => { // Given - vi.mocked(getPartnersToken).mockReturnValue('custom_cli_token') + vi.mocked(getCliToken).mockReturnValue('custom_cli_token') vi.mocked(exchangeCliTokenForAppManagementAccessToken).mockResolvedValueOnce({ accessToken: 'app-management-token', userId: '575e2102-cb13-7bea-4631-ce3469eac491cdcba07d', diff --git a/packages/cli-kit/src/public/node/session.ts b/packages/cli-kit/src/public/node/session.ts index c1ddcf2038..9757e55862 100644 --- a/packages/cli-kit/src/public/node/session.ts +++ b/packages/cli-kit/src/public/node/session.ts @@ -1,6 +1,6 @@ import {shopifyFetch} from './http.js' import {nonRandomUUID} from './crypto.js' -import {getPartnersToken} from './environment.js' +import {getCliToken} from './environment.js' import {AbortError, BugError} from './error.js' import {outputContent, outputToken, outputDebug} from './output.js' import * as sessionStore from '../../private/node/session/store.js' @@ -110,7 +110,7 @@ export async function ensureAuthenticatedPartners( outputDebug(outputContent`Ensuring that the user is authenticated with the Partners API with the following scopes: ${outputToken.json(scopes)} `) - const envToken = getPartnersToken() + const envToken = getCliToken() if (envToken) { const result = await exchangeCustomPartnerToken(envToken) return {token: result.accessToken, userId: result.userId} @@ -141,7 +141,7 @@ export async function ensureAuthenticatedAppManagementAndBusinessPlatform( ${outputToken.json(appManagementScopes)} `) - const envToken = getPartnersToken() + const envToken = getCliToken() if (envToken) { const appManagmentToken = await exchangeCliTokenForAppManagementAccessToken(envToken) const businessPlatformToken = await exchangeCliTokenForBusinessPlatformAccessToken(envToken)