agent-security-scanner-mcp 3.9.0 → 3.10.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 +119 -4
- package/index.js +81 -1
- package/openclaw.plugin.json +41 -0
- package/package.json +4 -1
- package/regex_fallback.py +3 -1
- package/rules/clawhavoc.yaml +443 -0
- package/src/cli/audit.js +18 -0
- package/src/cli/harden.js +15 -0
- package/src/context.js +4 -0
- package/src/daemon-client.js +10 -0
- package/src/plugin-config.js +77 -0
- package/src/plugin-health.js +49 -0
- package/src/tools/scan-security.js +32 -5
- package/src/tools/scan-skill.js +743 -0
- package/src/utils.js +58 -0
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
// src/tools/scan-security.js
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { existsSync, readFileSync } from "fs";
|
|
4
|
-
import {
|
|
4
|
+
import { dirname } from "path";
|
|
5
|
+
import { detectLanguage, runAnalyzerAsync, generateFix, toSarif, getEngineMode, extractImports, isTestFile } from '../utils.js';
|
|
5
6
|
import { deduplicateFindings } from '../dedup.js';
|
|
6
7
|
import { applyContextFilter, detectFrameworks, applyFrameworkAdjustments } from '../context.js';
|
|
7
8
|
import { loadConfig, shouldExcludeFile, applyConfig } from '../config.js';
|
|
9
|
+
import { discoverProjectContext } from './project-context.js';
|
|
8
10
|
|
|
9
11
|
export const scanSecuritySchema = {
|
|
10
12
|
file_path: z.string().describe("Path to the file to scan"),
|
|
11
13
|
output_format: z.enum(['json', 'sarif']).optional().describe("Output format: 'json' (default) or 'sarif' for GitHub/GitLab integration"),
|
|
12
14
|
verbosity: z.enum(['minimal', 'compact', 'full']).optional().describe("Response detail level: 'minimal' (counts only), 'compact' (default, actionable info), 'full' (complete metadata)"),
|
|
13
|
-
engine: z.enum(['auto', 'ast', 'regex']).optional().describe("Analysis engine: 'auto' (default, AST with regex fallback), 'ast' (tree-sitter only), 'regex' (regex only)")
|
|
15
|
+
engine: z.enum(['auto', 'ast', 'regex']).optional().describe("Analysis engine: 'auto' (default, AST with regex fallback), 'ast' (tree-sitter only), 'regex' (regex only)"),
|
|
16
|
+
project_context: z.boolean().optional().describe("Include project context (framework, security middleware, dependencies)"),
|
|
17
|
+
include_context: z.boolean().optional().describe("Include surrounding code context for each issue")
|
|
14
18
|
};
|
|
15
19
|
|
|
16
20
|
// Verbosity formatters
|
|
@@ -58,7 +62,7 @@ function formatFull(file_path, language, issues) {
|
|
|
58
62
|
};
|
|
59
63
|
}
|
|
60
64
|
|
|
61
|
-
export async function scanSecurity({ file_path, output_format, verbosity, engine }) {
|
|
65
|
+
export async function scanSecurity({ file_path, output_format, verbosity, engine, project_context, include_context }) {
|
|
62
66
|
if (!existsSync(file_path)) {
|
|
63
67
|
return {
|
|
64
68
|
content: [{ type: "text", text: JSON.stringify({ error: "File not found" }) }]
|
|
@@ -101,15 +105,30 @@ export async function scanSecurity({ file_path, output_format, verbosity, engine
|
|
|
101
105
|
// Apply .scannerrc configuration (rule suppression, severity/confidence thresholds)
|
|
102
106
|
const issues = applyConfig(frameworkAdjusted, file_path, config);
|
|
103
107
|
|
|
104
|
-
// Enhance issues with fix suggestions
|
|
108
|
+
// Enhance issues with fix suggestions and optional surrounding context
|
|
105
109
|
const enhancedIssues = issues.map(issue => {
|
|
106
110
|
const line = lines[issue.line] || '';
|
|
107
111
|
const fix = generateFix(issue, line, language);
|
|
108
|
-
|
|
112
|
+
const enhanced = {
|
|
109
113
|
...issue,
|
|
110
114
|
line_content: line.trim(),
|
|
111
115
|
suggested_fix: fix
|
|
112
116
|
};
|
|
117
|
+
|
|
118
|
+
if (include_context) {
|
|
119
|
+
const lineIdx = issue.line;
|
|
120
|
+
const contextLines = 3;
|
|
121
|
+
enhanced.context_before = [];
|
|
122
|
+
enhanced.context_after = [];
|
|
123
|
+
for (let i = Math.max(0, lineIdx - contextLines); i < lineIdx; i++) {
|
|
124
|
+
enhanced.context_before.push({ line: i + 1, content: lines[i] || '' });
|
|
125
|
+
}
|
|
126
|
+
for (let i = lineIdx + 1; i <= Math.min(lines.length - 1, lineIdx + contextLines); i++) {
|
|
127
|
+
enhanced.context_after.push({ line: i + 1, content: lines[i] || '' });
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return enhanced;
|
|
113
132
|
});
|
|
114
133
|
|
|
115
134
|
// Determine verbosity (default: compact)
|
|
@@ -139,6 +158,14 @@ export async function scanSecurity({ file_path, output_format, verbosity, engine
|
|
|
139
158
|
result = formatCompact(file_path, language, enhancedIssues);
|
|
140
159
|
}
|
|
141
160
|
|
|
161
|
+
// Attach project context if requested
|
|
162
|
+
if (project_context) {
|
|
163
|
+
const projectDir = dirname(file_path);
|
|
164
|
+
result.project = discoverProjectContext(projectDir);
|
|
165
|
+
result.is_test_file = isTestFile(file_path);
|
|
166
|
+
result.file_imports = extractImports(content, language);
|
|
167
|
+
}
|
|
168
|
+
|
|
142
169
|
return {
|
|
143
170
|
content: [{
|
|
144
171
|
type: "text",
|