guardvibe 0.6.4 → 0.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/LICENSE +1 -1
- package/build/data/rules/auth.d.ts +3 -0
- package/build/data/rules/auth.d.ts.map +1 -0
- package/build/data/rules/auth.js +100 -0
- package/build/data/rules/auth.js.map +1 -0
- package/build/data/rules/database.d.ts +3 -0
- package/build/data/rules/database.d.ts.map +1 -0
- package/build/data/rules/database.js +100 -0
- package/build/data/rules/database.js.map +1 -0
- package/build/data/rules/deployment.d.ts +3 -0
- package/build/data/rules/deployment.d.ts.map +1 -0
- package/build/data/rules/deployment.js +192 -0
- package/build/data/rules/deployment.js.map +1 -0
- package/build/data/rules/index.d.ts +1 -0
- package/build/data/rules/index.d.ts.map +1 -1
- package/build/data/rules/index.js +10 -0
- package/build/data/rules/index.js.map +1 -1
- package/build/data/rules/nextjs.d.ts +3 -0
- package/build/data/rules/nextjs.d.ts.map +1 -0
- package/build/data/rules/nextjs.js +148 -0
- package/build/data/rules/nextjs.js.map +1 -0
- package/build/index.js +62 -16
- package/build/index.js.map +1 -1
- package/build/plugins/loader.d.ts +18 -0
- package/build/plugins/loader.d.ts.map +1 -0
- package/build/plugins/loader.js +151 -0
- package/build/plugins/loader.js.map +1 -0
- package/build/plugins/types.d.ts +17 -0
- package/build/plugins/types.d.ts.map +1 -0
- package/build/plugins/types.js +2 -0
- package/build/plugins/types.js.map +1 -0
- package/build/tools/check-code.d.ts +3 -2
- package/build/tools/check-code.d.ts.map +1 -1
- package/build/tools/check-code.js +26 -4
- package/build/tools/check-code.js.map +1 -1
- package/build/tools/check-package-health.d.ts +29 -0
- package/build/tools/check-package-health.d.ts.map +1 -0
- package/build/tools/check-package-health.js +142 -0
- package/build/tools/check-package-health.js.map +1 -0
- package/build/tools/check-project.d.ts +2 -1
- package/build/tools/check-project.d.ts.map +1 -1
- package/build/tools/check-project.js +21 -3
- package/build/tools/check-project.js.map +1 -1
- package/build/tools/compliance-report.d.ts +2 -1
- package/build/tools/compliance-report.d.ts.map +1 -1
- package/build/tools/compliance-report.js +27 -3
- package/build/tools/compliance-report.js.map +1 -1
- package/build/tools/export-sarif.d.ts +2 -1
- package/build/tools/export-sarif.d.ts.map +1 -1
- package/build/tools/export-sarif.js +2 -2
- package/build/tools/export-sarif.js.map +1 -1
- package/build/tools/scan-dependencies.d.ts +1 -1
- package/build/tools/scan-dependencies.d.ts.map +1 -1
- package/build/tools/scan-dependencies.js +25 -2
- package/build/tools/scan-dependencies.js.map +1 -1
- package/build/tools/scan-directory.d.ts +2 -1
- package/build/tools/scan-directory.d.ts.map +1 -1
- package/build/tools/scan-directory.js +27 -4
- package/build/tools/scan-directory.js.map +1 -1
- package/build/tools/scan-secrets.d.ts +1 -1
- package/build/tools/scan-secrets.d.ts.map +1 -1
- package/build/tools/scan-secrets.js +10 -1
- package/build/tools/scan-secrets.js.map +1 -1
- package/build/tools/scan-staged.d.ts +2 -1
- package/build/tools/scan-staged.d.ts.map +1 -1
- package/build/tools/scan-staged.js +21 -3
- package/build/tools/scan-staged.js.map +1 -1
- package/build/utils/config.d.ts +1 -0
- package/build/utils/config.d.ts.map +1 -1
- package/build/utils/config.js +3 -0
- package/build/utils/config.js.map +1 -1
- package/build/utils/typosquat.d.ts +9 -0
- package/build/utils/typosquat.d.ts.map +1 -0
- package/build/utils/typosquat.js +101 -0
- package/build/utils/typosquat.js.map +1 -0
- package/package.json +7 -3
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// Security rules for Next.js App Router patterns
|
|
2
|
+
export const nextjsRules = [
|
|
3
|
+
{
|
|
4
|
+
id: "VG400",
|
|
5
|
+
name: "Client Component Secret Exposure",
|
|
6
|
+
severity: "critical",
|
|
7
|
+
owasp: "A01:2025 Broken Access Control",
|
|
8
|
+
description: "Server-side environment variable accessed in a 'use client' component. These values are exposed to the browser. Only NEXT_PUBLIC_ variables are safe in client components.",
|
|
9
|
+
pattern: /["']use client["'][\s\S]*?process\.env\.(?!NEXT_PUBLIC_)\w+/g,
|
|
10
|
+
languages: ["javascript", "typescript"],
|
|
11
|
+
fix: "Move this logic to a Server Component or Server Action. Only process.env.NEXT_PUBLIC_* variables are available in client components.",
|
|
12
|
+
fixCode: '// Move to a Server Component (no \'use client\')\nexport default async function Page() {\n const secret = process.env.SECRET_KEY;\n return <ClientComponent data={safeData} />;\n}',
|
|
13
|
+
compliance: ["SOC2:CC6.1", "HIPAA:§164.312(a)"],
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
id: "VG401",
|
|
17
|
+
name: "Server Action Missing Input Validation",
|
|
18
|
+
severity: "high",
|
|
19
|
+
owasp: "A03:2025 Injection",
|
|
20
|
+
description: "Server Action processes form data without schema validation. Unvalidated input can lead to injection attacks.",
|
|
21
|
+
pattern: /["']use server["'][\s\S]{0,500}?formData\.get\s*\(/g,
|
|
22
|
+
languages: ["javascript", "typescript"],
|
|
23
|
+
fix: "Validate all inputs with a schema library (zod, yup, valibot) before processing.",
|
|
24
|
+
fixCode: '"use server";\nimport { z } from "zod";\n\nconst schema = z.object({ name: z.string().min(1), email: z.string().email() });\n\nexport async function createUser(formData: FormData) {\n const data = schema.parse(Object.fromEntries(formData));\n}',
|
|
25
|
+
compliance: ["SOC2:CC7.1", "PCI-DSS:Req6.5.1"],
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
id: "VG402",
|
|
29
|
+
name: "Server Action Missing Auth Check",
|
|
30
|
+
severity: "critical",
|
|
31
|
+
owasp: "A01:2025 Broken Access Control",
|
|
32
|
+
description: "Server Action performs data mutations without verifying user authentication. Anyone can invoke Server Actions directly via POST request.",
|
|
33
|
+
pattern: /["']use server["'][\s\S]{0,200}?export\s+async\s+function\s+\w+\s*\([^)]*\)\s*\{(?:(?!auth\s*\(|getServerSession|currentUser|getUser|requireAuth|clerkClient)[\s\S])*?\}/g,
|
|
34
|
+
languages: ["javascript", "typescript"],
|
|
35
|
+
fix: "Always verify authentication at the start of every Server Action.",
|
|
36
|
+
fixCode: '"use server";\nimport { auth } from "@clerk/nextjs/server";\n\nexport async function deleteItem(id: string) {\n const { userId } = await auth();\n if (!userId) throw new Error("Unauthorized");\n}',
|
|
37
|
+
compliance: ["SOC2:CC6.6", "PCI-DSS:Req6.5.10", "HIPAA:§164.312(d)"],
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
id: "VG403",
|
|
41
|
+
name: "Route Handler CORS Wildcard",
|
|
42
|
+
severity: "high",
|
|
43
|
+
owasp: "A01:2025 Broken Access Control",
|
|
44
|
+
description: "Route handler sets Access-Control-Allow-Origin to wildcard (*). This allows any website to make requests to your API.",
|
|
45
|
+
pattern: /(?:GET|POST|PUT|DELETE|PATCH|OPTIONS)\s*\([\s\S]*?["']Access-Control-Allow-Origin["']\s*[,:]\s*["']\*["']/g,
|
|
46
|
+
languages: ["javascript", "typescript"],
|
|
47
|
+
fix: "Restrict CORS to specific trusted origins instead of wildcard.",
|
|
48
|
+
fixCode: '// Restrict to specific origin\nconst allowedOrigin = process.env.ALLOWED_ORIGIN;\nreturn new Response(data, {\n headers: { "Access-Control-Allow-Origin": allowedOrigin }\n});',
|
|
49
|
+
compliance: ["SOC2:CC6.6"],
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: "VG404",
|
|
53
|
+
name: "Middleware Auth Bypass Risk",
|
|
54
|
+
severity: "high",
|
|
55
|
+
owasp: "A01:2025 Broken Access Control",
|
|
56
|
+
description: "Middleware or proxy has overly broad public path matcher that may accidentally expose protected routes.",
|
|
57
|
+
pattern: /(?:matcher|config)\s*[=:]\s*[\s\S]*?["']\/\(\.\*\)["']/g,
|
|
58
|
+
languages: ["javascript", "typescript"],
|
|
59
|
+
fix: "Use specific path matchers instead of catch-all patterns.",
|
|
60
|
+
fixCode: '// Be specific with matchers\nexport const config = {\n matcher: ["/dashboard/:path*", "/api/:path*"]\n};',
|
|
61
|
+
compliance: ["SOC2:CC6.6"],
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
id: "VG405",
|
|
65
|
+
name: "Missing Security Headers in Next Config",
|
|
66
|
+
severity: "medium",
|
|
67
|
+
owasp: "A05:2025 Security Misconfiguration",
|
|
68
|
+
description: "next.config is missing important security headers (Content-Security-Policy, Strict-Transport-Security, X-Frame-Options).",
|
|
69
|
+
pattern: /(?:async\s+)?headers\s*\(\s*\)\s*\{[\s\S]*?return\s*\[[\s\S]*?\][\s\S]*?\}/g,
|
|
70
|
+
languages: ["javascript", "typescript"],
|
|
71
|
+
fix: "Add security headers in next.config.ts headers() function.",
|
|
72
|
+
fixCode: '// next.config.ts\nasync headers() {\n return [{\n source: "/(.*)",\n headers: [\n { key: "X-Frame-Options", value: "DENY" },\n { key: "X-Content-Type-Options", value: "nosniff" },\n { key: "Strict-Transport-Security", value: "max-age=63072000; includeSubDomains" },\n ]\n }];\n}',
|
|
73
|
+
compliance: ["SOC2:CC6.1", "PCI-DSS:Req6.5.10"],
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
id: "VG406",
|
|
77
|
+
name: "Unsanitized Dynamic Route Params",
|
|
78
|
+
severity: "high",
|
|
79
|
+
owasp: "A03:2025 Injection",
|
|
80
|
+
description: "Dynamic route parameters (params, searchParams) are used directly in database queries or operations without validation.",
|
|
81
|
+
pattern: /(?:params|searchParams)\s*[\.\[]\s*["']?\w+["']?\s*[\]\)]?\s*(?:;|\))\s*[\s\S]*?(?:query|execute|findUnique|findFirst|findMany|delete|update|create)\s*\(/g,
|
|
82
|
+
languages: ["javascript", "typescript"],
|
|
83
|
+
fix: "Always validate and sanitize dynamic route parameters before using them in queries.",
|
|
84
|
+
fixCode: '// Validate params before use\nimport { z } from "zod";\nconst idSchema = z.string().uuid();\n\nexport default async function Page({ params }: { params: { id: string } }) {\n const id = idSchema.parse((await params).id);\n const item = await db.item.findUnique({ where: { id } });\n}',
|
|
85
|
+
compliance: ["SOC2:CC7.1", "PCI-DSS:Req6.5.1"],
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
id: "VG407",
|
|
89
|
+
name: "Server Data Leaked to Client Component",
|
|
90
|
+
severity: "high",
|
|
91
|
+
owasp: "A01:2025 Broken Access Control",
|
|
92
|
+
description: "Sensitive data (tokens, secrets, internal IDs) appears to be passed from server to client component as props.",
|
|
93
|
+
pattern: /(?:secret|token|password|apiKey|privateKey|internalId|ssn|creditCard)\s*=\s*\{[\s\S]*?\}/g,
|
|
94
|
+
languages: ["javascript", "typescript"],
|
|
95
|
+
fix: "Never pass sensitive data as props to client components. Keep secrets server-side.",
|
|
96
|
+
fixCode: "// Keep sensitive data server-side\nexport default async function Page() {\n const secret = process.env.API_SECRET;\n const publicData = await fetchData(secret);\n return <ClientComponent data={publicData} />;\n}",
|
|
97
|
+
compliance: ["SOC2:CC6.1", "HIPAA:§164.312(a)"],
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
id: "VG408",
|
|
101
|
+
name: "Unsafe innerHTML Usage",
|
|
102
|
+
severity: "high",
|
|
103
|
+
owasp: "A03:2025 Injection",
|
|
104
|
+
description: "Using dangerouslySetInnerHTML renders unescaped HTML, which can lead to XSS if the content includes user input. This is a security rule detector — it flags vulnerable code patterns.",
|
|
105
|
+
pattern: /dangerouslySetInnerHTML\s*=\s*\{\s*\{\s*__html\s*:/g,
|
|
106
|
+
languages: ["javascript", "typescript"],
|
|
107
|
+
fix: "Sanitize HTML with DOMPurify before rendering, or use a markdown renderer instead.",
|
|
108
|
+
fixCode: '// Use a sanitizer library\nimport DOMPurify from "dompurify";\nconst clean = DOMPurify.sanitize(content);\n\n// Or use a markdown renderer\nimport ReactMarkdown from "react-markdown";\n<ReactMarkdown>{content}</ReactMarkdown>',
|
|
109
|
+
compliance: ["SOC2:CC7.1", "PCI-DSS:Req6.5.7"],
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
id: "VG409",
|
|
113
|
+
name: "Open Redirect via User Input",
|
|
114
|
+
severity: "medium",
|
|
115
|
+
owasp: "A01:2025 Broken Access Control",
|
|
116
|
+
description: "redirect() or NextResponse.redirect() uses user-controlled input (searchParams, query) which can redirect users to malicious sites.",
|
|
117
|
+
pattern: /redirect\s*\(\s*(?:searchParams|params|req\.query|request\.url|url|query)\s*[\.\[]/g,
|
|
118
|
+
languages: ["javascript", "typescript"],
|
|
119
|
+
fix: "Validate redirect URLs against an allowlist of trusted domains.",
|
|
120
|
+
fixCode: '// Validate redirect URL\nconst ALLOWED_HOSTS = ["example.com"];\nconst target = searchParams.get("next") ?? "/";\ntry {\n const url = new URL(target, request.url);\n if (!ALLOWED_HOSTS.includes(url.hostname)) redirect("/");\n redirect(url.pathname);\n} catch {\n redirect("/");\n}',
|
|
121
|
+
compliance: ["SOC2:CC6.6"],
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
id: "VG410",
|
|
125
|
+
name: "Unauthorized Cache Revalidation",
|
|
126
|
+
severity: "medium",
|
|
127
|
+
owasp: "A01:2025 Broken Access Control",
|
|
128
|
+
description: "revalidateTag() or revalidatePath() is called in a route handler without authentication check. Anyone could trigger cache invalidation.",
|
|
129
|
+
pattern: /(?:GET|POST|PUT|DELETE)\s*\([\s\S]*?(?:revalidateTag|revalidatePath)\s*\([\s\S]*?(?![\s\S]*?(?:auth\s*\(|getServerSession|currentUser))/g,
|
|
130
|
+
languages: ["javascript", "typescript"],
|
|
131
|
+
fix: "Protect revalidation endpoints with authentication or a secret token.",
|
|
132
|
+
fixCode: 'import { auth } from "@clerk/nextjs/server";\n\nexport async function POST(req: Request) {\n const { userId } = await auth();\n if (!userId) return new Response("Unauthorized", { status: 401 });\n revalidateTag("posts");\n return Response.json({ revalidated: true });\n}',
|
|
133
|
+
compliance: ["SOC2:CC6.6"],
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
id: "VG411",
|
|
137
|
+
name: "NEXT_PUBLIC_ Secret Leak",
|
|
138
|
+
severity: "critical",
|
|
139
|
+
owasp: "A07:2025 Sensitive Data Exposure",
|
|
140
|
+
description: "Environment variable prefixed with NEXT_PUBLIC_ contains a secret keyword (SECRET, KEY, PASSWORD, TOKEN). NEXT_PUBLIC_ variables are embedded in the client bundle and visible to anyone.",
|
|
141
|
+
pattern: /NEXT_PUBLIC_\w*(?:SECRET|_KEY|PASSWORD|TOKEN|PRIVATE|CREDENTIAL)\w*\s*=/gi,
|
|
142
|
+
languages: ["javascript", "typescript", "shell"],
|
|
143
|
+
fix: "Remove NEXT_PUBLIC_ prefix from secret variables. Access them only server-side.",
|
|
144
|
+
fixCode: "# .env.local — WRONG\n# NEXT_PUBLIC_SECRET_KEY=sk_live_xxx\n\n# .env.local — CORRECT\nSECRET_KEY=sk_live_xxx\n# Access server-side only: process.env.SECRET_KEY",
|
|
145
|
+
compliance: ["SOC2:CC6.1", "PCI-DSS:Req2.3", "HIPAA:§164.312(a)"],
|
|
146
|
+
},
|
|
147
|
+
];
|
|
148
|
+
//# sourceMappingURL=nextjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nextjs.js","sourceRoot":"","sources":["../../../src/data/rules/nextjs.ts"],"names":[],"mappings":"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"}
|
package/build/index.js
CHANGED
|
@@ -12,9 +12,13 @@ import { scanSecrets } from "./tools/scan-secrets.js";
|
|
|
12
12
|
import { scanStaged } from "./tools/scan-staged.js";
|
|
13
13
|
import { complianceReport } from "./tools/compliance-report.js";
|
|
14
14
|
import { exportSarif } from "./tools/export-sarif.js";
|
|
15
|
+
import { checkPackageHealth } from "./tools/check-package-health.js";
|
|
16
|
+
import { discoverPlugins } from "./plugins/loader.js";
|
|
17
|
+
import { builtinRules } from "./data/rules/index.js";
|
|
18
|
+
import { loadConfig } from "./utils/config.js";
|
|
15
19
|
const server = new McpServer({
|
|
16
20
|
name: "guardvibe",
|
|
17
|
-
version: "0.
|
|
21
|
+
version: "0.8.0",
|
|
18
22
|
});
|
|
19
23
|
// Tool 1: Analyze code for security vulnerabilities
|
|
20
24
|
server.tool("check_code", "Analyze code for security vulnerabilities (OWASP Top 10, XSS, SQL injection, insecure patterns). Use this when reviewing or writing code to catch security issues early.", {
|
|
@@ -26,8 +30,10 @@ server.tool("check_code", "Analyze code for security vulnerabilities (OWASP Top
|
|
|
26
30
|
.string()
|
|
27
31
|
.optional()
|
|
28
32
|
.describe("Framework context (e.g. express, nextjs, fastapi, react, django)"),
|
|
29
|
-
|
|
30
|
-
|
|
33
|
+
format: z.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (human) or json (machine-readable for agents)"),
|
|
34
|
+
}, async ({ code, language, framework, format }) => {
|
|
35
|
+
const rules = globalThis.__guardvibe_rules;
|
|
36
|
+
const results = checkCode(code, language, framework, undefined, undefined, format, rules);
|
|
31
37
|
return {
|
|
32
38
|
content: [{ type: "text", text: results }],
|
|
33
39
|
};
|
|
@@ -40,8 +46,10 @@ server.tool("check_project", "Scan multiple files for security vulnerabilities a
|
|
|
40
46
|
content: z.string().describe("File source code"),
|
|
41
47
|
}))
|
|
42
48
|
.describe("List of files to scan: [{path, content}]"),
|
|
43
|
-
|
|
44
|
-
|
|
49
|
+
format: z.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (human) or json (machine-readable for agents)"),
|
|
50
|
+
}, async ({ files, format }) => {
|
|
51
|
+
const rules = globalThis.__guardvibe_rules;
|
|
52
|
+
const results = checkProject(files, format, rules);
|
|
45
53
|
return {
|
|
46
54
|
content: [{ type: "text", text: results }],
|
|
47
55
|
};
|
|
@@ -89,46 +97,84 @@ server.tool("scan_directory", "Scan an entire project directory for security vul
|
|
|
89
97
|
path: z.string().describe("Directory path to scan (e.g. './src', '.')"),
|
|
90
98
|
recursive: z.boolean().optional().default(true).describe("Scan subdirectories"),
|
|
91
99
|
exclude: z.array(z.string()).optional().default([]).describe("Additional directories to exclude"),
|
|
92
|
-
|
|
93
|
-
|
|
100
|
+
format: z.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (human) or json (machine-readable for agents)"),
|
|
101
|
+
}, async ({ path, recursive, exclude, format }) => {
|
|
102
|
+
const rules = globalThis.__guardvibe_rules;
|
|
103
|
+
const results = scanDirectory(path, recursive, exclude, format, rules);
|
|
94
104
|
return { content: [{ type: "text", text: results }] };
|
|
95
105
|
});
|
|
96
106
|
// Tool 6: Scan manifest/lockfile for dependency vulnerabilities
|
|
97
107
|
server.tool("scan_dependencies", "Parse a lockfile or manifest (package.json, package-lock.json, requirements.txt, go.mod) and check all dependencies for known CVEs via the OSV database. Reads the file directly.", {
|
|
98
108
|
manifest_path: z.string().describe("Path to manifest file (e.g. 'package.json', 'requirements.txt', 'go.mod')"),
|
|
99
|
-
|
|
100
|
-
|
|
109
|
+
format: z.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (human) or json (machine-readable for agents)"),
|
|
110
|
+
}, async ({ manifest_path, format }) => {
|
|
111
|
+
const results = await scanDependencies(manifest_path, format);
|
|
101
112
|
return { content: [{ type: "text", text: results }] };
|
|
102
113
|
});
|
|
103
114
|
// Tool 7: Scan for leaked secrets, API keys, and credentials
|
|
104
115
|
server.tool("scan_secrets", "Scan files and directories for leaked secrets, API keys, tokens, and credentials. Checks .env files, config files, and source code. Verifies .gitignore coverage.", {
|
|
105
116
|
path: z.string().describe("File or directory path to scan"),
|
|
106
117
|
recursive: z.boolean().optional().default(true).describe("Scan subdirectories"),
|
|
107
|
-
|
|
108
|
-
|
|
118
|
+
format: z.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (human) or json (machine-readable for agents)"),
|
|
119
|
+
}, async ({ path, recursive, format }) => {
|
|
120
|
+
const results = scanSecrets(path, recursive, format);
|
|
109
121
|
return { content: [{ type: "text", text: results }] };
|
|
110
122
|
});
|
|
111
123
|
// Tool 8: Scan git-staged files before committing
|
|
112
|
-
server.tool("scan_staged", "Scan git-staged files for security vulnerabilities before committing. Run this before every commit to catch issues early. No input needed — automatically reads staged files.", {
|
|
113
|
-
|
|
124
|
+
server.tool("scan_staged", "Scan git-staged files for security vulnerabilities before committing. Run this before every commit to catch issues early. No input needed — automatically reads staged files.", {
|
|
125
|
+
format: z.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (human) or json (machine-readable for agents)"),
|
|
126
|
+
}, async ({ format }) => {
|
|
127
|
+
const rules = globalThis.__guardvibe_rules;
|
|
128
|
+
const results = scanStaged(process.cwd(), format, rules);
|
|
114
129
|
return { content: [{ type: "text", text: results }] };
|
|
115
130
|
});
|
|
116
131
|
// Tool 9: Generate compliance-focused security report
|
|
117
132
|
server.tool("compliance_report", "Generate a compliance-focused security report mapped to SOC2, PCI-DSS, or HIPAA controls. Scans a directory and groups findings by compliance control.", {
|
|
118
133
|
path: z.string().describe("Directory to scan"),
|
|
119
134
|
framework: z.enum(["SOC2", "PCI-DSS", "HIPAA", "all"]).describe("Compliance framework"),
|
|
120
|
-
|
|
121
|
-
|
|
135
|
+
format: z.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (human) or json (machine-readable for agents)"),
|
|
136
|
+
}, async ({ path, framework, format }) => {
|
|
137
|
+
const rules = globalThis.__guardvibe_rules;
|
|
138
|
+
const results = complianceReport(path, framework, format, rules);
|
|
122
139
|
return { content: [{ type: "text", text: results }] };
|
|
123
140
|
});
|
|
124
141
|
// Tool 10: Export scan results in SARIF v2.1.0 format
|
|
125
142
|
server.tool("export_sarif", "Scan a directory and export results in SARIF v2.1.0 format for CI/CD integration (GitHub, GitLab, Azure DevOps). Returns JSON string.", {
|
|
126
143
|
path: z.string().describe("Directory to scan"),
|
|
127
144
|
}, async ({ path }) => {
|
|
128
|
-
const
|
|
145
|
+
const rules = globalThis.__guardvibe_rules;
|
|
146
|
+
const results = exportSarif(path, rules);
|
|
147
|
+
return { content: [{ type: "text", text: results }] };
|
|
148
|
+
});
|
|
149
|
+
// Tool 11: Check package health and typosquat risk
|
|
150
|
+
server.tool("check_package_health", "Check npm packages for typosquat risk, maintenance status, adoption metrics, and deprecation. Use this before adding new dependencies to catch suspicious or risky packages.", {
|
|
151
|
+
packages: z.array(z.string()).describe("List of package names to check (e.g. ['lodash', 'expres', 'react-qeury'])"),
|
|
152
|
+
format: z.enum(["markdown", "json"]).default("markdown").describe("Output format: markdown (human) or json (machine-readable for agents)"),
|
|
153
|
+
}, async ({ packages, format }) => {
|
|
154
|
+
const results = await checkPackageHealth(packages, format);
|
|
129
155
|
return { content: [{ type: "text", text: results }] };
|
|
130
156
|
});
|
|
131
157
|
async function main() {
|
|
158
|
+
// Load plugins
|
|
159
|
+
const config = loadConfig(process.cwd());
|
|
160
|
+
const plugins = await discoverPlugins(process.cwd(), config.plugins);
|
|
161
|
+
if (plugins.loaded.length > 0) {
|
|
162
|
+
console.error(`[guardvibe] Loaded ${plugins.loaded.length} plugin(s): ${plugins.loaded.join(", ")}`);
|
|
163
|
+
}
|
|
164
|
+
for (const err of plugins.errors) {
|
|
165
|
+
console.error(`[guardvibe] Plugin warning: ${err}`);
|
|
166
|
+
}
|
|
167
|
+
// Merge rules: builtin + plugin
|
|
168
|
+
const allRules = [...builtinRules, ...plugins.rules];
|
|
169
|
+
// Register plugin tools
|
|
170
|
+
for (const tool of plugins.tools) {
|
|
171
|
+
server.tool(tool.name, tool.description, tool.schema, async (input) => {
|
|
172
|
+
const result = await tool.handler(input);
|
|
173
|
+
return { content: [{ type: "text", text: result }] };
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
// Store merged rules for tool handlers
|
|
177
|
+
globalThis.__guardvibe_rules = allRules;
|
|
132
178
|
const transport = new StdioServerTransport();
|
|
133
179
|
await server.connect(transport);
|
|
134
180
|
console.error("GuardVibe Security MCP server running on stdio");
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { SecurityRule } from "../data/rules/types.js";
|
|
2
|
+
import type { GuardVibeTool } from "./types.js";
|
|
3
|
+
interface ValidationResult {
|
|
4
|
+
valid: boolean;
|
|
5
|
+
rules: SecurityRule[];
|
|
6
|
+
tools: GuardVibeTool[];
|
|
7
|
+
errors: string[];
|
|
8
|
+
}
|
|
9
|
+
export declare function validatePlugin(raw: any): ValidationResult;
|
|
10
|
+
export interface LoadedPlugins {
|
|
11
|
+
rules: SecurityRule[];
|
|
12
|
+
tools: GuardVibeTool[];
|
|
13
|
+
loaded: string[];
|
|
14
|
+
errors: string[];
|
|
15
|
+
}
|
|
16
|
+
export declare function discoverPlugins(baseDir: string, configPlugins?: string[]): Promise<LoadedPlugins>;
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/plugins/loader.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,KAAK,EAAmB,aAAa,EAAE,MAAM,YAAY,CAAC;AAEjE,UAAU,gBAAgB;IACxB,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAgBD,wBAAgB,cAAc,CAAC,GAAG,EAAE,GAAG,GAAG,gBAAgB,CAsCzD;AA2DD,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,GAAE,MAAM,EAAO,GAAG,OAAO,CAAC,aAAa,CAAC,CA0D3G"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { readdirSync } from "fs";
|
|
2
|
+
import { join, resolve, isAbsolute } from "path";
|
|
3
|
+
function isValidRule(rule) {
|
|
4
|
+
return (rule &&
|
|
5
|
+
typeof rule === "object" &&
|
|
6
|
+
typeof rule.id === "string" &&
|
|
7
|
+
typeof rule.name === "string" &&
|
|
8
|
+
typeof rule.severity === "string" &&
|
|
9
|
+
typeof rule.description === "string" &&
|
|
10
|
+
rule.pattern instanceof RegExp &&
|
|
11
|
+
Array.isArray(rule.languages) &&
|
|
12
|
+
typeof rule.fix === "string");
|
|
13
|
+
}
|
|
14
|
+
export function validatePlugin(raw) {
|
|
15
|
+
const errors = [];
|
|
16
|
+
if (!raw || typeof raw !== "object") {
|
|
17
|
+
return { valid: false, rules: [], tools: [], errors: ["Plugin is not an object"] };
|
|
18
|
+
}
|
|
19
|
+
if (typeof raw.name !== "string" || !raw.name) {
|
|
20
|
+
return { valid: false, rules: [], tools: [], errors: ["Plugin missing 'name'"] };
|
|
21
|
+
}
|
|
22
|
+
if (typeof raw.version !== "string" || !raw.version) {
|
|
23
|
+
return { valid: false, rules: [], tools: [], errors: ["Plugin missing 'version'"] };
|
|
24
|
+
}
|
|
25
|
+
const rules = [];
|
|
26
|
+
if (Array.isArray(raw.rules)) {
|
|
27
|
+
for (const rule of raw.rules) {
|
|
28
|
+
if (isValidRule(rule)) {
|
|
29
|
+
rules.push(rule);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
errors.push(`Invalid rule skipped: ${rule?.id ?? "unknown"}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const tools = [];
|
|
37
|
+
if (Array.isArray(raw.tools)) {
|
|
38
|
+
for (const tool of raw.tools) {
|
|
39
|
+
if (tool && typeof tool.name === "string" && typeof tool.handler === "function") {
|
|
40
|
+
tools.push(tool);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
errors.push(`Invalid tool skipped: ${tool?.name ?? "unknown"}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return { valid: true, rules, tools, errors };
|
|
48
|
+
}
|
|
49
|
+
const PLUGIN_PATTERNS = [
|
|
50
|
+
/^guardvibe-rules-/,
|
|
51
|
+
/^@guardvibe\/rules-/,
|
|
52
|
+
/^@guardvibe-pro\/rules-/,
|
|
53
|
+
];
|
|
54
|
+
function findPluginPackages(nodeModulesDir) {
|
|
55
|
+
const found = [];
|
|
56
|
+
let entries;
|
|
57
|
+
try {
|
|
58
|
+
entries = readdirSync(nodeModulesDir);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return found;
|
|
62
|
+
}
|
|
63
|
+
for (const entry of entries) {
|
|
64
|
+
if (PLUGIN_PATTERNS[0].test(entry)) {
|
|
65
|
+
found.push(entry);
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
if (entry === "@guardvibe" || entry === "@guardvibe-pro") {
|
|
69
|
+
try {
|
|
70
|
+
const scopedEntries = readdirSync(join(nodeModulesDir, entry));
|
|
71
|
+
for (const scoped of scopedEntries) {
|
|
72
|
+
if (scoped.startsWith("rules-")) {
|
|
73
|
+
found.push(`${entry}/${scoped}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch { }
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return found;
|
|
81
|
+
}
|
|
82
|
+
async function loadPluginModule(specifier, baseDir) {
|
|
83
|
+
try {
|
|
84
|
+
let modulePath;
|
|
85
|
+
if (specifier.startsWith(".") || isAbsolute(specifier)) {
|
|
86
|
+
modulePath = resolve(baseDir, specifier);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
modulePath = join(baseDir, "node_modules", specifier);
|
|
90
|
+
}
|
|
91
|
+
const mod = await import(modulePath);
|
|
92
|
+
const plugin = mod.default ?? mod.plugin ?? mod;
|
|
93
|
+
return plugin;
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
console.error(`[guardvibe] Failed to load plugin "${specifier}": ${err instanceof Error ? err.message : err}`);
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
export async function discoverPlugins(baseDir, configPlugins = []) {
|
|
101
|
+
const result = { rules: [], tools: [], loaded: [], errors: [] };
|
|
102
|
+
const seen = new Set();
|
|
103
|
+
// 1. Convention-based discovery
|
|
104
|
+
const nodeModulesDir = join(baseDir, "node_modules");
|
|
105
|
+
const conventionPackages = findPluginPackages(nodeModulesDir);
|
|
106
|
+
for (const pkgName of conventionPackages) {
|
|
107
|
+
if (seen.has(pkgName))
|
|
108
|
+
continue;
|
|
109
|
+
seen.add(pkgName);
|
|
110
|
+
const raw = await loadPluginModule(pkgName, baseDir);
|
|
111
|
+
if (!raw) {
|
|
112
|
+
result.errors.push(`Failed to load: ${pkgName}`);
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
const validation = validatePlugin(raw);
|
|
116
|
+
if (!validation.valid) {
|
|
117
|
+
result.errors.push(`Invalid plugin ${pkgName}: ${validation.errors.join(", ")}`);
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
result.rules.push(...validation.rules);
|
|
121
|
+
result.tools.push(...validation.tools);
|
|
122
|
+
result.loaded.push(pkgName);
|
|
123
|
+
if (validation.errors.length > 0) {
|
|
124
|
+
result.errors.push(...validation.errors.map(e => `${pkgName}: ${e}`));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// 2. Config-based plugins
|
|
128
|
+
for (const specifier of configPlugins) {
|
|
129
|
+
if (seen.has(specifier))
|
|
130
|
+
continue;
|
|
131
|
+
seen.add(specifier);
|
|
132
|
+
const raw = await loadPluginModule(specifier, baseDir);
|
|
133
|
+
if (!raw) {
|
|
134
|
+
result.errors.push(`Failed to load: ${specifier}`);
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
const validation = validatePlugin(raw);
|
|
138
|
+
if (!validation.valid) {
|
|
139
|
+
result.errors.push(`Invalid plugin ${specifier}: ${validation.errors.join(", ")}`);
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
result.rules.push(...validation.rules);
|
|
143
|
+
result.tools.push(...validation.tools);
|
|
144
|
+
result.loaded.push(specifier);
|
|
145
|
+
if (validation.errors.length > 0) {
|
|
146
|
+
result.errors.push(...validation.errors.map(e => `${specifier}: ${e}`));
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return result;
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/plugins/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { SecurityRule } from "../data/rules/types.js";
|
|
2
|
+
export interface GuardVibeTool {
|
|
3
|
+
name: string;
|
|
4
|
+
description: string;
|
|
5
|
+
schema: Record<string, unknown>;
|
|
6
|
+
handler: (input: any) => Promise<string>;
|
|
7
|
+
}
|
|
8
|
+
export interface GuardVibePlugin {
|
|
9
|
+
name: string;
|
|
10
|
+
version: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
author?: string;
|
|
13
|
+
license?: "free" | "pro";
|
|
14
|
+
rules?: SecurityRule[];
|
|
15
|
+
tools?: GuardVibeTool[];
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/plugins/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAE3D,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,OAAO,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CAC1C;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IACzB,KAAK,CAAC,EAAE,YAAY,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,aAAa,EAAE,CAAC;CACzB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/plugins/types.ts"],"names":[],"mappings":""}
|
|
@@ -4,6 +4,7 @@ export interface Finding {
|
|
|
4
4
|
match: string;
|
|
5
5
|
line: number;
|
|
6
6
|
}
|
|
7
|
-
export declare function analyzeCode(code: string, language: string, framework?: string, filePath?: string, configDir?: string): Finding[];
|
|
8
|
-
export declare function
|
|
7
|
+
export declare function analyzeCode(code: string, language: string, framework?: string, filePath?: string, configDir?: string, rules?: SecurityRule[]): Finding[];
|
|
8
|
+
export declare function formatFindingsJson(findings: Finding[], extra?: Record<string, unknown>): string;
|
|
9
|
+
export declare function checkCode(code: string, language: string, framework?: string, filePath?: string, configDir?: string, format?: "markdown" | "json", rules?: SecurityRule[]): string;
|
|
9
10
|
//# sourceMappingURL=check-code.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check-code.d.ts","sourceRoot":"","sources":["../../src/tools/check-code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAGvE,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAgCD,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"check-code.d.ts","sourceRoot":"","sources":["../../src/tools/check-code.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAGvE,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAgCD,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,MAAM,EAClB,KAAK,CAAC,EAAE,YAAY,EAAE,GACrB,OAAO,EAAE,CAwCX;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAkB/F;AAED,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,MAAM,EAClB,MAAM,GAAE,UAAU,GAAG,MAAmB,EACxC,KAAK,CAAC,EAAE,YAAY,EAAE,GACrB,MAAM,CAYR"}
|
|
@@ -21,12 +21,13 @@ function parseSuppressionsFromCode(lines) {
|
|
|
21
21
|
function isLineSuppressed(suppressions, line, ruleId) {
|
|
22
22
|
return suppressions.some(s => s.line === line && (s.ruleId === null || s.ruleId === ruleId));
|
|
23
23
|
}
|
|
24
|
-
export function analyzeCode(code, language, framework, filePath, configDir) {
|
|
24
|
+
export function analyzeCode(code, language, framework, filePath, configDir, rules) {
|
|
25
25
|
const config = loadConfig(configDir);
|
|
26
26
|
const findings = [];
|
|
27
27
|
const lines = code.split("\n");
|
|
28
28
|
const suppressions = parseSuppressionsFromCode(lines);
|
|
29
|
-
|
|
29
|
+
const effectiveRules = rules ?? owaspRules;
|
|
30
|
+
for (const rule of effectiveRules) {
|
|
30
31
|
if (!rule.languages.includes(language))
|
|
31
32
|
continue;
|
|
32
33
|
// Config: skip disabled rules
|
|
@@ -57,8 +58,29 @@ export function analyzeCode(code, language, framework, filePath, configDir) {
|
|
|
57
58
|
}
|
|
58
59
|
return findings;
|
|
59
60
|
}
|
|
60
|
-
export function
|
|
61
|
-
const
|
|
61
|
+
export function formatFindingsJson(findings, extra) {
|
|
62
|
+
const critical = findings.filter(f => f.rule.severity === "critical").length;
|
|
63
|
+
const high = findings.filter(f => f.rule.severity === "high").length;
|
|
64
|
+
const medium = findings.filter(f => f.rule.severity === "medium").length;
|
|
65
|
+
const low = findings.filter(f => f.rule.severity === "low").length;
|
|
66
|
+
return JSON.stringify({
|
|
67
|
+
summary: {
|
|
68
|
+
total: findings.length, critical, high, medium, low,
|
|
69
|
+
blocked: critical > 0 || high > 0,
|
|
70
|
+
...extra,
|
|
71
|
+
},
|
|
72
|
+
findings: findings.map(f => ({
|
|
73
|
+
id: f.rule.id, name: f.rule.name, severity: f.rule.severity,
|
|
74
|
+
owasp: f.rule.owasp, line: f.line, match: f.match,
|
|
75
|
+
fix: f.rule.fix, fixCode: f.rule.fixCode, compliance: f.rule.compliance,
|
|
76
|
+
})),
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
export function checkCode(code, language, framework, filePath, configDir, format = "markdown", rules) {
|
|
80
|
+
const findings = analyzeCode(code, language, framework, filePath, configDir, rules);
|
|
81
|
+
if (format === "json") {
|
|
82
|
+
return formatFindingsJson(findings);
|
|
83
|
+
}
|
|
62
84
|
if (findings.length === 0) {
|
|
63
85
|
return formatCleanReport(language, framework);
|
|
64
86
|
}
|