grepleaks 1.0.2 → 1.0.3

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.
Files changed (2) hide show
  1. package/bin/grepleaks.js +71 -36
  2. package/package.json +1 -1
package/bin/grepleaks.js CHANGED
@@ -9,7 +9,7 @@ const readline = require('readline');
9
9
  const { exec } = require('child_process');
10
10
  const archiver = require('archiver');
11
11
 
12
- const VERSION = '1.0.2';
12
+ const VERSION = '1.0.3';
13
13
  const API_URL = 'https://grepleaks.com/api/v1';
14
14
  const WEB_URL = 'https://grepleaks.com';
15
15
  const CONFIG_DIR = path.join(os.homedir(), '.grepleaks');
@@ -491,18 +491,46 @@ function generateMarkdownReport(result) {
491
491
  const score = result.security_score || 0;
492
492
  const grade = result.grade_level || 'N/A';
493
493
  const projectName = result.project_name || 'Unknown Project';
494
+ const lang = getLang();
495
+
496
+ const dateStr = new Date().toLocaleDateString(lang === 'fr' ? 'fr-FR' : 'en-US', {
497
+ year: 'numeric',
498
+ month: 'long',
499
+ day: 'numeric'
500
+ });
494
501
 
495
- const dateStr = new Date().toLocaleDateString(getLang() === 'fr' ? 'fr-FR' : 'en-US');
502
+ // Count by severity
503
+ const counts = { critical: 0, high: 0, medium: 0, low: 0 };
504
+ for (const v of vulns) {
505
+ const sev = (v.severity || 'low').toLowerCase();
506
+ if (counts[sev] !== undefined) counts[sev]++;
507
+ }
496
508
 
497
- let md = `# ${t('reportTitle')} - ${projectName}\n\n`;
498
- md += `**${t('reportDate')}** ${dateStr}\n`;
499
- md += `**${t('reportScore')}** ${score}/100 (${grade})\n`;
500
- md += `**${t('reportVulns')}** ${vulns.length}\n\n`;
509
+ // Header
510
+ let md = `# ${t('reportTitle')}\n\n`;
511
+ md += `> **${projectName}** | ${dateStr}\n\n`;
512
+
513
+ // Score card
514
+ const scoreEmoji = score >= 90 ? '🛡️' : score >= 75 ? '✅' : score >= 50 ? '⚠️' : '🚨';
515
+ md += `## ${scoreEmoji} ${lang === 'fr' ? 'Score de Sécurité' : 'Security Score'}: ${score}/100 (${grade})\n\n`;
516
+
517
+ // Summary table
518
+ if (vulns.length > 0) {
519
+ md += `| ${lang === 'fr' ? 'Sévérité' : 'Severity'} | ${lang === 'fr' ? 'Nombre' : 'Count'} |\n`;
520
+ md += `|----------|-------|\n`;
521
+ if (counts.critical > 0) md += `| 🔴 Critical | ${counts.critical} |\n`;
522
+ if (counts.high > 0) md += `| 🟠 High | ${counts.high} |\n`;
523
+ if (counts.medium > 0) md += `| 🟡 Medium | ${counts.medium} |\n`;
524
+ if (counts.low > 0) md += `| 🟢 Low | ${counts.low} |\n`;
525
+ md += `\n`;
526
+ }
501
527
 
528
+ // Vulnerabilities
502
529
  if (vulns.length === 0) {
503
- md += `## ${t('reportNoVulns')}\n\n`;
530
+ md += `## ${t('reportNoVulns')}\n\n`;
504
531
  md += `${t('reportCongrats')}\n`;
505
532
  } else {
533
+ md += `---\n\n`;
506
534
  md += `## ${t('reportVulnsDetected')}\n\n`;
507
535
 
508
536
  const bySeverity = { CRITICAL: [], HIGH: [], MEDIUM: [], LOW: [] };
@@ -518,64 +546,71 @@ function generateMarkdownReport(result) {
518
546
  severity === 'HIGH' ? '🟠' :
519
547
  severity === 'MEDIUM' ? '🟡' : '🟢';
520
548
 
521
- md += `### ${emoji} ${severity} (${items.length})\n\n`;
549
+ const severityLabel = lang === 'fr'
550
+ ? { CRITICAL: 'Critique', HIGH: 'Élevée', MEDIUM: 'Moyenne', LOW: 'Faible' }[severity]
551
+ : severity.charAt(0) + severity.slice(1).toLowerCase();
522
552
 
523
- for (const v of items) {
524
- // Title: use rule_id or description snippet
525
- const title = v.rule_id || (v.description ? v.description.substring(0, 50) + '...' : 'Vulnerability');
526
- md += `#### ${title}\n\n`;
553
+ md += `### ${emoji} ${severityLabel}\n\n`;
527
554
 
528
- // Location (file/line)
529
- if (v.location) {
530
- md += `- **${t('reportFile')}** \`${v.location}\`\n`;
555
+ for (let i = 0; i < items.length; i++) {
556
+ const v = items[i];
557
+
558
+ // Title from description (first sentence or truncated)
559
+ let title = v.description || 'Security Issue';
560
+ const firstSentence = title.match(/^[^.!?]+[.!?]/);
561
+ if (firstSentence) {
562
+ title = firstSentence[0];
563
+ } else if (title.length > 80) {
564
+ title = title.substring(0, 77) + '...';
531
565
  }
532
566
 
533
- // Scanner source
534
- if (v.source) {
535
- md += `- **${t('reportScanner')}** ${v.source}\n`;
567
+ md += `<details>\n<summary><strong>${title}</strong></summary>\n\n`;
568
+
569
+ // Location
570
+ if (v.location) {
571
+ md += `📍 **${lang === 'fr' ? 'Emplacement' : 'Location'}:** \`${v.location}\`\n\n`;
536
572
  }
537
573
 
538
- // CVE if available
574
+ // CVE
539
575
  if (v.cve) {
540
- md += `- **CVE:** ${v.cve}\n`;
576
+ md += `🔖 **CVE:** [${v.cve}](https://nvd.nist.gov/vuln/detail/${v.cve})\n\n`;
541
577
  }
542
578
 
543
- // Package info (for Trivy findings)
579
+ // Package info
544
580
  if (v.package_name) {
545
- md += `- **Package:** ${v.package_name}`;
546
- if (v.current_version) md += ` (${v.current_version})`;
581
+ md += `📦 **Package:** \`${v.package_name}\``;
582
+ if (v.current_version) md += ` v${v.current_version}`;
547
583
  md += `\n`;
548
584
  if (v.fixed_version) {
549
- md += `- **Fix:** Upgrade to ${v.fixed_version}\n`;
585
+ md += `✅ **${lang === 'fr' ? 'Correction' : 'Fix'}:** ${lang === 'fr' ? 'Mettre à jour vers' : 'Upgrade to'} v${v.fixed_version}\n`;
550
586
  }
551
- }
552
-
553
- // Description
554
- if (v.description) {
555
- md += `\n${v.description}\n`;
587
+ md += `\n`;
556
588
  }
557
589
 
558
590
  // Code snippet
559
591
  if (v.code_snippet) {
560
- md += `\n\`\`\`\n${v.code_snippet}\n\`\`\`\n`;
592
+ md += `**${lang === 'fr' ? 'Code concerné' : 'Affected code'}:**\n\`\`\`\n${v.code_snippet}\n\`\`\`\n\n`;
561
593
  }
562
594
 
563
595
  // Recommendation
564
- if (v.recommendation || v.llm_recommendation) {
565
- md += `\n**${t('reportRecommendation')}** ${v.llm_recommendation || v.recommendation}\n`;
596
+ const rec = v.llm_recommendation || v.recommendation;
597
+ if (rec) {
598
+ md += `💡 **${t('reportRecommendation')}**\n\n${rec}\n\n`;
566
599
  }
567
600
 
568
- // Reference URL
601
+ // Reference
569
602
  if (v.reference_url) {
570
- md += `\n**Reference:** ${v.reference_url}\n`;
603
+ md += `🔗 [${lang === 'fr' ? 'Plus d\'informations' : 'Learn more'}](${v.reference_url})\n\n`;
571
604
  }
572
605
 
573
- md += `\n---\n\n`;
606
+ md += `</details>\n\n`;
574
607
  }
575
608
  }
576
609
  }
577
610
 
578
- md += `\n---\n*${t('reportGeneratedBy')} [grepleaks](https://grepleaks.com)*\n`;
611
+ // Footer
612
+ md += `---\n\n`;
613
+ md += `<sub>${t('reportGeneratedBy')} [grepleaks](https://grepleaks.com) ${scoreEmoji}</sub>\n`;
579
614
 
580
615
  return md;
581
616
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grepleaks",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "Security scanner for your code - detect vulnerabilities, secrets, and misconfigurations",
5
5
  "main": "bin/grepleaks.js",
6
6
  "bin": {