Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions src/modules/ai/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# AI Module

This minimal AI framework provides:

- A provider abstraction (`providers/ai-provider.interface.ts`) for plugging in different AI/threat-analysis backends.
- A lightweight example provider (`providers/openai.provider.ts`) that implements deterministic heuristics so teams can use the framework without network access.
- A simple `AIService` that aggregates provider results and selects a best summary.
- Config helper at `config/ai.config.ts` to choose providers at runtime.

## Usage

Create a service instance via `createAIService()` in `ai.module.ts` or construct `new AIService([new OpenAIProvider(apiKey)])`.

## Examples

- See `providers/openai.provider.ts` for required provider API (`analyzeThreat(event)`).
- Summaries implement the `ThreatSummary` interface in `interfaces/threat-summary.interface.ts`.

## Design notes

- Keep provider interface small and explicit so new providers (Azure, local models, LLMs) can be added.
- The `OpenAIProvider` currently uses local heuristics. Implementers can extend it to call external LLM APIs and enrich `confidence` and `description` fields.

## Acceptance

- Provider abstraction implemented.
- `ThreatSummary` interface documented.
- Configurable provider selection implemented via `AIConfig`.
15 changes: 15 additions & 0 deletions src/modules/ai/ai.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { AIService } from './ai.service';
import { AIProvider } from './providers/ai-provider.interface';
import { OpenAIProvider } from './providers/openai.provider';
import { AIConfig } from './config/ai.config';

export function createAIService(config: AIConfig = AIConfig.default()): AIService {
const providers: AIProvider[] = [];

if (config.provider === 'openai') {
const c = config.providers.openai;
providers.push(new OpenAIProvider(c.apiKey));
}

return new AIService(providers);
}
22 changes: 22 additions & 0 deletions src/modules/ai/ai.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { AIProvider } from './providers/ai-provider.interface';
import { ThreatSummary, Severity } from './interfaces/threat-summary.interface';

export class AIService {
constructor(private providers: AIProvider[] = []) {}

async summarize(event: any): Promise<ThreatSummary[]> {

Check warning on line 7 in src/modules/ai/ai.service.ts

View workflow job for this annotation

GitHub Actions / Linting (20.x)

Unexpected any. Specify a different type

Check warning on line 7 in src/modules/ai/ai.service.ts

View workflow job for this annotation

GitHub Actions / Linting (22.x)

Unexpected any. Specify a different type
const results = await Promise.all(this.providers.map(p => p.analyzeThreat(event)));
return results;
}

async bestSummary(event: any): Promise<ThreatSummary | null> {

Check warning on line 12 in src/modules/ai/ai.service.ts

View workflow job for this annotation

GitHub Actions / Linting (20.x)

Unexpected any. Specify a different type

Check warning on line 12 in src/modules/ai/ai.service.ts

View workflow job for this annotation

GitHub Actions / Linting (22.x)

Unexpected any. Specify a different type
const summaries = await this.summarize(event);
if (summaries.length === 0) return null;

const order: Record<Severity, number> = { low: 1, medium: 2, high: 3, critical: 4 };
summaries.sort(
(a, b) => order[b.severity] - order[a.severity] || (b.score || 0) - (a.score || 0),
);
return summaries[0];
}
}
24 changes: 24 additions & 0 deletions src/modules/ai/config/ai.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export type AIProviderName = 'openai' | 'mock';

export interface OpenAIConfig {
apiKey: string;
}

export interface AIConfigShape {
provider: AIProviderName;
providers: { openai: OpenAIConfig };
}

export class AIConfig implements AIConfigShape {
provider: AIProviderName;
providers: { openai: OpenAIConfig };

constructor(provider: AIProviderName, providers: { openai: OpenAIConfig }) {
this.provider = provider;
this.providers = providers;
}

static default(): AIConfig {
return new AIConfig('openai', { openai: { apiKey: process.env.OPENAI_API_KEY || '' } });
}
}
12 changes: 12 additions & 0 deletions src/modules/ai/interfaces/threat-summary.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export type Severity = 'low' | 'medium' | 'high' | 'critical';

