agent-security-scanner-mcp 3.7.0 → 3.8.0
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/README.md +42 -8
- package/analyzer.py +22 -5
- package/cross_file_analyzer.py +216 -0
- package/daemon.py +179 -0
- package/index.js +279 -3
- package/package.json +19 -5
- package/packages/npm-bloom.json +1 -0
- package/pattern_matcher.py +1 -0
- package/regex_fallback.py +199 -1
- package/requirements.txt +1 -0
- package/rules/prompt-injection.security.yaml +273 -41
- package/scripts/postinstall.js +60 -0
- package/skills/openclaw/SKILL.md +102 -0
- package/skills/security-review.md +139 -0
- package/skills/security-scan-batch.md +107 -0
- package/skills/security-scanner.md +76 -0
- package/src/cli/doctor.js +29 -1
- package/src/cli/init.js +93 -0
- package/src/cli/report.js +444 -0
- package/src/config.js +247 -0
- package/src/context.js +289 -0
- package/src/daemon-client.js +233 -0
- package/src/dedup.js +129 -0
- package/src/fix-patterns.js +76 -19
- package/src/history.js +159 -0
- package/src/tools/check-package.js +36 -12
- package/src/tools/fix-security.js +32 -5
- package/src/tools/import-resolver.js +249 -0
- package/src/tools/project-context.js +365 -0
- package/src/tools/scan-action.js +489 -0
- package/src/tools/scan-mcp.js +588 -0
- package/src/tools/scan-project.js +16 -4
- package/src/tools/scan-prompt.js +292 -527
- package/src/tools/scan-security.js +37 -6
- package/src/typosquat.js +210 -0
- package/src/utils.js +215 -8
- package/templates/gitlab-ci-security.yml +225 -0
- package/templates/pre-commit-hook.sh +233 -0
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# GitLab CI Template: agent-security-scanner-mcp
|
|
3
|
+
# =============================================================================
|
|
4
|
+
#
|
|
5
|
+
# Include this template in your .gitlab-ci.yml to add security scanning:
|
|
6
|
+
#
|
|
7
|
+
# include:
|
|
8
|
+
# - project: 'your-group/agent-security-scanner-mcp'
|
|
9
|
+
# file: 'templates/gitlab-ci-security.yml'
|
|
10
|
+
#
|
|
11
|
+
# Or via remote URL:
|
|
12
|
+
#
|
|
13
|
+
# include:
|
|
14
|
+
# - remote: 'https://raw.githubusercontent.com/sinewaveai/agent-security-scanner-mcp/main/templates/gitlab-ci-security.yml'
|
|
15
|
+
#
|
|
16
|
+
# Override variables to customize behavior:
|
|
17
|
+
#
|
|
18
|
+
# variables:
|
|
19
|
+
# SECURITY_SEVERITY_THRESHOLD: "error" # Only block on errors
|
|
20
|
+
# SECURITY_SCAN_VERBOSITY: "full" # More detailed output
|
|
21
|
+
#
|
|
22
|
+
# =============================================================================
|
|
23
|
+
|
|
24
|
+
# ---------------------------------------------------------------------------
|
|
25
|
+
# Configurable variables
|
|
26
|
+
# ---------------------------------------------------------------------------
|
|
27
|
+
variables:
|
|
28
|
+
# Minimum severity to block the pipeline: "error", "warning", or "info"
|
|
29
|
+
SECURITY_SEVERITY_THRESHOLD: "warning"
|
|
30
|
+
# Verbosity of scan output: "minimal", "compact", or "full"
|
|
31
|
+
SECURITY_SCAN_VERBOSITY: "compact"
|
|
32
|
+
# Node.js version to use
|
|
33
|
+
NODE_VERSION: "18"
|
|
34
|
+
|
|
35
|
+
# ---------------------------------------------------------------------------
|
|
36
|
+
# Define the security-scan stage
|
|
37
|
+
# ---------------------------------------------------------------------------
|
|
38
|
+
stages:
|
|
39
|
+
- security-scan
|
|
40
|
+
|
|
41
|
+
# ---------------------------------------------------------------------------
|
|
42
|
+
# Job: security-scan
|
|
43
|
+
#
|
|
44
|
+
# Scans the entire project for security vulnerabilities using
|
|
45
|
+
# agent-security-scanner-mcp. Results are saved as artifacts and the job
|
|
46
|
+
# exit code is determined by the severity threshold.
|
|
47
|
+
# ---------------------------------------------------------------------------
|
|
48
|
+
security-scan:
|
|
49
|
+
stage: security-scan
|
|
50
|
+
image: node:${NODE_VERSION}
|
|
51
|
+
|
|
52
|
+
before_script:
|
|
53
|
+
# Install Python (needed by the analyzer engine)
|
|
54
|
+
- apt-get update -qq && apt-get install -y -qq python3 python3-pip > /dev/null 2>&1
|
|
55
|
+
- pip3 install pyyaml --break-system-packages > /dev/null 2>&1
|
|
56
|
+
# Install the scanner
|
|
57
|
+
- npm install -g agent-security-scanner-mcp > /dev/null 2>&1
|
|
58
|
+
|
|
59
|
+
script:
|
|
60
|
+
- echo "Running security scan with verbosity=${SECURITY_SCAN_VERBOSITY}, threshold=${SECURITY_SEVERITY_THRESHOLD}"
|
|
61
|
+
- |
|
|
62
|
+
# Run the project scan and capture output
|
|
63
|
+
set +e
|
|
64
|
+
agent-security-scanner-mcp scan-project . \
|
|
65
|
+
--verbosity "${SECURITY_SCAN_VERBOSITY}" > scan-results.json 2>&1
|
|
66
|
+
SCAN_EXIT=$?
|
|
67
|
+
set -e
|
|
68
|
+
|
|
69
|
+
# Display the results
|
|
70
|
+
cat scan-results.json
|
|
71
|
+
|
|
72
|
+
# Parse results and evaluate against the threshold
|
|
73
|
+
python3 <<PYEOF
|
|
74
|
+
import json, sys
|
|
75
|
+
|
|
76
|
+
try:
|
|
77
|
+
data = json.load(open("scan-results.json"))
|
|
78
|
+
except Exception as e:
|
|
79
|
+
print(f"Could not parse scan results: {e}")
|
|
80
|
+
sys.exit(0)
|
|
81
|
+
|
|
82
|
+
total = data.get("issues_count", data.get("total", 0))
|
|
83
|
+
grade = data.get("grade", "?")
|
|
84
|
+
|
|
85
|
+
# Count issues by severity
|
|
86
|
+
error_count = 0
|
|
87
|
+
warning_count = 0
|
|
88
|
+
info_count = 0
|
|
89
|
+
|
|
90
|
+
for f in data.get("files", []):
|
|
91
|
+
for issue in f.get("issues", []):
|
|
92
|
+
sev = issue.get("severity", "").upper()
|
|
93
|
+
if sev == "ERROR":
|
|
94
|
+
error_count += 1
|
|
95
|
+
elif sev == "WARNING":
|
|
96
|
+
warning_count += 1
|
|
97
|
+
else:
|
|
98
|
+
info_count += 1
|
|
99
|
+
|
|
100
|
+
# Also handle flat issue lists (from scan-diff)
|
|
101
|
+
for issue in data.get("issues", []):
|
|
102
|
+
sev = issue.get("severity", "").upper()
|
|
103
|
+
if sev == "ERROR":
|
|
104
|
+
error_count += 1
|
|
105
|
+
elif sev == "WARNING":
|
|
106
|
+
warning_count += 1
|
|
107
|
+
else:
|
|
108
|
+
info_count += 1
|
|
109
|
+
|
|
110
|
+
print(f"\n{'='*60}")
|
|
111
|
+
print(f"Security Scan Summary")
|
|
112
|
+
print(f"{'='*60}")
|
|
113
|
+
print(f"Grade: {grade}")
|
|
114
|
+
print(f"Total: {total}")
|
|
115
|
+
print(f"Errors: {error_count}")
|
|
116
|
+
print(f"Warnings: {warning_count}")
|
|
117
|
+
print(f"Info: {info_count}")
|
|
118
|
+
print(f"{'='*60}\n")
|
|
119
|
+
|
|
120
|
+
threshold = "${SECURITY_SEVERITY_THRESHOLD}"
|
|
121
|
+
|
|
122
|
+
if threshold == "error" and error_count > 0:
|
|
123
|
+
print(f"FAILED: {error_count} error-level issue(s) found (threshold: error)")
|
|
124
|
+
sys.exit(1)
|
|
125
|
+
elif threshold == "warning" and (error_count > 0 or warning_count > 0):
|
|
126
|
+
print(f"FAILED: {error_count} error(s), {warning_count} warning(s) (threshold: warning)")
|
|
127
|
+
sys.exit(1)
|
|
128
|
+
elif threshold == "info" and total > 0:
|
|
129
|
+
print(f"FAILED: {total} issue(s) found (threshold: info)")
|
|
130
|
+
sys.exit(1)
|
|
131
|
+
else:
|
|
132
|
+
print(f"PASSED: No issues at or above '{threshold}' severity.")
|
|
133
|
+
sys.exit(0)
|
|
134
|
+
PYEOF
|
|
135
|
+
|
|
136
|
+
# Save scan results as a downloadable artifact
|
|
137
|
+
artifacts:
|
|
138
|
+
when: always
|
|
139
|
+
paths:
|
|
140
|
+
- scan-results.json
|
|
141
|
+
reports:
|
|
142
|
+
# If you generate a JUnit-compatible report, you can add it here:
|
|
143
|
+
# junit: scan-results-junit.xml
|
|
144
|
+
codequality: scan-results.json
|
|
145
|
+
expire_in: 30 days
|
|
146
|
+
|
|
147
|
+
# Allow warnings to pass the pipeline; only block on errors when threshold is "error"
|
|
148
|
+
allow_failure:
|
|
149
|
+
exit_codes:
|
|
150
|
+
- 1
|
|
151
|
+
|
|
152
|
+
rules:
|
|
153
|
+
# Run on merge requests
|
|
154
|
+
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
|
155
|
+
# Run on pushes to default branch
|
|
156
|
+
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
|
|
157
|
+
# Run on manual trigger
|
|
158
|
+
- if: '$CI_PIPELINE_SOURCE == "web"'
|
|
159
|
+
# Allow running on schedules (e.g., nightly scans)
|
|
160
|
+
- if: '$CI_PIPELINE_SOURCE == "schedule"'
|
|
161
|
+
|
|
162
|
+
# ---------------------------------------------------------------------------
|
|
163
|
+
# Job: security-scan-diff (merge requests only)
|
|
164
|
+
#
|
|
165
|
+
# A lighter-weight job that only scans changed files in merge requests.
|
|
166
|
+
# This runs in addition to the full scan above, giving quick feedback.
|
|
167
|
+
# ---------------------------------------------------------------------------
|
|
168
|
+
security-scan-diff:
|
|
169
|
+
stage: security-scan
|
|
170
|
+
image: node:${NODE_VERSION}
|
|
171
|
+
|
|
172
|
+
before_script:
|
|
173
|
+
- apt-get update -qq && apt-get install -y -qq python3 python3-pip > /dev/null 2>&1
|
|
174
|
+
- pip3 install pyyaml --break-system-packages > /dev/null 2>&1
|
|
175
|
+
- npm install -g agent-security-scanner-mcp > /dev/null 2>&1
|
|
176
|
+
|
|
177
|
+
script:
|
|
178
|
+
- echo "Running diff-only security scan"
|
|
179
|
+
- |
|
|
180
|
+
set +e
|
|
181
|
+
agent-security-scanner-mcp scan-diff \
|
|
182
|
+
"origin/${CI_MERGE_REQUEST_TARGET_BRANCH_NAME}" HEAD \
|
|
183
|
+
--verbosity "${SECURITY_SCAN_VERBOSITY}" > scan-diff-results.json 2>&1
|
|
184
|
+
SCAN_EXIT=$?
|
|
185
|
+
set -e
|
|
186
|
+
|
|
187
|
+
cat scan-diff-results.json
|
|
188
|
+
|
|
189
|
+
# Evaluate: block only on errors for the diff scan
|
|
190
|
+
python3 <<PYEOF
|
|
191
|
+
import json, sys
|
|
192
|
+
|
|
193
|
+
try:
|
|
194
|
+
data = json.load(open("scan-diff-results.json"))
|
|
195
|
+
except Exception:
|
|
196
|
+
sys.exit(0)
|
|
197
|
+
|
|
198
|
+
total = data.get("issues_count", data.get("total", 0))
|
|
199
|
+
error_count = sum(
|
|
200
|
+
1 for issue in data.get("issues", [])
|
|
201
|
+
if issue.get("severity", "").upper() == "ERROR"
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
print(f"Diff scan found {total} issue(s), {error_count} error(s)")
|
|
205
|
+
|
|
206
|
+
if error_count > 0:
|
|
207
|
+
print(f"BLOCKED: {error_count} error-level issue(s) in changed code")
|
|
208
|
+
sys.exit(1)
|
|
209
|
+
elif total > 0:
|
|
210
|
+
print(f"WARNING: {total} issue(s) found, but none are error-level. Allowing.")
|
|
211
|
+
sys.exit(0)
|
|
212
|
+
else:
|
|
213
|
+
print("PASSED: No issues found in changed files.")
|
|
214
|
+
sys.exit(0)
|
|
215
|
+
PYEOF
|
|
216
|
+
|
|
217
|
+
artifacts:
|
|
218
|
+
when: always
|
|
219
|
+
paths:
|
|
220
|
+
- scan-diff-results.json
|
|
221
|
+
expire_in: 7 days
|
|
222
|
+
|
|
223
|
+
rules:
|
|
224
|
+
# Only run on merge requests
|
|
225
|
+
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# =============================================================================
|
|
3
|
+
# Pre-commit hook: agent-security-scanner-mcp
|
|
4
|
+
# =============================================================================
|
|
5
|
+
#
|
|
6
|
+
# Scans staged changes for security vulnerabilities before allowing a commit.
|
|
7
|
+
#
|
|
8
|
+
# Behavior:
|
|
9
|
+
# - BLOCKS the commit if any ERROR-severity issues are found
|
|
10
|
+
# - WARNS (but allows) the commit if only WARNING-severity issues are found
|
|
11
|
+
# - Silently passes if no issues are found
|
|
12
|
+
#
|
|
13
|
+
# Installation:
|
|
14
|
+
#
|
|
15
|
+
# Option 1 — Automatic (recommended):
|
|
16
|
+
# npx agent-security-scanner-mcp init-hooks
|
|
17
|
+
#
|
|
18
|
+
# Option 2 — Manual:
|
|
19
|
+
# cp templates/pre-commit-hook.sh .git/hooks/pre-commit
|
|
20
|
+
# chmod +x .git/hooks/pre-commit
|
|
21
|
+
#
|
|
22
|
+
# Option 3 — Symlink (stays up to date):
|
|
23
|
+
# ln -sf ../../templates/pre-commit-hook.sh .git/hooks/pre-commit
|
|
24
|
+
#
|
|
25
|
+
# Configuration:
|
|
26
|
+
# Set environment variables to customize behavior:
|
|
27
|
+
#
|
|
28
|
+
# SECURITY_SCAN_THRESHOLD Minimum severity to block: "error" (default),
|
|
29
|
+
# "warning", or "info"
|
|
30
|
+
# SECURITY_SCAN_SKIP Set to "1" to bypass the hook entirely
|
|
31
|
+
# SECURITY_SCAN_VERBOSITY Output detail: "minimal", "compact" (default),
|
|
32
|
+
# or "full"
|
|
33
|
+
#
|
|
34
|
+
# =============================================================================
|
|
35
|
+
|
|
36
|
+
set -euo pipefail
|
|
37
|
+
|
|
38
|
+
# ---------------------------------------------------------------------------
|
|
39
|
+
# Configuration
|
|
40
|
+
# ---------------------------------------------------------------------------
|
|
41
|
+
|
|
42
|
+
# Allow users to skip the hook via environment variable
|
|
43
|
+
if [ "${SECURITY_SCAN_SKIP:-0}" = "1" ]; then
|
|
44
|
+
exit 0
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
THRESHOLD="${SECURITY_SCAN_THRESHOLD:-error}"
|
|
48
|
+
VERBOSITY="${SECURITY_SCAN_VERBOSITY:-compact}"
|
|
49
|
+
|
|
50
|
+
# ---------------------------------------------------------------------------
|
|
51
|
+
# Check prerequisites
|
|
52
|
+
# ---------------------------------------------------------------------------
|
|
53
|
+
|
|
54
|
+
# Verify that npx is available
|
|
55
|
+
if ! command -v npx &> /dev/null; then
|
|
56
|
+
echo "[security-scan] WARNING: npx not found. Skipping security scan."
|
|
57
|
+
echo "[security-scan] Install Node.js 18+ to enable pre-commit scanning."
|
|
58
|
+
exit 0
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
# Verify that python3 is available (needed by the analyzer)
|
|
62
|
+
if ! command -v python3 &> /dev/null; then
|
|
63
|
+
echo "[security-scan] WARNING: python3 not found. Skipping security scan."
|
|
64
|
+
echo "[security-scan] Install Python 3 to enable pre-commit scanning."
|
|
65
|
+
exit 0
|
|
66
|
+
fi
|
|
67
|
+
|
|
68
|
+
# ---------------------------------------------------------------------------
|
|
69
|
+
# Get staged files
|
|
70
|
+
# ---------------------------------------------------------------------------
|
|
71
|
+
|
|
72
|
+
# Get list of staged files that are added or modified (not deleted)
|
|
73
|
+
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM)
|
|
74
|
+
|
|
75
|
+
if [ -z "$STAGED_FILES" ]; then
|
|
76
|
+
# No staged files to scan
|
|
77
|
+
exit 0
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
# Filter to only scannable file types
|
|
81
|
+
SCANNABLE_FILES=""
|
|
82
|
+
for FILE in $STAGED_FILES; do
|
|
83
|
+
case "$FILE" in
|
|
84
|
+
*.py|*.js|*.ts|*.tsx|*.jsx|*.java|*.go|*.rb|*.php|*.rs|*.c|*.cpp|*.cc|*.h|*.hpp|*.cs|*.tf|*.hcl|*.sql)
|
|
85
|
+
SCANNABLE_FILES="$SCANNABLE_FILES $FILE"
|
|
86
|
+
;;
|
|
87
|
+
esac
|
|
88
|
+
done
|
|
89
|
+
|
|
90
|
+
SCANNABLE_FILES=$(echo "$SCANNABLE_FILES" | xargs)
|
|
91
|
+
|
|
92
|
+
if [ -z "$SCANNABLE_FILES" ]; then
|
|
93
|
+
# No scannable files in this commit
|
|
94
|
+
exit 0
|
|
95
|
+
fi
|
|
96
|
+
|
|
97
|
+
# ---------------------------------------------------------------------------
|
|
98
|
+
# Run the security scan on staged changes
|
|
99
|
+
# ---------------------------------------------------------------------------
|
|
100
|
+
|
|
101
|
+
echo "[security-scan] Scanning staged changes for security vulnerabilities..."
|
|
102
|
+
|
|
103
|
+
# Create a temporary file for scan output
|
|
104
|
+
SCAN_OUTPUT=$(mktemp)
|
|
105
|
+
trap 'rm -f "$SCAN_OUTPUT"' EXIT
|
|
106
|
+
|
|
107
|
+
# Use scan-diff to analyze only the staged changes.
|
|
108
|
+
# We compare the index (staged) against HEAD to get exactly what will be committed.
|
|
109
|
+
set +e
|
|
110
|
+
npx -y agent-security-scanner-mcp scan-diff HEAD \
|
|
111
|
+
--verbosity "$VERBOSITY" > "$SCAN_OUTPUT" 2>&1
|
|
112
|
+
SCAN_EXIT=$?
|
|
113
|
+
set -e
|
|
114
|
+
|
|
115
|
+
# ---------------------------------------------------------------------------
|
|
116
|
+
# Parse and evaluate results
|
|
117
|
+
# ---------------------------------------------------------------------------
|
|
118
|
+
|
|
119
|
+
# Try to parse the JSON output
|
|
120
|
+
if ! python3 -c "import json; json.load(open('$SCAN_OUTPUT'))" 2>/dev/null; then
|
|
121
|
+
# If the output is not valid JSON, it may be an error message
|
|
122
|
+
if [ $SCAN_EXIT -ne 0 ]; then
|
|
123
|
+
echo "[security-scan] WARNING: Scanner returned an error. Allowing commit."
|
|
124
|
+
echo "[security-scan] Output:"
|
|
125
|
+
head -5 "$SCAN_OUTPUT" 2>/dev/null || true
|
|
126
|
+
fi
|
|
127
|
+
exit 0
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
# Extract counts from the scan results
|
|
131
|
+
COUNTS=$(python3 -c "
|
|
132
|
+
import json, sys
|
|
133
|
+
try:
|
|
134
|
+
data = json.load(open('$SCAN_OUTPUT'))
|
|
135
|
+
total = data.get('issues_count', data.get('total', 0))
|
|
136
|
+
issues = data.get('issues', [])
|
|
137
|
+
error_count = sum(1 for i in issues if i.get('severity', '').upper() == 'ERROR')
|
|
138
|
+
warning_count = sum(1 for i in issues if i.get('severity', '').upper() == 'WARNING')
|
|
139
|
+
info_count = total - error_count - warning_count
|
|
140
|
+
print(f'{total} {error_count} {warning_count} {info_count}')
|
|
141
|
+
except Exception:
|
|
142
|
+
print('0 0 0 0')
|
|
143
|
+
" 2>/dev/null)
|
|
144
|
+
|
|
145
|
+
TOTAL=$(echo "$COUNTS" | cut -d' ' -f1)
|
|
146
|
+
ERRORS=$(echo "$COUNTS" | cut -d' ' -f2)
|
|
147
|
+
WARNINGS=$(echo "$COUNTS" | cut -d' ' -f3)
|
|
148
|
+
INFOS=$(echo "$COUNTS" | cut -d' ' -f4)
|
|
149
|
+
|
|
150
|
+
# No issues: pass silently
|
|
151
|
+
if [ "$TOTAL" -eq 0 ]; then
|
|
152
|
+
echo "[security-scan] No security issues found."
|
|
153
|
+
exit 0
|
|
154
|
+
fi
|
|
155
|
+
|
|
156
|
+
# ---------------------------------------------------------------------------
|
|
157
|
+
# Display findings
|
|
158
|
+
# ---------------------------------------------------------------------------
|
|
159
|
+
|
|
160
|
+
echo ""
|
|
161
|
+
echo "============================================================"
|
|
162
|
+
echo " Security Scan Results"
|
|
163
|
+
echo "============================================================"
|
|
164
|
+
echo " Errors: $ERRORS"
|
|
165
|
+
echo " Warnings: $WARNINGS"
|
|
166
|
+
echo " Info: $INFOS"
|
|
167
|
+
echo " Total: $TOTAL"
|
|
168
|
+
echo "============================================================"
|
|
169
|
+
|
|
170
|
+
# Show individual issues (up to 10)
|
|
171
|
+
python3 -c "
|
|
172
|
+
import json
|
|
173
|
+
try:
|
|
174
|
+
data = json.load(open('$SCAN_OUTPUT'))
|
|
175
|
+
issues = data.get('issues', [])
|
|
176
|
+
shown = 0
|
|
177
|
+
for issue in issues[:10]:
|
|
178
|
+
sev = issue.get('severity', '?')
|
|
179
|
+
line = issue.get('line', '?')
|
|
180
|
+
rule = issue.get('ruleId', '?')
|
|
181
|
+
msg = issue.get('message', '')[:80]
|
|
182
|
+
file_path = issue.get('file', issue.get('filePath', ''))
|
|
183
|
+
loc = f'{file_path}:{line}' if file_path else f'line {line}'
|
|
184
|
+
print(f' [{sev}] {loc} — {rule}: {msg}')
|
|
185
|
+
shown += 1
|
|
186
|
+
if len(issues) > 10:
|
|
187
|
+
print(f' ... and {len(issues) - 10} more issue(s)')
|
|
188
|
+
except Exception:
|
|
189
|
+
pass
|
|
190
|
+
" 2>/dev/null
|
|
191
|
+
|
|
192
|
+
echo ""
|
|
193
|
+
|
|
194
|
+
# ---------------------------------------------------------------------------
|
|
195
|
+
# Decide: block or warn
|
|
196
|
+
# ---------------------------------------------------------------------------
|
|
197
|
+
|
|
198
|
+
BLOCK=0
|
|
199
|
+
|
|
200
|
+
case "$THRESHOLD" in
|
|
201
|
+
error)
|
|
202
|
+
if [ "$ERRORS" -gt 0 ]; then
|
|
203
|
+
BLOCK=1
|
|
204
|
+
fi
|
|
205
|
+
;;
|
|
206
|
+
warning)
|
|
207
|
+
if [ "$ERRORS" -gt 0 ] || [ "$WARNINGS" -gt 0 ]; then
|
|
208
|
+
BLOCK=1
|
|
209
|
+
fi
|
|
210
|
+
;;
|
|
211
|
+
info)
|
|
212
|
+
if [ "$TOTAL" -gt 0 ]; then
|
|
213
|
+
BLOCK=1
|
|
214
|
+
fi
|
|
215
|
+
;;
|
|
216
|
+
esac
|
|
217
|
+
|
|
218
|
+
if [ "$BLOCK" -eq 1 ]; then
|
|
219
|
+
echo "COMMIT BLOCKED: Security issues at or above '$THRESHOLD' severity were found."
|
|
220
|
+
echo ""
|
|
221
|
+
echo "Options:"
|
|
222
|
+
echo " 1. Fix the issues and try again"
|
|
223
|
+
echo " 2. Skip this check: SECURITY_SCAN_SKIP=1 git commit ..."
|
|
224
|
+
echo " 3. Lower the threshold: SECURITY_SCAN_THRESHOLD=error git commit ..."
|
|
225
|
+
echo ""
|
|
226
|
+
exit 1
|
|
227
|
+
else
|
|
228
|
+
# Issues found but below threshold — warn and allow
|
|
229
|
+
echo "WARNING: Security issues found, but none at or above '$THRESHOLD' severity."
|
|
230
|
+
echo "Commit will proceed. Consider fixing the warnings above."
|
|
231
|
+
echo ""
|
|
232
|
+
exit 0
|
|
233
|
+
fi
|