guardvibe 1.9.4 → 1.9.5
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/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from "module";
|
|
3
|
-
import { readFileSync, writeFileSync, mkdirSync, existsSync, chmodSync, unlinkSync } from "fs";
|
|
3
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync, chmodSync, unlinkSync, statSync } from "fs";
|
|
4
4
|
import { join, dirname } from "path";
|
|
5
5
|
import { homedir } from "os";
|
|
6
6
|
const require = createRequire(import.meta.url);
|
|
@@ -523,8 +523,8 @@ function printUsage() {
|
|
|
523
523
|
Options:
|
|
524
524
|
--format <type> Output format: markdown (default), json, sarif
|
|
525
525
|
--output <file> Write results to file instead of stdout
|
|
526
|
-
--fail-on <level> Exit 1 when findings at this level exist
|
|
527
|
-
|
|
526
|
+
--fail-on <level> Exit 1 when findings at this level or above exist
|
|
527
|
+
critical (default) | high | medium | low | none
|
|
528
528
|
--baseline <file> Compare against a previous scan JSON for fix tracking
|
|
529
529
|
--save-baseline Save current scan as baseline (.guardvibe-baseline.json)
|
|
530
530
|
--version, -V Print version and exit
|
|
@@ -618,7 +618,14 @@ async function main() {
|
|
|
618
618
|
const cliArgs = args.slice(1);
|
|
619
619
|
const { flags, positional } = parseArgs(cliArgs);
|
|
620
620
|
const targetPath = positional[0] ?? ".";
|
|
621
|
-
|
|
621
|
+
// If target is a file (not directory), auto-redirect to check mode
|
|
622
|
+
if (targetPath !== "." && existsSync(targetPath) && !statSync(targetPath).isDirectory()) {
|
|
623
|
+
console.log(` [INFO] "${targetPath}" is a file. Running: guardvibe check ${targetPath}\n`);
|
|
624
|
+
await runFileCheck(targetPath, flags);
|
|
625
|
+
}
|
|
626
|
+
else {
|
|
627
|
+
await runDirectoryScan(targetPath, flags);
|
|
628
|
+
}
|
|
622
629
|
}
|
|
623
630
|
else if (command === "diff") {
|
|
624
631
|
const cliArgs = args.slice(1);
|
|
@@ -163,6 +163,10 @@ export function analyzeCode(code, language, framework, filePath, configDir, rule
|
|
|
163
163
|
const rateLimitRuleIds = new Set(["VG956", "VG030"]);
|
|
164
164
|
if (isCronRoute && rateLimitRuleIds.has(rule.id))
|
|
165
165
|
continue;
|
|
166
|
+
// Context-aware: skip rate limiting rules for webhook routes
|
|
167
|
+
// Webhooks are called by external services, not users — rate limiting is irrelevant
|
|
168
|
+
if (isWebhookRoute && rateLimitRuleIds.has(rule.id))
|
|
169
|
+
continue;
|
|
166
170
|
// Context-aware: skip rate limiting rules for admin routes that have admin auth
|
|
167
171
|
const isAdminRoute = filePath && /\/admin\//i.test(filePath);
|
|
168
172
|
const hasAdminAuth = isAdminRoute && /(?:requireAdmin|adminOnly|orgRole|org:admin|isAdmin|checkRole|requireRole)/i.test(code);
|
|
@@ -126,7 +126,7 @@ export function checkProject(files, format = "markdown", rules) {
|
|
|
126
126
|
actionItems.forEach((item, i) => {
|
|
127
127
|
const fileCount = item.files.size;
|
|
128
128
|
const fileLabel = fileCount === 1 ? "1 file" : `${fileCount} files`;
|
|
129
|
-
lines.push(`${i + 1}. **[${item.rule.severity.toUpperCase()}] ${item.rule.name}** (${item.rule.id}) — ${item.count} occurrences in ${fileLabel}`, ` ${item.rule.fix}`, ``);
|
|
129
|
+
lines.push(`${i + 1}. **[${item.rule.severity.toUpperCase()}] ${item.rule.name}** (${item.rule.id}) — ${item.count} ${item.count === 1 ? "occurrence" : "occurrences"} in ${fileLabel}`, ` ${item.rule.fix}`, ``);
|
|
130
130
|
});
|
|
131
131
|
}
|
|
132
132
|
lines.push(`---`, ``);
|
|
@@ -220,7 +220,7 @@ export function scanDirectory(path, recursive = true, exclude = [], format = "ma
|
|
|
220
220
|
actionItems.forEach((item, i) => {
|
|
221
221
|
const fileCount = item.files.size;
|
|
222
222
|
const fileLabel = fileCount === 1 ? "1 file" : `${fileCount} files`;
|
|
223
|
-
lines.push(`${i + 1}. **[${item.rule.severity.toUpperCase()}] ${item.rule.name}** (${item.rule.id}) — ${item.count} occurrences in ${fileLabel}`, ` ${item.rule.fix}`, ``);
|
|
223
|
+
lines.push(`${i + 1}. **[${item.rule.severity.toUpperCase()}] ${item.rule.name}** (${item.rule.id}) — ${item.count} ${item.count === 1 ? "occurrence" : "occurrences"} in ${fileLabel}`, ` ${item.rule.fix}`, ``);
|
|
224
224
|
});
|
|
225
225
|
lines.push(`---`, ``);
|
|
226
226
|
for (const result of scanResults) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "guardvibe",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.5",
|
|
4
4
|
"description": "Security MCP for vibe coding. 277 rules, 24 tools for Next.js, Supabase, Clerk, Stripe, Prisma, tRPC, Hono, GraphQL, Convex, Turso, Uploadthing, AI SDK, and the full AI-generated stack.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|