coverme-scanner 1.3.3 → 1.4.0
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/dist/prompts/orchestration.md +227 -7
- package/dist/report/generator.d.ts +33 -0
- package/dist/report/generator.d.ts.map +1 -1
- package/dist/report/generator.js +267 -0
- package/dist/report/generator.js.map +1 -1
- package/dist/report/index.d.ts +1 -1
- package/dist/report/index.d.ts.map +1 -1
- package/dist/report/index.js +13 -2
- package/dist/report/index.js.map +1 -1
- package/dist/templates/report-pdf.html +1497 -0
- package/dist/templates/report.html +513 -0
- package/dist/types.d.ts +28 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1630,6 +1630,187 @@ The final report should ONLY contain findings that are:
|
|
|
1630
1630
|
}
|
|
1631
1631
|
},
|
|
1632
1632
|
|
|
1633
|
+
"architectureOverview": {
|
|
1634
|
+
"components": [
|
|
1635
|
+
{
|
|
1636
|
+
"name": "API Server",
|
|
1637
|
+
"type": "service",
|
|
1638
|
+
"description": "Express.js REST API handling all client requests",
|
|
1639
|
+
"trustLevel": "semi-trusted"
|
|
1640
|
+
},
|
|
1641
|
+
{
|
|
1642
|
+
"name": "PostgreSQL",
|
|
1643
|
+
"type": "database",
|
|
1644
|
+
"description": "Primary data store for user and application data",
|
|
1645
|
+
"trustLevel": "trusted"
|
|
1646
|
+
},
|
|
1647
|
+
{
|
|
1648
|
+
"name": "Redis",
|
|
1649
|
+
"type": "cache",
|
|
1650
|
+
"description": "Session storage and rate limiting",
|
|
1651
|
+
"trustLevel": "trusted"
|
|
1652
|
+
},
|
|
1653
|
+
{
|
|
1654
|
+
"name": "External Payment API",
|
|
1655
|
+
"type": "external",
|
|
1656
|
+
"description": "Third-party payment processor",
|
|
1657
|
+
"trustLevel": "untrusted"
|
|
1658
|
+
}
|
|
1659
|
+
],
|
|
1660
|
+
"trustBoundaries": [
|
|
1661
|
+
{
|
|
1662
|
+
"name": "Client to API",
|
|
1663
|
+
"from": "Browser/Mobile",
|
|
1664
|
+
"to": "API Server",
|
|
1665
|
+
"protocol": "HTTPS"
|
|
1666
|
+
},
|
|
1667
|
+
{
|
|
1668
|
+
"name": "API to Database",
|
|
1669
|
+
"from": "API Server",
|
|
1670
|
+
"to": "PostgreSQL",
|
|
1671
|
+
"protocol": "TLS"
|
|
1672
|
+
}
|
|
1673
|
+
],
|
|
1674
|
+
"criticalAssets": [
|
|
1675
|
+
{
|
|
1676
|
+
"name": "User Credentials",
|
|
1677
|
+
"type": "credential",
|
|
1678
|
+
"location": "PostgreSQL users table",
|
|
1679
|
+
"protection": "bcrypt hashed"
|
|
1680
|
+
},
|
|
1681
|
+
{
|
|
1682
|
+
"name": "API Keys",
|
|
1683
|
+
"type": "key",
|
|
1684
|
+
"location": "Environment variables",
|
|
1685
|
+
"protection": "Encrypted at rest"
|
|
1686
|
+
},
|
|
1687
|
+
{
|
|
1688
|
+
"name": "Session Tokens",
|
|
1689
|
+
"type": "token",
|
|
1690
|
+
"location": "Redis",
|
|
1691
|
+
"protection": "HMAC signed"
|
|
1692
|
+
}
|
|
1693
|
+
],
|
|
1694
|
+
"dataFlows": [
|
|
1695
|
+
"User Authentication Flow",
|
|
1696
|
+
"Payment Processing Flow",
|
|
1697
|
+
"Data Export Flow"
|
|
1698
|
+
]
|
|
1699
|
+
},
|
|
1700
|
+
|
|
1701
|
+
"threatModel": [
|
|
1702
|
+
{
|
|
1703
|
+
"id": "T-001",
|
|
1704
|
+
"threat": "SQL Injection via user input",
|
|
1705
|
+
"category": "STRIDE",
|
|
1706
|
+
"strideType": "T",
|
|
1707
|
+
"status": "open",
|
|
1708
|
+
"relatedFindings": ["SEC-001", "DB-002"],
|
|
1709
|
+
"mitigation": "Use parameterized queries",
|
|
1710
|
+
"dreadScore": 8.5
|
|
1711
|
+
},
|
|
1712
|
+
{
|
|
1713
|
+
"id": "T-002",
|
|
1714
|
+
"threat": "Session hijacking via XSS",
|
|
1715
|
+
"category": "STRIDE",
|
|
1716
|
+
"strideType": "S",
|
|
1717
|
+
"status": "partial",
|
|
1718
|
+
"relatedFindings": ["SEC-003"],
|
|
1719
|
+
"mitigation": "CSP headers implemented but not comprehensive",
|
|
1720
|
+
"dreadScore": 7.2
|
|
1721
|
+
},
|
|
1722
|
+
{
|
|
1723
|
+
"id": "T-003",
|
|
1724
|
+
"threat": "Unauthorized data access",
|
|
1725
|
+
"category": "LINDDUN",
|
|
1726
|
+
"status": "mitigated",
|
|
1727
|
+
"relatedFindings": [],
|
|
1728
|
+
"mitigation": "Row-level security implemented",
|
|
1729
|
+
"dreadScore": 3.0
|
|
1730
|
+
}
|
|
1731
|
+
],
|
|
1732
|
+
|
|
1733
|
+
"qualityReview": {
|
|
1734
|
+
"deleteItems": [
|
|
1735
|
+
{
|
|
1736
|
+
"type": "delete",
|
|
1737
|
+
"file": "src/utils/oldHelpers.ts",
|
|
1738
|
+
"lines": 250,
|
|
1739
|
+
"description": "Entire file is dead code - functions never called",
|
|
1740
|
+
"reason": "No imports found in codebase"
|
|
1741
|
+
},
|
|
1742
|
+
{
|
|
1743
|
+
"type": "delete",
|
|
1744
|
+
"file": "src/legacy/auth.js",
|
|
1745
|
+
"lines": 180,
|
|
1746
|
+
"description": "Legacy auth implementation replaced by Clerk",
|
|
1747
|
+
"reason": "Migration completed 6 months ago"
|
|
1748
|
+
}
|
|
1749
|
+
],
|
|
1750
|
+
"mergeItems": [
|
|
1751
|
+
{
|
|
1752
|
+
"type": "merge",
|
|
1753
|
+
"file": "src/utils/validate.ts, src/helpers/validation.ts",
|
|
1754
|
+
"description": "Two files with overlapping validation functions",
|
|
1755
|
+
"reason": "DRY violation - consolidate into single module"
|
|
1756
|
+
}
|
|
1757
|
+
],
|
|
1758
|
+
"simplifyItems": [
|
|
1759
|
+
{
|
|
1760
|
+
"type": "simplify",
|
|
1761
|
+
"file": "src/services/payment.ts",
|
|
1762
|
+
"lines": 450,
|
|
1763
|
+
"description": "Overly complex payment flow with excessive error handling",
|
|
1764
|
+
"reason": "Can be reduced to ~200 lines with proper abstraction"
|
|
1765
|
+
}
|
|
1766
|
+
],
|
|
1767
|
+
"totalLinesRemovable": 680,
|
|
1768
|
+
"percentageOfCodebase": 4.2
|
|
1769
|
+
},
|
|
1770
|
+
|
|
1771
|
+
"actionItems": [
|
|
1772
|
+
{
|
|
1773
|
+
"id": "A-001",
|
|
1774
|
+
"title": "Fix SQL injection in user search",
|
|
1775
|
+
"priority": "immediate",
|
|
1776
|
+
"relatedFindings": ["SEC-001"],
|
|
1777
|
+
"effort": "low",
|
|
1778
|
+
"description": "Replace string concatenation with parameterized query"
|
|
1779
|
+
},
|
|
1780
|
+
{
|
|
1781
|
+
"id": "A-002",
|
|
1782
|
+
"title": "Implement rate limiting on auth endpoints",
|
|
1783
|
+
"priority": "immediate",
|
|
1784
|
+
"relatedFindings": ["AUTH-003"],
|
|
1785
|
+
"effort": "medium",
|
|
1786
|
+
"description": "Add Redis-based rate limiter to /login and /register"
|
|
1787
|
+
},
|
|
1788
|
+
{
|
|
1789
|
+
"id": "A-003",
|
|
1790
|
+
"title": "Add CSP headers",
|
|
1791
|
+
"priority": "high",
|
|
1792
|
+
"relatedFindings": ["SEC-005"],
|
|
1793
|
+
"effort": "low",
|
|
1794
|
+
"description": "Configure helmet with strict CSP policy"
|
|
1795
|
+
},
|
|
1796
|
+
{
|
|
1797
|
+
"id": "A-004",
|
|
1798
|
+
"title": "Clean up dead code",
|
|
1799
|
+
"priority": "medium",
|
|
1800
|
+
"relatedFindings": ["DEAD-001", "DEAD-002"],
|
|
1801
|
+
"effort": "medium",
|
|
1802
|
+
"description": "Remove 680 lines of unused code identified in quality review"
|
|
1803
|
+
},
|
|
1804
|
+
{
|
|
1805
|
+
"id": "A-005",
|
|
1806
|
+
"title": "Implement audit logging",
|
|
1807
|
+
"priority": "long-term",
|
|
1808
|
+
"relatedFindings": ["DATA-002"],
|
|
1809
|
+
"effort": "high",
|
|
1810
|
+
"description": "Add comprehensive audit trail for sensitive operations"
|
|
1811
|
+
}
|
|
1812
|
+
],
|
|
1813
|
+
|
|
1633
1814
|
"summary": {
|
|
1634
1815
|
"total": 10,
|
|
1635
1816
|
"critical": 1,
|
|
@@ -1638,17 +1819,42 @@ The final report should ONLY contain findings that are:
|
|
|
1638
1819
|
"low": 2,
|
|
1639
1820
|
"info": 0,
|
|
1640
1821
|
"mitigatedCount": 5,
|
|
1641
|
-
"falsePositiveCount": 3
|
|
1822
|
+
"falsePositiveCount": 3,
|
|
1823
|
+
"avgConfidence": 0.85
|
|
1642
1824
|
},
|
|
1643
1825
|
|
|
1644
1826
|
"findings": [
|
|
1645
1827
|
{
|
|
1646
1828
|
"id": "SEC-001",
|
|
1647
|
-
"title": "
|
|
1648
|
-
"severity": "
|
|
1829
|
+
"title": "SQL Injection in User Search",
|
|
1830
|
+
"severity": "critical",
|
|
1831
|
+
"category": "security",
|
|
1832
|
+
"file": "src/routes/users.ts",
|
|
1833
|
+
"line": 45,
|
|
1834
|
+
"code": "db.query(`SELECT * FROM users WHERE name LIKE '%${searchTerm}%'`)",
|
|
1835
|
+
"description": "User search parameter is directly concatenated into SQL query without sanitization",
|
|
1836
|
+
"impact": "Attacker can extract entire database contents, modify data, or execute system commands",
|
|
1837
|
+
"attackChain": [
|
|
1838
|
+
{"step": 1, "action": "Send malicious search term: ' OR '1'='1' --", "result": "Query returns all users"},
|
|
1839
|
+
{"step": 2, "action": "Use UNION SELECT to extract data from other tables", "result": "Database schema exposed"},
|
|
1840
|
+
{"step": 3, "action": "Extract password hashes and sensitive data", "result": "Full data breach"}
|
|
1841
|
+
],
|
|
1842
|
+
"recommendation": "Use parameterized queries: db.query('SELECT * FROM users WHERE name LIKE $1', [`%${searchTerm}%`])",
|
|
1843
|
+
"cwe": "CWE-89",
|
|
1844
|
+
"owasp": "A03:2021",
|
|
1845
|
+
"dreadScore": {
|
|
1846
|
+
"damage": 10,
|
|
1847
|
+
"reproducibility": 10,
|
|
1848
|
+
"exploitability": 9,
|
|
1849
|
+
"affectedUsers": 10,
|
|
1850
|
+
"discoverability": 8,
|
|
1851
|
+
"total": 9.4
|
|
1852
|
+
},
|
|
1853
|
+
"status": "open",
|
|
1854
|
+
"crossReferences": ["T-001"],
|
|
1855
|
+
"confidence": 95,
|
|
1649
1856
|
"fixOwner": "developer",
|
|
1650
|
-
"fixType": "code"
|
|
1651
|
-
"...": "other fields"
|
|
1857
|
+
"fixType": "code"
|
|
1652
1858
|
}
|
|
1653
1859
|
],
|
|
1654
1860
|
|
|
@@ -1682,8 +1888,22 @@ The final report should ONLY contain findings that are:
|
|
|
1682
1888
|
],
|
|
1683
1889
|
|
|
1684
1890
|
"positiveObservations": [
|
|
1685
|
-
|
|
1686
|
-
|
|
1891
|
+
{
|
|
1892
|
+
"title": "Strong Authentication Implementation",
|
|
1893
|
+
"description": "Clerk integration with proper session management, MFA support, and secure cookie settings"
|
|
1894
|
+
},
|
|
1895
|
+
{
|
|
1896
|
+
"title": "Comprehensive Input Validation",
|
|
1897
|
+
"description": "Zod schemas used consistently across API endpoints with proper error handling"
|
|
1898
|
+
},
|
|
1899
|
+
{
|
|
1900
|
+
"title": "Secure Database Access",
|
|
1901
|
+
"description": "Prisma ORM with parameterized queries, preventing SQL injection in core modules"
|
|
1902
|
+
},
|
|
1903
|
+
{
|
|
1904
|
+
"title": "Good Error Handling Patterns",
|
|
1905
|
+
"description": "Errors are caught and logged without exposing internal details to clients"
|
|
1906
|
+
}
|
|
1687
1907
|
],
|
|
1688
1908
|
|
|
1689
1909
|
"validationSummary": {
|
|
@@ -56,6 +56,30 @@ interface ExecutiveSummaryData {
|
|
|
56
56
|
architect?: number;
|
|
57
57
|
};
|
|
58
58
|
}
|
|
59
|
+
interface ScanStats {
|
|
60
|
+
filesScanned: number;
|
|
61
|
+
linesOfCode: number;
|
|
62
|
+
agentCount: number;
|
|
63
|
+
avgConfidence: number;
|
|
64
|
+
}
|
|
65
|
+
interface QualityReviewData {
|
|
66
|
+
deleteItems: Array<{
|
|
67
|
+
file: string;
|
|
68
|
+
lines: number;
|
|
69
|
+
description: string;
|
|
70
|
+
}>;
|
|
71
|
+
mergeItems: Array<{
|
|
72
|
+
file: string;
|
|
73
|
+
description: string;
|
|
74
|
+
}>;
|
|
75
|
+
simplifyItems: Array<{
|
|
76
|
+
file: string;
|
|
77
|
+
description: string;
|
|
78
|
+
}>;
|
|
79
|
+
totalLinesRemovable: number;
|
|
80
|
+
percentageOfCodebase: number;
|
|
81
|
+
totalItems: number;
|
|
82
|
+
}
|
|
59
83
|
interface ReportData {
|
|
60
84
|
projectName: string;
|
|
61
85
|
scanDate: string;
|
|
@@ -97,6 +121,9 @@ interface ReportData {
|
|
|
97
121
|
architectureOverviewHtml: string;
|
|
98
122
|
threatModelHtml: string;
|
|
99
123
|
actionItemsHtml: string;
|
|
124
|
+
scanStats?: ScanStats;
|
|
125
|
+
projectTree?: string;
|
|
126
|
+
qualityReview?: QualityReviewData;
|
|
100
127
|
}
|
|
101
128
|
export declare function calculateScore(result: ScanResult): {
|
|
102
129
|
grade: string;
|
|
@@ -116,5 +143,11 @@ export declare function generateHtmlReport(result: ScanResult, outputPath: strin
|
|
|
116
143
|
file?: string;
|
|
117
144
|
rejectionReason: string;
|
|
118
145
|
}>): Promise<void>;
|
|
146
|
+
export declare function generateProfessionalPdf(result: ScanResult, outputPath: string, falsePositives?: Array<{
|
|
147
|
+
id: string;
|
|
148
|
+
title: string;
|
|
149
|
+
file?: string;
|
|
150
|
+
rejectionReason: string;
|
|
151
|
+
}>): Promise<void>;
|
|
119
152
|
export {};
|
|
120
153
|
//# sourceMappingURL=generator.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/report/generator.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,
|
|
1
|
+
{"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/report/generator.ts"],"names":[],"mappings":"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"}
|
package/dist/report/generator.js
CHANGED
|
@@ -41,6 +41,7 @@ exports.generateExecutiveSummary = generateExecutiveSummary;
|
|
|
41
41
|
exports.renderTemplate = renderTemplate;
|
|
42
42
|
exports.generatePdfReport = generatePdfReport;
|
|
43
43
|
exports.generateHtmlReport = generateHtmlReport;
|
|
44
|
+
exports.generateProfessionalPdf = generateProfessionalPdf;
|
|
44
45
|
const fs = __importStar(require("fs"));
|
|
45
46
|
const path = __importStar(require("path"));
|
|
46
47
|
const puppeteer_1 = __importDefault(require("puppeteer"));
|
|
@@ -616,6 +617,33 @@ async function generateHtmlReport(result, outputPath, falsePositives = []) {
|
|
|
616
617
|
const typeGroups = createTypeGroups(result.findings);
|
|
617
618
|
const codeGroup = typeGroups.find(g => g.type === 'code');
|
|
618
619
|
const devopsGroup = typeGroups.find(g => g.type === 'devops');
|
|
620
|
+
// Prepare scan statistics
|
|
621
|
+
const scanStats = (result.filesScanned || result.linesOfCode) ? {
|
|
622
|
+
filesScanned: result.filesScanned || 0,
|
|
623
|
+
linesOfCode: result.linesOfCode || 0,
|
|
624
|
+
agentCount: result.agentsUsed?.length || 0,
|
|
625
|
+
avgConfidence: Math.round((result.summary?.avgConfidence || 0) * 100),
|
|
626
|
+
} : undefined;
|
|
627
|
+
// Prepare quality review data
|
|
628
|
+
const qr = result.qualityReview;
|
|
629
|
+
const qualityReview = qr ? {
|
|
630
|
+
deleteItems: qr.deleteItems?.map(i => ({
|
|
631
|
+
file: i.file,
|
|
632
|
+
lines: i.lines || 0,
|
|
633
|
+
description: i.description,
|
|
634
|
+
})) || [],
|
|
635
|
+
mergeItems: qr.mergeItems?.map(i => ({
|
|
636
|
+
file: i.file,
|
|
637
|
+
description: i.description,
|
|
638
|
+
})) || [],
|
|
639
|
+
simplifyItems: qr.simplifyItems?.map(i => ({
|
|
640
|
+
file: i.file,
|
|
641
|
+
description: i.description,
|
|
642
|
+
})) || [],
|
|
643
|
+
totalLinesRemovable: qr.totalLinesRemovable || 0,
|
|
644
|
+
percentageOfCodebase: qr.percentageOfCodebase || 0,
|
|
645
|
+
totalItems: (qr.deleteItems?.length || 0) + (qr.mergeItems?.length || 0) + (qr.simplifyItems?.length || 0),
|
|
646
|
+
} : undefined;
|
|
619
647
|
const data = {
|
|
620
648
|
projectName: result.projectName,
|
|
621
649
|
scanDate: new Date(result.scanDate).toLocaleDateString('en-US', {
|
|
@@ -654,9 +682,248 @@ async function generateHtmlReport(result, outputPath, falsePositives = []) {
|
|
|
654
682
|
architectureOverviewHtml: generateArchitectureOverviewHtml(result),
|
|
655
683
|
threatModelHtml: generateThreatModelHtml(result),
|
|
656
684
|
actionItemsHtml: generateActionItemsHtml(result),
|
|
685
|
+
// New scan statistics and quality review
|
|
686
|
+
scanStats,
|
|
687
|
+
projectTree: result.projectTree,
|
|
688
|
+
qualityReview,
|
|
657
689
|
};
|
|
658
690
|
const renderedHtml = renderTemplate(templateHtml, data);
|
|
659
691
|
fs.writeFileSync(outputPath, renderedHtml);
|
|
660
692
|
console.log(`HTML report generated: ${outputPath}`);
|
|
661
693
|
}
|
|
694
|
+
function formatDreadScore(score) {
|
|
695
|
+
if (!score)
|
|
696
|
+
return 'N/A';
|
|
697
|
+
return score.total.toFixed(2);
|
|
698
|
+
}
|
|
699
|
+
function getRiskLevel(result) {
|
|
700
|
+
const counts = getSeverityCounts(result.summary);
|
|
701
|
+
if (counts.critical > 0)
|
|
702
|
+
return 'CRITICAL';
|
|
703
|
+
if (counts.high > 0)
|
|
704
|
+
return 'HIGH';
|
|
705
|
+
if (counts.medium > 0)
|
|
706
|
+
return 'MEDIUM';
|
|
707
|
+
return 'LOW';
|
|
708
|
+
}
|
|
709
|
+
function enhanceFinding(f) {
|
|
710
|
+
return {
|
|
711
|
+
...f,
|
|
712
|
+
dreadTotal: formatDreadScore(f.dreadScore),
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
async function generateProfessionalPdf(result, outputPath, falsePositives = []) {
|
|
716
|
+
const templatePath = path.join(__dirname, '..', 'templates', 'report-pdf.html');
|
|
717
|
+
const templateHtml = fs.readFileSync(templatePath, 'utf-8');
|
|
718
|
+
const counts = getSeverityCounts(result.summary);
|
|
719
|
+
const riskLevel = getRiskLevel(result);
|
|
720
|
+
const { grade, value } = calculateScore(result);
|
|
721
|
+
// Prepare findings with enhanced data
|
|
722
|
+
const criticalFindings = result.findings.filter(f => f.severity === 'critical').map(enhanceFinding);
|
|
723
|
+
const highFindings = result.findings.filter(f => f.severity === 'high').map(enhanceFinding);
|
|
724
|
+
const mediumFindings = result.findings.filter(f => f.severity === 'medium').map(enhanceFinding);
|
|
725
|
+
const lowFindings = result.findings.filter(f => f.severity === 'low' || f.severity === 'info').map(enhanceFinding);
|
|
726
|
+
// Prepare executive summary data
|
|
727
|
+
const execSummary = result.executiveSummary;
|
|
728
|
+
const topRisks = typeof execSummary === 'object' && execSummary?.topRisks
|
|
729
|
+
? execSummary.topRisks
|
|
730
|
+
: criticalFindings.slice(0, 3).map(f => f.title);
|
|
731
|
+
const keyPositives = typeof execSummary === 'object' && execSummary?.positives
|
|
732
|
+
? execSummary.positives
|
|
733
|
+
: (result.positiveObservations || []).slice(0, 3).map(o => typeof o === 'string' ? o : o.title || o.description || '');
|
|
734
|
+
// Prepare architecture data
|
|
735
|
+
const arch = result.architectureOverview;
|
|
736
|
+
const architectureComponents = arch?.components?.map(c => ({
|
|
737
|
+
name: c.name,
|
|
738
|
+
type: c.type,
|
|
739
|
+
description: c.description,
|
|
740
|
+
trustLevel: c.trustLevel,
|
|
741
|
+
})) || [];
|
|
742
|
+
const criticalAssets = arch?.criticalAssets?.map(a => ({
|
|
743
|
+
name: a.name,
|
|
744
|
+
type: a.type,
|
|
745
|
+
location: a.location,
|
|
746
|
+
})) || [];
|
|
747
|
+
const entryPoints = arch?.dataFlows || [];
|
|
748
|
+
// Prepare threat model
|
|
749
|
+
const threatModelEntries = result.threatModel?.map(t => ({
|
|
750
|
+
id: t.id,
|
|
751
|
+
threat: t.threat,
|
|
752
|
+
category: t.category,
|
|
753
|
+
strideType: t.strideType,
|
|
754
|
+
status: t.status,
|
|
755
|
+
dreadScore: t.dreadScore,
|
|
756
|
+
relatedFindings: t.relatedFindings?.join(', ') || '',
|
|
757
|
+
})) || [];
|
|
758
|
+
// Prepare quality review
|
|
759
|
+
const qr = result.qualityReview;
|
|
760
|
+
const qualityReview = {
|
|
761
|
+
deleteItems: qr?.deleteItems?.map(i => ({
|
|
762
|
+
file: i.file,
|
|
763
|
+
lines: i.lines || 0,
|
|
764
|
+
description: i.description,
|
|
765
|
+
})) || [],
|
|
766
|
+
mergeItems: qr?.mergeItems?.map(i => ({
|
|
767
|
+
files: i.file,
|
|
768
|
+
description: i.description,
|
|
769
|
+
})) || [],
|
|
770
|
+
simplifyItems: qr?.simplifyItems?.map(i => ({
|
|
771
|
+
file: i.file,
|
|
772
|
+
description: i.description,
|
|
773
|
+
})) || [],
|
|
774
|
+
totalLinesRemovable: qr?.totalLinesRemovable || 0,
|
|
775
|
+
percentageOfCodebase: qr?.percentageOfCodebase || 0,
|
|
776
|
+
};
|
|
777
|
+
// Prepare action items
|
|
778
|
+
const actions = result.actionItems || [];
|
|
779
|
+
const mapActions = (items) => items.map(a => ({
|
|
780
|
+
id: a.id,
|
|
781
|
+
title: a.title,
|
|
782
|
+
effort: a.effort,
|
|
783
|
+
relatedFindings: a.relatedFindings?.join(', ') || '',
|
|
784
|
+
}));
|
|
785
|
+
const immediateActions = mapActions(actions.filter(a => a.priority === 'immediate'));
|
|
786
|
+
const highPriorityActions = mapActions(actions.filter(a => a.priority === 'high'));
|
|
787
|
+
const mediumPriorityActions = mapActions(actions.filter(a => a.priority === 'medium'));
|
|
788
|
+
const longTermActions = mapActions(actions.filter(a => a.priority === 'long-term'));
|
|
789
|
+
// Prepare positive observations
|
|
790
|
+
const positiveObservations = (result.positiveObservations || []).map(o => {
|
|
791
|
+
if (typeof o === 'string') {
|
|
792
|
+
return { title: o, description: '' };
|
|
793
|
+
}
|
|
794
|
+
return { title: o.title || '', description: o.description || '' };
|
|
795
|
+
});
|
|
796
|
+
// Prepare project overview
|
|
797
|
+
const projOverview = result.projectOverview;
|
|
798
|
+
const projectType = projOverview?.type || 'Application';
|
|
799
|
+
const projectDescription = projOverview?.purpose || '';
|
|
800
|
+
const stack = projOverview?.stack?.join(', ') || '';
|
|
801
|
+
const componentsText = projOverview?.keyComponents?.join(', ') || '';
|
|
802
|
+
// Prepare trust boundaries and assets as strings for display
|
|
803
|
+
const trustBoundariesText = arch?.trustBoundaries?.map(b => `${b.from} -> ${b.to} (${b.protocol || 'N/A'})`).join(', ') || '';
|
|
804
|
+
const criticalAssetsText = arch?.criticalAssets?.map(a => `${a.name} (${a.type})`).join(', ') || '';
|
|
805
|
+
const entryPointsText = entryPoints.join(', ') || '';
|
|
806
|
+
// Quality review with total items count
|
|
807
|
+
const qualityReviewWithTotals = {
|
|
808
|
+
...qualityReview,
|
|
809
|
+
totalItems: (qualityReview.deleteItems?.length || 0) +
|
|
810
|
+
(qualityReview.mergeItems?.length || 0) +
|
|
811
|
+
(qualityReview.simplifyItems?.length || 0),
|
|
812
|
+
};
|
|
813
|
+
// Generate executive summary HTML
|
|
814
|
+
const execSummaryText = generateExecutiveSummary(result);
|
|
815
|
+
const executiveSummaryHtml = `<p>${execSummaryText}</p>`;
|
|
816
|
+
// Cover description
|
|
817
|
+
const coverDescription = projectDescription ||
|
|
818
|
+
`Security assessment covering ${result.filesScanned || 0} files with ${result.findings?.length || 0} findings identified.`;
|
|
819
|
+
const data = {
|
|
820
|
+
projectName: result.projectName,
|
|
821
|
+
scanDate: new Date(result.scanDate).toLocaleDateString('en-US', {
|
|
822
|
+
year: 'numeric',
|
|
823
|
+
month: 'long',
|
|
824
|
+
day: 'numeric',
|
|
825
|
+
}),
|
|
826
|
+
scanDateFull: new Date(result.scanDate).toISOString(),
|
|
827
|
+
branch: result.branch,
|
|
828
|
+
commit: result.commit?.substring(0, 8),
|
|
829
|
+
scope: 'Full Security Assessment',
|
|
830
|
+
assessedBy: 'CoverMe Security Scanner',
|
|
831
|
+
version: '2.0',
|
|
832
|
+
// Project Overview
|
|
833
|
+
projectType,
|
|
834
|
+
projectDescription,
|
|
835
|
+
stack,
|
|
836
|
+
componentsText,
|
|
837
|
+
coverDescription,
|
|
838
|
+
// Project Tree and Lines of Code
|
|
839
|
+
projectTree: result.projectTree,
|
|
840
|
+
linesOfCode: result.linesOfCode || 0,
|
|
841
|
+
// Severity counts
|
|
842
|
+
criticalCount: counts.critical,
|
|
843
|
+
highCount: counts.high,
|
|
844
|
+
mediumCount: counts.medium,
|
|
845
|
+
lowCount: counts.low,
|
|
846
|
+
infoCount: counts.info,
|
|
847
|
+
totalFindings: result.findings?.length || 0,
|
|
848
|
+
// Risk
|
|
849
|
+
riskScore: `${grade.toUpperCase()} (${value}/100)`,
|
|
850
|
+
riskLevel,
|
|
851
|
+
// Executive Summary
|
|
852
|
+
executiveSummary: execSummaryText,
|
|
853
|
+
executiveSummaryHtml,
|
|
854
|
+
topRisks,
|
|
855
|
+
keyPositives,
|
|
856
|
+
// Architecture
|
|
857
|
+
architectureComponents,
|
|
858
|
+
criticalAssets: criticalAssetsText,
|
|
859
|
+
trustBoundaries: trustBoundariesText,
|
|
860
|
+
entryPoints: entryPointsText,
|
|
861
|
+
// Findings
|
|
862
|
+
criticalFindings,
|
|
863
|
+
highFindings,
|
|
864
|
+
mediumFindings,
|
|
865
|
+
lowFindings,
|
|
866
|
+
// Threat Model
|
|
867
|
+
threatModel: threatModelEntries,
|
|
868
|
+
// Quality Review
|
|
869
|
+
qualityReview: qualityReviewWithTotals,
|
|
870
|
+
// Resolved Issues (empty for now, can be populated from scan results)
|
|
871
|
+
resolvedIssues: [],
|
|
872
|
+
// Action Items
|
|
873
|
+
immediateActions,
|
|
874
|
+
highPriorityActions,
|
|
875
|
+
mediumPriorityActions,
|
|
876
|
+
longTermActions,
|
|
877
|
+
// Positive Observations
|
|
878
|
+
positiveObservations,
|
|
879
|
+
// Stats
|
|
880
|
+
filesScanned: result.filesScanned || 0,
|
|
881
|
+
agentCount: result.agentsUsed?.length || 0,
|
|
882
|
+
scanDuration: `${Math.round((result.scanDuration || 0) / 1000)} seconds`,
|
|
883
|
+
avgConfidence: Math.round((result.summary?.avgConfidence || 0) * 100),
|
|
884
|
+
};
|
|
885
|
+
// Register Handlebars helpers
|
|
886
|
+
handlebars_1.default.registerHelper('eq', (a, b) => a === b);
|
|
887
|
+
handlebars_1.default.registerHelper('gt', (a, b) => a > b);
|
|
888
|
+
handlebars_1.default.registerHelper('gte', (a, b) => a >= b);
|
|
889
|
+
handlebars_1.default.registerHelper('lt', (a, b) => a < b);
|
|
890
|
+
handlebars_1.default.registerHelper('add', (a, b) => a + b);
|
|
891
|
+
handlebars_1.default.registerHelper('toFixed', (n, digits) => n?.toFixed(digits) || 'N/A');
|
|
892
|
+
const template = handlebars_1.default.compile(templateHtml);
|
|
893
|
+
const renderedHtml = template(data);
|
|
894
|
+
// Generate PDF with proper pagination
|
|
895
|
+
const browser = await puppeteer_1.default.launch({
|
|
896
|
+
headless: true,
|
|
897
|
+
args: ['--no-sandbox', '--disable-setuid-sandbox'],
|
|
898
|
+
});
|
|
899
|
+
const page = await browser.newPage();
|
|
900
|
+
await page.setContent(renderedHtml, { waitUntil: 'networkidle0' });
|
|
901
|
+
// A4 PDF with proper page breaks
|
|
902
|
+
await page.pdf({
|
|
903
|
+
path: outputPath,
|
|
904
|
+
format: 'A4',
|
|
905
|
+
margin: {
|
|
906
|
+
top: '20mm',
|
|
907
|
+
right: '15mm',
|
|
908
|
+
bottom: '20mm',
|
|
909
|
+
left: '15mm',
|
|
910
|
+
},
|
|
911
|
+
printBackground: true,
|
|
912
|
+
displayHeaderFooter: true,
|
|
913
|
+
headerTemplate: `
|
|
914
|
+
<div style="width: 100%; font-size: 9px; color: #666; padding: 0 15mm; display: flex; justify-content: space-between;">
|
|
915
|
+
<span>${escapeHtml(result.projectName)} - Security Assessment</span>
|
|
916
|
+
<span>CONFIDENTIAL</span>
|
|
917
|
+
</div>
|
|
918
|
+
`,
|
|
919
|
+
footerTemplate: `
|
|
920
|
+
<div style="width: 100%; font-size: 9px; color: #666; padding: 0 15mm; display: flex; justify-content: space-between;">
|
|
921
|
+
<span>Generated by CoverMe Security Scanner</span>
|
|
922
|
+
<span>Page <span class="pageNumber"></span> of <span class="totalPages"></span></span>
|
|
923
|
+
</div>
|
|
924
|
+
`,
|
|
925
|
+
});
|
|
926
|
+
await browser.close();
|
|
927
|
+
console.log(`Professional PDF report generated: ${outputPath}`);
|
|
928
|
+
}
|
|
662
929
|
//# sourceMappingURL=generator.js.map
|