Explorar el Código

test(file-reference-local): pin the unreadable-subtree test to POSIX non-root

chmod 0 can only deny directory reads on POSIX to a non-root owner:
Windows exposes no directory permission bits for readdir, and root
bypasses them. Where the fixture stays readable the sealed candidate is
indexed, so the unreadable-branch behavior is pinned on POSIX non-root.
An injected readdir failure keeps that branch covered on every platform.
Chinesezjc hace 3 semanas
padre
commit
6ac1b82939
Se han modificado 1 ficheros con 48 adiciones y 1 borrados
  1. 48 1
      packages/context/file-reference-local/tests/search.spec.ts

+ 48 - 1
packages/context/file-reference-local/tests/search.spec.ts

@@ -9,6 +9,24 @@ import {
   WorkspaceFileSearch,
 } from '../src/search.ts'
 
+const fsControl = vi.hoisted(() => ({
+  /** Absolute path whose `readdir` rejects; the injectable stand-in for chmod 0. */
+  denyReaddir: undefined as string | undefined,
+}))
+
+vi.mock('node:fs/promises', async (importOriginal) => {
+  const actual = await importOriginal<typeof import('node:fs/promises')>()
+  return {
+    ...actual,
+    readdir: (async (path: unknown, ...rest: never[]) => {
+      if (fsControl.denyReaddir !== undefined && String(path) === fsControl.denyReaddir) {
+        throw Object.assign(new Error('EACCES: injected unreadable directory'), { code: 'EACCES' })
+      }
+      return (actual.readdir as (path: unknown, ...args: never[]) => Promise<unknown>)(path, ...rest)
+    }) as typeof actual.readdir,
+  }
+})
+
 const searches: WorkspaceFileSearch[] = []
 const roots: string[] = []
 /** Permission-stripped directories; restored before cleanup can remove them. */
@@ -199,7 +217,13 @@ describe('WorkspaceFileSearch', () => {
     })
   })
 
-  it('lets an unreadable subtree cost only its own candidates', async () => {
+  // chmod 0 can only deny directory reads on POSIX to a non-root owner:
+  // Windows exposes no directory permission bits for readdir, and root
+  // bypasses them. Where the fixture stays readable the sealed candidate is
+  // indexed, so the unreadable-branch behavior is pinned on POSIX non-root.
+  it.runIf(
+    process.getuid !== undefined && process.getuid() !== 0,
+  )('lets an unreadable subtree cost only its own candidates', async () => {
     const root = await workspace()
     const locked = join(root, 'locked')
     await mkdir(locked, { recursive: true })
@@ -216,6 +240,29 @@ describe('WorkspaceFileSearch', () => {
     expect(await files.list('locked', signal)).toEqual([{ path: 'locked', kind: 'directory' }])
   })
 
+  // The chmod-0 fixture above cannot be built on Windows (no directory
+  // permission bits) or as root (bits are bypassed). An injected readdir
+  // failure keeps the unreadable-branch behavior covered on every platform.
+  it('lets an injected readdir failure cost only its own candidates', async () => {
+    const root = await workspace()
+    const locked = join(root, 'locked')
+    await mkdir(locked, { recursive: true })
+    await writeFile(join(locked, 'sealed.ts'), 'sealed')
+    fsControl.denyReaddir = locked
+    try {
+      const files = search(root)
+      const signal = new AbortController().signal
+
+      // The branch itself yields nothing, and the rest of the tree still does.
+      expect(await files.list('sealed', signal)).toEqual([])
+      expect(await files.list('README', signal)).toEqual([{ path: 'README.md', kind: 'file' }])
+      // The directory is still offered: only reading through it fails.
+      expect(await files.list('locked', signal)).toEqual([{ path: 'locked', kind: 'directory' }])
+    } finally {
+      fsControl.denyReaddir = undefined
+    }
+  })
+
   it('enforces the entry cap', async () => {
     const root = await workspace()
     const capped = search(root, { maxEntries: 2 })