push-sentinel 0.1.0 → 0.1.1
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/bin/cli.js +3 -2
- package/hook-template.sh +5 -1
- package/package.json +1 -1
- package/src/install.js +5 -1
- package/src/reporter.js +6 -2
- package/src/scan.js +15 -17
package/bin/cli.js
CHANGED
|
@@ -100,8 +100,9 @@ switch (command) {
|
|
|
100
100
|
const localSha = localShaIdx !== -1 ? args[localShaIdx + 1] : undefined;
|
|
101
101
|
const remoteSha = remoteShaIdx !== -1 ? args[remoteShaIdx + 1] : undefined;
|
|
102
102
|
const findings = scan(localSha, remoteSha);
|
|
103
|
-
|
|
104
|
-
|
|
103
|
+
const willBlock = blockOnHigh && hasHighFindings(findings);
|
|
104
|
+
report(findings, { willBlock });
|
|
105
|
+
if (willBlock) {
|
|
105
106
|
process.stderr.write('\n[push-sentinel] Push blocked: HIGH severity secret(s) detected. Remove the secret or run `push-sentinel ignore` to suppress.\n');
|
|
106
107
|
process.exit(1);
|
|
107
108
|
}
|
package/hook-template.sh
CHANGED
|
@@ -6,10 +6,14 @@
|
|
|
6
6
|
#
|
|
7
7
|
# We read each line and pass the SHAs explicitly so push-sentinel can compute
|
|
8
8
|
# the exact range of commits being pushed (including new branch / first push).
|
|
9
|
+
# Stdin is saved and re-supplied to pre-push.local so existing hooks still work.
|
|
9
10
|
|
|
10
11
|
EXIT_CODE=0
|
|
12
|
+
STDIN_DATA=""
|
|
11
13
|
|
|
12
14
|
while read local_ref local_sha remote_ref remote_sha; do
|
|
15
|
+
STDIN_DATA="${STDIN_DATA}${local_ref} ${local_sha} ${remote_ref} ${remote_sha}
|
|
16
|
+
"
|
|
13
17
|
npx push-sentinel scan --local-sha "$local_sha" --remote-sha "$remote_sha"
|
|
14
18
|
RESULT=$?
|
|
15
19
|
if [ $RESULT -ne 0 ]; then
|
|
@@ -22,5 +26,5 @@ if [ $EXIT_CODE -ne 0 ]; then
|
|
|
22
26
|
fi
|
|
23
27
|
|
|
24
28
|
if [ -f "$(git rev-parse --git-dir)/hooks/pre-push.local" ]; then
|
|
25
|
-
"$(git rev-parse --git-dir)/hooks/pre-push.local" "$@"
|
|
29
|
+
echo "$STDIN_DATA" | "$(git rev-parse --git-dir)/hooks/pre-push.local" "$@"
|
|
26
30
|
fi
|
package/package.json
CHANGED
package/src/install.js
CHANGED
|
@@ -33,10 +33,14 @@ ${SENTINEL_MARKER}
|
|
|
33
33
|
# <local-ref> <local-sha1> <remote-ref> <remote-sha1>
|
|
34
34
|
# We forward the SHAs so push-sentinel can determine exactly which commits
|
|
35
35
|
# are being pushed, including new branches (remote-sha = 0000...0000).
|
|
36
|
+
# Stdin is saved and re-supplied to pre-push.local so existing hooks still work.
|
|
36
37
|
|
|
37
38
|
EXIT_CODE=0
|
|
39
|
+
STDIN_DATA=""
|
|
38
40
|
|
|
39
41
|
while read local_ref local_sha remote_ref remote_sha; do
|
|
42
|
+
STDIN_DATA="${'$'}{STDIN_DATA}${'$'}{local_ref} ${'$'}{local_sha} ${'$'}{remote_ref} ${'$'}{remote_sha}
|
|
43
|
+
"
|
|
40
44
|
npx push-sentinel scan --local-sha "$local_sha" --remote-sha "$remote_sha"
|
|
41
45
|
RESULT=$?
|
|
42
46
|
if [ $RESULT -ne 0 ]; then
|
|
@@ -49,7 +53,7 @@ if [ $EXIT_CODE -ne 0 ]; then
|
|
|
49
53
|
fi
|
|
50
54
|
|
|
51
55
|
if [ -f "$(git rev-parse --git-dir)/hooks/pre-push.local" ]; then
|
|
52
|
-
"$(git rev-parse --git-dir)/hooks/pre-push.local" "$@"
|
|
56
|
+
echo "$STDIN_DATA" | "$(git rev-parse --git-dir)/hooks/pre-push.local" "$@"
|
|
53
57
|
fi
|
|
54
58
|
`;
|
|
55
59
|
}
|
package/src/reporter.js
CHANGED
|
@@ -13,7 +13,7 @@ function severityLabel(severity) {
|
|
|
13
13
|
return `[${severity}]`;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
function report(findings) {
|
|
16
|
+
function report(findings, { willBlock = false } = {}) {
|
|
17
17
|
if (findings.length === 0) {
|
|
18
18
|
process.stderr.write('[push-sentinel] \u2713 No secrets detected.\n');
|
|
19
19
|
return;
|
|
@@ -39,7 +39,11 @@ function report(findings) {
|
|
|
39
39
|
process.stderr.write(` + ${extra} more finding(s) not shown.\n\n`);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
if (willBlock) {
|
|
43
|
+
process.stderr.write(' Push will be blocked.\n');
|
|
44
|
+
} else {
|
|
45
|
+
process.stderr.write(' Push continues. Double-check before sharing.\n');
|
|
46
|
+
}
|
|
43
47
|
}
|
|
44
48
|
|
|
45
49
|
function hasHighFindings(findings) {
|
package/src/scan.js
CHANGED
|
@@ -55,33 +55,31 @@ function loadIgnoreRules(repoRoot) {
|
|
|
55
55
|
return { lines, patterns };
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
// Check if a file path matches a single glob-style ignore rule
|
|
59
|
+
function matchesGlob(filePath, rule) {
|
|
60
|
+
if (rule.endsWith('/**')) {
|
|
61
|
+
const dir = rule.slice(0, -3);
|
|
62
|
+
return filePath.startsWith(dir + '/') || filePath === dir;
|
|
63
|
+
}
|
|
64
|
+
if (rule.endsWith('*')) {
|
|
65
|
+
return filePath.startsWith(rule.slice(0, -1));
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
|
|
58
70
|
// Check if a file (regardless of line) matches any ignore rule
|
|
59
71
|
function matchesIgnoreFile(filePath, ignoreLines) {
|
|
60
72
|
for (const rule of ignoreLines) {
|
|
61
|
-
if (rule === filePath) return true;
|
|
62
|
-
if (rule.endsWith('/**')) {
|
|
63
|
-
const dir = rule.slice(0, -3);
|
|
64
|
-
if (filePath.startsWith(dir + '/') || filePath === dir) return true;
|
|
65
|
-
}
|
|
66
|
-
if (rule.endsWith('*')) {
|
|
67
|
-
if (filePath.startsWith(rule.slice(0, -1))) return true;
|
|
68
|
-
}
|
|
73
|
+
if (rule === filePath || matchesGlob(filePath, rule)) return true;
|
|
69
74
|
}
|
|
70
75
|
return false;
|
|
71
76
|
}
|
|
72
77
|
|
|
73
|
-
// Check if a file:line matches any ignore rule
|
|
78
|
+
// Check if a file:line matches any ignore rule
|
|
74
79
|
function matchesIgnoreLine(filePath, lineNum, ignoreLines) {
|
|
75
80
|
const target = `${filePath}:${lineNum}`;
|
|
76
81
|
for (const rule of ignoreLines) {
|
|
77
|
-
if (rule === target) return true;
|
|
78
|
-
if (rule.endsWith('/**')) {
|
|
79
|
-
const dir = rule.slice(0, -3);
|
|
80
|
-
if (filePath.startsWith(dir + '/') || filePath === dir) return true;
|
|
81
|
-
}
|
|
82
|
-
if (rule.endsWith('*')) {
|
|
83
|
-
if (filePath.startsWith(rule.slice(0, -1))) return true;
|
|
84
|
-
}
|
|
82
|
+
if (rule === target || matchesGlob(filePath, rule)) return true;
|
|
85
83
|
}
|
|
86
84
|
return false;
|
|
87
85
|
}
|