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.
@@ -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