export interface ThreatSummary {
title: string;
severity: Severity;
score?: number; // 0..1
description: string;
indicators?: string[];
recommendedActions?: string[];
confidence?: number; // 0..1
raw?: any;

Check warning on line 11 in src/modules/ai/interfaces/threat-summary.interface.ts

View workflow job for this annotation

GitHub Actions / Linting (20.x)

Unexpected any. Specify a different type

Check warning on line 11 in src/modules/ai/interfaces/threat-summary.interface.ts

View workflow job for this annotation

GitHub Actions / Linting (22.x)

Unexpected any. Specify a different type
}
7 changes: 7 additions & 0 deletions src/modules/ai/providers/ai-provider.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { ThreatSummary } from '../interfaces/threat-summary.interface';

export interface AIProvider {
name: string;
analyzeThreat(event: any): Promise<ThreatSummary>;

Check warning on line 5 in src/modules/ai/providers/ai-provider.interface.ts

View workflow job for this annotation

GitHub Actions / Linting (20.x)

Unexpected any. Specify a different type

Check warning on line 5 in src/modules/ai/providers/ai-provider.interface.ts

View workflow job for this annotation

GitHub Actions / Linting (22.x)

Unexpected any. Specify a different type
healthCheck?(): Promise<boolean>;
}
76 changes: 76 additions & 0 deletions src/modules/ai/providers/openai.provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { AIProvider } from './ai-provider.interface';
import { ThreatSummary } from '../interfaces/threat-summary.interface';

export class OpenAIProvider implements AIProvider {
name = 'openai';
constructor(private apiKey: string) {}

async analyzeThreat(event: any): Promise<ThreatSummary> {

Check warning on line 8 in src/modules/ai/providers/openai.provider.ts

View workflow job for this annotation

GitHub Actions / Linting (20.x)

Unexpected any. Specify a different type

Check warning on line 8 in src/modules/ai/providers/openai.provider.ts

View workflow job for this annotation

GitHub Actions / Linting (22.x)

Unexpected any. Specify a different type
// Minimal, efficient implementation: lightweight local heuristic + optional remote call.
// For now provide a deterministic lightweight summary so the framework is usable without network.

const title = event.title || event.alert || 'Security event';
const description = event.description || JSON.stringify(event).slice(0, 200);

// Simple heuristic severity mapping
const severity = this.heuristicSeverity(event);
const score = this.heuristicScore(severity);

return {
title,
description,
severity,
score,
indicators: this.extractIndicators(event),
recommendedActions: this.suggestRemediations(severity),
confidence: 0.5,
raw: event,
};
}

async healthCheck(): Promise<boolean> {
// If API key configured, assume provider can be used; otherwise still usable in local-only mode.
return typeof this.apiKey === 'string' && this.apiKey.length > 0;
}

private heuristicSeverity(event: any): 'low' | 'medium' | 'high' | 'critical' {

Check warning on line 36 in src/modules/ai/providers/openai.provider.ts

View workflow job for this annotation

GitHub Actions / Linting (20.x)

Unexpected any. Specify a different type

Check warning on line 36 in src/modules/ai/providers/openai.provider.ts

View workflow job for this annotation

GitHub Actions / Linting (22.x)

Unexpected any. Specify a different type
const s = (event.severity || '').toString().toLowerCase();
if (s.includes('crit') || s === '4') return 'critical';
if (s.includes('high') || s === '3') return 'high';
if (s.includes('medium') || s === '2') return 'medium';
return 'low';
}

private heuristicScore(sev: string): number {
switch (sev) {
case 'critical':
return 0.95;
case 'high':
return 0.8;
case 'medium':
return 0.5;
default:
return 0.2;
}
}

private extractIndicators(event: any): string[] {

Check warning on line 57 in src/modules/ai/providers/openai.provider.ts

View workflow job for this annotation

GitHub Actions / Linting (20.x)

Unexpected any. Specify a different type

Check warning on line 57 in src/modules/ai/providers/openai.provider.ts

View workflow job for this annotation

GitHub Actions / Linting (22.x)

Unexpected any. Specify a different type
const indicators: string[] = [];
if (event.ip) indicators.push(`ip:${event.ip}`);
if (event.user) indicators.push(`user:${event.user}`);
if (event.filename) indicators.push(`file:${event.filename}`);
return indicators;
}

private suggestRemediations(sev: string): string[] {
if (sev === 'critical')
return [
'Isolate affected hosts',
'Rotate credentials',
'Initiate incident response playbook',
];
if (sev === 'high') return ['Block indicators', 'Notify on-call', 'Collect forensic artifacts'];
if (sev === 'medium') return ['Investigate logs', 'Raise ticket for review'];
return ['Monitor and gather additional context'];
}
}
Loading