guardvibe 3.0.27 → 3.0.28
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/build/tools/check-code.js +41 -0
- package/package.json +1 -1
|
@@ -304,6 +304,20 @@ export function analyzeCode(code, language, framework, filePath, configDir, rule
|
|
|
304
304
|
continue;
|
|
305
305
|
if (rule.id.startsWith("VG21") && !filePath && language !== "yaml")
|
|
306
306
|
continue;
|
|
307
|
+
// Skip credential rules in test files — fixtures and assertions intentionally use fake values.
|
|
308
|
+
const isTestFile = filePath && /(?:\.(?:spec|test|e2e|stories)\.(?:ts|tsx|js|jsx|mjs|cjs)$|\/__tests__\/|\/tests?\/|\/cypress\/|\/playwright\/)/i.test(filePath);
|
|
309
|
+
if (isTestFile && (rule.id === "VG001" || rule.id === "VG062"))
|
|
310
|
+
continue;
|
|
311
|
+
// Skip Expo-specific rule (VG708) when project is not an Expo app.
|
|
312
|
+
// The rule's regex incorrectly matches the literal strings "app.json"/"app.config.ts"
|
|
313
|
+
// appearing in unrelated configs (e.g. angular.json's tsConfig field).
|
|
314
|
+
if (rule.id === "VG708" && filePath) {
|
|
315
|
+
const fileName = filePath.split("/").pop() ?? "";
|
|
316
|
+
const isExpoConfigFile = /^app\.(json|config\.(js|ts|mjs|cjs))$/.test(fileName);
|
|
317
|
+
const importsExpo = /(?:from\s+['"]expo[\w-]*['"]|require\s*\(\s*['"]expo[\w-]*['"])/i.test(code);
|
|
318
|
+
if (!isExpoConfigFile && !importsExpo)
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
307
321
|
// ── Context-aware rule skipping (pattern-agnostic) ──────────────
|
|
308
322
|
const authRuleIds = new Set(["VG420", "VG952", "VG002", "VG402"]);
|
|
309
323
|
const adminRoleRuleIds = new Set(["VG426", "VG957"]);
|
|
@@ -538,6 +552,28 @@ export function analyzeCode(code, language, framework, filePath, configDir, rule
|
|
|
538
552
|
if (isHumanReadableString(lines, lineNumber))
|
|
539
553
|
continue;
|
|
540
554
|
}
|
|
555
|
+
// Skip credential rules when the variable name signals test/example/mock intent.
|
|
556
|
+
// e.g. `testingPassword`, `examplePassword`, `mockApiKey`, `placeholderSecret`.
|
|
557
|
+
if (rule.id === "VG001" || rule.id === "VG062") {
|
|
558
|
+
const matchedLine = lines[lineNumber - 1] ?? "";
|
|
559
|
+
if (/(?:^|\s|\b)(?:testing|example|mock|placeholder|sample|demo|fake|dummy|stub|fixture)[A-Z_]/.test(matchedLine))
|
|
560
|
+
continue;
|
|
561
|
+
}
|
|
562
|
+
// Skip VG010 (SQL injection) on Angular HTTP service calls — http.get/post/etc.
|
|
563
|
+
// are HTTP client methods, not SQL. The existing pattern's `get` keyword catches them.
|
|
564
|
+
if (rule.id === "VG010") {
|
|
565
|
+
const matchedLine = lines[lineNumber - 1] ?? "";
|
|
566
|
+
const isHttpClientCall = /(?:this\.)?(?:http|httpClient|httpService|api|client)\.(?:get|post|put|delete|patch|head|options)\s*\(/i.test(matchedLine);
|
|
567
|
+
const importsHttpClient = /from\s+['"]@angular\/common\/http['"]/i.test(code) || /import\s+.*HttpClient/i.test(code);
|
|
568
|
+
const fileIsAngularService = filePath ? /\.(?:service|component|directive|pipe|guard|resolver|interceptor)\.ts$/i.test(filePath) : false;
|
|
569
|
+
if (isHttpClientCall && (importsHttpClient || fileIsAngularService))
|
|
570
|
+
continue;
|
|
571
|
+
// Also skip when matched call has no SQL keyword anywhere on the line — covers fetch/axios template-literal URLs.
|
|
572
|
+
const hasSqlKeyword = /\b(?:SELECT|INSERT|UPDATE|DELETE|FROM|WHERE|JOIN|UNION|DROP|TRUNCATE|ALTER|CREATE\s+TABLE)\b/i.test(matchedLine);
|
|
573
|
+
const isFetchOrAxios = /(?:fetch|axios|got|ky|undici|request)\s*[.\(]|axios\.(?:get|post|put|delete|patch)/i.test(matchedLine);
|
|
574
|
+
if (isFetchOrAxios && !hasSqlKeyword)
|
|
575
|
+
continue;
|
|
576
|
+
}
|
|
541
577
|
// Skip supply chain rules for known legitimate packages
|
|
542
578
|
if (["VG872", "VG873"].includes(rule.id)) {
|
|
543
579
|
const pkgMatch = /"([\w@/-]+)"/.exec(match[0]);
|
|
@@ -649,6 +685,11 @@ function isDuplicatePair(a, b) {
|
|
|
649
685
|
// Same rule name = same vulnerability
|
|
650
686
|
if (a.rule.name === b.rule.name)
|
|
651
687
|
return true;
|
|
688
|
+
// Both are SQL injection variants — VG010 (generic) and VG123 (template literal specific) overlap.
|
|
689
|
+
// VG123 is more specific so it should dominate. isMoreSpecific handles the prefix order.
|
|
690
|
+
const sqlInjectionRules = new Set(["VG010", "VG123"]);
|
|
691
|
+
if (sqlInjectionRules.has(a.rule.id) && sqlInjectionRules.has(b.rule.id))
|
|
692
|
+
return true;
|
|
652
693
|
// Both are XSS/innerHTML related — the core VG012+VG408 duplicate case
|
|
653
694
|
if (a.rule.name.includes("innerHTML") && b.rule.name.includes("innerHTML"))
|
|
654
695
|
return true;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "guardvibe",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.28",
|
|
4
4
|
"mcpName": "io.github.goklab/guardvibe",
|
|
5
5
|
"description": "Security MCP for vibe coding. 365 rules, 36 tools, CLI + doctor. Host security, auth coverage mapping, LLM-powered deep scan (IDOR/business logic), taint analysis. Plus Next.js, Supabase, Clerk, Stripe, Prisma, tRPC, Hono, GraphQL, Convex, Turso, Uploadthing, AI SDK, and the full AI-generated stack.",
|
|
6
6
|
"type": "module",
|