test(ignore-service): skip EACCES test under uid=0 (root bypasses chmod) (#1108)

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.
This commit is contained in:
ManniX-ITA 2026-04-27 11:06:16 +01:00 • committed by GitHub
parent 5c434ff313
commit 8fbbb35718
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -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', () => {