Files
orca/src/main/worktree-prunable-git-file.test.ts
T
Neil 41e42beab4 fix(worktrees): safely remove prunable git-file registrations (#20617)
Preserve checkout files and the named branch when removing a positively attested malformed Git-file registration. Reject file/symlink targets in deferred directory deletion.

Verified exact head with 75 focused tests including actual Git malformation, preserved marker/file bytes and branch HEAD. Independent review and complete product CI passed. WSL routing is covered by unit tests; direct SSH fails safely without local recovery.

Fixes #17316
2026-09-14 14:52:45 -07:00

75 lines
3.0 KiB
TypeScript

import { beforeEach, describe, expect, it, vi } from 'vitest'
import type { GitWorktreeInfo } from '../shared/worktree/types'
import { isPrunableGitFileWorktree } from './worktree-prunable-git-file'
const { statPath, pathAccess, runtimePath } = vi.hoisted(() => ({
statPath: vi.fn(),
pathAccess: vi.fn(),
runtimePath: vi.fn()
}))
vi.mock('./local-worktree-filesystem', () => ({
getLocalWorktreePathAccess: pathAccess,
toLocalWorktreeRuntimePath: runtimePath
}))
const worktree: GitWorktreeInfo = {
path: '/workspaces/feature/.git',
branch: 'refs/heads/feature',
head: 'a'.repeat(40),
isMainWorktree: false,
isBare: false,
prunable: true
}
beforeEach(() => {
vi.resetAllMocks()
statPath.mockResolvedValue({ isFile: () => true })
pathAccess.mockReturnValue({ statPath })
runtimePath.mockImplementation((path) => path)
})
describe('prunable Git-file registration proof', () => {
it('accepts an attested named-branch file without reading or changing its parent', async () => {
await expect(isPrunableGitFileWorktree(worktree)).resolves.toBe(true)
expect(statPath).toHaveBeenCalledExactlyOnceWith(worktree.path)
})
it.each([
{ prunable: false },
{ prunable: undefined },
{ isMainWorktree: true },
{ isBare: true },
{ locked: true },
{ branch: '' },
{ branch: 'refs/tags/feature' },
{ branch: 'refs/heads/' },
{ head: '' },
{ path: '/workspaces/feature' }
])('refuses insufficient registration evidence %j', async (override) => {
await expect(isPrunableGitFileWorktree({ ...worktree, ...override })).resolves.toBe(false)
expect(statPath).not.toHaveBeenCalled()
})
it.each([{ isFile: () => false }, { type: 'directory' }, { type: 'symlink' }, {}, null])(
'refuses non-file or unknown filesystem evidence %j',
async (entry) => {
statPath.mockResolvedValue(entry)
await expect(isPrunableGitFileWorktree(worktree)).resolves.toBe(false)
}
)
it('leaves a vanished marker to existing missing-path recovery', async () => {
statPath.mockRejectedValue(Object.assign(new Error('marker vanished'), { code: 'ENOENT' }))
await expect(isPrunableGitFileWorktree(worktree)).resolves.toBe(false)
})
it('does not turn host failure into cleanup permission', async () => {
statPath.mockRejectedValue(new Error('host unavailable'))
await expect(isPrunableGitFileWorktree(worktree)).rejects.toThrow('host unavailable')
})
it('uses the selected WSL distro and translated execution path', async () => {
const options = { wslDistro: 'Ubuntu' }
runtimePath.mockReturnValue('/home/dev/feature/.git')
statPath.mockResolvedValue({ type: 'file' })
await expect(
isPrunableGitFileWorktree({ ...worktree, path: 'C:\\workspaces\\feature\\.git' }, options)
).resolves.toBe(true)
expect(pathAccess).toHaveBeenCalledExactlyOnceWith(options)
expect(runtimePath).toHaveBeenCalledWith('C:\\workspaces\\feature\\.git', options)
expect(statPath).toHaveBeenCalledExactlyOnceWith('/home/dev/feature/.git')
})
})