fivosense 0.1.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.
Files changed (110) hide show
  1. package/.github/ISSUE_TEMPLATE/feature_request.md +21 -0
  2. package/.github/PULL_REQUEST_TEMPLATE.md +22 -0
  3. package/.github/workflows/ci.yml +52 -0
  4. package/BLUEPRINT.md +215 -0
  5. package/BUILD_PLAN.md +175 -0
  6. package/CONTRIBUTING.md +80 -0
  7. package/DOCS_VERIFICATION.md +232 -0
  8. package/FINAL_CHECKLIST.md +263 -0
  9. package/FINAL_SUMMARY.md +238 -0
  10. package/GITHUB_PUSH.md +64 -0
  11. package/LICENSE +21 -0
  12. package/PROGRESS.md +153 -0
  13. package/README.md +443 -0
  14. package/RELEASE_READY.md +201 -0
  15. package/SECURITY.md +211 -0
  16. package/SECURITY_DEEP_AUDIT.md +331 -0
  17. package/TODO.md +52 -0
  18. package/dist/ai/judge.d.ts +36 -0
  19. package/dist/ai/judge.d.ts.map +1 -0
  20. package/dist/ai/judge.js +75 -0
  21. package/dist/ai/judge.js.map +1 -0
  22. package/dist/cli/index.d.ts +6 -0
  23. package/dist/cli/index.d.ts.map +1 -0
  24. package/dist/cli/index.js +39 -0
  25. package/dist/cli/index.js.map +1 -0
  26. package/dist/editors/vscode.d.ts +30 -0
  27. package/dist/editors/vscode.d.ts.map +1 -0
  28. package/dist/editors/vscode.js +103 -0
  29. package/dist/editors/vscode.js.map +1 -0
  30. package/dist/engine/adversary.d.ts +24 -0
  31. package/dist/engine/adversary.d.ts.map +1 -0
  32. package/dist/engine/adversary.js +83 -0
  33. package/dist/engine/adversary.js.map +1 -0
  34. package/dist/engine/graph.d.ts +38 -0
  35. package/dist/engine/graph.d.ts.map +1 -0
  36. package/dist/engine/graph.js +131 -0
  37. package/dist/engine/graph.js.map +1 -0
  38. package/dist/engine/reach.d.ts +22 -0
  39. package/dist/engine/reach.d.ts.map +1 -0
  40. package/dist/engine/reach.js +107 -0
  41. package/dist/engine/reach.js.map +1 -0
  42. package/dist/engine/sinks.d.ts +52 -0
  43. package/dist/engine/sinks.d.ts.map +1 -0
  44. package/dist/engine/sinks.js +96 -0
  45. package/dist/engine/sinks.js.map +1 -0
  46. package/dist/engine/sources.d.ts +35 -0
  47. package/dist/engine/sources.d.ts.map +1 -0
  48. package/dist/engine/sources.js +59 -0
  49. package/dist/engine/sources.js.map +1 -0
  50. package/dist/engine/taint.d.ts +37 -0
  51. package/dist/engine/taint.d.ts.map +1 -0
  52. package/dist/engine/taint.js +83 -0
  53. package/dist/engine/taint.js.map +1 -0
  54. package/dist/engine/verify.d.ts +20 -0
  55. package/dist/engine/verify.d.ts.map +1 -0
  56. package/dist/engine/verify.js +65 -0
  57. package/dist/engine/verify.js.map +1 -0
  58. package/dist/features/badge.d.ts +20 -0
  59. package/dist/features/badge.d.ts.map +1 -0
  60. package/dist/features/badge.js +86 -0
  61. package/dist/features/badge.js.map +1 -0
  62. package/dist/features/fix.d.ts +20 -0
  63. package/dist/features/fix.d.ts.map +1 -0
  64. package/dist/features/fix.js +115 -0
  65. package/dist/features/fix.js.map +1 -0
  66. package/dist/features/roast.d.ts +23 -0
  67. package/dist/features/roast.d.ts.map +1 -0
  68. package/dist/features/roast.js +96 -0
  69. package/dist/features/roast.js.map +1 -0
  70. package/dist/hooks/agent.d.ts +19 -0
  71. package/dist/hooks/agent.d.ts.map +1 -0
  72. package/dist/hooks/agent.js +69 -0
  73. package/dist/hooks/agent.js.map +1 -0
  74. package/dist/index.d.ts +34 -0
  75. package/dist/index.d.ts.map +1 -0
  76. package/dist/index.js +116 -0
  77. package/dist/index.js.map +1 -0
  78. package/dist/rules/destructive.d.ts +35 -0
  79. package/dist/rules/destructive.d.ts.map +1 -0
  80. package/dist/rules/destructive.js +117 -0
  81. package/dist/rules/destructive.js.map +1 -0
  82. package/dist/rules/secrets.d.ts +29 -0
  83. package/dist/rules/secrets.d.ts.map +1 -0
  84. package/dist/rules/secrets.js +100 -0
  85. package/dist/rules/secrets.js.map +1 -0
  86. package/package.json +56 -0
  87. package/skill/SKILL.md +86 -0
  88. package/skill/prompts/path-judge.md +22 -0
  89. package/src/ai/judge.ts +100 -0
  90. package/src/cli/index.ts +46 -0
  91. package/src/editors/vscode.ts +125 -0
  92. package/src/engine/adversary.ts +100 -0
  93. package/src/engine/graph.ts +167 -0
  94. package/src/engine/reach.ts +141 -0
  95. package/src/engine/sinks.ts +113 -0
  96. package/src/engine/sources.ts +71 -0
  97. package/src/engine/taint.ts +117 -0
  98. package/src/engine/verify.ts +94 -0
  99. package/src/features/badge.ts +102 -0
  100. package/src/features/fix.ts +138 -0
  101. package/src/features/roast.ts +110 -0
  102. package/src/hooks/agent.ts +84 -0
  103. package/src/index.ts +147 -0
  104. package/src/rules/destructive.ts +131 -0
  105. package/src/rules/secrets.ts +120 -0
  106. package/test/engine.test.ts +110 -0
  107. package/test/features.test.ts +131 -0
  108. package/test/phase3.test.ts +129 -0
  109. package/tsconfig.json +20 -0
  110. package/vitest.config.ts +9 -0
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Fix Verification - Re-analyze code after fix to check for regressions
3
+ */
4
+
5
+ import { buildDataFlowGraph, getVulnerablePaths } from './graph.js';
6
+ import { generateTaintTraces } from './taint.js';
7
+
8
+ export interface VerificationResult {
9
+ success: boolean;
10
+ originalIssues: number;
11
+ remainingIssues: number;
12
+ newIssues: number;
13
+ regression: boolean;
14
+ message: string;
15
+ }
16
+
17
+ /**
18
+ * Verify that a fix actually resolved the vulnerability
19
+ */
20
+ export function verifyFix(
21
+ originalCode: string,
22
+ fixedCode: string,
23
+ targetLine: number
24
+ ): VerificationResult {
25
+ // Analyze original code
26
+ const originalGraph = buildDataFlowGraph(originalCode);
27
+ const originalTraces = generateTaintTraces(originalGraph, 'original.js');
28
+ const originalVulns = originalTraces.filter(t => !t.sanitized);
29
+
30
+ // Analyze fixed code
31
+ const fixedGraph = buildDataFlowGraph(fixedCode);
32
+ const fixedTraces = generateTaintTraces(fixedGraph, 'fixed.js');
33
+ const fixedVulns = fixedTraces.filter(t => !t.sanitized);
34
+
35
+ // Check for target vulnerability
36
+ const targetVuln = originalVulns.find(v => v.location.line === targetLine);
37
+ const targetFixed = !fixedVulns.find(v => v.location.line === targetLine);
38
+
39
+ // Check for regressions (new vulnerabilities introduced)
40
+ const newIssues = fixedVulns.filter(fv =>
41
+ !originalVulns.some(ov =>
42
+ ov.location.line === fv.location.line &&
43
+ ov.category === fv.category
44
+ )
45
+ ).length;
46
+
47
+ const regression = newIssues > 0;
48
+
49
+ let message = '';
50
+ if (targetFixed && !regression) {
51
+ message = '✅ Fix verified: vulnerability resolved, no regressions';
52
+ } else if (targetFixed && regression) {
53
+ message = `⚠️ Fix applied but introduced ${newIssues} new issue(s)`;
54
+ } else if (!targetFixed) {
55
+ message = '❌ Fix failed: vulnerability still present';
56
+ }
57
+
58
+ return {
59
+ success: targetFixed && !regression,
60
+ originalIssues: originalVulns.length,
61
+ remainingIssues: fixedVulns.length,
62
+ newIssues,
63
+ regression,
64
+ message,
65
+ };
66
+ }
67
+
68
+ /**
69
+ * Verify multiple fixes
70
+ */
71
+ export function verifyMultipleFixes(
72
+ originalCode: string,
73
+ fixedCode: string
74
+ ): VerificationResult {
75
+ const originalGraph = buildDataFlowGraph(originalCode);
76
+ const originalTraces = generateTaintTraces(originalGraph, 'original.js');
77
+ const originalVulns = originalTraces.filter(t => !t.sanitized);
78
+
79
+ const fixedGraph = buildDataFlowGraph(fixedCode);
80
+ const fixedTraces = generateTaintTraces(fixedGraph, 'fixed.js');
81
+ const fixedVulns = fixedTraces.filter(t => !t.sanitized);
82
+
83
+ const resolved = originalVulns.length - fixedVulns.length;
84
+ const newIssues = Math.max(0, fixedVulns.length - originalVulns.length);
85
+
86
+ return {
87
+ success: fixedVulns.length < originalVulns.length && newIssues === 0,
88
+ originalIssues: originalVulns.length,
89
+ remainingIssues: fixedVulns.length,
90
+ newIssues,
91
+ regression: newIssues > 0,
92
+ message: `Resolved ${resolved} issue(s), ${newIssues} new issue(s) introduced`,
93
+ };
94
+ }
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Security Badge Generator - Creates shareable security report cards
3
+ */
4
+
5
+ import { AuditResult } from '../index.js';
6
+
7
+ export interface SecurityBadge {
8
+ grade: string;
9
+ score: number;
10
+ color: string;
11
+ markdown: string;
12
+ shield: string;
13
+ }
14
+
15
+ /**
16
+ * Generate security badge
17
+ */
18
+ export function generateBadge(result: AuditResult): SecurityBadge {
19
+ const grade = calculateGrade(result);
20
+ const score = calculateScore(result);
21
+ const color = getGradeColor(grade);
22
+
23
+ const shield = `https://img.shields.io/badge/security-${grade}-${color}`;
24
+
25
+ const markdown = `## 🛡️ Security Report Card
26
+
27
+ ![Security Grade](${shield})
28
+
29
+ **Grade:** ${grade}
30
+ **Score:** ${score}/100
31
+
32
+ ### Summary
33
+ - Total Issues: ${result.summary.total}
34
+ - Critical: ${result.summary.critical}
35
+ - High: ${result.summary.high}
36
+ - Medium: ${result.summary.medium}
37
+
38
+ ---
39
+ Scanned by [FivoSense](https://github.com/fivosense) — Neuro-symbolic AI security scanner
40
+ `;
41
+
42
+ return {
43
+ grade,
44
+ score,
45
+ color,
46
+ markdown,
47
+ shield,
48
+ };
49
+ }
50
+
51
+ /**
52
+ * Calculate security grade (A+ to F)
53
+ */
54
+ function calculateGrade(result: AuditResult): string {
55
+ const { summary } = result;
56
+
57
+ if (summary.total === 0) return 'A+';
58
+ if (summary.critical === 0 && summary.high === 0) return 'A';
59
+ if (summary.critical === 0 && summary.high <= 2) return 'B';
60
+ if (summary.critical === 0 && summary.high <= 5) return 'C';
61
+ if (summary.critical <= 1) return 'D';
62
+ return 'F';
63
+ }
64
+
65
+ /**
66
+ * Calculate numeric security score (0-100)
67
+ */
68
+ function calculateScore(result: AuditResult): number {
69
+ const { summary } = result;
70
+
71
+ // Start at 100, deduct for issues
72
+ let score = 100;
73
+ score -= summary.critical * 20; // -20 per critical
74
+ score -= summary.high * 10; // -10 per high
75
+ score -= summary.medium * 5; // -5 per medium
76
+
77
+ return Math.max(0, score);
78
+ }
79
+
80
+ /**
81
+ * Get color for grade
82
+ */
83
+ function getGradeColor(grade: string): string {
84
+ const colors: Record<string, string> = {
85
+ 'A+': 'brightgreen',
86
+ 'A': 'green',
87
+ 'B': 'yellowgreen',
88
+ 'C': 'yellow',
89
+ 'D': 'orange',
90
+ 'F': 'red',
91
+ };
92
+
93
+ return colors[grade] || 'lightgrey';
94
+ }
95
+
96
+ /**
97
+ * Generate badge markdown for README
98
+ */
99
+ export function generateBadgeMarkdown(result: AuditResult): string {
100
+ const badge = generateBadge(result);
101
+ return badge.markdown;
102
+ }
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Auto-fix Generator - Suggests and applies security fixes
3
+ */
4
+
5
+ import { TaintTrace } from '../engine/taint.js';
6
+
7
+ export interface SecurityFix {
8
+ original: string;
9
+ fixed: string;
10
+ explanation: string;
11
+ confidence: number;
12
+ type: 'sanitize' | 'parameterize' | 'encode' | 'validate';
13
+ }
14
+
15
+ /**
16
+ * Generate fix for a vulnerability
17
+ */
18
+ export function generateFix(trace: TaintTrace, code: string): SecurityFix | null {
19
+ const { category, location } = trace;
20
+
21
+ switch (category) {
22
+ case 'sql':
23
+ return generateSQLFix(trace, code);
24
+ case 'xss':
25
+ return generateXSSFix(trace, code);
26
+ case 'command':
27
+ return generateCommandFix(trace, code);
28
+ default:
29
+ return null;
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Generate SQL injection fix
35
+ */
36
+ function generateSQLFix(trace: TaintTrace, code: string): SecurityFix {
37
+ // Extract the vulnerable line
38
+ const lines = code.split('\n');
39
+ const line = lines[trace.location.line - 1] || '';
40
+
41
+ // Detect query pattern
42
+ if (line.includes('db.execute') || line.includes('db.query')) {
43
+ return {
44
+ original: line.trim(),
45
+ fixed: line.replace(/`([^`]+)`/, (match, query) => {
46
+ // Convert template literal to parameterized query
47
+ const parameterized = query.replace(/\$\{([^}]+)\}/g, '?');
48
+ return `'${parameterized}', [${query.match(/\$\{([^}]+)\}/g)?.map((m: string) => m.slice(2, -1)).join(', ') || ''}]`;
49
+ }),
50
+ explanation: 'Use parameterized queries to prevent SQL injection',
51
+ confidence: 0.9,
52
+ type: 'parameterize',
53
+ };
54
+ }
55
+
56
+ return {
57
+ original: line.trim(),
58
+ fixed: line.trim(),
59
+ explanation: 'Manual review required - complex SQL pattern',
60
+ confidence: 0.5,
61
+ type: 'validate',
62
+ };
63
+ }
64
+
65
+ /**
66
+ * Generate XSS fix
67
+ */
68
+ function generateXSSFix(trace: TaintTrace, code: string): SecurityFix {
69
+ const lines = code.split('\n');
70
+ const line = lines[trace.location.line - 1] || '';
71
+
72
+ if (line.includes('res.send')) {
73
+ return {
74
+ original: line.trim(),
75
+ fixed: line.replace(/res\.send\(([^)]+)\)/, 'res.send(escapeHtml($1))'),
76
+ explanation: 'Escape HTML to prevent XSS',
77
+ confidence: 0.85,
78
+ type: 'encode',
79
+ };
80
+ }
81
+
82
+ if (line.includes('innerHTML')) {
83
+ return {
84
+ original: line.trim(),
85
+ fixed: line.replace(/\.innerHTML\s*=/, '.textContent ='),
86
+ explanation: 'Use textContent instead of innerHTML to prevent XSS',
87
+ confidence: 0.9,
88
+ type: 'encode',
89
+ };
90
+ }
91
+
92
+ return {
93
+ original: line.trim(),
94
+ fixed: line.trim(),
95
+ explanation: 'Manual review required - XSS context unclear',
96
+ confidence: 0.5,
97
+ type: 'encode',
98
+ };
99
+ }
100
+
101
+ /**
102
+ * Generate command injection fix
103
+ */
104
+ function generateCommandFix(trace: TaintTrace, code: string): SecurityFix {
105
+ const lines = code.split('\n');
106
+ const line = lines[trace.location.line - 1] || '';
107
+
108
+ if (line.includes('exec(')) {
109
+ return {
110
+ original: line.trim(),
111
+ fixed: line.replace(/exec\(([^)]+)\)/, 'execFile(command, args)'),
112
+ explanation: 'Use execFile with array arguments to prevent command injection',
113
+ confidence: 0.8,
114
+ type: 'validate',
115
+ };
116
+ }
117
+
118
+ return {
119
+ original: line.trim(),
120
+ fixed: line.trim(),
121
+ explanation: 'Validate and sanitize all command arguments',
122
+ confidence: 0.6,
123
+ type: 'validate',
124
+ };
125
+ }
126
+
127
+ /**
128
+ * Apply fix to code
129
+ */
130
+ export function applyFix(code: string, fix: SecurityFix, lineNumber: number): string {
131
+ const lines = code.split('\n');
132
+ if (lineNumber < 1 || lineNumber > lines.length) {
133
+ return code;
134
+ }
135
+
136
+ lines[lineNumber - 1] = fix.fixed;
137
+ return lines.join('\n');
138
+ }
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Roast Mode - Generates viral, shareable roasts for insecure code
3
+ */
4
+
5
+ import { AuditResult } from '../index.js';
6
+
7
+ export interface Roast {
8
+ title: string;
9
+ message: string;
10
+ severity: 'mild' | 'spicy' | 'brutal';
11
+ emoji: string;
12
+ }
13
+
14
+ /**
15
+ * Generate roast based on audit results
16
+ */
17
+ export function generateRoast(result: AuditResult): Roast {
18
+ const { summary } = result;
19
+ const total = summary.total;
20
+ const critical = summary.critical;
21
+ const high = summary.high;
22
+
23
+ if (total === 0) {
24
+ return {
25
+ title: 'Clean Code Champion',
26
+ message: '🎉 No vulnerabilities found! Your code is cleaner than your browser history.',
27
+ severity: 'mild',
28
+ emoji: '✨',
29
+ };
30
+ }
31
+
32
+ if (critical >= 3) {
33
+ return {
34
+ title: 'Security Nightmare',
35
+ message: `💀 ${critical} critical vulnerabilities? Even script kiddies are embarrassed for you. This code is more open than a 24/7 convenience store.`,
36
+ severity: 'brutal',
37
+ emoji: '💀',
38
+ };
39
+ }
40
+
41
+ if (critical >= 1) {
42
+ return {
43
+ title: 'Living Dangerously',
44
+ message: `🔥 ${critical} critical issue(s) detected. Your code has more holes than Swiss cheese. SQL injection goes brrr.`,
45
+ severity: 'spicy',
46
+ emoji: '🔥',
47
+ };
48
+ }
49
+
50
+ if (high >= 3) {
51
+ return {
52
+ title: 'Almost There',
53
+ message: `⚠️ ${high} high-severity issues. You're one XSS away from trending on HackerNews for the wrong reasons.`,
54
+ severity: 'spicy',
55
+ emoji: '⚠️',
56
+ };
57
+ }
58
+
59
+ return {
60
+ title: 'Needs Improvement',
61
+ message: `📝 ${total} security issue(s) found. Not terrible, but your future self will judge you.`,
62
+ severity: 'mild',
63
+ emoji: '📝',
64
+ };
65
+ }
66
+
67
+ /**
68
+ * Format roast for display
69
+ */
70
+ export function formatRoast(roast: Roast): string {
71
+ return `
72
+ ${roast.emoji} ${roast.title} ${roast.emoji}
73
+
74
+ ${roast.message}
75
+ `;
76
+ }
77
+
78
+ /**
79
+ * Generate shareable roast badge
80
+ */
81
+ export function generateRoastBadge(result: AuditResult): string {
82
+ const roast = generateRoast(result);
83
+ const grade = getSecurityGrade(result);
84
+
85
+ return `
86
+ ## 🛡️ FivoSense Security Roast
87
+
88
+ **Grade:** ${grade}
89
+ **Verdict:** ${roast.title}
90
+
91
+ ${roast.message}
92
+
93
+ ---
94
+ Roasted by [FivoSense](https://github.com/fivosense) — Neuro-symbolic security scanner
95
+ `;
96
+ }
97
+
98
+ /**
99
+ * Get security grade (A-F)
100
+ */
101
+ function getSecurityGrade(result: AuditResult): string {
102
+ const { summary } = result;
103
+
104
+ if (summary.total === 0) return 'A+';
105
+ if (summary.critical === 0 && summary.high === 0) return 'A';
106
+ if (summary.critical === 0 && summary.high <= 2) return 'B';
107
+ if (summary.critical === 0) return 'C';
108
+ if (summary.critical <= 1) return 'D';
109
+ return 'F';
110
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Agent PreToolUse Hook - Blocks dangerous AI actions in real-time
3
+ */
4
+
5
+ import { detectDestructive } from '../rules/destructive.js';
6
+ import { detectSecrets } from '../rules/secrets.js';
7
+
8
+ export interface BlockResult {
9
+ blocked: boolean;
10
+ reason: string;
11
+ severity: 'critical' | 'high' | 'medium';
12
+ suggestion?: string;
13
+ }
14
+
15
+ /**
16
+ * Check if proposed action should be blocked
17
+ */
18
+ export function checkAction(action: string, code?: string): BlockResult {
19
+ // Check for destructive commands
20
+ const destructive = detectDestructive(action);
21
+ if (destructive.length > 0) {
22
+ return {
23
+ blocked: true,
24
+ reason: `Destructive command detected: ${destructive[0].description}`,
25
+ severity: destructive[0].severity,
26
+ suggestion: 'Review the command carefully before executing',
27
+ };
28
+ }
29
+
30
+ // Check for hardcoded secrets in code
31
+ if (code) {
32
+ const secrets = detectSecrets(code);
33
+ if (secrets.length > 0) {
34
+ return {
35
+ blocked: true,
36
+ reason: `Hardcoded secret detected: ${secrets[0].description}`,
37
+ severity: 'high',
38
+ suggestion: 'Use environment variables instead',
39
+ };
40
+ }
41
+ }
42
+
43
+ return {
44
+ blocked: false,
45
+ reason: '',
46
+ severity: 'medium',
47
+ };
48
+ }
49
+
50
+ /**
51
+ * PreToolUse hook for AI agents
52
+ * Returns exit code 2 if action should be blocked
53
+ */
54
+ export function preToolUseHook(toolName: string, args: any): number {
55
+ // Check file write operations
56
+ if (toolName === 'write_file' || toolName === 'edit_file') {
57
+ const content = args.content || args.new_content || '';
58
+ const result = checkAction('', content);
59
+
60
+ if (result.blocked) {
61
+ console.error(`\n❌ BLOCKED: ${result.reason}`);
62
+ if (result.suggestion) {
63
+ console.error(`💡 Suggestion: ${result.suggestion}`);
64
+ }
65
+ return 2; // Exit code 2 signals block
66
+ }
67
+ }
68
+
69
+ // Check shell commands
70
+ if (toolName === 'bash' || toolName === 'execute') {
71
+ const command = args.command || args.cmd || '';
72
+ const result = checkAction(command);
73
+
74
+ if (result.blocked) {
75
+ console.error(`\n❌ BLOCKED: ${result.reason}`);
76
+ if (result.suggestion) {
77
+ console.error(`💡 Suggestion: ${result.suggestion}`);
78
+ }
79
+ return 2;
80
+ }
81
+ }
82
+
83
+ return 0; // Allow
84
+ }
package/src/index.ts ADDED
@@ -0,0 +1,147 @@
1
+ /**
2
+ * FivoSense - Neuro-symbolic AI security plugin
3
+ * Entry point for the engine
4
+ */
5
+
6
+ import { readFileSync, statSync } from 'fs';
7
+ import { buildDataFlowGraph, getVulnerablePaths } from './engine/graph.js';
8
+ import { generateTaintTraces, getVulnerableTraces, formatTrace } from './engine/taint.js';
9
+ import { detectSecrets } from './rules/secrets.js';
10
+ import { detectDestructive } from './rules/destructive.js';
11
+
12
+ export interface AuditResult {
13
+ vulnerabilities: any[];
14
+ secrets: any[];
15
+ destructive: any[];
16
+ summary: {
17
+ total: number;
18
+ critical: number;
19
+ high: number;
20
+ medium: number;
21
+ };
22
+ }
23
+
24
+ // Security: Max file size to prevent memory exhaustion
25
+ const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
26
+
27
+ /**
28
+ * Audit a file for security issues
29
+ */
30
+ export async function auditFile(filepath: string): Promise<AuditResult> {
31
+ // Security check: File size limit
32
+ const stats = statSync(filepath);
33
+ if (stats.size > MAX_FILE_SIZE) {
34
+ throw new Error(`File too large: ${(stats.size / 1024 / 1024).toFixed(2)}MB (max ${MAX_FILE_SIZE / 1024 / 1024}MB)`);
35
+ }
36
+
37
+ const code = readFileSync(filepath, 'utf-8');
38
+ return auditCode(code, filepath);
39
+ }
40
+
41
+ /**
42
+ * Audit code string for security issues
43
+ */
44
+ export async function auditCode(code: string, filename = 'input.js'): Promise<AuditResult> {
45
+ // Security check: Code length
46
+ if (code.length > MAX_FILE_SIZE) {
47
+ throw new Error(`Code too large: ${(code.length / 1024 / 1024).toFixed(2)}MB (max ${MAX_FILE_SIZE / 1024 / 1024}MB)`);
48
+ }
49
+
50
+ // Build data-flow graph
51
+ const graph = buildDataFlowGraph(code, filename);
52
+
53
+ // Generate taint traces
54
+ const allTraces = generateTaintTraces(graph, filename);
55
+ const vulnerabilities = getVulnerableTraces(allTraces);
56
+
57
+ // Detect secrets
58
+ const secrets = detectSecrets(code);
59
+
60
+ // Detect destructive commands
61
+ const destructive = detectDestructive(code);
62
+
63
+ // Calculate summary
64
+ const criticalCount = vulnerabilities.filter(v => v.severity === 'critical').length +
65
+ destructive.filter(d => d.severity === 'critical').length;
66
+ const highCount = vulnerabilities.filter(v => v.severity === 'high').length +
67
+ secrets.length +
68
+ destructive.filter(d => d.severity === 'high').length;
69
+ const mediumCount = vulnerabilities.filter(v => v.severity === 'medium').length;
70
+
71
+ return {
72
+ vulnerabilities,
73
+ secrets,
74
+ destructive,
75
+ summary: {
76
+ total: vulnerabilities.length + secrets.length + destructive.length,
77
+ critical: criticalCount,
78
+ high: highCount,
79
+ medium: mediumCount,
80
+ },
81
+ };
82
+ }
83
+
84
+ /**
85
+ * Format audit result for display
86
+ */
87
+ export function formatAuditResult(result: AuditResult): string {
88
+ const lines: string[] = [];
89
+
90
+ lines.push('🛡️ FivoSense Security Audit\n');
91
+ lines.push('═'.repeat(50));
92
+ lines.push('');
93
+
94
+ // Summary
95
+ lines.push('📊 Summary:');
96
+ lines.push(` Total findings: ${result.summary.total}`);
97
+ lines.push(` Critical: ${result.summary.critical}`);
98
+ lines.push(` High: ${result.summary.high}`);
99
+ lines.push(` Medium: ${result.summary.medium}`);
100
+ lines.push('');
101
+
102
+ // Vulnerabilities
103
+ if (result.vulnerabilities.length > 0) {
104
+ lines.push('❌ Vulnerabilities:');
105
+ lines.push('');
106
+ result.vulnerabilities.forEach((vuln, i) => {
107
+ lines.push(`${i + 1}. ${formatTrace(vuln)}`);
108
+ lines.push('');
109
+ });
110
+ }
111
+
112
+ // Secrets
113
+ if (result.secrets.length > 0) {
114
+ lines.push('🔑 Hardcoded Secrets:');
115
+ lines.push('');
116
+ result.secrets.forEach((secret, i) => {
117
+ lines.push(`${i + 1}. [${secret.severity.toUpperCase()}] ${secret.description}`);
118
+ lines.push(` Line ${secret.line}: ${secret.match}`);
119
+ lines.push('');
120
+ });
121
+ }
122
+
123
+ // Destructive commands
124
+ if (result.destructive.length > 0) {
125
+ lines.push('💥 Destructive Commands:');
126
+ lines.push('');
127
+ result.destructive.forEach((cmd, i) => {
128
+ lines.push(`${i + 1}. [${cmd.severity.toUpperCase()}] ${cmd.description}`);
129
+ lines.push(` Category: ${cmd.category}`);
130
+ lines.push('');
131
+ });
132
+ }
133
+
134
+ if (result.summary.total === 0) {
135
+ lines.push('✅ No security issues found!');
136
+ }
137
+
138
+ return lines.join('\n');
139
+ }
140
+
141
+ // Export main functions
142
+ export * from './engine/graph.js';
143
+ export * from './engine/taint.js';
144
+ export * from './engine/sources.js';
145
+ export * from './engine/sinks.js';
146
+ export * from './rules/secrets.js';
147
+ export * from './rules/destructive.js';