faultmesh 1.0.0 → 1.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.
- package/README.md +61 -19
- package/dist/dashboard/app.js +1906 -139
- package/dist/dashboard/index.html +393 -99
- package/dist/dashboard/styles.css +1191 -23
- package/dist/engine/ControlApi.d.ts +13 -1
- package/dist/engine/ControlApi.js +304 -14
- package/dist/engine/FaultMeshProxy.d.ts +2 -0
- package/dist/engine/FaultMeshProxy.js +41 -5
- package/dist/engine/TelemetryHub.d.ts +1 -0
- package/dist/engine/TelemetryHub.js +3 -0
- package/dist/engine/ToxicPipeline.d.ts +5 -4
- package/dist/engine/ToxicPipeline.js +17 -4
- package/dist/healer/AiHealer.d.ts +30 -0
- package/dist/healer/AiHealer.js +188 -0
- package/dist/healer/AutoHealer.d.ts +24 -0
- package/dist/healer/AutoHealer.js +503 -0
- package/dist/healer/DiffGenerator.d.ts +10 -0
- package/dist/healer/DiffGenerator.js +63 -0
- package/dist/healer/DiffUtil.d.ts +6 -0
- package/dist/healer/DiffUtil.js +67 -0
- package/dist/healer/transformers/ExpressTransformers.d.ts +43 -0
- package/dist/healer/transformers/ExpressTransformers.js +228 -0
- package/dist/healer/transformers/FastApiTransformers.d.ts +19 -0
- package/dist/healer/transformers/FastApiTransformers.js +93 -0
- package/dist/healer/transformers/GoTransformers.d.ts +19 -0
- package/dist/healer/transformers/GoTransformers.js +106 -0
- package/dist/healer/types.d.ts +59 -0
- package/dist/healer/types.js +1 -0
- package/dist/redteam/EccAgentBridge.d.ts +20 -0
- package/dist/redteam/EccAgentBridge.js +303 -0
- package/dist/redteam/RedTeamEngine.d.ts +56 -0
- package/dist/redteam/RedTeamEngine.js +709 -0
- package/dist/redteam/types.d.ts +117 -0
- package/dist/redteam/types.js +5 -0
- package/dist/scorer/ResilienceScorer.d.ts +5 -0
- package/dist/scorer/ResilienceScorer.js +323 -7
- package/dist/scorer/SecurityAuditor.d.ts +8 -0
- package/dist/scorer/SecurityAuditor.js +471 -69
- package/dist/scorer/TrafficStormAuditor.d.ts +5 -0
- package/dist/scorer/TrafficStormAuditor.js +328 -69
- package/dist/server.js +17 -10
- package/dist/types.d.ts +7 -3
- package/package.json +2 -1
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
export class AiHealer {
|
|
2
|
+
/**
|
|
3
|
+
* Checks if an AI provider is reachable or configured
|
|
4
|
+
*/
|
|
5
|
+
static async isAvailable(config) {
|
|
6
|
+
if (config?.apiKey || config?.endpoint) {
|
|
7
|
+
return { available: true, provider: config.provider };
|
|
8
|
+
}
|
|
9
|
+
if (process.env.ANTHROPIC_API_KEY)
|
|
10
|
+
return { available: true, provider: 'anthropic' };
|
|
11
|
+
if (process.env.OPENAI_API_KEY)
|
|
12
|
+
return { available: true, provider: 'openai' };
|
|
13
|
+
if (process.env.GEMINI_API_KEY)
|
|
14
|
+
return { available: true, provider: 'gemini' };
|
|
15
|
+
// Check if local Ollama instance is active (http://127.0.0.1:11434)
|
|
16
|
+
try {
|
|
17
|
+
const res = await fetch('http://127.0.0.1:11434/api/tags', { signal: AbortSignal.timeout(600) });
|
|
18
|
+
if (res.ok) {
|
|
19
|
+
return { available: true, provider: 'ollama' };
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
catch { }
|
|
23
|
+
return { available: false };
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Generates a surgical code remediation using the configured or detected LLM provider
|
|
27
|
+
*/
|
|
28
|
+
static async generateRemediation(options) {
|
|
29
|
+
const { filePath, originalContent, framework, failedChecks, config } = options;
|
|
30
|
+
let provider = config?.provider;
|
|
31
|
+
let apiKey = config?.apiKey;
|
|
32
|
+
let endpoint = config?.endpoint;
|
|
33
|
+
let model = config?.model;
|
|
34
|
+
if (!provider) {
|
|
35
|
+
if (process.env.ANTHROPIC_API_KEY) {
|
|
36
|
+
provider = 'anthropic';
|
|
37
|
+
apiKey = process.env.ANTHROPIC_API_KEY;
|
|
38
|
+
}
|
|
39
|
+
else if (process.env.OPENAI_API_KEY) {
|
|
40
|
+
provider = 'openai';
|
|
41
|
+
apiKey = process.env.OPENAI_API_KEY;
|
|
42
|
+
}
|
|
43
|
+
else if (process.env.GEMINI_API_KEY) {
|
|
44
|
+
provider = 'gemini';
|
|
45
|
+
apiKey = process.env.GEMINI_API_KEY;
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
provider = 'ollama';
|
|
49
|
+
endpoint = 'http://127.0.0.1:11434';
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const systemPrompt = `You are FaultMesh Auto-Healer, a specialized automated code remediation agent.
|
|
53
|
+
Your objective is to fix network resilience and security vulnerabilities in the provided source code.
|
|
54
|
+
|
|
55
|
+
Target Framework/Language: ${framework}
|
|
56
|
+
File Path: ${filePath}
|
|
57
|
+
|
|
58
|
+
Identified Vulnerabilities:
|
|
59
|
+
${failedChecks.map((c, i) => `${i + 1}. ${c}`).join('\n')}
|
|
60
|
+
|
|
61
|
+
MANDATORY RULES:
|
|
62
|
+
1. Fix all identified vulnerabilities according to standard, safe industry practices for ${framework}.
|
|
63
|
+
2. Preserve all existing business routes, endpoints, function signatures, variables, and logic.
|
|
64
|
+
3. Do NOT add dummy placeholders, truncation, or comments like "// rest of code remains unchanged". Return the complete, production-ready file.
|
|
65
|
+
4. Output ONLY the raw replacement source code inside a single standard markdown code block. Do NOT include any chat or greeting.`;
|
|
66
|
+
const userPrompt = `Here is the current source code of ${filePath}:\n\n\`\`\`\n${originalContent}\n\`\`\`\n\nGenerate the complete, patched source code now.`;
|
|
67
|
+
try {
|
|
68
|
+
let rawText = '';
|
|
69
|
+
if (provider === 'ollama') {
|
|
70
|
+
const ollamaUrl = endpoint || 'http://127.0.0.1:11434';
|
|
71
|
+
const ollamaModel = model || 'deepseek-coder:6.7b';
|
|
72
|
+
const res = await fetch(`${ollamaUrl}/api/generate`, {
|
|
73
|
+
method: 'POST',
|
|
74
|
+
headers: { 'Content-Type': 'application/json' },
|
|
75
|
+
body: JSON.stringify({
|
|
76
|
+
model: ollamaModel,
|
|
77
|
+
prompt: `${systemPrompt}\n\n${userPrompt}`,
|
|
78
|
+
stream: false,
|
|
79
|
+
}),
|
|
80
|
+
signal: AbortSignal.timeout(30000),
|
|
81
|
+
});
|
|
82
|
+
if (!res.ok)
|
|
83
|
+
throw new Error(`Ollama API error (${res.status}): ${await res.text()}`);
|
|
84
|
+
const data = await res.json();
|
|
85
|
+
rawText = data.response || '';
|
|
86
|
+
}
|
|
87
|
+
else if (provider === 'openai' || provider === 'custom') {
|
|
88
|
+
const openAiUrl = endpoint || 'https://api.openai.com/v1/chat/completions';
|
|
89
|
+
const openAiModel = model || 'gpt-4o';
|
|
90
|
+
const res = await fetch(openAiUrl, {
|
|
91
|
+
method: 'POST',
|
|
92
|
+
headers: {
|
|
93
|
+
'Content-Type': 'application/json',
|
|
94
|
+
...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}),
|
|
95
|
+
},
|
|
96
|
+
body: JSON.stringify({
|
|
97
|
+
model: openAiModel,
|
|
98
|
+
messages: [
|
|
99
|
+
{ role: 'system', content: systemPrompt },
|
|
100
|
+
{ role: 'user', content: userPrompt },
|
|
101
|
+
],
|
|
102
|
+
temperature: 0.1,
|
|
103
|
+
}),
|
|
104
|
+
signal: AbortSignal.timeout(30000),
|
|
105
|
+
});
|
|
106
|
+
if (!res.ok)
|
|
107
|
+
throw new Error(`OpenAI API error (${res.status}): ${await res.text()}`);
|
|
108
|
+
const data = await res.json();
|
|
109
|
+
rawText = data.choices?.[0]?.message?.content || '';
|
|
110
|
+
}
|
|
111
|
+
else if (provider === 'anthropic') {
|
|
112
|
+
const res = await fetch('https://api.anthropic.com/v1/messages', {
|
|
113
|
+
method: 'POST',
|
|
114
|
+
headers: {
|
|
115
|
+
'Content-Type': 'application/json',
|
|
116
|
+
'x-api-key': apiKey || '',
|
|
117
|
+
'anthropic-version': '2023-06-01',
|
|
118
|
+
},
|
|
119
|
+
body: JSON.stringify({
|
|
120
|
+
model: model || 'claude-3-5-sonnet-20241022',
|
|
121
|
+
max_tokens: 4096,
|
|
122
|
+
system: systemPrompt,
|
|
123
|
+
messages: [{ role: 'user', content: userPrompt }],
|
|
124
|
+
temperature: 0.1,
|
|
125
|
+
}),
|
|
126
|
+
signal: AbortSignal.timeout(30000),
|
|
127
|
+
});
|
|
128
|
+
if (!res.ok)
|
|
129
|
+
throw new Error(`Anthropic API error (${res.status}): ${await res.text()}`);
|
|
130
|
+
const data = await res.json();
|
|
131
|
+
rawText = data.content?.[0]?.text || '';
|
|
132
|
+
}
|
|
133
|
+
else if (provider === 'gemini') {
|
|
134
|
+
const geminiModel = model || 'gemini-1.5-flash';
|
|
135
|
+
const res = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/${geminiModel}:generateContent?key=${apiKey}`, {
|
|
136
|
+
method: 'POST',
|
|
137
|
+
headers: { 'Content-Type': 'application/json' },
|
|
138
|
+
body: JSON.stringify({
|
|
139
|
+
contents: [{ parts: [{ text: `${systemPrompt}\n\n${userPrompt}` }] }],
|
|
140
|
+
}),
|
|
141
|
+
signal: AbortSignal.timeout(30000),
|
|
142
|
+
});
|
|
143
|
+
if (!res.ok)
|
|
144
|
+
throw new Error(`Gemini API error (${res.status}): ${await res.text()}`);
|
|
145
|
+
const data = await res.json();
|
|
146
|
+
rawText = data.candidates?.[0]?.content?.parts?.[0]?.text || '';
|
|
147
|
+
}
|
|
148
|
+
const extracted = this.extractCodeBlock(rawText);
|
|
149
|
+
if (!extracted || extracted.trim().length === 0) {
|
|
150
|
+
return {
|
|
151
|
+
success: false,
|
|
152
|
+
content: originalContent,
|
|
153
|
+
description: 'AI model returned empty or unparseable code',
|
|
154
|
+
error: 'Empty response',
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
return {
|
|
158
|
+
success: true,
|
|
159
|
+
content: extracted,
|
|
160
|
+
description: `AI-engineered remediation for ${failedChecks.join(', ')} (${provider})`,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
return {
|
|
165
|
+
success: false,
|
|
166
|
+
content: originalContent,
|
|
167
|
+
description: `AI Remediation failed: ${err.message}`,
|
|
168
|
+
error: err.message,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Safely strips enclosing markdown code fences from model outputs
|
|
174
|
+
*/
|
|
175
|
+
static extractCodeBlock(text) {
|
|
176
|
+
const trimmed = text.trim();
|
|
177
|
+
const codeBlockMatch = trimmed.match(/^```(?:[a-zA-Z0-9_-]+)?\r?\n([\s\S]*?)\r?\n```$/);
|
|
178
|
+
if (codeBlockMatch) {
|
|
179
|
+
return codeBlockMatch[1];
|
|
180
|
+
}
|
|
181
|
+
// If multiple blocks or leading text
|
|
182
|
+
const anyBlockMatch = trimmed.match(/```(?:[a-zA-Z0-9_-]+)?\r?\n([\s\S]*?)\r?\n```/);
|
|
183
|
+
if (anyBlockMatch) {
|
|
184
|
+
return anyBlockMatch[1];
|
|
185
|
+
}
|
|
186
|
+
return trimmed;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { HealApplyOptions, HealApplyResult, HealRollbackOptions, HealRollbackResult, HealScanOptions, HealScanResult } from './types.js';
|
|
2
|
+
export declare class AutoHealer {
|
|
3
|
+
private static BLACKLISTED_NAMES;
|
|
4
|
+
/**
|
|
5
|
+
* Scan a target project directory and generate reviewable remediation patches
|
|
6
|
+
*/
|
|
7
|
+
static scan(options: HealScanOptions): Promise<HealScanResult>;
|
|
8
|
+
/**
|
|
9
|
+
* Safely applies generated remediation patches to disk with automatic backup
|
|
10
|
+
*/
|
|
11
|
+
static apply(options: HealApplyOptions): Promise<HealApplyResult>;
|
|
12
|
+
/**
|
|
13
|
+
* Restores files from a previously created .faultmesh-backup directory
|
|
14
|
+
*/
|
|
15
|
+
static rollback(options: HealRollbackOptions): Promise<HealRollbackResult>;
|
|
16
|
+
/**
|
|
17
|
+
* Validates target directory exists and prevents targeting system root or parent escapes
|
|
18
|
+
*/
|
|
19
|
+
private static validateProjectDir;
|
|
20
|
+
/**
|
|
21
|
+
* Detects project backend framework and primary entry file
|
|
22
|
+
*/
|
|
23
|
+
private static detectFrameworkAndEntry;
|
|
24
|
+
}
|