diff --git a/src/services/api/providerConfig.codexSecureStorage.test.ts b/src/services/api/providerConfig.codexSecureStorage.test.ts index 799a899132..224d34fa35 100644 --- a/src/services/api/providerConfig.codexSecureStorage.test.ts +++ b/src/services/api/providerConfig.codexSecureStorage.test.ts @@ -6,6 +6,16 @@ import * as realOs from 'node:os' import * as realCodexCredentials from '../../utils/codexCredentials.js' import { acquireEnvMutex, releaseEnvMutex } from '../../entrypoints/sdk/shared.js' +type ProviderConfigModule = typeof import('./providerConfig.js') + +function importFreshProviderConfig( + cacheKey: string, +): Promise { + return import( + `./providerConfig.js?${cacheKey}` + ) as Promise +} + function makeJwt(payload: Record): string { const header = Buffer.from(JSON.stringify({ alg: 'none', typ: 'JWT' })) .toString('base64url') @@ -35,10 +45,8 @@ describe('resolveCodexApiCredentials with secure storage', () => { }), })) - // @ts-expect-error cache-busting query string for Bun module mocks - const { resolveCodexApiCredentials } = await import( - './providerConfig.js?codex-secure-storage' - ) + const { resolveCodexApiCredentials } = + await importFreshProviderConfig('codex-secure-storage') const credentials = resolveCodexApiCredentials({} as NodeJS.ProcessEnv) expect(credentials.apiKey).toBe('codex-api-key-token') @@ -57,10 +65,8 @@ describe('resolveCodexApiCredentials with secure storage', () => { }), })) - // @ts-expect-error cache-busting query string for Bun module mocks - const { resolveCodexApiCredentials } = await import( - './providerConfig.js?codex-env-precedence' - ) + const { resolveCodexApiCredentials } = + await importFreshProviderConfig('codex-env-precedence') const credentials = resolveCodexApiCredentials({ CODEX_API_KEY: 'env-token', @@ -80,10 +86,8 @@ describe('resolveCodexApiCredentials with secure storage', () => { readCodexCredentials: () => undefined, })) - // @ts-expect-error cache-busting query string for Bun module mocks - const { resolveCodexApiCredentials } = await import( - './providerConfig.js?codex-env-nested-account' - ) + const { resolveCodexApiCredentials } = + await importFreshProviderConfig('codex-env-nested-account') const credentials = resolveCodexApiCredentials({ CODEX_API_KEY: makeJwt({ @@ -121,10 +125,8 @@ describe('resolveCodexApiCredentials with secure storage', () => { ) try { - // @ts-expect-error cache-busting query string for Bun module mocks - const { resolveCodexApiCredentials } = await import( - './providerConfig.js?codex-auth-json-nested-account' - ) + const { resolveCodexApiCredentials } = + await importFreshProviderConfig('codex-auth-json-nested-account') const credentials = resolveCodexApiCredentials({ CODEX_AUTH_JSON_PATH: authPath, @@ -149,10 +151,8 @@ describe('resolveCodexApiCredentials with secure storage', () => { }), })) - // @ts-expect-error cache-busting query string for Bun module mocks - const { resolveCodexApiCredentials } = await import( - './providerConfig.js?codex-secure-storage-no-auth-io' - ) + const { resolveCodexApiCredentials } = + await importFreshProviderConfig('codex-secure-storage-no-auth-io') const credentials = resolveCodexApiCredentials({} as NodeJS.ProcessEnv) expect(credentials.apiKey).toBe('codex-api-key-token') @@ -189,10 +189,8 @@ describe('resolveCodexApiCredentials with secure storage', () => { }), })) - // @ts-expect-error cache-busting query string for Bun module mocks - const { resolveCodexApiCredentials } = await import( - './providerConfig.js?codex-refresh-cooldown-fallback' - ) + const { resolveCodexApiCredentials } = + await importFreshProviderConfig('codex-refresh-cooldown-fallback') try { const credentials = resolveCodexApiCredentials({} as NodeJS.ProcessEnv) @@ -229,9 +227,8 @@ describe('resolveCodexApiCredentials with secure storage', () => { }), })) - // @ts-expect-error cache-busting query string for Bun module mocks - const { resolveCodexApiCredentials } = await import( - './providerConfig.js?codex-refresh-cooldown-account-id-fallback' + const { resolveCodexApiCredentials } = await importFreshProviderConfig( + 'codex-refresh-cooldown-account-id-fallback', ) try { diff --git a/src/services/api/providerConfig.runtimeCodexCredentials.test.ts b/src/services/api/providerConfig.runtimeCodexCredentials.test.ts index c707cfeeaa..14b62b2966 100644 --- a/src/services/api/providerConfig.runtimeCodexCredentials.test.ts +++ b/src/services/api/providerConfig.runtimeCodexCredentials.test.ts @@ -9,6 +9,16 @@ import { releaseSharedMutationLock, } from '../../test/sharedMutationLock.js' +type ProviderConfigModule = typeof import('./providerConfig.js') + +function importFreshProviderConfig( + cacheKey: string, +): Promise { + return import( + `./providerConfig.js?${cacheKey}` + ) as Promise +} + beforeEach(async () => { await acquireSharedMutationLock('services/api/providerConfig.runtimeCodexCredentials.test.ts') }) @@ -99,9 +109,8 @@ test('runtime credential resolution avoids sync secure-storage reads when async }, })) - // @ts-expect-error cache-busting query string for Bun module mocks - const { resolveRuntimeCodexCredentials } = await import( - './providerConfig.js?runtime-no-sync-secure-storage' + const { resolveRuntimeCodexCredentials } = await importFreshProviderConfig( + 'runtime-no-sync-secure-storage', ) const credentials = resolveRuntimeCodexCredentials({ diff --git a/src/utils/codexCredentials.test.ts b/src/utils/codexCredentials.test.ts index da235a78ff..e38e990212 100644 --- a/src/utils/codexCredentials.test.ts +++ b/src/utils/codexCredentials.test.ts @@ -8,6 +8,16 @@ import { releaseSharedMutationLock, } from '../test/sharedMutationLock.js' +type CodexCredentialsModule = typeof import('./codexCredentials.js') + +function importFreshCodexCredentials( + cacheKey: string, +): Promise { + return import( + `./codexCredentials.js?${cacheKey}` + ) as Promise +} + function makeJwt(payload: Record): string { const header = Buffer.from(JSON.stringify({ alg: 'none', typ: 'JWT' })) .toString('base64url') @@ -85,10 +95,8 @@ describe('codexCredentials', () => { test('save returns failure in bare mode', async () => { process.env.CLAUDE_CODE_SIMPLE = '1' - // @ts-expect-error cache-busting query string for Bun module mocks - const { saveCodexCredentials } = await import( - './codexCredentials.js?save-bare-mode' - ) + const { saveCodexCredentials } = + await importFreshCodexCredentials('save-bare-mode') const result = saveCodexCredentials({ accessToken: 'token', @@ -123,10 +131,8 @@ describe('codexCredentials', () => { getSecureStorage, })) - // @ts-expect-error cache-busting query string for Bun module mocks - const { readCodexCredentials, saveCodexCredentials } = await import( - './codexCredentials.js?save-plaintext-fallback' - ) + const { readCodexCredentials, saveCodexCredentials } = + await importFreshCodexCredentials('save-plaintext-fallback') const result = saveCodexCredentials({ accessToken: 'fallback-access-token', @@ -189,10 +195,8 @@ describe('codexCredentials', () => { }, })) - // @ts-expect-error cache-busting query string for Bun module mocks - const { saveCodexCredentials } = await import( - './codexCredentials.js?save-scoped-plaintext-fallback' - ) + const { saveCodexCredentials } = + await importFreshCodexCredentials('save-scoped-plaintext-fallback') const result = saveCodexCredentials({ accessToken: 'codex-access-token', @@ -249,9 +253,8 @@ describe('codexCredentials', () => { }, })) - // @ts-expect-error cache-busting query string for Bun module mocks - const { saveCodexCredentials } = await import( - './codexCredentials.js?save-fail-closed-shadowed-fallback' + const { saveCodexCredentials } = await importFreshCodexCredentials( + 'save-fail-closed-shadowed-fallback', ) const result = saveCodexCredentials({ @@ -293,10 +296,8 @@ describe('codexCredentials', () => { }, })) - // @ts-expect-error cache-busting query string for Bun module mocks - const { readCodexCredentials, saveCodexCredentials } = await import( - './codexCredentials.js?save-fail-closed-stale-native-delete' - ) + const { readCodexCredentials, saveCodexCredentials } = + await importFreshCodexCredentials('save-fail-closed-stale-native-delete') const result = saveCodexCredentials({ accessToken: 'codex-access-token', @@ -347,10 +348,10 @@ describe('codexCredentials', () => { }, })) - // @ts-expect-error cache-busting query string for Bun module mocks - const { readCodexCredentials, saveCodexCredentials } = await import( - './codexCredentials.js?save-native-success-plaintext-cleanup-fails' - ) + const { readCodexCredentials, saveCodexCredentials } = + await importFreshCodexCredentials( + 'save-native-success-plaintext-cleanup-fails', + ) const result = saveCodexCredentials({ accessToken: 'native-codex-access-token', @@ -384,10 +385,8 @@ describe('codexCredentials', () => { getSecureStorage, })) - // @ts-expect-error cache-busting query string for Bun module mocks - const { saveCodexCredentials } = await import( - './codexCredentials.js?save-incomplete' - ) + const { saveCodexCredentials } = + await importFreshCodexCredentials('save-incomplete') const result = saveCodexCredentials({ accessToken: '', @@ -480,9 +479,8 @@ describe('codexCredentials', () => { }, ) as unknown as typeof fetch - // @ts-expect-error cache-busting query string for Bun module mocks const { refreshCodexAccessTokenIfNeeded, readCodexCredentials } = - await import('./codexCredentials.js?refresh-success') + await importFreshCodexCredentials('refresh-success') const result = await refreshCodexAccessTokenIfNeeded() expect(result.refreshed).toBe(true) @@ -541,9 +539,8 @@ describe('codexCredentials', () => { ) }) as unknown as typeof fetch - // @ts-expect-error cache-busting query string for Bun module mocks const { refreshCodexAccessTokenIfNeeded, readCodexCredentials } = - await import('./codexCredentials.js?refresh-cooldown') + await importFreshCodexCredentials('refresh-cooldown') await expect(refreshCodexAccessTokenIfNeeded()).rejects.toThrow( 'Codex token refresh failed (invalid_grant): refresh token expired', @@ -628,9 +625,8 @@ describe('codexCredentials', () => { }, ) as unknown as typeof fetch - // @ts-expect-error cache-busting query string for Bun module mocks const { refreshCodexAccessTokenIfNeeded, readCodexCredentials } = - await import('./codexCredentials.js?refresh-drop-stale-api-key') + await importFreshCodexCredentials('refresh-drop-stale-api-key') const result = await refreshCodexAccessTokenIfNeeded() expect(result.refreshed).toBe(true) @@ -725,10 +721,8 @@ describe('codexCredentials', () => { ) }) as unknown as typeof fetch - // @ts-expect-error cache-busting query string for Bun module mocks - const { refreshCodexAccessTokenIfNeeded } = await import( - './codexCredentials.js?refresh-dedupe' - ) + const { refreshCodexAccessTokenIfNeeded } = + await importFreshCodexCredentials('refresh-dedupe') const firstRefresh = refreshCodexAccessTokenIfNeeded() const secondRefresh = refreshCodexAccessTokenIfNeeded() @@ -768,10 +762,8 @@ describe('codexCredentials', () => { }), })) - // @ts-expect-error cache-busting query string for Bun module mocks - const { readCodexCredentials, saveCodexCredentials } = await import( - './codexCredentials.js?preserve-profile-id' - ) + const { readCodexCredentials, saveCodexCredentials } = + await importFreshCodexCredentials('preserve-profile-id') const saved = saveCodexCredentials({ accessToken: 'access-new', @@ -805,11 +797,10 @@ describe('codexCredentials', () => { }), })) - // @ts-expect-error cache-busting query string for Bun module mocks const { attachCodexProfileIdToStoredCredentials, readCodexCredentials, - } = await import('./codexCredentials.js?attach-profile-id') + } = await importFreshCodexCredentials('attach-profile-id') const result = attachCodexProfileIdToStoredCredentials('profile_codex_oauth') @@ -852,10 +843,8 @@ describe('codexCredentials', () => { }, })) - // @ts-expect-error cache-busting query string for Bun module mocks - const { clearCodexCredentials } = await import( - './codexCredentials.js?clear-scoped-plaintext-fallback' - ) + const { clearCodexCredentials } = + await importFreshCodexCredentials('clear-scoped-plaintext-fallback') const result = clearCodexCredentials() @@ -897,10 +886,8 @@ describe('codexCredentials', () => { }), })) - // @ts-expect-error cache-busting query string for Bun module mocks - const { refreshCodexAccessTokenIfNeeded } = await import( - './codexCredentials.js?refresh-async-read' - ) + const { refreshCodexAccessTokenIfNeeded } = + await importFreshCodexCredentials('refresh-async-read') const result = await refreshCodexAccessTokenIfNeeded() expect(result.refreshed).toBe(false) @@ -955,10 +942,8 @@ describe('codexCredentials', () => { ) }) as unknown as typeof fetch - // @ts-expect-error cache-busting query string for Bun module mocks - const { refreshCodexAccessTokenIfNeeded } = await import( - './codexCredentials.js?refresh-memory-cooldown' - ) + const { refreshCodexAccessTokenIfNeeded } = + await importFreshCodexCredentials('refresh-memory-cooldown') await expect(refreshCodexAccessTokenIfNeeded()).rejects.toThrow( 'Codex token refresh failed (invalid_grant): refresh token expired', diff --git a/src/utils/githubModelsCredentials.hydrate.test.ts b/src/utils/githubModelsCredentials.hydrate.test.ts index 4f9315b647..c6d92398e3 100644 --- a/src/utils/githubModelsCredentials.hydrate.test.ts +++ b/src/utils/githubModelsCredentials.hydrate.test.ts @@ -9,6 +9,21 @@ import { releaseSharedMutationLock, } from '../test/sharedMutationLock.js' +type GithubModelsCredentialsModule = + typeof import('./githubModelsCredentials.js') + +function importFreshGithubModelsCredentials( + cacheKey: string, +): Promise { + return import( + `./githubModelsCredentials.js?${cacheKey}` + ) as Promise +} + +function getEnvValue(name: string): string | undefined { + return process.env[name] +} + describe('hydrateGithubModelsTokenFromSecureStorage', () => { const orig = { CLAUDE_CODE_USE_GITHUB: process.env.CLAUDE_CODE_USE_GITHUB, @@ -52,12 +67,11 @@ describe('hydrateGithubModelsTokenFromSecureStorage', () => { }), })) - const { hydrateGithubModelsTokenFromSecureStorage } = await import( - './githubModelsCredentials.js?hydrate=sets-token' - ) + const { hydrateGithubModelsTokenFromSecureStorage } = + await importFreshGithubModelsCredentials('hydrate=sets-token') hydrateGithubModelsTokenFromSecureStorage() - expect(process.env.GITHUB_TOKEN).toBe('stored-secret') - expect(process.env.CLAUDE_CODE_GITHUB_TOKEN_HYDRATED).toBe('1') + expect(getEnvValue('GITHUB_TOKEN')).toBe('stored-secret') + expect(getEnvValue('CLAUDE_CODE_GITHUB_TOKEN_HYDRATED')).toBe('1') }) test('does not override existing GITHUB_TOKEN', async () => { @@ -73,11 +87,10 @@ describe('hydrateGithubModelsTokenFromSecureStorage', () => { }), })) - const { hydrateGithubModelsTokenFromSecureStorage } = await import( - './githubModelsCredentials.js?hydrate=preserve-existing' - ) + const { hydrateGithubModelsTokenFromSecureStorage } = + await importFreshGithubModelsCredentials('hydrate=preserve-existing') hydrateGithubModelsTokenFromSecureStorage() - expect(process.env.GITHUB_TOKEN).toBe('already') - expect(process.env.CLAUDE_CODE_GITHUB_TOKEN_HYDRATED).toBeUndefined() + expect(getEnvValue('GITHUB_TOKEN')).toBe('already') + expect(getEnvValue('CLAUDE_CODE_GITHUB_TOKEN_HYDRATED')).toBeUndefined() }) }) diff --git a/src/utils/githubModelsCredentials.refresh.test.ts b/src/utils/githubModelsCredentials.refresh.test.ts index d7ca7ea04d..2087ff0ff5 100644 --- a/src/utils/githubModelsCredentials.refresh.test.ts +++ b/src/utils/githubModelsCredentials.refresh.test.ts @@ -11,6 +11,10 @@ async function importFreshModule() { return import(`./githubModelsCredentials.ts?ts=${Date.now()}-${Math.random()}`) } +function getGithubTokenEnv(): string | undefined { + return process.env.GITHUB_TOKEN +} + describe('refreshGithubModelsTokenIfNeeded', () => { const orig = { CLAUDE_CODE_USE_GITHUB: process.env.CLAUDE_CODE_USE_GITHUB, @@ -81,7 +85,7 @@ describe('refreshGithubModelsTokenIfNeeded', () => { const refreshed = await refreshGithubModelsTokenIfNeeded() expect(refreshed).toBe(true) - expect(process.env.GITHUB_TOKEN?.startsWith('tid=fresh;exp=')).toBe(true) + expect(getGithubTokenEnv()?.startsWith('tid=fresh;exp=')).toBe(true) const githubModels = (store.githubModels ?? {}) as { accessToken?: string @@ -129,7 +133,7 @@ describe('refreshGithubModelsTokenIfNeeded', () => { const refreshed = await refreshGithubModelsTokenIfNeeded() expect(refreshed).toBe(false) expect(exchangeSpy).not.toHaveBeenCalled() - expect(process.env.GITHUB_TOKEN?.startsWith('tid=already-valid;exp=')).toBe( + expect(getGithubTokenEnv()?.startsWith('tid=already-valid;exp=')).toBe( true, ) }) diff --git a/src/utils/githubModelsCredentials.test.ts b/src/utils/githubModelsCredentials.test.ts index 1eda8864e4..6e40d5fadb 100644 --- a/src/utils/githubModelsCredentials.test.ts +++ b/src/utils/githubModelsCredentials.test.ts @@ -6,6 +6,17 @@ import { const originalSimple = process.env.CLAUDE_CODE_SIMPLE +type GithubModelsCredentialsModule = + typeof import('./githubModelsCredentials.js') + +function importFreshGithubModelsCredentials( + cacheKey: string, +): Promise { + return import( + `./githubModelsCredentials.js?${cacheKey}` + ) as Promise +} + beforeEach(async () => { await acquireSharedMutationLock('utils/githubModelsCredentials.test.ts') }) @@ -24,9 +35,8 @@ afterEach(() => { describe('readGithubModelsToken', () => { test('returns undefined in bare mode', async () => { - const { readGithubModelsToken } = await import( - './githubModelsCredentials.js?read-bare-mode' - ) + const { readGithubModelsToken } = + await importFreshGithubModelsCredentials('read-bare-mode') process.env.CLAUDE_CODE_SIMPLE = '1' expect(readGithubModelsToken()).toBeUndefined() @@ -35,9 +45,8 @@ describe('readGithubModelsToken', () => { describe('saveGithubModelsToken / clearGithubModelsToken', () => { test('save returns failure in bare mode', async () => { - const { saveGithubModelsToken } = await import( - './githubModelsCredentials.js?save-bare-mode' - ) + const { saveGithubModelsToken } = + await importFreshGithubModelsCredentials('save-bare-mode') process.env.CLAUDE_CODE_SIMPLE = '1' const r = saveGithubModelsToken('abc') @@ -46,12 +55,10 @@ describe('saveGithubModelsToken / clearGithubModelsToken', () => { }) test('clear succeeds in bare mode', async () => { - const { clearGithubModelsToken } = await import( - './githubModelsCredentials.js?clear-bare-mode' - ) + const { clearGithubModelsToken } = + await importFreshGithubModelsCredentials('clear-bare-mode') process.env.CLAUDE_CODE_SIMPLE = '1' expect(clearGithubModelsToken().success).toBe(true) }) }) -