isOwnWorkingTree() treated any target at or below cwd as own, so a foreign clone under cwd (cwd = $HOME, a vendor clone in a project) still had its .llm-security-ignore, policy.json and custom SIG rules read. The target must now also share cwd's git root: nearest ancestor with a `.git` entry (dir for a clone, file for a submodule/worktree), or none for both. No git spawn. tmpdir stays foreign. Chosen per the PM order: it is exactly the line between "my repo" and "something I fetched", and the failure direction is safe (foreign => config ignored => more findings, never fewer). Red first: tests/lib/own-working-tree.test.mjs 4 fail / 5 pass (the 5 are known-positives), tests/scanners/nested-clone-scope.test.mjs 5 fail / 4 pass on the old rule. Green after; reverting the git-root comparison turns 9 red. Suite 2306 / 2300 pass / 0 fail / 6 skip; hooks 370/0 (implicit root untouched); golden 109/7/4, 61/61. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
102 lines
3.9 KiB
JavaScript
102 lines
3.9 KiB
JavaScript
// own-working-tree.test.mjs — isOwnWorkingTree() rule (v8.1.1).
|
|
//
|
|
// v8.1.0 treated any target at or below the process cwd as the caller's own
|
|
// working tree. That is too wide: a foreign clone that sits UNDER cwd (cwd =
|
|
// $HOME, or a project with a cloned vendor dir) still had its .llm-security
|
|
// config read. v8.1.1 narrows the rule: the target must be at or below cwd
|
|
// AND have the same git root as cwd — the nearest ancestor holding a `.git`
|
|
// (directory for a clone, file for a submodule/worktree), or none for both.
|
|
// A nested clone therefore counts as foreign. The failure direction is safe:
|
|
// foreign means the target's config is ignored, so more findings, never fewer.
|
|
//
|
|
// Fixtures live under $HOME (outside os.tmpdir(), which is always foreign,
|
|
// and outside this repo's git tree); $HOME itself must not be a git root.
|
|
|
|
import { describe, it, before, after } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { join } from 'node:path';
|
|
import { mkdirSync, writeFileSync, rmSync, existsSync } from 'node:fs';
|
|
import { homedir } from 'node:os';
|
|
import { spawnSync } from 'node:child_process';
|
|
import { isOwnWorkingTree } from '../../scanners/lib/own-working-tree.mjs';
|
|
import { mkOwnTreeDir } from '../helpers/own-tree.mjs';
|
|
|
|
function gitInit(dir) {
|
|
mkdirSync(dir, { recursive: true });
|
|
const r = spawnSync('git', ['init', '-q', dir], { encoding: 'utf8' });
|
|
assert.equal(r.status, 0, `git init failed: ${r.stderr}`);
|
|
}
|
|
|
|
function ownFrom(cwd, target) {
|
|
const prev = process.cwd();
|
|
process.chdir(cwd);
|
|
try {
|
|
return isOwnWorkingTree(target);
|
|
} finally {
|
|
process.chdir(prev);
|
|
}
|
|
}
|
|
|
|
describe('isOwnWorkingTree(): same git root as cwd (v8.1.1)', () => {
|
|
let root;
|
|
let repo;
|
|
let homeish;
|
|
|
|
before(() => {
|
|
assert.ok(!existsSync(join(homedir(), '.git')), 'precondition: $HOME is not a git root');
|
|
root = mkOwnTreeDir('owt-unit-');
|
|
// A repo the user works in, with a plain subdir, a nested clone and a
|
|
// submodule-style checkout (`.git` is a file).
|
|
repo = join(root, 'repo');
|
|
gitInit(repo);
|
|
mkdirSync(join(repo, 'sub', 'deeper'), { recursive: true });
|
|
gitInit(join(repo, 'vendor', 'clone'));
|
|
mkdirSync(join(repo, 'vendor', 'clone', 'inner'), { recursive: true });
|
|
mkdirSync(join(repo, 'submod'), { recursive: true });
|
|
writeFileSync(join(repo, 'submod', '.git'), 'gitdir: ../.git/modules/submod\n');
|
|
// A $HOME-like dir: no git root, holding one clone and one plain dir.
|
|
homeish = join(root, 'homeish');
|
|
mkdirSync(join(homeish, 'plain'), { recursive: true });
|
|
gitInit(join(homeish, 'clone'));
|
|
});
|
|
|
|
after(() => { rmSync(root, { recursive: true, force: true }); });
|
|
|
|
it('cwd itself is own', () => {
|
|
assert.equal(ownFrom(repo, repo), true);
|
|
assert.equal(ownFrom(repo, '.'), true);
|
|
});
|
|
|
|
it('(b) a subdir of the same repo is own (known-positive)', () => {
|
|
assert.equal(ownFrom(repo, join(repo, 'sub')), true);
|
|
assert.equal(ownFrom(join(repo, 'sub'), join(repo, 'sub', 'deeper')), true);
|
|
});
|
|
|
|
it('(a) a nested clone under the repo is foreign', () => {
|
|
assert.equal(ownFrom(repo, join(repo, 'vendor', 'clone')), false);
|
|
});
|
|
|
|
it('(a) a subdir inside a nested clone is foreign', () => {
|
|
assert.equal(ownFrom(repo, join(repo, 'vendor', 'clone', 'inner')), false);
|
|
});
|
|
|
|
it('a submodule/worktree checkout (`.git` file) is foreign', () => {
|
|
assert.equal(ownFrom(repo, join(repo, 'submod')), false);
|
|
});
|
|
|
|
it('(c) a clone under a cwd with no git root is foreign', () => {
|
|
assert.equal(ownFrom(homeish, join(homeish, 'clone')), false);
|
|
});
|
|
|
|
it('a plain subdir of a cwd with no git root is own', () => {
|
|
assert.equal(ownFrom(homeish, join(homeish, 'plain')), true);
|
|
});
|
|
|
|
it('a clone the user has cd\'d into is own (it is cwd)', () => {
|
|
assert.equal(ownFrom(join(homeish, 'clone'), '.'), true);
|
|
});
|
|
|
|
it('a target outside cwd is foreign', () => {
|
|
assert.equal(ownFrom(join(repo, 'sub'), repo), false);
|
|
});
|
|
});
|