| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364 |
- /**
- * `fileExists` must not probe outside the project root (#1631).
- *
- * `resolveRelativeImport` hands this callback paths built with
- * `path.relative(projectRoot, basePath)`, which can carry `../` segments, and
- * `path.join` does not clamp — so a crafted relative import in an indexed file
- * made the resolver stat arbitrary absolute paths. Nothing outside is read (the
- * content sinks are guarded separately, #527) and no edge is produced, but the
- * probe itself is an existence oracle driven by repository content.
- */
- import { describe, it, expect, beforeEach, afterEach } from 'vitest';
- import * as fs from 'fs';
- import * as os from 'os';
- import * as path from 'path';
- import { ReferenceResolver } from '../src/resolution';
- import type { QueryBuilder } from '../src/db/queries';
- describe('fileExists containment (#1631)', () => {
- let sandbox: string;
- let projectRoot: string;
- /** The resolver only needs a project root here — `fileExists` never queries. */
- const contextFor = (root: string) =>
- new ReferenceResolver(root, {} as unknown as QueryBuilder).getResolutionContext();
- beforeEach(() => {
- sandbox = fs.mkdtempSync(path.join(os.tmpdir(), 'codegraph-test-'));
- projectRoot = path.join(sandbox, 'proj');
- fs.mkdirSync(path.join(projectRoot, 'src'), { recursive: true });
- fs.writeFileSync(path.join(projectRoot, 'src', 'a.js'), 'export const a = 1;');
- // A real file two levels above the root, as the reproduction in #1631 has.
- fs.mkdirSync(path.join(sandbox, 'outside'), { recursive: true });
- fs.writeFileSync(path.join(sandbox, 'outside', 'secret.js'), 'export const secret = 42;');
- });
- afterEach(() => {
- fs.rmSync(sandbox, { recursive: true, force: true });
- });
- it('still reports files inside the root', () => {
- expect(contextFor(projectRoot).fileExists('src/a.js')).toBe(true);
- expect(contextFor(projectRoot).fileExists('src/missing.js')).toBe(false);
- });
- it('refuses to probe a path that escapes the root, even though it exists', () => {
- const escaping = path.join('..', 'outside', 'secret.js');
- // Baseline: the target really is there — so `false` can only come from the guard.
- expect(fs.existsSync(path.join(projectRoot, escaping))).toBe(true);
- expect(contextFor(projectRoot).fileExists(escaping)).toBe(false);
- });
- it('keeps following an in-root symlink whose target is outside the root (#935)', () => {
- const link = path.join(projectRoot, 'vendor');
- try {
- fs.symlinkSync(path.join(sandbox, 'outside'), link, 'dir');
- } catch {
- return; // symlink creation not permitted (e.g. Windows without privilege)
- }
- // Lexically inside the root, physically outside — the indexing tier allows this.
- expect(contextFor(projectRoot).fileExists(path.join('vendor', 'secret.js'))).toBe(true);
- });
- });
|