@opena2a/oasb 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 (68) hide show
  1. package/LICENSE +98 -0
  2. package/README.md +287 -0
  3. package/config/arp-lab-default.yaml +54 -0
  4. package/config/dvaa-targets.ts +97 -0
  5. package/dist/harness/arp-wrapper.d.ts +28 -0
  6. package/dist/harness/arp-wrapper.js +133 -0
  7. package/dist/harness/dvaa-client.d.ts +45 -0
  8. package/dist/harness/dvaa-client.js +97 -0
  9. package/dist/harness/dvaa-manager.d.ts +16 -0
  10. package/dist/harness/dvaa-manager.js +131 -0
  11. package/dist/harness/event-collector.d.ts +32 -0
  12. package/dist/harness/event-collector.js +85 -0
  13. package/dist/harness/metrics.d.ts +13 -0
  14. package/dist/harness/metrics.js +55 -0
  15. package/dist/harness/mock-llm-adapter.d.ts +33 -0
  16. package/dist/harness/mock-llm-adapter.js +68 -0
  17. package/dist/harness/types.d.ts +73 -0
  18. package/dist/harness/types.js +2 -0
  19. package/package.json +39 -0
  20. package/src/atomic/enforcement/AT-ENF-001.log-action.test.ts +89 -0
  21. package/src/atomic/enforcement/AT-ENF-002.alert-callback.test.ts +120 -0
  22. package/src/atomic/enforcement/AT-ENF-003.pause-sigstop.test.ts +104 -0
  23. package/src/atomic/enforcement/AT-ENF-004.kill-sigterm.test.ts +153 -0
  24. package/src/atomic/enforcement/AT-ENF-005.resume-sigcont.test.ts +164 -0
  25. package/src/atomic/filesystem/AT-FS-001.sensitive-path.test.ts +118 -0
  26. package/src/atomic/filesystem/AT-FS-002.outside-allowed.test.ts +122 -0
  27. package/src/atomic/filesystem/AT-FS-003.credential-file.test.ts +115 -0
  28. package/src/atomic/filesystem/AT-FS-004.mass-file-creation.test.ts +137 -0
  29. package/src/atomic/filesystem/AT-FS-005.dotfile-write.test.ts +154 -0
  30. package/src/atomic/intelligence/AT-INT-001.l0-rule-match.test.ts +107 -0
  31. package/src/atomic/intelligence/AT-INT-002.l1-anomaly-score.test.ts +94 -0
  32. package/src/atomic/intelligence/AT-INT-003.l2-escalation.test.ts +124 -0
  33. package/src/atomic/intelligence/AT-INT-004.budget-exhaustion.test.ts +108 -0
  34. package/src/atomic/intelligence/AT-INT-005.baseline-learning.test.ts +121 -0
  35. package/src/atomic/network/AT-NET-001.new-outbound.test.ts +103 -0
  36. package/src/atomic/network/AT-NET-002.suspicious-host.test.ts +82 -0
  37. package/src/atomic/network/AT-NET-003.connection-burst.test.ts +91 -0
  38. package/src/atomic/network/AT-NET-004.allowed-host-bypass.test.ts +129 -0
  39. package/src/atomic/network/AT-NET-005.exfil-destination.test.ts +117 -0
  40. package/src/atomic/process/AT-PROC-001.spawn-child.test.ts +148 -0
  41. package/src/atomic/process/AT-PROC-002.suspicious-binary.test.ts +123 -0
  42. package/src/atomic/process/AT-PROC-003.high-cpu.test.ts +120 -0
  43. package/src/atomic/process/AT-PROC-004.privilege-escalation.test.ts +114 -0
  44. package/src/atomic/process/AT-PROC-005.process-terminated.test.ts +150 -0
  45. package/src/baseline/BL-001.normal-agent-profile.test.ts +140 -0
  46. package/src/baseline/BL-002.anomaly-injection.test.ts +134 -0
  47. package/src/baseline/BL-003.baseline-persistence.test.ts +130 -0
  48. package/src/e2e/E2E-001.live-filesystem-detection.test.ts +129 -0
  49. package/src/e2e/E2E-002.live-process-detection.test.ts +106 -0
  50. package/src/e2e/E2E-003.live-network-detection.test.ts +114 -0
  51. package/src/e2e/E2E-004.interceptor-process.test.ts +125 -0
  52. package/src/e2e/E2E-005.interceptor-network.test.ts +134 -0
  53. package/src/e2e/E2E-006.interceptor-filesystem.test.ts +140 -0
  54. package/src/harness/arp-wrapper.ts +121 -0
  55. package/src/harness/dvaa-client.ts +130 -0
  56. package/src/harness/dvaa-manager.ts +106 -0
  57. package/src/harness/event-collector.ts +100 -0
  58. package/src/harness/metrics.ts +64 -0
  59. package/src/harness/mock-llm-adapter.ts +90 -0
  60. package/src/harness/types.ts +77 -0
  61. package/src/integration/INT-001.data-exfil-detection.test.ts +228 -0
  62. package/src/integration/INT-002.mcp-tool-abuse.test.ts +236 -0
  63. package/src/integration/INT-003.prompt-injection-response.test.ts +238 -0
  64. package/src/integration/INT-004.a2a-trust-exploitation.test.ts +280 -0
  65. package/src/integration/INT-005.baseline-then-attack.test.ts +239 -0
  66. package/src/integration/INT-006.multi-monitor-correlation.test.ts +265 -0
  67. package/src/integration/INT-007.budget-exhaustion-attack.test.ts +249 -0
  68. package/src/integration/INT-008.kill-switch-recovery.test.ts +314 -0
