coverme-security-scanner 3.7.2 → 3.7.4

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/bin/coverme.js CHANGED
File without changes
File without changes
File without changes
@@ -1,36 +1,21 @@
1
1
  # Security Assessment
2
2
 
3
- You MUST follow these steps exactly. Do NOT deviate. Do NOT ask questions. Execute automatically.
3
+ Run a security scan and generate a PDF report. Execute automatically without asking questions.
4
4
 
5
- ## Step 1: Create directory
5
+ ## Step 1: Setup
6
6
  ```bash
7
7
  mkdir -p .coverme
8
8
  ```
9
9
 
10
- ## Step 2: Launch 7 agents IN PARALLEL
10
+ ## Step 2: Run Security Scan
11
+ Use ONE Task agent with subagent_type="general-purpose" to perform the full security assessment:
11
12
 
12
- You MUST use the Task tool 7 times in a SINGLE message. Each Task MUST have subagent_type="general-purpose" (NOT Explore).
13
+ prompt: "Perform a comprehensive security assessment of this codebase. Analyze: 1) Architecture and tech stack 2) API endpoints and attack surface 3) Security vulnerabilities (secrets, injection, XSS, auth issues) 4) Infrastructure (Docker, CI/CD, dependencies). When done, use the Write tool to create .coverme/scan.json with this structure: {\"project\":\"<name>\",\"date\":\"2026-02-19\",\"executiveSummary\":\"<summary>\",\"summary\":{\"critical\":0,\"high\":0,\"medium\":0,\"low\":0,\"total\":0},\"overallRiskLevel\":\"low|medium|high|critical\",\"findings\":[{\"id\":\"VULN-01\",\"title\":\"\",\"severity\":\"critical|high|medium|low\",\"file\":\"\",\"line\":0,\"issue\":\"\",\"why\":\"\",\"fix\":\"\",\"cwe\":\"\"}],\"architecture\":{\"overview\":\"\",\"components\":[]},\"positiveObservations\":[{\"title\":\"\",\"description\":\"\"}]}"
13
14
 
14
- Task 1: description="Security Executive", subagent_type="general-purpose", prompt="Analyze codebase architecture and security posture. Then use the Write tool to create .coverme/partial-01-executive.json with this exact structure: {\"project\":\"<name>\",\"date\":\"2026-02-19\",\"executiveSummary\":\"<summary>\",\"architecture\":{\"overview\":\"<text>\",\"components\":[{\"name\":\"\",\"technology\":\"\",\"description\":\"\"}],\"trustBoundaries\":[{\"id\":\"\",\"boundary\":\"\",\"trustLevel\":\"\",\"description\":\"\"}]},\"topPriorities\":[{\"finding\":\"\",\"severity\":\"\",\"action\":\"\"}]}"
15
-
16
- Task 2: description="Attack Surface", subagent_type="general-purpose", prompt="Map API endpoints and entry points. Then use the Write tool to create .coverme/partial-02-surface.json with: {\"network\":{\"diagram\":\"\",\"ports\":[],\"externalDeps\":[]},\"findings\":[]}"
17
-
18
- Task 3: description="Vulnerability Scan", subagent_type="general-purpose", prompt="Find security vulnerabilities with code evidence. Then use the Write tool to create .coverme/partial-03-vulns.json with: {\"findings\":[{\"id\":\"\",\"title\":\"\",\"severity\":\"\",\"file\":\"\",\"line\":0,\"issue\":\"\",\"why\":\"\",\"fix\":\"\",\"cwe\":\"\",\"codeEvidence\":[],\"proofOfConcept\":\"\"}]}"
19
-
20
- Task 4: description="Attack Chains", subagent_type="general-purpose", prompt="Identify attack chains. Then use the Write tool to create .coverme/partial-04-chains.json with: {\"attackChains\":[{\"id\":\"\",\"name\":\"\",\"description\":\"\",\"likelihood\":\"\",\"impact\":\"\",\"steps\":[],\"mitigationStrategy\":\"\"}],\"riskMatrix\":[]}"
21
-
22
- Task 5: description="Business Logic", subagent_type="general-purpose", prompt="Find business logic flaws. Then use the Write tool to create .coverme/partial-05-business.json with: {\"findings\":[],\"threatModel\":[]}"
23
-
24
- Task 6: description="Infrastructure", subagent_type="general-purpose", prompt="Check Docker, CI/CD, dependencies. Then use the Write tool to create .coverme/partial-06-infra.json with: {\"findings\":[],\"qualityReview\":{}}"
25
-
26
- Task 7: description="Compliance", subagent_type="general-purpose", prompt="Map to compliance frameworks. Then use the Write tool to create .coverme/partial-07-compliance.json with: {\"complianceMapping\":[],\"remediation\":{\"p0\":[],\"p1\":[],\"p2\":[],\"p3\":[]},\"positiveObservations\":[],\"privacyAnalysis\":[]}"
27
-
28
- ## Step 3: Wait for agents
29
- Use AgentOutputTool to wait for all 7 agents to complete.
15
+ ## Step 3: Wait for agent to complete
16
+ Use AgentOutputTool to wait for the agent.
30
17
 
