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.
@@ -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
- const counts = parseSectionCounts(parsed);
173
- const secretFindings = (parsed.findings ?? []).map((f) => ({
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
- sections.push({ name: "secrets", status: "ok", ...counts, details: counts.findings === 0 ? "No secrets found" : `${counts.findings} secret(s) detected`, sectionFindings: secretFindings });
183
- for (const f of parsed.findings ?? []) {
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
- "MCP: Call scan_secrets with format: json OR CLI: run `npx guardvibe scan --format json` and look for SECRET: findings in the output",
385
- "For EACH secret found: (a) if it's in a .env file, ensure .env* is in .gitignore, (b) if it's hardcoded in source code, move it to an environment variable, (c) NEVER dismiss secrets as 'already in .gitignore' — if GuardVibe found it, the FILE exists and contains real values",
386
- "Rotate any API keys/tokens that were committed to git history — run `git log --all -p -S 'YOUR_KEY_PREFIX' -- '*.env*'` to check",
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 aboveeach 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
- "MCP: Call scan_directory with format: json OR CLI: run `npx guardvibe scan --format json` to get full finding list",
396
- "Fix ALL critical and high severity findings. Read each flagged file, understand the vulnerability, apply the fix suggested in the finding",
397
- "After fixing each file, re-scan it: MCP: Call scan_file — OR CLI: run `npx guardvibe check <file> --format json` to confirm the finding is gone",
398
- "Re-run full scan to confirm total code findings dropped",
406
+ "Look at sectionFindings aboveeach 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
- "MCP: Call scan_dependencies with format: json OR CLI: run `npx guardvibe scan --format json` and check dependency findings, also run `npm audit`",
406
- "Run `npm audit fix` to auto-fix what's possible. If that doesn't work, run `npm update <package>` for each vulnerable package",
407
- "If a package can't be updated (breaking changes), find an alternative or pin to a patched version",
408
- "Re-run `npx guardvibe audit` and confirm dependency findings dropped to 0",
415
+ "Look at sectionFindings aboveeach 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
- "MCP: Call audit_config with format: json OR CLI: run `npx guardvibe audit --format json` and parse the config section details",
416
- "Common config fixes: add missing security headers in next.config.ts (CSP, HSTS, X-Frame-Options, Referrer-Policy, Permissions-Policy), set poweredByHeader: false, configure CORS properly",
417
- "MCP: Call explain_remediation for each rule ID — OR CLI: run `npx guardvibe explain <RULE_ID>` to get specific fix guidance",
418
- "Re-run audit and confirm config findings dropped",
424
+ "Look at sectionFindings aboveeach 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
- "MCP: Call analyze_cross_file_dataflow — OR CLI: run `npx guardvibe audit --format json` and parse the taint section. Look for user input (URL params, form data, req.body) flowing to dangerous sinks (SQL, HTML, file system)",
426
- "Fix each tainted flow: add Zod/joi validation at the input source, use parameterized queries for SQL, use sanitizeUrl/DOMPurify for HTML output, validate file paths",
427
- "Re-run audit and confirm taint findings dropped to 0",
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
- "MCP: Call auth_coverage with format: json OR CLI: run `npx guardvibe auth-coverage --format json` to list all unprotected routes",
435
- "For each unprotected route: (a) if it needs auth, add middleware or auth guard (Clerk/NextAuth/Supabase), (b) if it's intentionally public (homepage, blog, about, etc.), add it to .guardviberc file under authExceptions with a reason",
436
- "Create or update .guardviberc in project root: {\"authExceptions\": [{\"path\": \"/blog\", \"reason\": \"Public page\"}]}",
437
- "Re-run `npx guardvibe auth-coverage --format json` and confirm unprotected count matches your authExceptions count",
442
+ "Look at sectionFindings aboveeach 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: `MANDATORY: You must fix ALL ${plan.length} sections below. Do NOT fix only the code section and skip the rest. Work through each section in priority order. After completing ALL sections, call verify_remediation to confirm.`,
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
- "Do NOT dismiss findings as 'false positive' without running the section-specific tool first and verifying the finding is genuinely wrong.",
477
- "Do NOT say 'npm audit is clean' to skip dependencies GuardVibe uses the OSV database which may detect CVEs that npm audit misses.",
478
- "Do NOT say 'already in .gitignore' to skip secrets — if GuardVibe detects secrets, they exist in the scanned files and must be removed or moved to env vars.",
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 sectionFindingsnot 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(`> **IMPORTANT: You MUST fix ALL ${plan.length} sections below. Do NOT fix only the code section and skip the rest. Work through each section in priority order. After completing ALL sections, call \`verify_remediation\` to confirm.**`);
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.16",
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",