@@ -0,0 +1,130 @@
1
+ import http from 'http';
2
+
3
+ interface ChatResponse {
4
+ id: string;
5
+ choices: Array<{
6
+ message: { role: string; content: string };
7
+ finish_reason: string;
8
+ }>;
9
+ }
10
+
11
+ interface MCPToolResponse {
12
+ success: boolean;
13
+ content?: string;
14
+ output?: string;
15
+ results?: unknown[];
16
+ note?: string;
17
+ }
18
+
19
+ interface HealthResponse {
20
+ status: string;
21
+ agent: string;
22
+ port: number;
23
+ }
24
+
25
+ interface StatsResponse {
26
+ totalRequests: number;
27
+ attacksDetected: number;
28
+ attacksSuccessful: number;
29
+ }
30
+
31
+ /**
32
+ * HTTP client for DVAA agent endpoints.
33
+ */
34
+ export class DVAAClient {
35
+ /** Send a chat message to an API agent */
36
+ async chat(port: number, message: string): Promise<ChatResponse> {
37
+ return this.post<ChatResponse>(port, '/v1/chat/completions', {
38
+ messages: [{ role: 'user', content: message }],
39
+ });
40
+ }
41
+
42
+ /** Execute an MCP tool on an MCP agent */
43
+ async mcpExecute(port: number, tool: string, args: Record<string, unknown>): Promise<MCPToolResponse> {
44
+ return this.post<MCPToolResponse>(port, '/mcp/execute', {
45
+ tool,
46
+ arguments: args,
47
+ });
48
+ }
49
+
50
+ /** Send an A2A message */
51
+ async a2aMessage(port: number, from: string, message: string): Promise<ChatResponse> {
52
+ return this.post<ChatResponse>(port, '/v1/chat/completions', {
53
+ messages: [
54
+ { role: 'system', content: `Message from agent: ${from}` },
55
+ { role: 'user', content: message },
56
+ ],
57
+ });
58
+ }
59
+
60
+ /** Health check */
61
+ async health(port: number): Promise<HealthResponse> {
62
+ return this.get<HealthResponse>(port, '/health');
63
+ }
64
+
65
+ /** Get stats */
66
+ async stats(port: number): Promise<StatsResponse> {
67
+ return this.get<StatsResponse>(port, '/stats');
68
+ }
69
+
70
+ private get<T>(port: number, path: string): Promise<T> {
71
+ return new Promise((resolve, reject) => {
72
+ const req = http.get(`http://localhost:${port}${path}`, (res) => {
73
+ let body = '';
74
+ res.on('data', (chunk) => { body += chunk; });
75
+ res.on('end', () => {
76
+ try {
77
+ resolve(JSON.parse(body) as T);
78
+ } catch {
79
+ reject(new Error(`Invalid JSON from port ${port}${path}: ${body.slice(0, 200)}`));
80
+ }
81
+ });
82
+ });
83
+
84
+ req.on('error', reject);
85
+ req.setTimeout(10000, () => {
86
+ req.destroy();
87
+ reject(new Error(`Request to port ${port}${path} timed out`));
88
+ });
89
+ });
90
+ }
91
+
92
+ private post<T>(port: number, path: string, body: unknown): Promise<T> {
93
+ const payload = JSON.stringify(body);
94
+
95
+ return new Promise((resolve, reject) => {
96
+ const req = http.request(
97
+ {
98
+ hostname: 'localhost',
99
+ port,
100
+ path,
101
+ method: 'POST',
102
+ headers: {
103
+ 'Content-Type': 'application/json',
104
+ 'Content-Length': Buffer.byteLength(payload),
105
+ },
106
+ },
107
+ (res) => {
108
+ let data = '';
109
+ res.on('data', (chunk) => { data += chunk; });
110
+ res.on('end', () => {
111
+ try {
112
+ resolve(JSON.parse(data) as T);
113
+ } catch {
114
+ reject(new Error(`Invalid JSON from port ${port}${path}: ${data.slice(0, 200)}`));
115
+ }
116
+ });
117
+ },
118
+ );
119
+
120
+ req.on('error', reject);
121
+ req.setTimeout(10000, () => {
122
+ req.destroy();
123
+ reject(new Error(`POST to port ${port}${path} timed out`));
124
+ });
125
+
126
+ req.write(payload);
127
+ req.end();
128
+ });
129
+ }
130
+ }
@@ -0,0 +1,106 @@
1
+ import { fork, type ChildProcess } from 'child_process';
2
+ import * as path from 'path';
3
+ import http from 'http';
4
+
5
+ const DVAA_PATH = path.resolve(__dirname, '../../../damn-vulnerable-ai-agent');
6
+ const HEALTH_CHECK_TIMEOUT = 30000;
7
+ const HEALTH_CHECK_INTERVAL = 500;
8
+
9
+ /**
10
+ * Manages the DVAA (Damn Vulnerable AI Agent) process lifecycle for integration tests.
11
+ */
12
+ export class DVAAManager {
13
+ private process: ChildProcess | null = null;
14
+ private started = false;
15
+
16
+ /** Start DVAA with all agents */
17
+ async start(): Promise<void> {
18
+ if (this.started) return;
19
+
20
+ const entryPoint = path.join(DVAA_PATH, 'src', 'index.js');
21
+
22
+ this.process = fork(entryPoint, [], {
23
+ cwd: DVAA_PATH,
24
+ stdio: 'pipe',
25
+ env: { ...process.env, NODE_ENV: 'test' },
26
+ });
27
+
28
+ this.process.on('error', (err) => {
29
+ console.error('DVAA process error:', err.message);
30
+ });
31
+
32
+ // Wait for health checks on key ports
33
+ await this.waitForHealth(3000); // Dashboard
34
+ await this.waitForHealth(3001); // SecureBot
35
+ await this.waitForHealth(3003); // LegacyBot
36
+
37
+ this.started = true;
38
+ }
39
+
40
+ /** Stop DVAA gracefully */
41
+ async stop(): Promise<void> {
42
+ if (!this.process || !this.started) return;
43
+
44
+ return new Promise<void>((resolve) => {
45
+ const timeout = setTimeout(() => {
46
+ if (this.process) {
47
+ this.process.kill('SIGKILL');
48
+ }
49
+ resolve();
50
+ }, 5000);
51
+
52
+ this.process!.once('exit', () => {
53
+ clearTimeout(timeout);
54
+ resolve();
55
+ });
56
+
57
+ this.process!.kill('SIGTERM');
58
+ this.started = false;
59
+ this.process = null;
60
+ });
61
+ }
62
+
63
+ /** Get the DVAA process PID (for ARP to monitor) */
64
+ getPid(): number | undefined {
65
+ return this.process?.pid;
66
+ }
67
+
68
+ /** Check if DVAA is running */
69
+ isRunning(): boolean {
70
+ return this.started && this.process !== null;
71
+ }
72
+
73
+ private waitForHealth(port: number): Promise<void> {
74
+ const deadline = Date.now() + HEALTH_CHECK_TIMEOUT;
75
+
76
+ return new Promise((resolve, reject) => {
77
+ const check = () => {
78
+ if (Date.now() > deadline) {
79
+ reject(new Error(`DVAA health check timed out on port ${port}`));
80
+ return;
81
+ }
82
+
83
+ const req = http.get(`http://localhost:${port}/health`, (res) => {
84
+ if (res.statusCode === 200) {
85
+ res.resume();
86
+ resolve();
87
+ } else {
88
+ res.resume();
89
+ setTimeout(check, HEALTH_CHECK_INTERVAL);
90
+ }
91
+ });
92
+
93
+ req.on('error', () => {
94
+ setTimeout(check, HEALTH_CHECK_INTERVAL);
95
+ });
96
+
97
+ req.setTimeout(2000, () => {
98
+ req.destroy();
99
+ setTimeout(check, HEALTH_CHECK_INTERVAL);
100
+ });
101
+ };
102
+
103
+ check();
104
+ });
105
+ }
106
+ }
@@ -0,0 +1,100 @@
1
+ import type { ARPEvent, EnforcementResult } from '@opena2a/arp';
2
+
3
+ /**
4
+ * Collects ARP events and enforcement results for test assertions.
5
+ * Supports async waiting for specific events with timeout.
6
+ */
7
+ export class EventCollector {
8
+ private events: ARPEvent[] = [];
9
+ private enforcements: EnforcementResult[] = [];
10
+ private waiters: Array<{
11
+ predicate: (event: ARPEvent) => boolean;
12
+ resolve: (event: ARPEvent) => void;
13
+ timer: ReturnType<typeof setTimeout>;
14
+ }> = [];
15
+
16
+ /** Handler to register on ARP's onEvent */
17
+ readonly eventHandler = (event: ARPEvent): void => {
18
+ this.events.push(event);
19
+
20
+ // Check if any waiters match
21
+ for (let i = this.waiters.length - 1; i >= 0; i--) {
22
+ const waiter = this.waiters[i];
23
+ if (waiter.predicate(event)) {
24
+ clearTimeout(waiter.timer);
25
+ waiter.resolve(event);
26
+ this.waiters.splice(i, 1);
27
+ }
28
+ }
29
+ };
30
+
31
+ /** Handler to register on ARP's onEnforcement */
32
+ readonly enforcementHandler = (result: EnforcementResult): void => {
33
+ this.enforcements.push(result);
34
+ };
35
+
36
+ /** Wait for an event matching a predicate, with timeout */
37
+ waitForEvent(
38
+ predicate: (event: ARPEvent) => boolean,
39
+ timeoutMs: number = 10000,
40
+ ): Promise<ARPEvent> {
41
+ // Check existing events first
42
+ const existing = this.events.find(predicate);
43
+ if (existing) return Promise.resolve(existing);
44
+
45
+ return new Promise((resolve, reject) => {
46
+ const timer = setTimeout(() => {
47
+ const idx = this.waiters.findIndex((w) => w.resolve === resolve);
48
+ if (idx >= 0) this.waiters.splice(idx, 1);
49
+ reject(new Error(`Timed out after ${timeoutMs}ms waiting for event`));
50
+ }, timeoutMs);
51
+
52
+ this.waiters.push({ predicate, resolve, timer });
53
+ });
54
+ }
55
+
56
+ /** Check if any event matches a predicate */
57
+ hasEvent(predicate: (event: ARPEvent) => boolean): boolean {
58
+ return this.events.some(predicate);
59
+ }
60
+
61
+ /** Get all events */
62
+ getEvents(): ARPEvent[] {
63
+ return [...this.events];
64
+ }
65
+
66
+ /** Get events by category */
67
+ eventsByCategory(category: string): ARPEvent[] {
68
+ return this.events.filter((e) => e.category === category);
69
+ }
70
+
71
+ /** Get events by severity */
72
+ eventsBySeverity(severity: string): ARPEvent[] {
73
+ return this.events.filter((e) => e.severity === severity);
74
+ }
75
+
76
+ /** Get events by source */
77
+ eventsBySource(source: string): ARPEvent[] {
78
+ return this.events.filter((e) => e.source === source);
79
+ }
80
+
81
+ /** Get all enforcement results */
82
+ getEnforcements(): EnforcementResult[] {
83
+ return [...this.enforcements];
84
+ }
85
+
86
+ /** Get enforcement results by action */
87
+ enforcementsByAction(action: string): EnforcementResult[] {
88
+ return this.enforcements.filter((e) => e.action === action);
89
+ }
90
+
91
+ /** Reset all collected data */
92
+ reset(): void {
93
+ this.events = [];
94
+ this.enforcements = [];
95
+ for (const waiter of this.waiters) {
96
+ clearTimeout(waiter.timer);
97
+ }
98
+ this.waiters = [];
99
+ }
100
+ }
@@ -0,0 +1,64 @@
1
+ import type { TestResult, TestAnnotation, SuiteMetrics } from './types';
2
+
3
+ /**
4
+ * Computes detection effectiveness metrics from test results.
5
+ */
6
+ export function computeMetrics(results: TestResult[]): SuiteMetrics {
7
+ const attacks = results.filter((r) => r.annotation.isAttack);
8
+ const benign = results.filter((r) => !r.annotation.isAttack);
9
+
10
+ const truePositives = attacks.filter((r) => r.detected).length;
11
+ const falseNegatives = attacks.filter((r) => !r.detected).length;
12
+ const trueNegatives = benign.filter((r) => !r.detected).length;
13
+ const falsePositives = benign.filter((r) => r.detected).length;
14
+
15
+ const detectionTimes = attacks
16
+ .filter((r) => r.detected && r.detectionTimeMs !== undefined)
17
+ .map((r) => r.detectionTimeMs!);
18
+
19
+ detectionTimes.sort((a, b) => a - b);
20
+
21
+ const meanDetectionTimeMs = detectionTimes.length > 0
22
+ ? detectionTimes.reduce((sum, t) => sum + t, 0) / detectionTimes.length
23
+ : 0;
24
+
25
+ const p95Index = Math.ceil(detectionTimes.length * 0.95) - 1;
26
+ const p95DetectionTimeMs = detectionTimes.length > 0
27
+ ? detectionTimes[Math.max(0, p95Index)]
28
+ : 0;
29
+
30
+ return {
31
+ totalTests: results.length,
32
+ attacks: attacks.length,
33
+ benign: benign.length,
34
+ truePositives,
35
+ falsePositives,
36
+ trueNegatives,
37
+ falseNegatives,
38
+ detectionRate: attacks.length > 0 ? truePositives / attacks.length : 1,
39
+ falsePositiveRate: benign.length > 0 ? falsePositives / benign.length : 0,
40
+ meanDetectionTimeMs,
41
+ p95DetectionTimeMs,
42
+ };
43
+ }
44
+
45
+ /** Create a test annotation for attack scenarios */
46
+ export function attackAnnotation(opts: {
47
+ atlasId?: string;
48
+ owaspId?: string;
49
+ expectedSeverity?: 'info' | 'low' | 'medium' | 'high' | 'critical';
50
+ }): TestAnnotation {
51
+ return {
52
+ isAttack: true,
53
+ expectedDetection: true,
54
+ ...opts,
55
+ };
56
+ }
57
+
58
+ /** Create a test annotation for benign scenarios */
59
+ export function benignAnnotation(): TestAnnotation {
60
+ return {
61
+ isAttack: false,
62
+ expectedDetection: false,
63
+ };
64
+ }
@@ -0,0 +1,90 @@
1
+ import type { LLMAdapter, LLMResponse } from '@opena2a/arp';
2
+
3
+ interface MockCall {
4
+ prompt: string;
5
+ maxTokens: number;
6
+ timestamp: number;
7
+ }
8
+
9
+ /**
10
+ * Deterministic LLM adapter for testing L2 intelligence layer.
11
+ * Returns structured responses based on input patterns.
12
+ */
13
+ export class MockLLMAdapter implements LLMAdapter {
14
+ readonly name = 'mock';
15
+ private calls: MockCall[] = [];
16
+ private latencyMs: number;
17
+ private costPerCall: number;
18
+
19
+ constructor(options?: { latencyMs?: number; costPerCall?: number }) {
20
+ this.latencyMs = options?.latencyMs ?? 10;
21
+ this.costPerCall = options?.costPerCall ?? 0.001;
22
+ }
23
+
24
+ async assess(prompt: string, maxTokens: number): Promise<LLMResponse> {
25
+ this.calls.push({ prompt, maxTokens, timestamp: Date.now() });
26
+
27
+ if (this.latencyMs > 0) {
28
+ await new Promise((r) => setTimeout(r, this.latencyMs));
29
+ }
30
+
31
+ const response = this.generateResponse(prompt);
32
+
33
+ return {
34
+ content: response,
35
+ inputTokens: Math.ceil(prompt.length / 4),
36
+ outputTokens: Math.ceil(response.length / 4),
37
+ model: 'mock-llm',
38
+ };
39
+ }
40
+
41
+ estimateCost(inputTokens: number, outputTokens: number): number {
42
+ return this.costPerCall;
43
+ }
44
+
45
+ async healthCheck(): Promise<boolean> {
46
+ return true;
47
+ }
48
+
49
+ /** Get number of calls made */
50
+ getCallCount(): number {
51
+ return this.calls.length;
52
+ }
53
+
54
+ /** Get all calls for assertions */
55
+ getCalls(): MockCall[] {
56
+ return [...this.calls];
57
+ }
58
+
59
+ /** Get the most recent call */
60
+ getLastCall(): MockCall | undefined {
61
+ return this.calls[this.calls.length - 1];
62
+ }
63
+
64
+ /** Reset call history */
65
+ reset(): void {
66
+ this.calls = [];
67
+ }
68
+
69
+ private generateResponse(prompt: string): string {
70
+ const lower = prompt.toLowerCase();
71
+
72
+ // Threat patterns - always flag
73
+ if (lower.includes('threat') || lower.includes('critical') || lower.includes('kill')) {
74
+ return 'CONSISTENT: NO\nCONFIDENCE: 0.95\nREASONING: Activity matches known attack pattern\nACTION: KILL';
75
+ }
76
+
77
+ // Violation patterns - flag as suspicious
78
+ if (lower.includes('violation') || lower.includes('suspicious') || lower.includes('high')) {
79
+ return 'CONSISTENT: NO\nCONFIDENCE: 0.80\nREASONING: Behavior deviates from declared capabilities\nACTION: ALERT';
80
+ }
81
+
82
+ // Anomaly patterns - moderate concern
83
+ if (lower.includes('anomaly') || lower.includes('unusual')) {
84
+ return 'CONSISTENT: NO\nCONFIDENCE: 0.60\nREASONING: Statistical anomaly detected but uncertain\nACTION: ALERT';
85
+ }
86
+
87
+ // Default - allow
88
+ return 'CONSISTENT: YES\nCONFIDENCE: 0.90\nREASONING: Activity consistent with agent purpose\nACTION: ALLOW';
89
+ }
90
+ }
@@ -0,0 +1,77 @@
1
+ import type { ARPEvent, EnforcementResult } from '@opena2a/arp';
2
+
3
+ /** Annotation metadata for test cases */
4
+ export interface TestAnnotation {
5
+ /** Is this scenario an actual attack? */
6
+ isAttack: boolean;
7
+ /** MITRE ATLAS technique ID */
8
+ atlasId?: string;
9
+ /** OWASP Agentic Top 10 category */
10
+ owaspId?: string;
11
+ /** Whether ARP should detect this */
12
+ expectedDetection: boolean;
13
+ /** Expected minimum severity if detected */
14
+ expectedSeverity?: 'info' | 'low' | 'medium' | 'high' | 'critical';
15
+ /** Timestamp when the attack was initiated */
16
+ attackTimestamp?: number;
17
+ }
18
+
19
+ /** Collected test result with timing info */
20
+ export interface TestResult {
21
+ testId: string;
22
+ annotation: TestAnnotation;
23
+ detected: boolean;
24
+ detectionTimeMs?: number;
25
+ events: ARPEvent[];
26
+ enforcements: EnforcementResult[];
27
+ }
28
+
29
+ /** Suite-level metrics */
30
+ export interface SuiteMetrics {
31
+ totalTests: number;
32
+ attacks: number;
33
+ benign: number;
34
+ truePositives: number;
35
+ falsePositives: number;
36
+ trueNegatives: number;
37
+ falseNegatives: number;
38
+ detectionRate: number;
39
+ falsePositiveRate: number;
40
+ meanDetectionTimeMs: number;
41
+ p95DetectionTimeMs: number;
42
+ }
43
+
44
+ /** ARP wrapper configuration for tests */
45
+ export interface LabConfig {
46
+ monitors?: {
47
+ process?: boolean;
48
+ network?: boolean;
49
+ filesystem?: boolean;
50
+ };
51
+ rules?: import('@opena2a/arp').AlertRule[];
52
+ intelligence?: {
53
+ enabled?: boolean;
54
+ };
55
+ /** Temp data dir (auto-created per test) */
56
+ dataDir?: string;
57
+ /** Filesystem paths to watch (for real FilesystemMonitor) */
58
+ filesystemWatchPaths?: string[];
59
+ /** Filesystem allowed paths (for real FilesystemMonitor) */
60
+ filesystemAllowedPaths?: string[];
61
+ /** Network allowed hosts (for real NetworkMonitor) */
62
+ networkAllowedHosts?: string[];
63
+ /** Process monitor poll interval in ms */
64
+ processIntervalMs?: number;
65
+ /** Network monitor poll interval in ms */
66
+ networkIntervalMs?: number;
67
+ /** Application-level interceptors (zero-latency hooks) */
68
+ interceptors?: {
69
+ process?: boolean;
70
+ network?: boolean;
71
+ filesystem?: boolean;
72
+ };
73
+ /** Interceptor network allowed hosts */
74
+ interceptorNetworkAllowedHosts?: string[];
75
+ /** Interceptor filesystem allowed paths */
76
+ interceptorFilesystemAllowedPaths?: string[];
77
+ }