@vaultcompass/vault-guard-core 1.4.2 → 1.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,8 +7,25 @@ export interface InstallHookOptions {
7
7
  export declare class PreCommitHook {
8
8
  /**
9
9
  * Resolve the directory where Git expects the \`pre-commit\` executable.
10
- * Honors \`core.hooksPath\` (local then global). Relative paths are resolved
11
- * against the **.git** directory, per Git documentation.
10
+ * Honors \`core.hooksPath\` (local then global).
11
+ *
12
+ * A RELATIVE \`core.hooksPath\` resolves against the WORKING-TREE ROOT,
13
+ * not against the .git directory. This resolved against the .git
14
+ * directory until a review caught it: husky 9 sets exactly this shape
15
+ * (core.hooksPath=.husky/_), so a repository using husky 9 had its hook
16
+ * written to a path git never reads, reported as installed, and never
17
+ * ran. Verified by driving a real commit rather than by re-reading the
18
+ * documentation that was misread the first time: with
19
+ * core.hooksPath=.husky/_ and an executable hook planted at BOTH
20
+ * .husky/_/pre-commit and .git/.husky/_/pre-commit, a commit runs the
21
+ * former. pre-commit-hook.test.ts pins it the same way.
22
+ *
23
+ * An ABSOLUTE \`core.hooksPath\` is used exactly as given, and no
24
+ * \`core.hooksPath\` at all still resolves against the git directory
25
+ * (never the working-tree root) -- both of those are unaffected by the
26
+ * bug above and must stay that way: a linked worktree or a submodule
27
+ * has its own git directory that is not its working-tree root, and that
28
+ * is precisely where an unset \`core.hooksPath\` needs to keep pointing.
12
29
  */
13
30
  getEffectiveHooksDir(cwd: string): {
14
31
  hooksDir: string;
@@ -47,4 +64,11 @@ export declare class PreCommitHook {
47
64
  private installPreCommitFramework;
48
65
  private uninstallPreCommitFramework;
49
66
  private resolveGitDir;
67
+ /**
68
+ * The working-tree root, or null when it cannot be determined. Asked of
69
+ * git rather than assumed to be \`cwd\`, so a relative \`core.hooksPath\`
70
+ * resolves correctly when \`install\`/\`getEffectiveHooksDir\` is called
71
+ * from a subdirectory of the repository.
72
+ */
73
+ private resolveWorktreeRoot;
50
74
  }
@@ -106,8 +106,25 @@ repos:
106
106
  class PreCommitHook {
107
107
  /**
108
108
  * Resolve the directory where Git expects the \`pre-commit\` executable.
109
- * Honors \`core.hooksPath\` (local then global). Relative paths are resolved
110
- * against the **.git** directory, per Git documentation.
109
+ * Honors \`core.hooksPath\` (local then global).
110
+ *
111
+ * A RELATIVE \`core.hooksPath\` resolves against the WORKING-TREE ROOT,
112
+ * not against the .git directory. This resolved against the .git
113
+ * directory until a review caught it: husky 9 sets exactly this shape
114
+ * (core.hooksPath=.husky/_), so a repository using husky 9 had its hook
115
+ * written to a path git never reads, reported as installed, and never
116
+ * ran. Verified by driving a real commit rather than by re-reading the
117
+ * documentation that was misread the first time: with
118
+ * core.hooksPath=.husky/_ and an executable hook planted at BOTH
119
+ * .husky/_/pre-commit and .git/.husky/_/pre-commit, a commit runs the
120
+ * former. pre-commit-hook.test.ts pins it the same way.
121
+ *
122
+ * An ABSOLUTE \`core.hooksPath\` is used exactly as given, and no
123
+ * \`core.hooksPath\` at all still resolves against the git directory
124
+ * (never the working-tree root) -- both of those are unaffected by the
125
+ * bug above and must stay that way: a linked worktree or a submodule
126
+ * has its own git directory that is not its working-tree root, and that
127
+ * is precisely where an unset \`core.hooksPath\` needs to keep pointing.
111
128
  */
112
129
  getEffectiveHooksDir(cwd) {
113
130
  const gitDirAbs = this.resolveGitDir(cwd);
@@ -128,10 +145,11 @@ class PreCommitHook {
128
145
  if (!hooksPath) {
129
146
  return { hooksDir: path_1.default.join(gitDirAbs, 'hooks'), viaHooksPath: false };
130
147
  }
131
- const hooksDir = path_1.default.isAbsolute(hooksPath)
132
- ? hooksPath
133
- : path_1.default.join(gitDirAbs, hooksPath);
134
- return { hooksDir, viaHooksPath: true };
148
+ if (path_1.default.isAbsolute(hooksPath)) {
149
+ return { hooksDir: hooksPath, viaHooksPath: true };
150
+ }
151
+ const worktreeRoot = this.resolveWorktreeRoot(cwd) ?? cwd;
152
+ return { hooksDir: path_1.default.join(worktreeRoot, hooksPath), viaHooksPath: true };
135
153
  }
136
154
  /**
137
155
  * Absolute path to the \`pre-commit\` hook file for the given manager.
@@ -480,5 +498,24 @@ class PreCommitHook {
480
498
  return null;
481
499
  }
482
500
  }
501
+ /**
502
+ * The working-tree root, or null when it cannot be determined. Asked of
503
+ * git rather than assumed to be \`cwd\`, so a relative \`core.hooksPath\`
504
+ * resolves correctly when \`install\`/\`getEffectiveHooksDir\` is called
505
+ * from a subdirectory of the repository.
506
+ */
507
+ resolveWorktreeRoot(cwd) {
508
+ try {
509
+ const rel = (0, child_process_1.execSync)('git rev-parse --show-toplevel', {
510
+ cwd,
511
+ encoding: 'utf-8',
512
+ stdio: ['ignore', 'pipe', 'pipe'],
513
+ }).trim();
514
+ return path_1.default.resolve(cwd, rel);
515
+ }
516
+ catch {
517
+ return null;
518
+ }
519
+ }
483
520
  }
484
521
  exports.PreCommitHook = PreCommitHook;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vaultcompass/vault-guard-core",
3
- "version": "1.4.2",
3
+ "version": "1.4.3",
4
4
  "description": "Secret-scanning engine: vendor-anchored patterns, entropy gating, baselines, SARIF/JSON, hook helpers.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",