From 8fbbb357183e7ec0ddbfd6f2b3082b3ed2a2a801 Mon Sep 17 00:00:00 2001 From: ManniX-ITA <20623405+mann1x@users.noreply.github.com> Date: Mon, 27 Apr 2026 11:06:16 +0100 Subject: [PATCH] test(ignore-service): skip EACCES test under uid=0 (root bypasses chmod) (#1108) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `loadIgnoreRules — error handling > warns on EACCES but does not throw` test relies on `chmod 000` denying read access to a temporary .gitignore file. On Linux, root bypasses POSIX read-permission checks, so chmod 000 does NOT trigger EACCES under uid=0 — fs.readFile reads the file anyway and loadIgnoreRules returns parsed rules instead of the `null` the test expects. Symptom under root: assertion fails with `Ignore { _rules: [...] } to be null`, surfaced as a single test failure in any privileged test environment (rootful Docker container, CI runners configured to run tests as root, etc.). Fix: extend the existing `skipIf(process.platform === 'win32')` guard with `process.getuid?.() === 0`. The non-root code path still exercises the real EACCES branch — root just can't reproduce the failure mode the test asserts on, so skipping there is the correct posture (matches the win32 skip's reasoning: the OS-level mechanism the test depends on isn't available there). Optional chaining (`getuid?.()`) keeps Windows compatibility — Node on Windows doesn't expose `process.getuid` at all. --- gitnexus/test/unit/ignore-service.test.ts | 35 ++++++++++++++--------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/gitnexus/test/unit/ignore-service.test.ts b/gitnexus/test/unit/ignore-service.test.ts index 5bcacf8c4..de32eb8d9 100644 --- a/gitnexus/test/unit/ignore-service.test.ts +++ b/gitnexus/test/unit/ignore-service.test.ts @@ -561,21 +561,30 @@ describe('loadIgnoreRules — error handling', () => { await fs.rm(tmpDir, { recursive: true, force: true }); }); - it.skipIf(process.platform === 'win32')('warns on EACCES but does not throw', async () => { - const gitignorePath = path.join(tmpDir, '.gitignore'); - await fs.writeFile(gitignorePath, 'data/\n'); - await fs.chmod(gitignorePath, 0o000); + // Also skip under uid=0: root bypasses POSIX read-permission checks, so + // chmod 000 does NOT trigger EACCES — fs.readFile reads the file anyway + // and loadIgnoreRules returns parsed rules instead of null. This makes + // the test fail in any privileged environment (rootful Docker, CI runners + // configured with root). The non-root branch still exercises the real + // EACCES path; root just can't reproduce the failure mode. + it.skipIf(process.platform === 'win32' || process.getuid?.() === 0)( + 'warns on EACCES but does not throw', + async () => { + const gitignorePath = path.join(tmpDir, '.gitignore'); + await fs.writeFile(gitignorePath, 'data/\n'); + await fs.chmod(gitignorePath, 0o000); - const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}); - const result = await loadIgnoreRules(tmpDir); - // Should still return (null or partial), not throw - expect(result).toBeNull(); - expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('.gitignore')); + const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}); + const result = await loadIgnoreRules(tmpDir); + // Should still return (null or partial), not throw + expect(result).toBeNull(); + expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('.gitignore')); - warnSpy.mockRestore(); - await fs.chmod(gitignorePath, 0o644); - await fs.unlink(gitignorePath); - }); + warnSpy.mockRestore(); + await fs.chmod(gitignorePath, 0o644); + await fs.unlink(gitignorePath); + }, + ); }); describe('loadIgnoreRules — GITNEXUS_NO_GITIGNORE env var', () => {