faultmesh 1.0.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 +98 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +105 -0
- package/dist/dashboard/app.js +998 -0
- package/dist/dashboard/index.html +291 -0
- package/dist/dashboard/styles.css +1120 -0
- package/dist/engine/ControlApi.d.ts +24 -0
- package/dist/engine/ControlApi.js +269 -0
- package/dist/engine/FaultMeshProxy.d.ts +16 -0
- package/dist/engine/FaultMeshProxy.js +167 -0
- package/dist/engine/TelemetryHub.d.ts +16 -0
- package/dist/engine/TelemetryHub.js +67 -0
- package/dist/engine/ToxicPipeline.d.ts +22 -0
- package/dist/engine/ToxicPipeline.js +67 -0
- package/dist/scorer/ResilienceScorer.d.ts +13 -0
- package/dist/scorer/ResilienceScorer.js +330 -0
- package/dist/scorer/SecurityAuditor.d.ts +13 -0
- package/dist/scorer/SecurityAuditor.js +428 -0
- package/dist/scorer/TrafficStormAuditor.d.ts +10 -0
- package/dist/scorer/TrafficStormAuditor.js +261 -0
- package/dist/server.d.ts +21 -0
- package/dist/server.js +169 -0
- package/dist/toxics/BandwidthToxic.d.ts +11 -0
- package/dist/toxics/BandwidthToxic.js +36 -0
- package/dist/toxics/BaseToxic.d.ts +11 -0
- package/dist/toxics/BaseToxic.js +19 -0
- package/dist/toxics/CorruptToxic.d.ts +11 -0
- package/dist/toxics/CorruptToxic.js +53 -0
- package/dist/toxics/CutToxic.d.ts +9 -0
- package/dist/toxics/CutToxic.js +31 -0
- package/dist/toxics/LatencyToxic.d.ts +13 -0
- package/dist/toxics/LatencyToxic.js +40 -0
- package/dist/toxics/StatusToxic.d.ts +9 -0
- package/dist/toxics/StatusToxic.js +22 -0
- package/dist/types.d.ts +123 -0
- package/dist/types.js +4 -0
- package/package.json +35 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { BaseToxic } from './BaseToxic.js';
|
|
2
|
+
export class LatencyToxic extends BaseToxic {
|
|
3
|
+
type = 'latency';
|
|
4
|
+
latencyMs;
|
|
5
|
+
jitterMs;
|
|
6
|
+
pendingTimer = null;
|
|
7
|
+
constructor(config) {
|
|
8
|
+
super();
|
|
9
|
+
this.latencyMs = Math.max(0, config.latencyMs);
|
|
10
|
+
this.jitterMs = Math.max(0, config.jitterMs ?? 0);
|
|
11
|
+
}
|
|
12
|
+
calculateDelay() {
|
|
13
|
+
if (this.jitterMs === 0)
|
|
14
|
+
return this.latencyMs;
|
|
15
|
+
const jitter = (Math.random() * 2 - 1) * this.jitterMs;
|
|
16
|
+
return Math.max(0, Math.round(this.latencyMs + jitter));
|
|
17
|
+
}
|
|
18
|
+
_transform(chunk, encoding, callback) {
|
|
19
|
+
const delay = this.calculateDelay();
|
|
20
|
+
this.bytesProcessed += chunk.length;
|
|
21
|
+
if (delay === 0) {
|
|
22
|
+
this.push(chunk);
|
|
23
|
+
callback();
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
this.pendingTimer = setTimeout(() => {
|
|
27
|
+
this.pendingTimer = null;
|
|
28
|
+
if (!this.destroyedCleanly) {
|
|
29
|
+
this.push(chunk);
|
|
30
|
+
callback();
|
|
31
|
+
}
|
|
32
|
+
}, delay);
|
|
33
|
+
}
|
|
34
|
+
cleanup() {
|
|
35
|
+
if (this.pendingTimer) {
|
|
36
|
+
clearTimeout(this.pendingTimer);
|
|
37
|
+
this.pendingTimer = null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { StatusToxicConfig, ToxicType } from '../types.js';
|
|
2
|
+
export declare class StatusToxic {
|
|
3
|
+
readonly type: ToxicType;
|
|
4
|
+
readonly statusCode: number;
|
|
5
|
+
readonly statusMessage: string;
|
|
6
|
+
readonly responseBody?: string;
|
|
7
|
+
constructor(config: StatusToxicConfig);
|
|
8
|
+
private getDefaultMessage;
|
|
9
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export class StatusToxic {
|
|
2
|
+
type = 'status';
|
|
3
|
+
statusCode;
|
|
4
|
+
statusMessage;
|
|
5
|
+
responseBody;
|
|
6
|
+
constructor(config) {
|
|
7
|
+
this.statusCode = config.statusCode;
|
|
8
|
+
this.statusMessage = config.statusMessage || this.getDefaultMessage(config.statusCode);
|
|
9
|
+
this.responseBody = config.responseBody;
|
|
10
|
+
}
|
|
11
|
+
getDefaultMessage(code) {
|
|
12
|
+
switch (code) {
|
|
13
|
+
case 400: return 'Bad Request (FaultMesh Injected)';
|
|
14
|
+
case 429: return 'Too Many Requests (FaultMesh Rate-Limit)';
|
|
15
|
+
case 500: return 'Internal Server Error (FaultMesh Injected)';
|
|
16
|
+
case 502: return 'Bad Gateway (FaultMesh Upstream Dropped)';
|
|
17
|
+
case 503: return 'Service Unavailable (FaultMesh Maintenance)';
|
|
18
|
+
case 504: return 'Gateway Timeout (FaultMesh Deadlock)';
|
|
19
|
+
default: return 'FaultMesh Overridden Status';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FaultMesh Core Domain Types & Contracts
|
|
3
|
+
*/
|
|
4
|
+
export type ToxicType = 'latency' | 'bandwidth' | 'cut' | 'corrupt' | 'status';
|
|
5
|
+
export type ToxicStreamDirection = 'upstream' | 'downstream';
|
|
6
|
+
export interface LatencyToxicConfig {
|
|
7
|
+
latencyMs: number;
|
|
8
|
+
jitterMs?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface BandwidthToxicConfig {
|
|
11
|
+
rateKbps: number;
|
|
12
|
+
}
|
|
13
|
+
export interface CutToxicConfig {
|
|
14
|
+
cutAfterBytes?: number;
|
|
15
|
+
cutAfterPercent?: number;
|
|
16
|
+
}
|
|
17
|
+
export interface CorruptToxicConfig {
|
|
18
|
+
corruptProbability?: number;
|
|
19
|
+
corruptType?: 'bitflip' | 'truncate' | 'garbage';
|
|
20
|
+
}
|
|
21
|
+
export interface StatusToxicConfig {
|
|
22
|
+
statusCode: number;
|
|
23
|
+
statusMessage?: string;
|
|
24
|
+
responseBody?: string;
|
|
25
|
+
}
|
|
26
|
+
export type ToxicConfigMap = {
|
|
27
|
+
latency: LatencyToxicConfig;
|
|
28
|
+
bandwidth: BandwidthToxicConfig;
|
|
29
|
+
cut: CutToxicConfig;
|
|
30
|
+
corrupt: CorruptToxicConfig;
|
|
31
|
+
status: StatusToxicConfig;
|
|
32
|
+
};
|
|
33
|
+
export interface ToxicRule<T extends ToxicType = ToxicType> {
|
|
34
|
+
id: string;
|
|
35
|
+
name: string;
|
|
36
|
+
type: T;
|
|
37
|
+
direction: ToxicStreamDirection;
|
|
38
|
+
enabled: boolean;
|
|
39
|
+
config: ToxicConfigMap[T];
|
|
40
|
+
}
|
|
41
|
+
export interface ProxyConfig {
|
|
42
|
+
port: number;
|
|
43
|
+
targetUrl: string;
|
|
44
|
+
host?: string;
|
|
45
|
+
}
|
|
46
|
+
export interface TelemetryEvent {
|
|
47
|
+
id: string;
|
|
48
|
+
timestamp: number;
|
|
49
|
+
method: string;
|
|
50
|
+
path: string;
|
|
51
|
+
statusCode: number;
|
|
52
|
+
durationMs: number;
|
|
53
|
+
bytesReceived: number;
|
|
54
|
+
bytesSent: number;
|
|
55
|
+
appliedToxics: string[];
|
|
56
|
+
error?: string;
|
|
57
|
+
}
|
|
58
|
+
export interface ProxyMetrics {
|
|
59
|
+
totalRequests: number;
|
|
60
|
+
activeConnections: number;
|
|
61
|
+
bytesProxied: number;
|
|
62
|
+
faultsInjected: number;
|
|
63
|
+
avgLatencyMs: number;
|
|
64
|
+
}
|
|
65
|
+
export interface ResilienceAttackResult {
|
|
66
|
+
name: string;
|
|
67
|
+
description: string;
|
|
68
|
+
toxicUsed: ToxicType;
|
|
69
|
+
passed: boolean;
|
|
70
|
+
latencyMs: number;
|
|
71
|
+
errorCaught?: string;
|
|
72
|
+
details: string;
|
|
73
|
+
}
|
|
74
|
+
export interface ResilienceScorecard {
|
|
75
|
+
score: number;
|
|
76
|
+
grade: 'A' | 'B' | 'C' | 'D' | 'F';
|
|
77
|
+
timestamp: number;
|
|
78
|
+
totalAttacks: number;
|
|
79
|
+
passedAttacks: number;
|
|
80
|
+
results: ResilienceAttackResult[];
|
|
81
|
+
recommendations: string[];
|
|
82
|
+
}
|
|
83
|
+
export type SecuritySeverity = 'critical' | 'high' | 'medium' | 'low';
|
|
84
|
+
export interface SecurityCheckResult {
|
|
85
|
+
id: string;
|
|
86
|
+
name: string;
|
|
87
|
+
category: 'headers' | 'cors' | 'leakage' | 'injection' | 'errors' | 'pii-leakage' | 'traversal';
|
|
88
|
+
description: string;
|
|
89
|
+
passed: boolean;
|
|
90
|
+
severity: SecuritySeverity;
|
|
91
|
+
latencyMs: number;
|
|
92
|
+
details: string;
|
|
93
|
+
remediation: string;
|
|
94
|
+
}
|
|
95
|
+
export interface SecurityScorecard {
|
|
96
|
+
score: number;
|
|
97
|
+
grade: 'A' | 'B' | 'C' | 'D' | 'F';
|
|
98
|
+
timestamp: number;
|
|
99
|
+
totalChecks: number;
|
|
100
|
+
passedChecks: number;
|
|
101
|
+
checks: SecurityCheckResult[];
|
|
102
|
+
recommendations: string[];
|
|
103
|
+
}
|
|
104
|
+
export interface TrafficStormResult {
|
|
105
|
+
id: string;
|
|
106
|
+
name: string;
|
|
107
|
+
category: 'ratelimit' | 'payload' | 'slowloris' | 'idempotency';
|
|
108
|
+
description: string;
|
|
109
|
+
passed: boolean;
|
|
110
|
+
severity: SecuritySeverity;
|
|
111
|
+
latencyMs: number;
|
|
112
|
+
details: string;
|
|
113
|
+
remediation: string;
|
|
114
|
+
}
|
|
115
|
+
export interface TrafficStormScorecard {
|
|
116
|
+
score: number;
|
|
117
|
+
grade: 'A' | 'B' | 'C' | 'D' | 'F';
|
|
118
|
+
timestamp: number;
|
|
119
|
+
totalChecks: number;
|
|
120
|
+
passedChecks: number;
|
|
121
|
+
checks: TrafficStormResult[];
|
|
122
|
+
recommendations: string[];
|
|
123
|
+
}
|
package/dist/types.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "faultmesh",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "High-Precision Network & API Fault Injection Engine and Live Resilience Dashboard",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/server.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"faultmesh": "dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"publishConfig": {
|
|
15
|
+
"registry": "https://registry.npmjs.org/",
|
|
16
|
+
"access": "public"
|
|
17
|
+
},
|
|
18
|
+
"scripts": {
|
|
19
|
+
"start": "tsx src/server.ts",
|
|
20
|
+
"build": "tsc && node scripts/copy-assets.js",
|
|
21
|
+
"test": "vitest run",
|
|
22
|
+
"test:watch": "vitest",
|
|
23
|
+
"test:coverage": "vitest run --coverage"
|
|
24
|
+
},
|
|
25
|
+
"keywords": ["chaos-engineering", "fault-injection", "proxy", "resilience", "testing"],
|
|
26
|
+
"author": "",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/node": "^22.10.1",
|
|
30
|
+
"@vitest/coverage-v8": "^2.1.8",
|
|
31
|
+
"tsx": "^4.19.2",
|
|
32
|
+
"typescript": "^5.7.2",
|
|
33
|
+
"vitest": "^2.1.8"
|
|
34
|
+
}
|
|
35
|
+
}
|