diff --git a/src/main/github/github-api-repository-probe.ts b/src/main/github/github-api-repository-probe.ts index 04a140faefe..08d0c5fd6e3 100644 --- a/src/main/github/github-api-repository-probe.ts +++ b/src/main/github/github-api-repository-probe.ts @@ -1,4 +1,5 @@ import type { LocalGitExecOptions } from './github-repository-identity' +import { getSshGitProviderGeneration } from '../providers/ssh-git-dispatch' export function githubApiRepositoryProbeCacheKey( repoPath: string, @@ -7,7 +8,10 @@ export function githubApiRepositoryProbeCacheKey( localGitOptions: LocalGitExecOptions, requireVerifiedSshProbe: boolean ): string { - return `${connectionId ?? 'local'}\0${localGitOptions.wslDistro ?? ''}\0${repoPath}\0${remoteName}\0${requireVerifiedSshProbe ? 'verified' : 'tolerant'}` + const runtimeKey = connectionId + ? `ssh:${connectionId}:${getSshGitProviderGeneration(connectionId)}` + : `local:${localGitOptions.wslDistro ?? 'host'}` + return `${runtimeKey}\0${repoPath}\0${remoteName}\0${requireVerifiedSshProbe ? 'verified' : 'tolerant'}` } export function resolveGitHubApiRepositoryProbe( diff --git a/src/main/github/github-api-repository.test.ts b/src/main/github/github-api-repository.test.ts index b7fdb6c16da..bf1948588ed 100644 --- a/src/main/github/github-api-repository.test.ts +++ b/src/main/github/github-api-repository.test.ts @@ -1,19 +1,27 @@ import { beforeEach, describe, expect, it, vi } from 'vitest' import type * as GitHubEnterpriseRepository from './github-enterprise-repository' import type * as GhUtils from './gh-utils' +import type * as SshGitDispatch from '../providers/ssh-git-dispatch' const { getEnterpriseGitHubRepoSlugMock, getOwnerRepoMock, getOwnerRepoForRemoteMock, + getSshGitProviderGenerationMock, isGitHubHostAuthenticatedMock } = vi.hoisted(() => ({ getEnterpriseGitHubRepoSlugMock: vi.fn(), getOwnerRepoMock: vi.fn(), getOwnerRepoForRemoteMock: vi.fn(), + getSshGitProviderGenerationMock: vi.fn(() => 0), isGitHubHostAuthenticatedMock: vi.fn() })) +vi.mock('../providers/ssh-git-dispatch', async (importOriginal) => ({ + ...(await importOriginal()), + getSshGitProviderGeneration: getSshGitProviderGenerationMock +})) + vi.mock('./gh-utils', async (importOriginal) => ({ ...(await importOriginal()), getOwnerRepo: getOwnerRepoMock, @@ -41,6 +49,7 @@ beforeEach(() => { getEnterpriseGitHubRepoSlugMock.mockReset().mockResolvedValue(null) getOwnerRepoMock.mockReset().mockResolvedValue(null) getOwnerRepoForRemoteMock.mockReset().mockResolvedValue(null) + getSshGitProviderGenerationMock.mockReset().mockReturnValue(0) isGitHubHostAuthenticatedMock.mockReset().mockResolvedValue(false) }) @@ -183,6 +192,23 @@ describe('resolveGitHubRepoExecution', () => { }) describe('origin repository cache', () => { + it('isolates Enterprise identity across SSH provider generations', async () => { + const beforeReconnect = { owner: 'acme', repo: 'widgets', host: 'github.acme-corp.com' } + const afterReconnect = { owner: 'acme', repo: 'other', host: 'github.acme-corp.com' } + getEnterpriseGitHubRepoSlugMock + .mockResolvedValueOnce(beforeReconnect) + .mockResolvedValueOnce(afterReconnect) + + await expect(getOriginGitHubApiRepository('/remote/repo', 'ssh-1')).resolves.toEqual( + beforeReconnect + ) + getSshGitProviderGenerationMock.mockReturnValue(1) + await expect(getOriginGitHubApiRepository('/remote/repo', 'ssh-1')).resolves.toEqual( + afterReconnect + ) + expect(getEnterpriseGitHubRepoSlugMock).toHaveBeenCalledTimes(2) + }) + it('keeps an indeterminate auth inventory unverifiable during candidate discovery', async () => { getEnterpriseGitHubRepoSlugMock.mockResolvedValue(undefined)