Preserve instruction symlink guard through fs seam
This commit is contained in:
@@ -92,6 +92,29 @@ describe('stat', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('lstat', () => {
|
||||
it('reports path metadata without following the final symlink component', async () => {
|
||||
await writeFile(join(dir, 'real.txt'), 'hello')
|
||||
await symlink(join(dir, 'real.txt'), join(dir, 'link.txt'))
|
||||
|
||||
expect((await fs.lstat('real.txt'))?.type).toBe('file')
|
||||
expect((await fs.lstat('link.txt'))?.type).toBe('symlink')
|
||||
expect(await fs.lstat('missing.txt')).toBeUndefined()
|
||||
})
|
||||
|
||||
it('resolves relative paths against opts.cwd and honors a pre-aborted signal', async () => {
|
||||
const other = await mkdtemp(join(tmpdir(), 'dsh-fs-other-'))
|
||||
try {
|
||||
await writeFile(join(other, 'x.txt'), 'in other')
|
||||
expect((await fs.lstat('x.txt', { cwd: other }))?.type).toBe('file')
|
||||
await expect(fs.lstat('x.txt', { cwd: other }, AbortSignal.abort())).rejects.toMatchObject({ code: 'FS_ABORTED' })
|
||||
await expect(fs.lstat(' ')).rejects.toMatchObject({ code: 'FS_NOT_FOUND' })
|
||||
} finally {
|
||||
await rm(other, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('readText / streamText', () => {
|
||||
it('reads whole-file text', async () => {
|
||||
await writeFile(join(dir, 'a.txt'), 'one\ntwo\nthree')
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
applyLiteralEdit,
|
||||
listDirectory,
|
||||
probe,
|
||||
probeNoFollow,
|
||||
readForEdit,
|
||||
readWholeText,
|
||||
resolveLocalTarget,
|
||||
@@ -146,6 +147,27 @@ describe('probe', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('probeNoFollow', () => {
|
||||
it('reports symlinks without following them', async () => {
|
||||
const real = join(dir, 'real.txt')
|
||||
const link = join(dir, 'link.txt')
|
||||
await writeFile(real, 'hi')
|
||||
await symlink(real, link)
|
||||
|
||||
expect((await probeNoFollow(real))?.type).toBe('file')
|
||||
const linkInfo = await probeNoFollow(link)
|
||||
expect(linkInfo?.type).toBe('symlink')
|
||||
expect(typeof linkInfo?.version).toBe('string')
|
||||
expect(linkInfo?.size).toBeGreaterThan(0)
|
||||
})
|
||||
|
||||
it('returns null for a missing path or a file-valued ancestor path segment', async () => {
|
||||
expect(await probeNoFollow(join(dir, 'missing'))).toBeNull()
|
||||
await writeFile(join(dir, 'afile'), 'i am a file')
|
||||
expect(await probeNoFollow(join(dir, 'afile', 'child.txt'))).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
describe('listDirectory', () => {
|
||||
it('lists direct children in stable order without reading content', async () => {
|
||||
const root = join(dir, 'skills')
|
||||
|
||||
Reference in New Issue
Block a user