guardvibe 3.0.16 → 3.0.17
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/full-audit.js +40 -43
- package/package.json +1 -1
|
@@ -169,8 +169,14 @@ export async function runFullAudit(path, options) {
|
|
|
169
169
|
const secretsJson = scanSecrets(projectRoot, true, "json");
|
|
170
170
|
const parsed = safeJsonParse(secretsJson);
|
|
171
171
|
if (parsed) {
|
|
172
|
-
|
|
173
|
-
const
|
|
172
|
+
// Filter out gitignored secrets — they're local dev files, not a security risk
|
|
173
|
+
const rawFindings = parsed.findings ?? [];
|
|
174
|
+
const actionableFindings = rawFindings.filter((f) => f.gitStatus !== "ignored");
|
|
175
|
+
const ignoredCount = rawFindings.length - actionableFindings.length;
|
|
176
|
+
const actionableCritical = actionableFindings.filter((f) => f.severity === "critical").length;
|
|
177
|
+
const actionableHigh = actionableFindings.filter((f) => f.severity === "high").length;
|
|
178
|
+
const actionableMedium = actionableFindings.length - actionableCritical - actionableHigh;
|
|
179
|
+
const secretFindings = actionableFindings.map((f) => ({
|
|
174
180
|
ruleId: `SECRET:${(f.provider ?? "unknown")}`,
|
|
175
181
|
severity: (f.severity ?? "high"),
|
|
176
182
|
file: (f.file ?? ""),
|
|
@@ -179,8 +185,15 @@ export async function runFullAudit(path, options) {
|
|
|
179
185
|
description: (f.match ?? f.description ?? ""),
|
|
180
186
|
fix: "Move this secret to an environment variable and ensure the file is in .gitignore",
|
|
181
187
|
}));
|
|
182
|
-
|
|
183
|
-
|
|
188
|
+
const detailText = actionableFindings.length === 0
|
|
189
|
+
? (ignoredCount > 0 ? `${ignoredCount} secret(s) in .gitignore (safe)` : "No secrets found")
|
|
190
|
+
: `${actionableFindings.length} secret(s) detected${ignoredCount > 0 ? ` (${ignoredCount} in .gitignore excluded)` : ""}`;
|
|
191
|
+
sections.push({
|
|
192
|
+
name: "secrets", status: "ok",
|
|
193
|
+
findings: actionableFindings.length, critical: actionableCritical, high: actionableHigh, medium: actionableMedium,
|
|
194
|
+
details: detailText, sectionFindings: secretFindings,
|
|
195
|
+
});
|
|
196
|
+
for (const f of actionableFindings) {
|
|
184
197
|
allFindings.push({ ruleId: `SECRET:${f.provider ?? "unknown"}`, severity: f.severity, file: f.file ?? "", line: f.line ?? 0 });
|
|
185
198
|
}
|
|
186
199
|
}
|
|
@@ -381,60 +394,54 @@ function buildInlineRemediationPlan(result) {
|
|
|
381
394
|
priority: 1,
|
|
382
395
|
tool: "scan_secrets",
|
|
383
396
|
actions: [
|
|
384
|
-
"
|
|
385
|
-
"For
|
|
386
|
-
"
|
|
387
|
-
"MCP: Call scan_secrets_history — OR CLI: run `npx guardvibe scan --format json` to verify",
|
|
388
|
-
"Re-run the scan and confirm secret count dropped to 0. If it didn't, your fix didn't work — try again",
|
|
397
|
+
"Look at sectionFindings above — each has file, line, description",
|
|
398
|
+
"For each: move hardcoded secret to .env, add file to .gitignore",
|
|
399
|
+
"Verify: run `npx guardvibe audit --format json 2>&1 | head -1` — secrets count must be 0",
|
|
389
400
|
],
|
|
390
401
|
},
|
|
391
402
|
code: {
|
|
392
403
|
priority: 2,
|
|
393
404
|
tool: "scan_directory",
|
|
394
405
|
actions: [
|
|
395
|
-
"
|
|
396
|
-
"
|
|
397
|
-
"
|
|
398
|
-
"Re-run full scan to confirm total code findings dropped",
|
|
406
|
+
"Look at sectionFindings above — each has ruleId, file, line, fix",
|
|
407
|
+
"Read each file, apply the fix. Run `npx guardvibe explain <RULE_ID>` if unclear",
|
|
408
|
+
"Verify each file: `npx guardvibe check <file> --format json` — must show 0 findings",
|
|
399
409
|
],
|
|
400
410
|
},
|
|
401
411
|
dependencies: {
|
|
402
412
|
priority: 3,
|
|
403
413
|
tool: "scan_dependencies",
|
|
404
414
|
actions: [
|
|
405
|
-
"
|
|
406
|
-
"Run `npm
|
|
407
|
-
"
|
|
408
|
-
"Re-run `npx guardvibe audit` and confirm dependency findings dropped to 0",
|
|
415
|
+
"Look at sectionFindings above — each has package name and CVE",
|
|
416
|
+
"Run `npm update <package>` for each. If already latest, check for alternative package",
|
|
417
|
+
"Verify: re-run audit — dependencies count must drop",
|
|
409
418
|
],
|
|
410
419
|
},
|
|
411
420
|
config: {
|
|
412
421
|
priority: 4,
|
|
413
422
|
tool: "audit_config",
|
|
414
423
|
actions: [
|
|
415
|
-
"
|
|
416
|
-
"
|
|
417
|
-
"
|
|
418
|
-
"Re-run audit and confirm config findings dropped",
|
|
424
|
+
"Look at sectionFindings above — each has ruleId, file, title, fix",
|
|
425
|
+
"Run `npx guardvibe explain <RULE_ID>` for each finding to get exact fix code",
|
|
426
|
+
"Apply fixes to the listed files. Verify: re-run audit — config count must drop",
|
|
419
427
|
],
|
|
420
428
|
},
|
|
421
429
|
taint: {
|
|
422
430
|
priority: 5,
|
|
423
431
|
tool: "analyze_cross_file_dataflow",
|
|
424
432
|
actions: [
|
|
425
|
-
"
|
|
426
|
-
"
|
|
427
|
-
"
|
|
433
|
+
"Look at sectionFindings above — each shows source file:line → sink file:line",
|
|
434
|
+
"Add input validation (Zod) at source, or sanitization at sink",
|
|
435
|
+
"Verify: re-run audit — taint count must be 0",
|
|
428
436
|
],
|
|
429
437
|
},
|
|
430
438
|
"auth-coverage": {
|
|
431
439
|
priority: 6,
|
|
432
440
|
tool: "auth_coverage",
|
|
433
441
|
actions: [
|
|
434
|
-
"
|
|
435
|
-
"
|
|
436
|
-
"
|
|
437
|
-
"Re-run `npx guardvibe auth-coverage --format json` and confirm unprotected count matches your authExceptions count",
|
|
442
|
+
"Look at sectionFindings above — each shows unprotected route path and file",
|
|
443
|
+
"Add auth guard, or add to .guardviberc authExceptions: {\"path\": \"/route\", \"reason\": \"Public\"}",
|
|
444
|
+
"Verify: `npx guardvibe auth-coverage --format json` — unprotected must be 0",
|
|
438
445
|
],
|
|
439
446
|
},
|
|
440
447
|
};
|
|
@@ -471,14 +478,11 @@ export function formatAuditResult(result, format) {
|
|
|
471
478
|
...result,
|
|
472
479
|
remediationPlan: {
|
|
473
480
|
totalSectionsWithFindings: plan.length,
|
|
474
|
-
warning: `
|
|
481
|
+
warning: `FIX ALL ${plan.length} SECTIONS. Each section has sectionFindings with exact file, line, and fix. Process every finding. After ALL sections: re-run audit to verify.`,
|
|
475
482
|
rules: [
|
|
476
|
-
"
|
|
477
|
-
"
|
|
478
|
-
"
|
|
479
|
-
"Do NOT skip auth-coverage by saying routes are 'intentionally public' — either add auth guards or add them to .guardviberc authExceptions so the scanner recognizes them.",
|
|
480
|
-
"After fixing each section, re-run the section-specific tool to confirm the finding count dropped. If it didn't drop, your fix didn't work.",
|
|
481
|
-
"Only call verify_remediation AFTER you have worked through ALL sections and confirmed each one improved.",
|
|
483
|
+
"NEVER use 'npx guardvibe diff' — use 'npx guardvibe audit --format json 2>&1 | head -1'",
|
|
484
|
+
"Fix EVERY finding in sectionFindings — not just one section",
|
|
485
|
+
"After fixing, re-run audit and verify finding count dropped",
|
|
482
486
|
],
|
|
483
487
|
steps: plan,
|
|
484
488
|
},
|
|
@@ -554,14 +558,7 @@ export function formatAuditResult(result, format) {
|
|
|
554
558
|
lines.push(``);
|
|
555
559
|
lines.push(`## Mandatory Remediation Plan`);
|
|
556
560
|
lines.push(``);
|
|
557
|
-
lines.push(`> **
|
|
558
|
-
lines.push(``);
|
|
559
|
-
lines.push(`**Rules:**`);
|
|
560
|
-
lines.push(`- Do NOT dismiss findings as "false positive" without running the section-specific tool first`);
|
|
561
|
-
lines.push(`- Do NOT say "npm audit is clean" to skip dependencies — GuardVibe uses OSV which may detect CVEs npm misses`);
|
|
562
|
-
lines.push(`- Do NOT say "already in .gitignore" to skip secrets — if detected, they exist in scanned files`);
|
|
563
|
-
lines.push(`- After fixing each section, re-run the section tool to confirm finding count dropped`);
|
|
564
|
-
lines.push(`- Only call verify_remediation AFTER all sections show improvement`);
|
|
561
|
+
lines.push(`> **FIX ALL ${plan.length} SECTIONS. Each section's sectionFindings has exact file, line, and fix. Process every finding. Re-run audit after ALL sections to verify.**`);
|
|
565
562
|
lines.push(``);
|
|
566
563
|
for (const step of plan) {
|
|
567
564
|
lines.push(`### Step ${step.priority}: ${step.section} (${step.findings} findings — ${step.critical} critical, ${step.high} high)`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "guardvibe",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.17",
|
|
4
4
|
"mcpName": "io.github.goklab/guardvibe",
|
|
5
5
|
"description": "Security MCP for vibe coding. 335 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",
|