mirror of
https://github.com/affaan-m/ECC.git
synced 2026-09-28 04:25:11 +02:00
fix(hooks): resolve the venv path before asking git whether it is tracked
The guard added in9cdc40e6was incomplete. `git ls-files` reports paths as they are indexed and does not follow symlinks, so a repository that commits `.venv` as a symlink to its own root alongside a tracked `bin/python` gets asked about `.venv/bin/python` -- a path git has never heard of -- and the answer is "untracked". The interpreter then runs. Measured on that shape: the planted executable logged two invocations against9cdc40e6and none against this commit. `repo_ships_interpreter` now resolves the bin directory with `cd -P`/`pwd -P`, resolves the worktree root the same way, and asks git about the resolved path relative to it. The three cases that matter all hold: a plainly committed venv is still refused, the symlink shape is now refused, and a developer's own untracked venv still resolves and runs. `cd -P`/`pwd -P` rather than `realpath` or `readlink -f`, because neither is portable to a stock macOS.
This commit is contained in:
@@ -319,6 +319,7 @@ function runHermeticPythonPrePush({
|
||||
venvName = null,
|
||||
venvExit = 0,
|
||||
trackVenv = false,
|
||||
trackedSymlinkVenv = false,
|
||||
pytestCmd = null,
|
||||
overrideStub = false,
|
||||
pathPytestVersionLine = null,
|
||||
@@ -350,6 +351,16 @@ function runHermeticPythonPrePush({
|
||||
}
|
||||
}
|
||||
|
||||
// The shape that defeats a naive `git ls-files -- .venv/bin/python` check: the
|
||||
// repository commits `.venv` as a symlink to its own root plus a tracked
|
||||
// `bin/python`, so git is asked about a path it has never indexed.
|
||||
if (trackedSymlinkVenv) {
|
||||
writeExecutable(path.join(projectDir, 'bin', 'python'), `#!/bin/sh\n${record}\nexit 0\n`);
|
||||
fs.symlinkSync('.', path.join(projectDir, '.venv'));
|
||||
const added = spawnSync('git', ['add', '-f', '--', 'bin/python', '.venv'], { cwd: projectDir });
|
||||
assert.strictEqual(added.status, 0, added.stderr?.toString());
|
||||
}
|
||||
|
||||
// Deliberately does NOT special-case --version: an operator's wrapper would not
|
||||
// either, and the recorded calls are what prove the hook never probed it.
|
||||
const overrideStubPath = overrideStub ? path.join(tempDir, 'bin', 'wrapper') : null;
|
||||
@@ -416,7 +427,18 @@ if (
|
||||
const { result, calls } = runHermeticPythonPrePush({ venvName: '.venv', trackVenv: true });
|
||||
assert.strictEqual(result.status, 0, `${result.stdout}\n${result.stderr}`);
|
||||
assert.deepStrictEqual(calls, [], JSON.stringify(calls));
|
||||
assert.match(result.stdout, /it is tracked in this repository/);
|
||||
assert.match(result.stdout, /the repository ships it/);
|
||||
})
|
||||
)
|
||||
passed++;
|
||||
else failed++;
|
||||
|
||||
if (
|
||||
test('pre-push refuses a tracked interpreter reached through a committed symlink', () => {
|
||||
const { result, calls } = runHermeticPythonPrePush({ trackedSymlinkVenv: true });
|
||||
assert.strictEqual(result.status, 0, `${result.stdout}\n${result.stderr}`);
|
||||
assert.deepStrictEqual(calls, [], JSON.stringify(calls));
|
||||
assert.match(result.stdout, /the repository ships it/);
|
||||
})
|
||||
)
|
||||
passed++;
|
||||
|
||||
Reference in New Issue
Block a user