@atlascrew/apparatus 0.9.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/bin/apparatus.mjs +2 -0
- package/certs/server.crt +17 -0
- package/certs/server.key +28 -0
- package/dist/ai/client.js +104 -0
- package/dist/ai/client.js.map +1 -0
- package/dist/ai/personas.js +104 -0
- package/dist/ai/personas.js.map +1 -0
- package/dist/ai/redteam.js +1404 -0
- package/dist/ai/redteam.js.map +1 -0
- package/dist/ai/report-store.js +309 -0
- package/dist/ai/report-store.js.map +1 -0
- package/dist/app.js +525 -0
- package/dist/app.js.map +1 -0
- package/dist/attack-sim.js +69 -0
- package/dist/attack-sim.js.map +1 -0
- package/dist/attacker-tracker.js +276 -0
- package/dist/attacker-tracker.js.map +1 -0
- package/dist/blackhole.js +95 -0
- package/dist/blackhole.js.map +1 -0
- package/dist/chaos.js +88 -0
- package/dist/chaos.js.map +1 -0
- package/dist/cluster.js +462 -0
- package/dist/cluster.js.map +1 -0
- package/dist/config.js +61 -0
- package/dist/config.js.map +1 -0
- package/dist/deception.js +205 -0
- package/dist/deception.js.map +1 -0
- package/dist/demo-mode.js +109 -0
- package/dist/demo-mode.js.map +1 -0
- package/dist/dist-dashboard/assets/index-BsMhEnGu.js +648 -0
- package/dist/dist-dashboard/assets/index-CNOkYC_Q.css +10 -0
- package/dist/dist-dashboard/assets/index-CW2grvPC.js +648 -0
- package/dist/dist-dashboard/assets/logo/apparatus-favicon.svg +15 -0
- package/dist/dist-dashboard/assets/logo/apparatus-icon-dark.svg +24 -0
- package/dist/dist-dashboard/assets/logo/apparatus-icon-light.svg +24 -0
- package/dist/dist-dashboard/assets/logo/apparatus-logo-512.png +0 -0
- package/dist/dist-dashboard/assets/logo/apparatus-logo-dark.svg +18 -0
- package/dist/dist-dashboard/assets/logo/apparatus-logo.svg +17 -0
- package/dist/dist-dashboard/assets/logo/apple-touch-icon.png +0 -0
- package/dist/dist-dashboard/assets/logo/favicon-192.png +0 -0
- package/dist/dist-dashboard/assets/logo/favicon-32.png +0 -0
- package/dist/dist-dashboard/assets/logo/favicon.ico +0 -0
- package/dist/dist-dashboard/assets/logo/icon-192.png +0 -0
- package/dist/dist-dashboard/assets/logo/icon-512.png +0 -0
- package/dist/dist-dashboard/assets/logo/icon-light-512.png +0 -0
- package/dist/dist-dashboard/assets/react-vendor-DpRMSntD.js +1 -0
- package/dist/dist-dashboard/assets/router-DSc5pRwN.js +59 -0
- package/dist/dist-dashboard/docs-index.json +1577 -0
- package/dist/dist-dashboard/index.html +21 -0
- package/dist/dlp.js +40 -0
- package/dist/dlp.js.map +1 -0
- package/dist/drills.js +770 -0
- package/dist/drills.js.map +1 -0
- package/dist/echoHandler.js +113 -0
- package/dist/echoHandler.js.map +1 -0
- package/dist/escape/index.js +225 -0
- package/dist/escape/index.js.map +1 -0
- package/dist/escape/methods/dns.js +74 -0
- package/dist/escape/methods/dns.js.map +1 -0
- package/dist/escape/methods/http.js +81 -0
- package/dist/escape/methods/http.js.map +1 -0
- package/dist/escape/methods/icmp.js +36 -0
- package/dist/escape/methods/icmp.js.map +1 -0
- package/dist/escape/methods/tcp.js +38 -0
- package/dist/escape/methods/tcp.js.map +1 -0
- package/dist/escape/methods/udp.js +27 -0
- package/dist/escape/methods/udp.js.map +1 -0
- package/dist/escape/methods/websocket.js +37 -0
- package/dist/escape/methods/websocket.js.map +1 -0
- package/dist/forensics.js +111 -0
- package/dist/forensics.js.map +1 -0
- package/dist/generator.js +67 -0
- package/dist/generator.js.map +1 -0
- package/dist/ghosting.js +414 -0
- package/dist/ghosting.js.map +1 -0
- package/dist/graphql.js +44 -0
- package/dist/graphql.js.map +1 -0
- package/dist/history.js +40 -0
- package/dist/history.js.map +1 -0
- package/dist/imposter/creds.js +16 -0
- package/dist/imposter/creds.js.map +1 -0
- package/dist/imposter/index.js +44 -0
- package/dist/imposter/index.js.map +1 -0
- package/dist/imposter/providers/aws.js +103 -0
- package/dist/imposter/providers/aws.js.map +1 -0
- package/dist/imposter/providers/gcp.js +26 -0
- package/dist/imposter/providers/gcp.js.map +1 -0
- package/dist/index.js +53 -0
- package/dist/index.js.map +1 -0
- package/dist/infra-debug.js +68 -0
- package/dist/infra-debug.js.map +1 -0
- package/dist/jwt-debug.js +272 -0
- package/dist/jwt-debug.js.map +1 -0
- package/dist/kv.js +22 -0
- package/dist/kv.js.map +1 -0
- package/dist/lib/generators.js +43 -0
- package/dist/lib/generators.js.map +1 -0
- package/dist/lib/json.js +26 -0
- package/dist/lib/json.js.map +1 -0
- package/dist/logger.js +9 -0
- package/dist/logger.js.map +1 -0
- package/dist/metrics.js +20 -0
- package/dist/metrics.js.map +1 -0
- package/dist/mtd.js +30 -0
- package/dist/mtd.js.map +1 -0
- package/dist/oidc.js +69 -0
- package/dist/oidc.js.map +1 -0
- package/dist/persistence/cluster-state.js +47 -0
- package/dist/persistence/cluster-state.js.map +1 -0
- package/dist/persistence/deception-history.js +65 -0
- package/dist/persistence/deception-history.js.map +1 -0
- package/dist/persistence/drill-runs.js +138 -0
- package/dist/persistence/drill-runs.js.map +1 -0
- package/dist/persistence/request-history.js +41 -0
- package/dist/persistence/request-history.js.map +1 -0
- package/dist/persistence/scenario-catalog.js +73 -0
- package/dist/persistence/scenario-catalog.js.map +1 -0
- package/dist/persistence/status.js +51 -0
- package/dist/persistence/status.js.map +1 -0
- package/dist/persistence/tarpit-state.js +47 -0
- package/dist/persistence/tarpit-state.js.map +1 -0
- package/dist/persistence/webhook-store.js +69 -0
- package/dist/persistence/webhook-store.js.map +1 -0
- package/dist/proxy.js +28 -0
- package/dist/proxy.js.map +1 -0
- package/dist/ratelimit.js +32 -0
- package/dist/ratelimit.js.map +1 -0
- package/dist/redteam.js +442 -0
- package/dist/redteam.js.map +1 -0
- package/dist/scenarios.js +229 -0
- package/dist/scenarios.js.map +1 -0
- package/dist/scripting.js +30 -0
- package/dist/scripting.js.map +1 -0
- package/dist/self-healing.js +42 -0
- package/dist/self-healing.js.map +1 -0
- package/dist/sentinel.js +50 -0
- package/dist/sentinel.js.map +1 -0
- package/dist/server-bad-ssl.js +47 -0
- package/dist/server-bad-ssl.js.map +1 -0
- package/dist/server-grpc.js +66 -0
- package/dist/server-grpc.js.map +1 -0
- package/dist/server-http1.js +5 -0
- package/dist/server-http1.js.map +1 -0
- package/dist/server-http2.js +27 -0
- package/dist/server-http2.js.map +1 -0
- package/dist/server-icap.js +46 -0
- package/dist/server-icap.js.map +1 -0
- package/dist/server-l4.js +30 -0
- package/dist/server-l4.js.map +1 -0
- package/dist/server-mqtt.js +29 -0
- package/dist/server-mqtt.js.map +1 -0
- package/dist/server-protocols.js +18 -0
- package/dist/server-protocols.js.map +1 -0
- package/dist/server-redis.js +112 -0
- package/dist/server-redis.js.map +1 -0
- package/dist/server-smtp.js +66 -0
- package/dist/server-smtp.js.map +1 -0
- package/dist/server-syslog.js +23 -0
- package/dist/server-syslog.js.map +1 -0
- package/dist/server-ws.js +18 -0
- package/dist/server-ws.js.map +1 -0
- package/dist/sidecar/chaos/engine.js +41 -0
- package/dist/sidecar/chaos/engine.js.map +1 -0
- package/dist/sidecar/index.js +98 -0
- package/dist/sidecar/index.js.map +1 -0
- package/dist/simulator/dependency-graph.js +102 -0
- package/dist/simulator/dependency-graph.js.map +1 -0
- package/dist/simulator/supply-chain.js +67 -0
- package/dist/simulator/supply-chain.js.map +1 -0
- package/dist/sink.js +24 -0
- package/dist/sink.js.map +1 -0
- package/dist/sse-broadcast.js +105 -0
- package/dist/sse-broadcast.js.map +1 -0
- package/dist/swagger.js +309 -0
- package/dist/swagger.js.map +1 -0
- package/dist/sysinfo.js +36 -0
- package/dist/sysinfo.js.map +1 -0
- package/dist/tarpit.js +126 -0
- package/dist/tarpit.js.map +1 -0
- package/dist/tool-executor.js +315 -0
- package/dist/tool-executor.js.map +1 -0
- package/dist/tui/api-client.js +341 -0
- package/dist/tui/api-client.js.map +1 -0
- package/dist/tui/core/action-handler.js +302 -0
- package/dist/tui/core/action-handler.js.map +1 -0
- package/dist/tui/core/index.js +18 -0
- package/dist/tui/core/index.js.map +1 -0
- package/dist/tui/core/keyboard.js +329 -0
- package/dist/tui/core/keyboard.js.map +1 -0
- package/dist/tui/core/modal.js +397 -0
- package/dist/tui/core/modal.js.map +1 -0
- package/dist/tui/core/screen-manager.js +262 -0
- package/dist/tui/core/screen-manager.js.map +1 -0
- package/dist/tui/core/store.js +254 -0
- package/dist/tui/core/store.js.map +1 -0
- package/dist/tui/core/widget.js +167 -0
- package/dist/tui/core/widget.js.map +1 -0
- package/dist/tui/dashboard.js +649 -0
- package/dist/tui/dashboard.js.map +1 -0
- package/dist/tui/index.js +118 -0
- package/dist/tui/index.js.map +1 -0
- package/dist/tui/modals/add-rule-modal.js +190 -0
- package/dist/tui/modals/add-rule-modal.js.map +1 -0
- package/dist/tui/modals/dlp-output-modal.js +102 -0
- package/dist/tui/modals/dlp-output-modal.js.map +1 -0
- package/dist/tui/modals/dns-form-modal.js +26 -0
- package/dist/tui/modals/dns-form-modal.js.map +1 -0
- package/dist/tui/modals/ghost-config-modal.js +35 -0
- package/dist/tui/modals/ghost-config-modal.js.map +1 -0
- package/dist/tui/modals/har-results-modal.js +41 -0
- package/dist/tui/modals/har-results-modal.js.map +1 -0
- package/dist/tui/modals/index.js +15 -0
- package/dist/tui/modals/index.js.map +1 -0
- package/dist/tui/modals/jwt-decode-modal.js +45 -0
- package/dist/tui/modals/jwt-decode-modal.js.map +1 -0
- package/dist/tui/modals/jwt-mint-modal.js +70 -0
- package/dist/tui/modals/jwt-mint-modal.js.map +1 -0
- package/dist/tui/modals/ping-form-modal.js +19 -0
- package/dist/tui/modals/ping-form-modal.js.map +1 -0
- package/dist/tui/modals/redteam-results-modal.js +43 -0
- package/dist/tui/modals/redteam-results-modal.js.map +1 -0
- package/dist/tui/modals/scan-form-modal.js +26 -0
- package/dist/tui/modals/scan-form-modal.js.map +1 -0
- package/dist/tui/screens/defense-screen.js +281 -0
- package/dist/tui/screens/defense-screen.js.map +1 -0
- package/dist/tui/screens/forensics-screen.js +81 -0
- package/dist/tui/screens/forensics-screen.js.map +1 -0
- package/dist/tui/screens/index.js +140 -0
- package/dist/tui/screens/index.js.map +1 -0
- package/dist/tui/screens/system-screen.js +81 -0
- package/dist/tui/screens/system-screen.js.map +1 -0
- package/dist/tui/screens/testing-screen.js +429 -0
- package/dist/tui/screens/testing-screen.js.map +1 -0
- package/dist/tui/screens/traffic-screen.js +76 -0
- package/dist/tui/screens/traffic-screen.js.map +1 -0
- package/dist/tui/sse-client.js +130 -0
- package/dist/tui/sse-client.js.map +1 -0
- package/dist/tui/state/metrics-buffer.js +195 -0
- package/dist/tui/state/metrics-buffer.js.map +1 -0
- package/dist/tui/state/metrics-buffer.test.js +102 -0
- package/dist/tui/state/metrics-buffer.test.js.map +1 -0
- package/dist/tui/theme.js +136 -0
- package/dist/tui/theme.js.map +1 -0
- package/dist/tui/types.js +6 -0
- package/dist/tui/types.js.map +1 -0
- package/dist/tui/widgets/chaos-widget.js +152 -0
- package/dist/tui/widgets/chaos-widget.js.map +1 -0
- package/dist/tui/widgets/cluster-widget.js +156 -0
- package/dist/tui/widgets/cluster-widget.js.map +1 -0
- package/dist/tui/widgets/dlp-widget.js +161 -0
- package/dist/tui/widgets/dlp-widget.js.map +1 -0
- package/dist/tui/widgets/ghost-widget.js +169 -0
- package/dist/tui/widgets/ghost-widget.js.map +1 -0
- package/dist/tui/widgets/har-widget.js +173 -0
- package/dist/tui/widgets/har-widget.js.map +1 -0
- package/dist/tui/widgets/index.js +122 -0
- package/dist/tui/widgets/index.js.map +1 -0
- package/dist/tui/widgets/jwt-widget.js +177 -0
- package/dist/tui/widgets/jwt-widget.js.map +1 -0
- package/dist/tui/widgets/kv-widget.js +261 -0
- package/dist/tui/widgets/kv-widget.js.map +1 -0
- package/dist/tui/widgets/mtd-widget.js +181 -0
- package/dist/tui/widgets/mtd-widget.js.map +1 -0
- package/dist/tui/widgets/netdiag-widget.js +155 -0
- package/dist/tui/widgets/netdiag-widget.js.map +1 -0
- package/dist/tui/widgets/oidc-widget.js +162 -0
- package/dist/tui/widgets/oidc-widget.js.map +1 -0
- package/dist/tui/widgets/pcap-widget.js +239 -0
- package/dist/tui/widgets/pcap-widget.js.map +1 -0
- package/dist/tui/widgets/redteam-widget.js +155 -0
- package/dist/tui/widgets/redteam-widget.js.map +1 -0
- package/dist/tui/widgets/rps-gauge-widget.js +124 -0
- package/dist/tui/widgets/rps-gauge-widget.js.map +1 -0
- package/dist/tui/widgets/sentinel-widget.js +171 -0
- package/dist/tui/widgets/sentinel-widget.js.map +1 -0
- package/dist/tui/widgets/sparklines-widget.js +127 -0
- package/dist/tui/widgets/sparklines-widget.js.map +1 -0
- package/dist/tui/widgets/sysinfo-widget.js +197 -0
- package/dist/tui/widgets/sysinfo-widget.js.map +1 -0
- package/dist/tui/widgets/traffic-chart-widget.js +170 -0
- package/dist/tui/widgets/traffic-chart-widget.js.map +1 -0
- package/dist/tui/widgets/webhook-widget.js +259 -0
- package/dist/tui/widgets/webhook-widget.js.map +1 -0
- package/dist/utils/ip.js +18 -0
- package/dist/utils/ip.js.map +1 -0
- package/dist/victim/index.js +71 -0
- package/dist/victim/index.js.map +1 -0
- package/dist/webhook.js +88 -0
- package/dist/webhook.js.map +1 -0
- package/package.json +90 -0
- package/proto/echo.proto +19 -0
package/dist/lib/json.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safely stringify an object to JSON, handling circular references and depth limits.
|
|
3
|
+
*/
|
|
4
|
+
export function safeStringify(obj, depth = 10) {
|
|
5
|
+
const cache = new Set();
|
|
6
|
+
const replacer = (key, value) => {
|
|
7
|
+
if (typeof value === "object" && value !== null) {
|
|
8
|
+
if (cache.has(value)) {
|
|
9
|
+
return "[Circular]";
|
|
10
|
+
}
|
|
11
|
+
cache.add(value);
|
|
12
|
+
}
|
|
13
|
+
// Handle BigInt which JSON.stringify doesn't like
|
|
14
|
+
if (typeof value === "bigint") {
|
|
15
|
+
return value.toString();
|
|
16
|
+
}
|
|
17
|
+
return value;
|
|
18
|
+
};
|
|
19
|
+
try {
|
|
20
|
+
return JSON.stringify(obj, replacer);
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
return `{"error": "Failed to stringify object", "message": "${err instanceof Error ? err.message : String(err)}"}`;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=json.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json.js","sourceRoot":"","sources":["../../src/lib/json.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,GAAQ,EAAE,QAAgB,EAAE;IACtD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAE,CAAC;IAExB,MAAM,QAAQ,GAAG,CAAC,GAAW,EAAE,KAAU,EAAE,EAAE;QACzC,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YAC9C,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;gBACnB,OAAO,YAAY,CAAC;YACxB,CAAC;YACD,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;QAED,kDAAkD;QAClD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC5B,OAAO,KAAK,CAAC,QAAQ,EAAE,CAAC;QAC5B,CAAC;QAED,OAAO,KAAK,CAAC;IACjB,CAAC,CAAC;IAEF,IAAI,CAAC;QACD,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IACzC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACX,OAAO,uDAAuD,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;IACvH,CAAC;AACL,CAAC"}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import pino from "pino";
|
|
2
|
+
export const logger = pino({
|
|
3
|
+
level: process.env.NODE_ENV === "test" ? "silent" : (process.env.LOG_LEVEL || "info"),
|
|
4
|
+
transport: (process.env.NODE_ENV !== "production" && process.env.NODE_ENV !== "test") ? {
|
|
5
|
+
target: "pino-pretty",
|
|
6
|
+
options: { colorize: true, translateTime: "SYS:standard" }
|
|
7
|
+
} : undefined
|
|
8
|
+
});
|
|
9
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,CAAC;IACvB,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,MAAM,CAAC;IACrF,SAAS,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC;QACpF,MAAM,EAAE,aAAa;QACrB,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,aAAa,EAAE,cAAc,EAAE;KAC7D,CAAC,CAAC,CAAC,SAAS;CAChB,CAAC,CAAC"}
|
package/dist/metrics.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import client from "prom-client";
|
|
2
|
+
// Create a Registry
|
|
3
|
+
export const register = new client.Registry();
|
|
4
|
+
// Add default metrics (cpu, memory, event loop lag, etc.)
|
|
5
|
+
client.collectDefaultMetrics({ register, prefix: "echo_" });
|
|
6
|
+
// Define custom metrics
|
|
7
|
+
export const httpRequestDurationMicroseconds = new client.Histogram({
|
|
8
|
+
name: "echo_http_request_duration_seconds",
|
|
9
|
+
help: "Duration of HTTP requests in seconds",
|
|
10
|
+
labelNames: ["method", "route", "status_code"],
|
|
11
|
+
buckets: [0.01, 0.05, 0.1, 0.5, 1, 2, 5], // 10ms to 5s
|
|
12
|
+
registers: [register],
|
|
13
|
+
});
|
|
14
|
+
export const httpRequestsTotal = new client.Counter({
|
|
15
|
+
name: "echo_http_requests_total",
|
|
16
|
+
help: "Total number of HTTP requests",
|
|
17
|
+
labelNames: ["method", "route", "status_code"],
|
|
18
|
+
registers: [register],
|
|
19
|
+
});
|
|
20
|
+
//# sourceMappingURL=metrics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.js","sourceRoot":"","sources":["../src/metrics.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AAEjC,oBAAoB;AACpB,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;AAE9C,0DAA0D;AAC1D,MAAM,CAAC,qBAAqB,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;AAE5D,wBAAwB;AACxB,MAAM,CAAC,MAAM,+BAA+B,GAAG,IAAI,MAAM,CAAC,SAAS,CAAC;IAChE,IAAI,EAAE,oCAAoC;IAC1C,IAAI,EAAE,sCAAsC;IAC5C,UAAU,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,aAAa,CAAC;IAC9C,OAAO,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,aAAa;IACvD,SAAS,EAAE,CAAC,QAAQ,CAAC;CACxB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC;IAChD,IAAI,EAAE,0BAA0B;IAChC,IAAI,EAAE,+BAA+B;IACrC,UAAU,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,aAAa,CAAC;IAC9C,SAAS,EAAE,CAAC,QAAQ,CAAC;CACxB,CAAC,CAAC"}
|
package/dist/mtd.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { MTD_SKIP_ROUTE_PREFIXES } from "./config.js";
|
|
2
|
+
let currentPrefix = "";
|
|
3
|
+
export function setMtdPrefix(prefix) {
|
|
4
|
+
currentPrefix = prefix;
|
|
5
|
+
}
|
|
6
|
+
export function mtdHandler(req, res) {
|
|
7
|
+
if (req.method === "POST") {
|
|
8
|
+
// Rotate prefix
|
|
9
|
+
currentPrefix = req.body.prefix || Math.random().toString(36).substring(7);
|
|
10
|
+
return res.json({ status: "rotated", prefix: currentPrefix, instructions: "Prepend this prefix to all future API calls" });
|
|
11
|
+
}
|
|
12
|
+
res.json({ currentPrefix });
|
|
13
|
+
}
|
|
14
|
+
export function polymorphicRouteMiddleware(req, res, next) {
|
|
15
|
+
if (!currentPrefix)
|
|
16
|
+
return next();
|
|
17
|
+
// If prefix is active, req.url MUST start with it (except for system/management routes)
|
|
18
|
+
if (MTD_SKIP_ROUTE_PREFIXES.some(route => req.path === route || req.path.startsWith(`${route}/`)))
|
|
19
|
+
return next();
|
|
20
|
+
if (req.url.startsWith(`/${currentPrefix}`)) {
|
|
21
|
+
// Rewrite URL to strip prefix so downstream handlers work
|
|
22
|
+
req.url = req.url.replace(`/${currentPrefix}`, "") || "/";
|
|
23
|
+
next();
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
// 404/403 - Hide the real API
|
|
27
|
+
res.status(404).send("Not Found (MTD Active)");
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=mtd.js.map
|
package/dist/mtd.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mtd.js","sourceRoot":"","sources":["../src/mtd.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAEtD,IAAI,aAAa,GAAG,EAAE,CAAC;AAEvB,MAAM,UAAU,YAAY,CAAC,MAAc;IACvC,aAAa,GAAG,MAAM,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,GAAY,EAAE,GAAa;IAClD,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QACxB,gBAAgB;QAChB,aAAa,GAAG,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QAC3E,OAAO,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,YAAY,EAAE,6CAA6C,EAAE,CAAC,CAAC;IAC/H,CAAC;IAED,GAAG,CAAC,IAAI,CAAC,EAAE,aAAa,EAAE,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB;IACtF,IAAI,CAAC,aAAa;QAAE,OAAO,IAAI,EAAE,CAAC;IAElC,wFAAwF;IACxF,IAAI,uBAAuB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,KAAK,IAAI,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;QAAE,OAAO,IAAI,EAAE,CAAC;IAEjH,IAAI,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,aAAa,EAAE,CAAC,EAAE,CAAC;QAC1C,0DAA0D;QAC1D,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,aAAa,EAAE,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC;QAC1D,IAAI,EAAE,CAAC;IACX,CAAC;SAAM,CAAC;QACJ,8BAA8B;QAC9B,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAC;IACnD,CAAC;AACL,CAAC"}
|
package/dist/oidc.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import * as jose from "jose";
|
|
2
|
+
async function getKeys() {
|
|
3
|
+
const { publicKey, privateKey } = await jose.generateKeyPair("RS256");
|
|
4
|
+
const keyPair = { publicKey, privateKey };
|
|
5
|
+
const jwk = await jose.exportJWK(publicKey);
|
|
6
|
+
jwk.kid = "simulated-key-id-1";
|
|
7
|
+
jwk.use = "sig";
|
|
8
|
+
jwk.alg = "RS256";
|
|
9
|
+
return {
|
|
10
|
+
keyPair,
|
|
11
|
+
jwks: { keys: [jwk] },
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
let keyMaterialPromise;
|
|
15
|
+
async function getOrCreateKeys() {
|
|
16
|
+
if (!keyMaterialPromise) {
|
|
17
|
+
keyMaterialPromise = getKeys().catch((error) => {
|
|
18
|
+
keyMaterialPromise = undefined;
|
|
19
|
+
throw error;
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
return keyMaterialPromise;
|
|
23
|
+
}
|
|
24
|
+
export async function getOidcSigningMaterial() {
|
|
25
|
+
return getOrCreateKeys();
|
|
26
|
+
}
|
|
27
|
+
export async function jwksHandler(req, res) {
|
|
28
|
+
const { jwks } = await getOrCreateKeys();
|
|
29
|
+
res.json(jwks);
|
|
30
|
+
}
|
|
31
|
+
export async function tokenMintHandler(req, res) {
|
|
32
|
+
const { keyPair } = await getOrCreateKeys();
|
|
33
|
+
try {
|
|
34
|
+
// Allow custom claims via body
|
|
35
|
+
const customClaims = req.body || {};
|
|
36
|
+
const jwt = await new jose.SignJWT({
|
|
37
|
+
iss: "urn:apparatus:oidc",
|
|
38
|
+
aud: "urn:apparatus:client",
|
|
39
|
+
...customClaims
|
|
40
|
+
})
|
|
41
|
+
.setProtectedHeader({ alg: "RS256", kid: "simulated-key-id-1" })
|
|
42
|
+
.setIssuedAt()
|
|
43
|
+
.setExpirationTime("1h")
|
|
44
|
+
.sign(keyPair.privateKey);
|
|
45
|
+
res.json({
|
|
46
|
+
access_token: jwt,
|
|
47
|
+
token_type: "Bearer",
|
|
48
|
+
expires_in: 3600
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
res.status(500).json({ error: "Token generation failed", details: err.message });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export function oidcDiscoveryHandler(req, res) {
|
|
56
|
+
const proto = req.protocol;
|
|
57
|
+
const host = req.get("host");
|
|
58
|
+
const baseUrl = `${proto}://${host}`;
|
|
59
|
+
res.json({
|
|
60
|
+
issuer: "urn:apparatus:oidc",
|
|
61
|
+
authorization_endpoint: `${baseUrl}/auth/authorize`, // Not implemented, just placeholder
|
|
62
|
+
token_endpoint: `${baseUrl}/auth/token`,
|
|
63
|
+
jwks_uri: `${baseUrl}/.well-known/jwks.json`,
|
|
64
|
+
response_types_supported: ["token"],
|
|
65
|
+
subject_types_supported: ["public"],
|
|
66
|
+
id_token_signing_alg_values_supported: ["RS256"]
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=oidc.js.map
|
package/dist/oidc.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oidc.js","sourceRoot":"","sources":["../src/oidc.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { logger } from "../logger.js";
|
|
5
|
+
function isPersistedMember(value) {
|
|
6
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
7
|
+
return false;
|
|
8
|
+
const candidate = value;
|
|
9
|
+
return typeof candidate.ip === "string" && Number.isFinite(candidate.lastSeen);
|
|
10
|
+
}
|
|
11
|
+
export function loadClusterStateSync(statePath) {
|
|
12
|
+
if (!statePath) {
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
const raw = readFileSync(statePath, "utf8");
|
|
17
|
+
const parsed = JSON.parse(raw);
|
|
18
|
+
if (Array.isArray(parsed)) {
|
|
19
|
+
return parsed.filter(isPersistedMember);
|
|
20
|
+
}
|
|
21
|
+
if (parsed && typeof parsed === "object" && Array.isArray(parsed.members)) {
|
|
22
|
+
return parsed.members.filter(isPersistedMember);
|
|
23
|
+
}
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
if (error?.code !== "ENOENT") {
|
|
28
|
+
logger.warn({ statePath, error: error?.message }, "Cluster state load failed; continuing with in-memory store");
|
|
29
|
+
}
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export async function writeClusterState(statePath, members) {
|
|
34
|
+
if (!statePath) {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
await mkdir(path.dirname(statePath), { recursive: true });
|
|
39
|
+
await writeFile(statePath, `${JSON.stringify({ members }, null, 2)}\n`, "utf8");
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
logger.warn({ statePath, error: error?.message }, "Cluster state persist failed; keeping data in memory");
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=cluster-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cluster-state.js","sourceRoot":"","sources":["../../src/persistence/cluster-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAOtC,SAAS,iBAAiB,CAAC,KAAc;IACrC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9E,MAAM,SAAS,GAAG,KAA+B,CAAC;IAClD,OAAO,OAAO,SAAS,CAAC,EAAE,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;AACnF,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,SAAiB;IAClD,IAAI,CAAC,SAAS,EAAE,CAAC;QACb,OAAO,EAAE,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACD,MAAM,GAAG,GAAG,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAY,CAAC;QAE1C,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACxB,OAAO,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;QAC5C,CAAC;QAED,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAE,MAAkC,CAAC,OAAO,CAAC,EAAE,CAAC;YACrG,OAAQ,MAAiC,CAAC,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;QAChF,CAAC;QAED,OAAO,EAAE,CAAC;IACd,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QAClB,IAAI,KAAK,EAAE,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC3B,MAAM,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,4DAA4D,CAAC,CAAC;QACpH,CAAC;QACD,OAAO,EAAE,CAAC;IACd,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACnC,SAAiB,EACjB,OAAiC;IAEjC,IAAI,CAAC,SAAS,EAAE,CAAC;QACb,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,IAAI,CAAC;QACD,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1D,MAAM,SAAS,CAAC,SAAS,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAChF,OAAO,IAAI,CAAC;IAChB,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QAClB,MAAM,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,sDAAsD,CAAC,CAAC;QAC1G,OAAO,KAAK,CAAC;IACjB,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { logger } from "../logger.js";
|
|
4
|
+
function isRecord(value) {
|
|
5
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6
|
+
}
|
|
7
|
+
function isPersistedDeceptionType(value) {
|
|
8
|
+
return value === "honeypot_hit" || value === "shell_command" || value === "sqli_probe";
|
|
9
|
+
}
|
|
10
|
+
function isPersistedDeceptionEvent(value) {
|
|
11
|
+
if (!isRecord(value))
|
|
12
|
+
return false;
|
|
13
|
+
if (typeof value.timestamp !== "string")
|
|
14
|
+
return false;
|
|
15
|
+
if (typeof value.ip !== "string")
|
|
16
|
+
return false;
|
|
17
|
+
if (!isPersistedDeceptionType(value.type))
|
|
18
|
+
return false;
|
|
19
|
+
if (typeof value.route !== "string")
|
|
20
|
+
return false;
|
|
21
|
+
if (typeof value.sessionId !== "undefined" && typeof value.sessionId !== "string")
|
|
22
|
+
return false;
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
function parseDeceptionHistory(payload) {
|
|
26
|
+
if (Array.isArray(payload)) {
|
|
27
|
+
return payload.filter(isPersistedDeceptionEvent);
|
|
28
|
+
}
|
|
29
|
+
if (isRecord(payload) && Array.isArray(payload.events)) {
|
|
30
|
+
return payload.events.filter(isPersistedDeceptionEvent);
|
|
31
|
+
}
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
export async function loadDeceptionHistory(historyPath) {
|
|
35
|
+
if (!historyPath) {
|
|
36
|
+
return [];
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
const raw = await readFile(historyPath, "utf8");
|
|
40
|
+
return parseDeceptionHistory(JSON.parse(raw));
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
if (error?.code === "ENOENT") {
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
logger.warn({ historyPath, error: error?.message }, "Deception history load failed; continuing with in-memory store");
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export async function writeDeceptionHistory(historyPath, events) {
|
|
51
|
+
if (!historyPath) {
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
await mkdir(path.dirname(historyPath), { recursive: true });
|
|
56
|
+
const payload = JSON.stringify({ events }, null, 2);
|
|
57
|
+
await writeFile(historyPath, `${payload}\n`, "utf8");
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
logger.warn({ historyPath, error: error?.message }, "Deception history persist failed; keeping data in memory");
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=deception-history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deception-history.js","sourceRoot":"","sources":["../../src/persistence/deception-history.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { logger } from "../logger.js";
|
|
4
|
+
function isRecord(value) {
|
|
5
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6
|
+
}
|
|
7
|
+
function isPersistedStatus(value) {
|
|
8
|
+
return value === "pending"
|
|
9
|
+
|| value === "arming"
|
|
10
|
+
|| value === "active"
|
|
11
|
+
|| value === "stabilizing"
|
|
12
|
+
|| value === "won"
|
|
13
|
+
|| value === "failed"
|
|
14
|
+
|| value === "cancelled";
|
|
15
|
+
}
|
|
16
|
+
function isTimelineEvent(value) {
|
|
17
|
+
if (!isRecord(value))
|
|
18
|
+
return false;
|
|
19
|
+
if (typeof value.at !== "string")
|
|
20
|
+
return false;
|
|
21
|
+
if (typeof value.type !== "string")
|
|
22
|
+
return false;
|
|
23
|
+
if (typeof value.message !== "string")
|
|
24
|
+
return false;
|
|
25
|
+
if (typeof value.data !== "undefined" && !isRecord(value.data))
|
|
26
|
+
return false;
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
function isSnapshot(value) {
|
|
30
|
+
if (!isRecord(value))
|
|
31
|
+
return false;
|
|
32
|
+
return typeof value.cpuPercent === "number"
|
|
33
|
+
&& typeof value.errorRate === "number"
|
|
34
|
+
&& typeof value.blockedSqliRatio === "number"
|
|
35
|
+
&& typeof value.detectedMarked === "boolean"
|
|
36
|
+
&& typeof value.clusterAttackActive === "boolean"
|
|
37
|
+
&& typeof value.ghostTrafficActive === "boolean";
|
|
38
|
+
}
|
|
39
|
+
function isScoreEntry(value) {
|
|
40
|
+
if (!isRecord(value))
|
|
41
|
+
return false;
|
|
42
|
+
return typeof value.code === "string"
|
|
43
|
+
&& typeof value.points === "number"
|
|
44
|
+
&& typeof value.reason === "string";
|
|
45
|
+
}
|
|
46
|
+
function isScore(value) {
|
|
47
|
+
if (!isRecord(value))
|
|
48
|
+
return false;
|
|
49
|
+
if (typeof value.total !== "number")
|
|
50
|
+
return false;
|
|
51
|
+
if (typeof value.ttdSec !== "number")
|
|
52
|
+
return false;
|
|
53
|
+
if (typeof value.ttmSec !== "number")
|
|
54
|
+
return false;
|
|
55
|
+
if (typeof value.ttrSec !== "number")
|
|
56
|
+
return false;
|
|
57
|
+
if (!Array.isArray(value.penalties) || !value.penalties.every(isScoreEntry))
|
|
58
|
+
return false;
|
|
59
|
+
if (!Array.isArray(value.bonuses) || !value.bonuses.every(isScoreEntry))
|
|
60
|
+
return false;
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
function isPersistedRun(value) {
|
|
64
|
+
if (!isRecord(value))
|
|
65
|
+
return false;
|
|
66
|
+
if (typeof value.runId !== "string")
|
|
67
|
+
return false;
|
|
68
|
+
if (typeof value.drillId !== "string")
|
|
69
|
+
return false;
|
|
70
|
+
if (typeof value.drillName !== "string")
|
|
71
|
+
return false;
|
|
72
|
+
if (!isPersistedStatus(value.status))
|
|
73
|
+
return false;
|
|
74
|
+
if (typeof value.startedAt !== "string")
|
|
75
|
+
return false;
|
|
76
|
+
if (typeof value.finishedAt !== "undefined" && typeof value.finishedAt !== "string")
|
|
77
|
+
return false;
|
|
78
|
+
if (typeof value.detectedAt !== "undefined" && typeof value.detectedAt !== "string")
|
|
79
|
+
return false;
|
|
80
|
+
if (typeof value.mitigatedAt !== "undefined" && typeof value.mitigatedAt !== "string")
|
|
81
|
+
return false;
|
|
82
|
+
if (typeof value.failureReason !== "undefined" && typeof value.failureReason !== "string")
|
|
83
|
+
return false;
|
|
84
|
+
if (!Array.isArray(value.timeline) || !value.timeline.every(isTimelineEvent))
|
|
85
|
+
return false;
|
|
86
|
+
if (typeof value.lastSnapshot !== "undefined" && !isSnapshot(value.lastSnapshot))
|
|
87
|
+
return false;
|
|
88
|
+
if (typeof value.score !== "undefined" && !isScore(value.score))
|
|
89
|
+
return false;
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
function parsePersistedState(payload) {
|
|
93
|
+
if (!isRecord(payload)) {
|
|
94
|
+
return { runs: [], latestRunByDrill: {} };
|
|
95
|
+
}
|
|
96
|
+
const runs = Array.isArray(payload.runs) ? payload.runs.filter(isPersistedRun) : [];
|
|
97
|
+
const latestRunByDrill = {};
|
|
98
|
+
if (isRecord(payload.latestRunByDrill)) {
|
|
99
|
+
for (const [drillId, runId] of Object.entries(payload.latestRunByDrill)) {
|
|
100
|
+
if (typeof runId === "string") {
|
|
101
|
+
latestRunByDrill[drillId] = runId;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return { runs, latestRunByDrill };
|
|
106
|
+
}
|
|
107
|
+
export async function loadDrillRunsState(statePath) {
|
|
108
|
+
if (!statePath) {
|
|
109
|
+
return { runs: [], latestRunByDrill: {} };
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
const raw = await readFile(statePath, "utf8");
|
|
113
|
+
return parsePersistedState(JSON.parse(raw));
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
if (error?.code === "ENOENT") {
|
|
117
|
+
return { runs: [], latestRunByDrill: {} };
|
|
118
|
+
}
|
|
119
|
+
logger.warn({ statePath, error: error?.message }, "Drill runs state load failed; continuing with in-memory store");
|
|
120
|
+
return { runs: [], latestRunByDrill: {} };
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
export async function writeDrillRunsState(statePath, state) {
|
|
124
|
+
if (!statePath) {
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
await mkdir(path.dirname(statePath), { recursive: true });
|
|
129
|
+
const payload = JSON.stringify(state, null, 2);
|
|
130
|
+
await writeFile(statePath, `${payload}\n`, "utf8");
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
logger.warn({ statePath, error: error?.message }, "Drill runs state persist failed; keeping data in memory");
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=drill-runs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drill-runs.js","sourceRoot":"","sources":["../../src/persistence/drill-runs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { logger } from "../logger.js";
|
|
5
|
+
export function loadRequestHistorySync(historyPath) {
|
|
6
|
+
if (!historyPath) {
|
|
7
|
+
return [];
|
|
8
|
+
}
|
|
9
|
+
try {
|
|
10
|
+
const raw = readFileSync(historyPath, "utf8");
|
|
11
|
+
const parsed = JSON.parse(raw);
|
|
12
|
+
if (Array.isArray(parsed)) {
|
|
13
|
+
return parsed;
|
|
14
|
+
}
|
|
15
|
+
if (parsed && typeof parsed === "object" && Array.isArray(parsed.entries)) {
|
|
16
|
+
return parsed.entries;
|
|
17
|
+
}
|
|
18
|
+
return [];
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
if (error?.code !== "ENOENT") {
|
|
22
|
+
logger.warn({ historyPath, error: error?.message }, "Request history load failed; continuing with in-memory store");
|
|
23
|
+
}
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export async function writeRequestHistory(historyPath, entries) {
|
|
28
|
+
if (!historyPath) {
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
await mkdir(path.dirname(historyPath), { recursive: true });
|
|
33
|
+
await writeFile(historyPath, `${JSON.stringify({ entries }, null, 2)}\n`, "utf8");
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
logger.warn({ historyPath, error: error?.message }, "Request history persist failed; keeping data in memory");
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=request-history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"request-history.js","sourceRoot":"","sources":["../../src/persistence/request-history.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC,MAAM,UAAU,sBAAsB,CAAC,WAAmB;IACtD,IAAI,CAAC,WAAW,EAAE,CAAC;QACf,OAAO,EAAE,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACD,MAAM,GAAG,GAAG,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QAC9C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAY,CAAC;QAC1C,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YACxB,OAAO,MAAM,CAAC;QAClB,CAAC;QACD,IAAI,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAE,MAAkC,CAAC,OAAO,CAAC,EAAE,CAAC;YACrG,OAAQ,MAAiC,CAAC,OAAO,CAAC;QACtD,CAAC;QACD,OAAO,EAAE,CAAC;IACd,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QAClB,IAAI,KAAK,EAAE,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC3B,MAAM,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,8DAA8D,CAAC,CAAC;QACxH,CAAC;QACD,OAAO,EAAE,CAAC;IACd,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,WAAmB,EAAE,OAAkB;IAC7E,IAAI,CAAC,WAAW,EAAE,CAAC;QACf,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,IAAI,CAAC;QACD,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5D,MAAM,SAAS,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAClF,OAAO,IAAI,CAAC;IAChB,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QAClB,MAAM,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,wDAAwD,CAAC,CAAC;QAC9G,OAAO,KAAK,CAAC;IACjB,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { logger } from "../logger.js";
|
|
4
|
+
function isRecord(value) {
|
|
5
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6
|
+
}
|
|
7
|
+
function isPersistedScenarioStep(value) {
|
|
8
|
+
if (!isRecord(value))
|
|
9
|
+
return false;
|
|
10
|
+
if (typeof value.id !== "string" || typeof value.action !== "string")
|
|
11
|
+
return false;
|
|
12
|
+
if (!isRecord(value.params))
|
|
13
|
+
return false;
|
|
14
|
+
if (typeof value.delayMs !== "undefined" && typeof value.delayMs !== "number")
|
|
15
|
+
return false;
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
function isPersistedScenario(value) {
|
|
19
|
+
if (!isRecord(value))
|
|
20
|
+
return false;
|
|
21
|
+
if (typeof value.id !== "string" || typeof value.name !== "string")
|
|
22
|
+
return false;
|
|
23
|
+
if (typeof value.createdAt !== "string")
|
|
24
|
+
return false;
|
|
25
|
+
if (typeof value.description !== "undefined" && typeof value.description !== "string")
|
|
26
|
+
return false;
|
|
27
|
+
if (!Array.isArray(value.steps) || !value.steps.every(isPersistedScenarioStep))
|
|
28
|
+
return false;
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
function parseScenarioList(payload) {
|
|
32
|
+
if (Array.isArray(payload)) {
|
|
33
|
+
return payload.filter(isPersistedScenario);
|
|
34
|
+
}
|
|
35
|
+
if (isRecord(payload) && Array.isArray(payload.scenarios)) {
|
|
36
|
+
return payload.scenarios.filter(isPersistedScenario);
|
|
37
|
+
}
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
export async function loadScenarioCatalog(catalogPath) {
|
|
41
|
+
if (!catalogPath) {
|
|
42
|
+
return new Map();
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const raw = await readFile(catalogPath, "utf8");
|
|
46
|
+
const parsed = JSON.parse(raw);
|
|
47
|
+
const scenarios = parseScenarioList(parsed);
|
|
48
|
+
return new Map(scenarios.map((scenario) => [scenario.id, scenario]));
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
if (error?.code === "ENOENT") {
|
|
52
|
+
return new Map();
|
|
53
|
+
}
|
|
54
|
+
logger.warn({ catalogPath, error: error?.message }, "Scenario catalog load failed; continuing with in-memory store");
|
|
55
|
+
return new Map();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export async function writeScenarioCatalog(catalogPath, scenarios) {
|
|
59
|
+
if (!catalogPath) {
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
await mkdir(path.dirname(catalogPath), { recursive: true });
|
|
64
|
+
const payload = JSON.stringify({ scenarios: Array.from(scenarios) }, null, 2);
|
|
65
|
+
await writeFile(catalogPath, `${payload}\n`, "utf8");
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
logger.warn({ catalogPath, error: error?.message }, "Scenario catalog persist failed; keeping data in memory");
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=scenario-catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scenario-catalog.js","sourceRoot":"","sources":["../../src/persistence/scenario-catalog.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
const persistenceStores = new Map();
|
|
2
|
+
function getOrCreateStore(key) {
|
|
3
|
+
const existing = persistenceStores.get(key);
|
|
4
|
+
if (existing) {
|
|
5
|
+
return existing;
|
|
6
|
+
}
|
|
7
|
+
const created = {
|
|
8
|
+
key,
|
|
9
|
+
path: "",
|
|
10
|
+
enabled: false,
|
|
11
|
+
hydrated: false,
|
|
12
|
+
};
|
|
13
|
+
persistenceStores.set(key, created);
|
|
14
|
+
return created;
|
|
15
|
+
}
|
|
16
|
+
export function registerPersistenceStore(key, path) {
|
|
17
|
+
const store = getOrCreateStore(key);
|
|
18
|
+
store.path = path;
|
|
19
|
+
store.enabled = Boolean(path);
|
|
20
|
+
}
|
|
21
|
+
export function markPersistenceHydrated(key) {
|
|
22
|
+
const store = getOrCreateStore(key);
|
|
23
|
+
store.hydrated = true;
|
|
24
|
+
store.lastLoadAt = new Date().toISOString();
|
|
25
|
+
}
|
|
26
|
+
export function markPersistenceWrite(key, ok) {
|
|
27
|
+
const store = getOrCreateStore(key);
|
|
28
|
+
store.lastWriteOk = ok;
|
|
29
|
+
store.lastWriteAt = new Date().toISOString();
|
|
30
|
+
}
|
|
31
|
+
export function getPersistenceHealth() {
|
|
32
|
+
const stores = Array.from(persistenceStores.values())
|
|
33
|
+
.map((store) => ({ ...store }))
|
|
34
|
+
.sort((a, b) => a.key.localeCompare(b.key));
|
|
35
|
+
const enabled = stores.filter((store) => store.enabled).length;
|
|
36
|
+
const disabled = stores.length - enabled;
|
|
37
|
+
const degraded = stores.filter((store) => store.enabled && store.lastWriteOk === false).length;
|
|
38
|
+
const healthy = enabled - degraded;
|
|
39
|
+
return {
|
|
40
|
+
generatedAt: new Date().toISOString(),
|
|
41
|
+
summary: {
|
|
42
|
+
total: stores.length,
|
|
43
|
+
enabled,
|
|
44
|
+
disabled,
|
|
45
|
+
healthy,
|
|
46
|
+
degraded,
|
|
47
|
+
},
|
|
48
|
+
stores,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/persistence/status.ts"],"names":[],"mappings":"AAUA,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAAkC,CAAC;AAEpE,SAAS,gBAAgB,CAAC,GAAW;IACjC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC5C,IAAI,QAAQ,EAAE,CAAC;QACX,OAAO,QAAQ,CAAC;IACpB,CAAC;IAED,MAAM,OAAO,GAA2B;QACpC,GAAG;QACH,IAAI,EAAE,EAAE;QACR,OAAO,EAAE,KAAK;QACd,QAAQ,EAAE,KAAK;KAClB,CAAC;IACF,iBAAiB,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACpC,OAAO,OAAO,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,GAAW,EAAE,IAAY;IAC9D,MAAM,KAAK,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;IACpC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC;IAClB,KAAK,CAAC,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,GAAW;IAC/C,MAAM,KAAK,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;IACpC,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC;IACtB,KAAK,CAAC,UAAU,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,GAAW,EAAE,EAAW;IACzD,MAAM,KAAK,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;IACpC,KAAK,CAAC,WAAW,GAAG,EAAE,CAAC;IACvB,KAAK,CAAC,WAAW,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,oBAAoB;IAChC,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,MAAM,EAAE,CAAC;SAChD,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC;SAC9B,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAEhD,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;IAC/D,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,GAAG,OAAO,CAAC;IACzC,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,WAAW,KAAK,KAAK,CAAC,CAAC,MAAM,CAAC;IAC/F,MAAM,OAAO,GAAG,OAAO,GAAG,QAAQ,CAAC;IAEnC,OAAO;QACH,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACrC,OAAO,EAAE;YACL,KAAK,EAAE,MAAM,CAAC,MAAM;YACpB,OAAO;YACP,QAAQ;YACR,OAAO;YACP,QAAQ;SACX;QACD,MAAM;KACT,CAAC;AACN,CAAC"}
|