From d6c482549df7a4dd0854bbdfc7c03e779114d0c5 Mon Sep 17 00:00:00 2001 From: MongLong0214 Date: Sun, 16 Aug 2026 09:00:30 +0900 Subject: [PATCH 1/2] Give the hook a path that outlives the release it was installed from commitlore.bin recorded /v/dist/commitlore.mjs, so an upgrade left every repository validating commits with the build it was installed from. Measured on the first machine to upgrade: three repositories pinned to 0.8.2 and 0.8.0 while the CLI was 1.0.1 -- this repository among them, through two releases. doctor said so on every run and stopped nothing. install.sh now maintains /current beside the versioned checkouts, and hooks record that. It stays an absolute path to a .mjs, so the recorded interpreter launches it and the hook remains independent of PATH -- the two properties the versioned path was chosen for. The bin wrapper cannot serve here and that is not a guess: #694 recorded it and hooks failed under the restricted PATH a hook actually runs in, because a shell script cannot be launched with a recorded interpreter. Two things deliberately narrow. The link is only recorded when it resolves to the running bundle -- a current belonging to another install would send the hook to code this one never verified, which is worse than a version pin. And a host where the symlink cannot be made still installs: hooks there keep recording the versioned path, and `commitlore hooks install` after an upgrade remains the repair doctor already names. The path is derived from the layout rather than from the directory being called commitlore, after the first attempt matched on that name and failed anywhere the data root is named otherwise. Existing pins still need `commitlore hooks install` re-run. This changes what is recorded from now on. Limit: a hook records a path that does not name a release Blast: system Undo: easy Certainty: firm Provenance: authored Record-Id: r-693curr --- dist/commands/hooks.js | 42 ++++++++++++- dist/commands/hooks.js.map | 2 +- dist/commitlore.mjs | 53 ++++++++++------- install.sh | 28 +++++++++ installer/canonical-artifact.json | 10 ++-- src/commands/hooks.ts | 41 ++++++++++++- test/hook-version-free-pin.test.ts | 94 ++++++++++++++++++++++++++++++ 7 files changed, 237 insertions(+), 33 deletions(-) create mode 100644 test/hook-version-free-pin.test.ts diff --git a/dist/commands/hooks.js b/dist/commands/hooks.js index 69f43fe0..620b0672 100644 --- a/dist/commands/hooks.js +++ b/dist/commands/hooks.js @@ -21,7 +21,7 @@ */ import { randomBytes } from 'node:crypto'; import { chmodSync, existsSync, mkdirSync, readFileSync, realpathSync, renameSync, statSync, unlinkSync, writeFileSync, } from 'node:fs'; -import { join, resolve } from 'node:path'; +import { basename, dirname, join, resolve } from 'node:path'; import { execGit } from '../core/git.js'; import { describeRecordedHookTarget, recordedHookIdentity, readRecordedHookTarget, } from '../core/hook-target.js'; import { PACKAGE_ROOT } from '../core/paths.js'; @@ -157,10 +157,46 @@ export const resolveEntryForRecord = (entry, cwd) => { } return null; }; +/** + * The same bundle reached through a path that does not name a release (#693). + * + * `process.argv[1]` under a normal install is + * `/v/dist/commitlore.mjs`, and recording it pins the + * repository to that release: an upgrade leaves the hook validating commits + * with the old build while the CLI reports the new one. Three repositories on + * the first machine to upgrade were doing exactly that, this one among them, + * throughout two releases. + * + * `install.sh` maintains `/current` beside the versioned checkouts. + * It is still an absolute path to a `.mjs`, so the recorded interpreter can + * launch it and the hook stays independent of PATH — the properties the + * versioned path was chosen for. The `bin` wrapper cannot serve here: it is a + * shell script, and a hook runs where PATH may carry no node at all. + * + * Only accepted when it resolves to the bundle that is running. A `current` + * pointing elsewhere belongs to another install, and sending a hook to code + * this one never verified is worse than pinning a version. + */ +const versionFreeEntryFor = (bundle) => { + // Derived from the layout, not from a directory name: /v/dist/. + // Matching on the literal "commitlore" would have made this depend on what the + // data root happens to be called. + const versionDir = dirname(dirname(bundle)); + if (!/^v\d/.test(basename(versionDir))) + return null; + const candidate = join(dirname(versionDir), 'current', 'dist', 'commitlore.mjs'); + try { + return realpathSync(candidate) === realpathSync(bundle) ? candidate : null; + } + catch { + return null; + } +}; const recordBinPath = (cwd) => { - const resolvedEntry = resolveEntryForRecord(process.argv[1], cwd); - if (resolvedEntry === null) + const running = resolveEntryForRecord(process.argv[1], cwd); + if (running === null) return; + const resolvedEntry = versionFreeEntryFor(running) ?? running; execGit(['config', '--local', 'commitlore.bin', resolvedEntry], { cwd }); // The interpreter as well: the branch that reads these back runs in a hook // whose PATH may not carry node, which is the whole reason it exists. For a diff --git a/dist/commands/hooks.js.map b/dist/commands/hooks.js.map index 6113619f..723e1083 100644 --- a/dist/commands/hooks.js.map +++ b/dist/commands/hooks.js.map @@ -1 +1 @@ -{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/commands/hooks.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/commands/hooks.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/commitlore.mjs b/dist/commitlore.mjs index 789dd2b8..8208fc75 100755 --- a/dist/commitlore.mjs +++ b/dist/commitlore.mjs @@ -17792,7 +17792,7 @@ var register3 = (program3) => { import { execFileSync } from "node:child_process"; import { mkdtempSync, rmSync as rmSync5, writeFileSync as writeFileSync13, mkdirSync as mkdirSync9 } from "node:fs"; import { tmpdir } from "node:os"; -import { dirname as dirname9, join as join14, resolve as resolve17 } from "node:path"; +import { dirname as dirname10, join as join14, resolve as resolve17 } from "node:path"; // src/demo/fixture.ts var targetPath = "src/pricing.ts"; @@ -21788,7 +21788,7 @@ import { unlinkSync as unlinkSync5, writeFileSync as writeFileSync11 } from "node:fs"; -import { join as join12, resolve as resolve15 } from "node:path"; +import { basename as basename2, dirname as dirname8, join as join12, resolve as resolve15 } from "node:path"; // src/hooks/post-commit.ts import { createHash as createHash7, randomBytes as randomBytes5 } from "node:crypto"; @@ -22452,9 +22452,20 @@ var resolveEntryForRecord = (entry, cwd) => { } return null; }; +var versionFreeEntryFor = (bundle) => { + const versionDir = dirname8(dirname8(bundle)); + if (!/^v\d/.test(basename2(versionDir))) return null; + const candidate = join12(dirname8(versionDir), "current", "dist", "commitlore.mjs"); + try { + return realpathSync4(candidate) === realpathSync4(bundle) ? candidate : null; + } catch { + return null; + } +}; var recordBinPath = (cwd) => { - const resolvedEntry = resolveEntryForRecord(process.argv[1], cwd); - if (resolvedEntry === null) return; + const running = resolveEntryForRecord(process.argv[1], cwd); + if (running === null) return; + const resolvedEntry = versionFreeEntryFor(running) ?? running; execGit(["config", "--local", "commitlore.bin", resolvedEntry], { cwd }); execGit(["config", "--local", "commitlore.node", process.execPath], { cwd }); try { @@ -22624,15 +22635,15 @@ var register9 = (program3) => { // src/core/agents-guidance.ts import { existsSync as existsSync19, readFileSync as readFileSync19, renameSync as renameSync8, rmSync as rmSync4, statSync as statSync8, writeFileSync as writeFileSync12 } from "node:fs"; -import { basename as basename2, dirname as dirname8, join as join13, resolve as resolve16 } from "node:path"; +import { basename as basename3, dirname as dirname9, join as join13, resolve as resolve16 } from "node:path"; import { fileURLToPath as fileURLToPath2 } from "node:url"; var AGENTS_SECTION_BEGIN = ""; var AGENTS_SECTION_END = ""; var messageOf6 = (error2) => error2 instanceof Error ? error2.message : String(error2); var shippedAgentsPath = () => { const source = fileURLToPath2(import.meta.url); - const here = dirname8(source); - return basename2(here) === "dist" ? resolve16(here, "..", "AGENTS.md") : resolve16(here, "..", "..", "AGENTS.md"); + const here = dirname9(source); + return basename3(here) === "dist" ? resolve16(here, "..", "AGENTS.md") : resolve16(here, "..", "..", "AGENTS.md"); }; var readCommitloreAgentsSection = () => { const contents = readFileSync19(shippedAgentsPath(), "utf8"); @@ -23193,12 +23204,12 @@ var runDemo = async (opts = {}) => { if (tmpResolved === userCwd || tmpResolved.startsWith(userCwd + "/") || userCwd.startsWith(tmpResolved + "/")) { throw new Error("demo: temporary directory overlaps with user repository \u2014 aborting"); } - git(["init", "--quiet", "--template=", "--initial-branch=main", tmpDir], dirname9(tmpDir)); + git(["init", "--quiet", "--template=", "--initial-branch=main", tmpDir], dirname10(tmpDir)); git(["config", "user.name", "CommitLore Demo"], tmpDir); git(["config", "user.email", "demo@commitlore.example"], tmpDir); git(["config", "commit.gpgsign", "false"], tmpDir); const targetFullPath = join14(tmpDir, targetPath); - mkdirSync9(dirname9(targetFullPath), { recursive: true }); + mkdirSync9(dirname10(targetFullPath), { recursive: true }); writeFileSync13(targetFullPath, "export const calculatePrice = () => {};\n"); git(["add", "."], tmpDir); git(["commit", "-m", predecessorCommitMessage], tmpDir); @@ -23666,7 +23677,7 @@ var register14 = (program3) => { import { spawnSync as spawnSync6 } from "node:child_process"; import { copyFileSync, existsSync as existsSync21, mkdirSync as mkdirSync10, readFileSync as readFileSync23, renameSync as renameSync9, statSync as statSync9, writeFileSync as writeFileSync16 } from "node:fs"; import { homedir } from "node:os"; -import { basename as basename3, dirname as dirname10, join as join15, resolve as resolve19 } from "node:path"; +import { basename as basename4, dirname as dirname11, join as join15, resolve as resolve19 } from "node:path"; // src/core/hermes-config.ts import { relative as relative2, resolve as resolve18, sep as sep3 } from "node:path"; @@ -23947,7 +23958,7 @@ var backupPathFor = (configPath) => { } }; var atomicallyWrite = (path2, contents, mode) => { - const temporary = join15(dirname10(path2), `.${basename3(path2)}.commitlore-${process.pid}.tmp`); + const temporary = join15(dirname11(path2), `.${basename4(path2)}.commitlore-${process.pid}.tmp`); try { if (mode === void 0) writeFileSync16(temporary, contents, "utf8"); else writeFileSync16(temporary, contents, { encoding: "utf8", mode }); @@ -23993,7 +24004,7 @@ var runHermesInstall = (options = {}) => { const dataRoot = options.dataRoot ?? join15(dataHome, "commitlore"); const versionedSkills = join15(dataRoot, `v${runtimeIdentity().version}`, "hermes", "skills"); const skillsDir = options.skillsDir ?? (existsSync21(versionedSkills) ? versionedSkills : installedPath("hermes", "skills")); - const detected = options.detected ?? (existsSync21(dirname10(configPath)) || commandExists("hermes")); + const detected = options.detected ?? (existsSync21(dirname11(configPath)) || commandExists("hermes")); const report = []; const verified = []; if (!detected) { @@ -24025,7 +24036,7 @@ var runHermesInstall = (options = {}) => { } if (edit.added.length > 0) { try { - mkdirSync10(dirname10(configPath), { recursive: true }); + mkdirSync10(dirname11(configPath), { recursive: true }); if (existsSync21(configPath)) { const backup = backupPathFor(configPath); copyFileSync(configPath, backup); @@ -24165,7 +24176,7 @@ var register16 = (program3) => { // src/commands/inject.ts import { readFileSync as readFileSync24, realpathSync as realpathSync5 } from "node:fs"; -import { basename as basename4, dirname as dirname11, isAbsolute as isAbsolute3, join as join16, relative as relative3, resolve as resolve20, sep as sep4 } from "node:path"; +import { basename as basename5, dirname as dirname12, isAbsolute as isAbsolute3, join as join16, relative as relative3, resolve as resolve20, sep as sep4 } from "node:path"; // src/core/inject.ts import { createHash as createHash9 } from "node:crypto"; @@ -24569,9 +24580,9 @@ var canonical = (target) => { const real = realpathSync5(current); return tail.length === 0 ? real : join16(real, ...tail); } catch { - const parent = dirname11(current); + const parent = dirname12(current); if (parent === current) return absolute; - tail.unshift(basename4(current)); + tail.unshift(basename5(current)); current = parent; } } @@ -24731,7 +24742,7 @@ var register17 = (program3) => { // src/commands/installer-hosts.ts import { existsSync as existsSync22, mkdirSync as mkdirSync11, renameSync as renameSync10, statSync as statSync10, unlinkSync as unlinkSync6, writeFileSync as writeFileSync17, readFileSync as readFileSync25 } from "node:fs"; -import { delimiter as delimiter2, dirname as dirname12, join as join17 } from "node:path"; +import { delimiter as delimiter2, dirname as dirname13, join as join17 } from "node:path"; import { randomUUID } from "node:crypto"; import { spawnSync as spawnSync7 } from "node:child_process"; var INSTALLER_HOSTS_SCHEMA = "commitlore_installer_hosts.v1"; @@ -24755,8 +24766,8 @@ var commandOf = (format, entry) => { }; var entryFor = (format, wrapper) => format === "json-mcp" ? { type: "local", command: [wrapper, "mcp"], enabled: true } : { command: wrapper, args: ["mcp"] }; var atomicJsonWrite = (path2, value) => { - mkdirSync11(dirname12(path2), { recursive: true }); - const temporary = join17(dirname12(path2), `.${String(path2.split("/").pop())}.commitlore-${process.pid}-${randomUUID()}.tmp`); + mkdirSync11(dirname13(path2), { recursive: true }); + const temporary = join17(dirname13(path2), `.${String(path2.split("/").pop())}.commitlore-${process.pid}-${randomUUID()}.tmp`); try { writeFileSync17(temporary, `${JSON.stringify(value, null, 2)} `, { encoding: "utf8", mode: 384 }); @@ -24845,8 +24856,8 @@ command = ${escaped} args = ["mcp"] `; try { - mkdirSync11(dirname12(path2), { recursive: true }); - const temporary = join17(dirname12(path2), `.${String(path2.split("/").pop())}.commitlore-${process.pid}-${randomUUID()}.tmp`); + mkdirSync11(dirname13(path2), { recursive: true }); + const temporary = join17(dirname13(path2), `.${String(path2.split("/").pop())}.commitlore-${process.pid}-${randomUUID()}.tmp`); try { writeFileSync17(temporary, next, { encoding: "utf8", mode: 384 }); if (process.env.COMMITLORE_INSTALLER_TEST_INTERRUPT_WRITE === "1") throw new Error("interrupted before atomic rename"); diff --git a/install.sh b/install.sh index b6e157c0..ba0dac30 100755 --- a/install.sh +++ b/install.sh @@ -626,6 +626,34 @@ if ! mv "$dest_tmp" "$dest"; then fi dest_tmp="" +# A version-free path to the bundle, maintained beside the versioned checkouts +# (#693). +# +# `commitlore hooks install` records an absolute path to the bundle so a hook is +# independent of PATH and of any node_modules/.bin/commitlore above the +# repository. Recording the versioned checkout pins that repository to one +# release: three repositories on the first machine to upgrade were still +# validating commits with 0.8.2 and 0.8.0, and this repository was one of them. +# +# The wrapper cannot stand in for it -- that was tried and fails, because a hook +# runs where PATH may carry no node and a shell script cannot be launched with +# the recorded interpreter. A symlink to the checkout keeps both properties: an +# absolute path to a .mjs, and one that does not name a release. +# +# Symlink, then rename: an existing `current` cannot be replaced in place while +# something is reading through it. +current_link="$data_root/current" +current_tmp="$current_link.commitlore-install.$$" +if ln -sfn "$candidate" "$current_tmp" 2>/dev/null && mv -f "$current_tmp" "$current_link" 2>/dev/null; then + log "current -> $(basename "$candidate")" +else + rm -f "$current_tmp" 2>/dev/null || true + # Not fatal. A host without symlinks still has a working install; hooks there + # keep recording the versioned path and `commitlore hooks install` after an + # upgrade remains the repair, which `doctor` already names. + log "note: could not maintain $current_link -- hooks will record a versioned path" +fi + log "installed to $dest" printf '%s\n' "$verified_version" diff --git a/installer/canonical-artifact.json b/installer/canonical-artifact.json index 574e1b5d..0c156b45 100644 --- a/installer/canonical-artifact.json +++ b/installer/canonical-artifact.json @@ -15,10 +15,10 @@ "tsconfig.json", "src" ], - "sha256": "064b3810c7c371bfa1cc838fbc3c2e8db8c856f22c0d07e8b2a4e61d3a660c11" + "sha256": "1d11f0bdafe983a545bf070830f32f1afcf6b437a7d154e6413f73651293fb75" }, "artifact": { - "sha256": "c312755d70a4d15b2743f95b9999694ef0fbc433f9ee645acc903c5275ef5a5d", + "sha256": "997d93d4667f50c81db815da8f0a0858cd5f63752d1cd1bbb9e3a2464fffc433", "files": [ { "path": "dist/cli.d.ts", @@ -422,11 +422,11 @@ }, { "path": "dist/commands/hooks.js", - "sha256": "f6c02cae9c88838b3ee7eb99670593e4b99c6dc416908141712708f009482f32" + "sha256": "33d6ebc8e69684983b258b3253423eef7085a49ce44e7579116bed4f7644c5e2" }, { "path": "dist/commands/hooks.js.map", - "sha256": "fd48593e755a6c4efd0350219595cb62de56366d0aefc4ad91c0c7ecd2f22513" + "sha256": "21f2746932ed945e5260d4d688b5da6ee6d591ee95a5472fd17d3098681c8958" }, { "path": "dist/commands/index-cmd.d.ts", @@ -586,7 +586,7 @@ }, { "path": "dist/commitlore.mjs", - "sha256": "136348243607bca3c8f3130825d458a862444c440307d396f1977b34ea6da910" + "sha256": "7dc734bebd046ff5e30277d17807673107fba5254637113772ab834dd9d98b15" }, { "path": "dist/core/agent-configs.d.ts", diff --git a/src/commands/hooks.ts b/src/commands/hooks.ts index 3830f183..e60d34ad 100644 --- a/src/commands/hooks.ts +++ b/src/commands/hooks.ts @@ -32,7 +32,7 @@ import { unlinkSync, writeFileSync, } from 'node:fs'; -import { join, resolve } from 'node:path'; +import { basename, dirname, join, resolve } from 'node:path'; import type { Command } from 'commander'; @@ -234,9 +234,44 @@ export const resolveEntryForRecord = (entry: string | undefined, cwd: string): s return null; }; +/** + * The same bundle reached through a path that does not name a release (#693). + * + * `process.argv[1]` under a normal install is + * `/v/dist/commitlore.mjs`, and recording it pins the + * repository to that release: an upgrade leaves the hook validating commits + * with the old build while the CLI reports the new one. Three repositories on + * the first machine to upgrade were doing exactly that, this one among them, + * throughout two releases. + * + * `install.sh` maintains `/current` beside the versioned checkouts. + * It is still an absolute path to a `.mjs`, so the recorded interpreter can + * launch it and the hook stays independent of PATH — the properties the + * versioned path was chosen for. The `bin` wrapper cannot serve here: it is a + * shell script, and a hook runs where PATH may carry no node at all. + * + * Only accepted when it resolves to the bundle that is running. A `current` + * pointing elsewhere belongs to another install, and sending a hook to code + * this one never verified is worse than pinning a version. + */ +const versionFreeEntryFor = (bundle: string): string | null => { + // Derived from the layout, not from a directory name: /v/dist/. + // Matching on the literal "commitlore" would have made this depend on what the + // data root happens to be called. + const versionDir = dirname(dirname(bundle)); + if (!/^v\d/.test(basename(versionDir))) return null; + const candidate = join(dirname(versionDir), 'current', 'dist', 'commitlore.mjs'); + try { + return realpathSync(candidate) === realpathSync(bundle) ? candidate : null; + } catch { + return null; + } +}; + const recordBinPath = (cwd: string): void => { - const resolvedEntry = resolveEntryForRecord(process.argv[1], cwd); - if (resolvedEntry === null) return; + const running = resolveEntryForRecord(process.argv[1], cwd); + if (running === null) return; + const resolvedEntry = versionFreeEntryFor(running) ?? running; execGit(['config', '--local', 'commitlore.bin', resolvedEntry], { cwd }); // The interpreter as well: the branch that reads these back runs in a hook // whose PATH may not carry node, which is the whole reason it exists. For a diff --git a/test/hook-version-free-pin.test.ts b/test/hook-version-free-pin.test.ts new file mode 100644 index 00000000..6a24aed4 --- /dev/null +++ b/test/hook-version-free-pin.test.ts @@ -0,0 +1,94 @@ +/** + * #693: the hook records a path that survives an upgrade. + * + * `commitlore.bin` held `/v0.8.2/dist/commitlore.mjs`, so an upgrade + * left the repository validating commits with the old build. Three repositories + * on the first machine to upgrade were in that state — this one among them, + * through two releases — and `doctor` said so on every run without stopping + * anything. + * + * `install.sh` now maintains `/current`. Recording that keeps what + * the versioned path was chosen for: an absolute path to a `.mjs`, launchable by + * the recorded interpreter, independent of PATH. The `bin` wrapper cannot serve + * here — it is a shell script, and a hook runs where PATH may carry no node. + * That was measured, not assumed: #694 tried it and hooks failed under the + * restricted PATH. + */ + +import { execFileSync } from 'node:child_process'; +import { cpSync, mkdirSync, mkdtempSync, realpathSync, rmSync, symlinkSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +import { afterAll, describe, expect, it } from 'vitest'; + +const REPO_ROOT = join(dirname(fileURLToPath(import.meta.url)), '..'); +const scratch: string[] = []; + +afterAll(() => { + for (const dir of scratch) rmSync(dir, { recursive: true, force: true }); +}); + +/** A data root with one versioned checkout, and `current` aimed wherever asked. */ +const installation = (currentTarget?: string): { bundle: string; dataRoot: string } => { + const dataRoot = mkdtempSync(join(tmpdir(), 'cl-vfree-')); + scratch.push(dataRoot); + const versioned = join(dataRoot, 'v1.0.1'); + cpSync(join(REPO_ROOT, 'dist'), join(versioned, 'dist'), { recursive: true }); + cpSync(join(REPO_ROOT, 'spec'), join(versioned, 'spec'), { recursive: true }); + cpSync(join(REPO_ROOT, 'package.json'), join(versioned, 'package.json')); + symlinkSync(currentTarget ?? versioned, join(dataRoot, 'current')); + return { bundle: join(versioned, 'dist', 'commitlore.mjs'), dataRoot }; +}; + +const repo = (): string => { + const dir = mkdtempSync(join(tmpdir(), 'cl-vfree-repo-')); + scratch.push(dir); + const run = (args: string[]): void => { + execFileSync('git', args, { cwd: dir, stdio: ['pipe', 'pipe', 'pipe'] }); + }; + run(['init', '-q']); + run(['config', 'user.email', 'a@b']); + run(['config', 'user.name', 'a']); + return dir; +}; + +const recordedPin = (cwd: string, bundle: string): string => { + execFileSync(process.execPath, [bundle, 'hooks', 'install'], { + cwd, + encoding: 'utf8', + stdio: ['pipe', 'pipe', 'pipe'], + }); + return execFileSync('git', ['config', '--local', '--get', 'commitlore.bin'], { + cwd, + encoding: 'utf8', + }).trim(); +}; + +describe('#693 what the hook pins itself to', () => { + it('records the version-free path when it resolves to this bundle', () => { + const { bundle, dataRoot } = installation(); + + const pin = recordedPin(repo(), bundle); + + // Compared by realpath: macOS resolves /var to /private/var, and the + // recorded value is the resolved form. + expect(pin, 'the upgrade-surviving path').toBe( + join(dataRoot, 'current', 'dist', 'commitlore.mjs'), + ); + expect(pin, 'and it names no release').not.toMatch(/\/v\d+\.\d+\.\d+\//); + expect(pin, 'still a .mjs, so the recorded interpreter can launch it').toMatch(/\.mjs$/); + }); + + // A `current` belonging to another installation would send the hook to code + // this one never verified — worse than pinning a version. + it('keeps the versioned path when current points at a different install', () => { + const elsewhere = mkdtempSync(join(tmpdir(), 'cl-vfree-other-')); + scratch.push(elsewhere); + mkdirSync(join(elsewhere, 'dist'), { recursive: true }); + const { bundle } = installation(elsewhere); + + expect(recordedPin(repo(), bundle), 'an unrelated current is not trusted').toBe(bundle); + }); +}); From c8149e7c506e8f64f075565938a6befc6c853f78 Mon Sep 17 00:00:00 2001 From: MongLong0214 Date: Sun, 16 Aug 2026 09:09:11 +0900 Subject: [PATCH 2/2] Make the rejection case prove the rejection The test asserting a foreign current is refused passed for the wrong reason: the fixture pointed current at a path with no bundle, so realpathSync threw and the fallback happened because the link was broken. The identity comparison never ran, and removing it left the test green. The other installation is now a working one. Only the comparison can reject it. Two mutations, two different failures: removing the derivation -> the version-free case fails removing the identity check -> the foreign-current case fails Before this, one mutation covered both and the second layer was unpinned. Caught in review by asking which mutation each assertion answers -- a question the passing suite could not answer for itself. Limit: a rejection test names what does the rejecting Blast: local Undo: easy Certainty: firm Provenance: authored Record-Id: r-693mut2 --- test/hook-version-free-pin.test.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/hook-version-free-pin.test.ts b/test/hook-version-free-pin.test.ts index 6a24aed4..34795613 100644 --- a/test/hook-version-free-pin.test.ts +++ b/test/hook-version-free-pin.test.ts @@ -16,7 +16,7 @@ */ import { execFileSync } from 'node:child_process'; -import { cpSync, mkdirSync, mkdtempSync, realpathSync, rmSync, symlinkSync } from 'node:fs'; +import { cpSync, mkdtempSync, realpathSync, rmSync, symlinkSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { dirname, join } from 'node:path'; import { fileURLToPath } from 'node:url'; @@ -84,9 +84,13 @@ describe('#693 what the hook pins itself to', () => { // A `current` belonging to another installation would send the hook to code // this one never verified — worse than pinning a version. it('keeps the versioned path when current points at a different install', () => { + // A *working* other installation, not a broken link. If the file simply + // did not exist, realpathSync would throw and the fallback would happen for + // that reason — the identity comparison would never run, and this case + // would pass while proving nothing. It did, until this fixture was fixed. const elsewhere = mkdtempSync(join(tmpdir(), 'cl-vfree-other-')); scratch.push(elsewhere); - mkdirSync(join(elsewhere, 'dist'), { recursive: true }); + cpSync(join(REPO_ROOT, 'dist'), join(elsewhere, 'dist'), { recursive: true }); const { bundle } = installation(elsewhere); expect(recordedPin(repo(), bundle), 'an unrelated current is not trusted').toBe(bundle);