@vaultcompass/vault-guard-core 1.4.1 → 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.
package/dist/scan-output.js
CHANGED
|
@@ -26,6 +26,35 @@ function normalizeFilePath(file, cwd) {
|
|
|
26
26
|
return file;
|
|
27
27
|
return rel || '.';
|
|
28
28
|
}
|
|
29
|
+
/** Matches a Windows drive-letter absolute path (`C:\...`, `C:/...`) or a UNC path (`\\server\share`). */
|
|
30
|
+
const WINDOWS_ABSOLUTE_PATH_RE = /^(?:[a-zA-Z]:[\\/]|\\\\)/;
|
|
31
|
+
function isWindowsStylePath(p) {
|
|
32
|
+
return WINDOWS_ABSOLUTE_PATH_RE.test(p);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* SARIF `artifactLocation.uri` must be a relative-reference URI: forward
|
|
36
|
+
* slashes only, no leading `./`, no leading `/` (the GitHub Code Scanning
|
|
37
|
+
* SARIF spec requires this even when the scanner itself runs on Windows,
|
|
38
|
+
* where `path.relative` returns backslash-separated paths).
|
|
39
|
+
*
|
|
40
|
+
* Picks `path.win32` when either side of the comparison looks like a
|
|
41
|
+
* Windows-style path, so this is correct both when the process itself runs
|
|
42
|
+
* on Windows (native `path` is already `path.win32`) and when a
|
|
43
|
+
* Windows-style path is normalized on a POSIX host (tests, or a SARIF file
|
|
44
|
+
* produced elsewhere and re-normalized).
|
|
45
|
+
*/
|
|
46
|
+
function toSarifArtifactUri(file, cwd) {
|
|
47
|
+
if (cwd === null)
|
|
48
|
+
return file.split('\\').join('/');
|
|
49
|
+
const base = cwd ?? process.cwd();
|
|
50
|
+
const impl = isWindowsStylePath(file) || isWindowsStylePath(base) ? path_1.default.win32 : path_1.default;
|
|
51
|
+
if (!impl.isAbsolute(file))
|
|
52
|
+
return file.split('\\').join('/');
|
|
53
|
+
const rel = impl.relative(base, file);
|
|
54
|
+
if (rel.startsWith('..') || impl.isAbsolute(rel))
|
|
55
|
+
return file.split('\\').join('/');
|
|
56
|
+
return (rel || '.').split('\\').join('/');
|
|
57
|
+
}
|
|
29
58
|
function formatJson(results, opts = {}) {
|
|
30
59
|
const fpCwd = opts.cwd === undefined ? process.cwd() : opts.cwd;
|
|
31
60
|
const output = {
|
|
@@ -60,6 +89,7 @@ function formatJson(results, opts = {}) {
|
|
|
60
89
|
}
|
|
61
90
|
/** SARIF 2.1.0 — compatible with GitHub Code Scanning (upload-sarif action). */
|
|
62
91
|
function formatSarif(results, opts = {}) {
|
|
92
|
+
const fpCwd = opts.cwd === undefined ? process.cwd() : opts.cwd;
|
|
63
93
|
const rules = [
|
|
64
94
|
...new Set(results.flatMap(r => r.matches.map(m => m.type))),
|
|
65
95
|
].map(id => ({
|
|
@@ -82,7 +112,7 @@ function formatSarif(results, opts = {}) {
|
|
|
82
112
|
locations: [
|
|
83
113
|
{
|
|
84
114
|
physicalLocation: {
|
|
85
|
-
artifactLocation: { uri:
|
|
115
|
+
artifactLocation: { uri: toSarifArtifactUri(file, opts.cwd), uriBaseId: '%SRCROOT%' },
|
|
86
116
|
region: {
|
|
87
117
|
startLine: m.line,
|
|
88
118
|
startColumn: m.column + 1,
|
|
@@ -91,6 +121,10 @@ function formatSarif(results, opts = {}) {
|
|
|
91
121
|
},
|
|
92
122
|
},
|
|
93
123
|
],
|
|
124
|
+
// Same fingerprint the JSON output emits per finding (positional: keyed
|
|
125
|
+
// on relative path + type + line + offset + matchLength). Lets GitHub
|
|
126
|
+
// Code Scanning track a finding's identity across runs.
|
|
127
|
+
partialFingerprints: { 'vault-guard/v1': (0, match_fingerprint_1.fingerprintForMatch)(fpCwd, file, m) },
|
|
94
128
|
})));
|
|
95
129
|
// Diagnostics are emitted as SARIF notifications (tool/driver/notifications)
|
|
96
130
|
// so they appear in the GitHub Code Scanning UI as tool warnings rather than
|
|
@@ -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).
|
|
11
|
-
*
|
|
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).
|
|
110
|
-
*
|
|
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
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
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.
|
|
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",
|