31
18
  ## Step 4: Generate PDF
32
19
  ```bash
33
- coverme-merge .coverme && coverme .coverme/scan.json security-report.pdf && open security-report.pdf
20
+ coverme .coverme/scan.json security-report.pdf && open security-report.pdf
34
21
  ```
35
-
36
- CRITICAL: Use subagent_type="general-purpose" for ALL agents. They MUST write JSON files using the Write tool.
@@ -402,6 +402,9 @@ export class PDFGenerator {
402
402
  this.y = this.doc.y + spacing.paragraph;
403
403
  }
404
404
  if (report.architecture?.components?.length) {
405
+ // Start components table on new page to keep it together
406
+ this.newPage();
407
+ this.y = spacing.page.top;
405
408
  this.subTitle('Components');
406
409
  this.renderSimpleTable(['Component', 'Technology', 'Description'], report.architecture.components.map(c => [c.name, c.technology, c.description]), [100, 150, 245]);
407
410
  }
@@ -434,7 +437,6 @@ export class PDFGenerator {
434
437
  this.y += 18;
435
438
  });
436
439
  }
437
- this.checkPageBreak();
438
440
  }
439
441
  // ─────────────────────────────────────────────────────────────────
440
442
  // Network
@@ -614,15 +616,20 @@ export class PDFGenerator {
614
616
  const boxPadding = 12;
615
617
  const boxInnerWidth = layout.content.width - (boxPadding * 2);
616
618
  const style = colors.severity[finding.severity];
617
- // ID in severity color, title in black
619
+ // ID in severity color, title in black - allow wrapping for long titles
620
+ const titleText = `[${finding.id}] ${finding.title}`;
621
+ const titleHeight = this.doc
622
+ .font(fonts.weights.bold)
623
+ .fontSize(fonts.sizes.body)
624
+ .heightOfString(titleText, { width: layout.content.width });
618
625
  this.doc
619
626
  .font(fonts.weights.bold)
620
627
  .fontSize(fonts.sizes.body)
621
628
  .fillColor(style.text)
622
629
  .text(`[${finding.id}]`, spacing.page.margin, this.y, { continued: true })
623
630
  .fillColor(colors.text.primary)
624
- .text(` ${finding.title}`);
625
- this.y += 18;
631
+ .text(` ${finding.title}`, { width: layout.content.width - 60 });
632
+ this.y = this.doc.y + 4;
626
633
  // Cross-references and DREAD score line
627
634
  const hasRefs = finding.relatedFindings?.length || finding.dreadScore || finding.cwe;
628
635
  if (hasRefs) {
@@ -1141,53 +1148,73 @@ export class PDFGenerator {
1141
1148
  this.y += 20;
1142
1149
  }
1143
1150
  renderSimpleTable(headers, rows, colWidths) {
1144
- const rowHeight = 24;
1151
+ const minRowHeight = 24;
1145
1152
  const x = spacing.page.margin;
1146
- // Header
1147
- this.doc
1148
- .rect(x, this.y, layout.content.width, rowHeight)
1149
- .fill(colors.table.header);
1150
- let colX = x;
1151
- headers.forEach((header, i) => {
1153
+ const cellPadding = 8;
1154
+ // Helper to render table header
1155
+ const renderHeader = () => {
1152
1156
  this.doc
1153
- .font(fonts.weights.bold)
1154
- .fontSize(fonts.sizes.small)
1155
- .fillColor(colors.table.headerText)
1156
- .text(header, colX + 8, this.y + 7, {
1157
- width: colWidths[i] - 16,
1157
+ .rect(x, this.y, layout.content.width, minRowHeight)
1158
+ .fill(colors.table.header);
1159
+ let colX = x;
1160
+ headers.forEach((header, i) => {
1161
+ this.doc
1162
+ .font(fonts.weights.bold)
1163
+ .fontSize(fonts.sizes.small)
1164
+ .fillColor(colors.table.headerText)
1165
+ .text(header, colX + cellPadding, this.y + 7, {
1166
+ width: colWidths[i] - (cellPadding * 2),
1167
+ });
1168
+ colX += colWidths[i];
1158
1169
  });
1159
- colX += colWidths[i];
1160
- });
1161
- this.y += rowHeight;
1162
- // Rows
1170
+ this.y += minRowHeight;
1171
+ };
1172
+ // Initial header
1173
+ renderHeader();
1174
+ // Rows - calculate dynamic height based on content
1163
1175
  rows.forEach((row, rowIndex) => {
1164
- this.checkPageBreak(rowHeight + 20);
1176
+ // Calculate the height needed for this row based on longest cell
1177
+ let maxCellHeight = minRowHeight;
1178
+ row.forEach((cell, i) => {
1179
+ const cellWidth = colWidths[i] - (cellPadding * 2);
1180
+ const textHeight = this.doc
1181
+ .font(fonts.weights.normal)
1182
+ .fontSize(fonts.sizes.small)
1183
+ .heightOfString(cell, { width: cellWidth });
1184
+ const cellHeight = Math.max(minRowHeight, textHeight + (cellPadding * 2));
1185
+ maxCellHeight = Math.max(maxCellHeight, cellHeight);
1186
+ });
1187
+ // Check if we need a page break - if so, re-render header on new page
1188
+ const needsPageBreak = this.y > layout.page.height - spacing.page.bottom - maxCellHeight - 20;
1189
+ if (needsPageBreak) {
1190
+ this.newPage();
1191
+ renderHeader();
1192
+ }
1165
1193
  // Alternating background
1166
1194
  if (rowIndex % 2 === 1) {
1167
1195
  this.doc
1168
- .rect(x, this.y, layout.content.width, rowHeight)
1196
+ .rect(x, this.y, layout.content.width, maxCellHeight)
1169
1197
  .fill(colors.table.altRow);
1170
1198
  }
1171
1199
  // Border
1172
1200
  this.doc
1173
- .moveTo(x, this.y + rowHeight)
1174
- .lineTo(x + layout.content.width, this.y + rowHeight)
1201
+ .moveTo(x, this.y + maxCellHeight)
1202
+ .lineTo(x + layout.content.width, this.y + maxCellHeight)
1175
1203
  .strokeColor(colors.table.border)
1176
1204
  .lineWidth(0.5)
1177
1205
  .stroke();
1178
- colX = x;
1206
+ let colX = x;
1179
1207
  row.forEach((cell, i) => {
1180
1208
  this.doc
1181
1209
  .font(fonts.weights.normal)
1182
1210
  .fontSize(fonts.sizes.small)
1183
1211
  .fillColor(colors.text.primary)
1184
- .text(cell, colX + 8, this.y + 7, {
1185
- width: colWidths[i] - 16,
1186
- ellipsis: true,
1212
+ .text(cell, colX + cellPadding, this.y + 7, {
1213
+ width: colWidths[i] - (cellPadding * 2),
1187
1214
  });
1188
1215
  colX += colWidths[i];
1189
1216
  });
1190
- this.y += rowHeight;
1217
+ this.y += maxCellHeight;
1191
1218
  });
1192
1219
  this.y += spacing.paragraph;
1193
1220
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coverme-security-scanner",
3
- "version": "3.7.2",
3
+ "version": "3.7.4",
4
4
  "description": "AI-powered security assessment reports with beautiful PDF output",
5
5
  "type": "module",
6
6
  "bin": {