feat(phase-28): add scoring system, operational metrics and executive dashboard (T-224 to T-226)
This commit is contained in:
101
frontend/src/api/operational-metrics.ts
Normal file
101
frontend/src/api/operational-metrics.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import client from "./client";
|
||||
|
||||
// ── Types ────────────────────────────────────────────────────────────
|
||||
|
||||
export interface MTTDMetric {
|
||||
mean_hours: number;
|
||||
median_hours: number;
|
||||
min_hours: number;
|
||||
max_hours: number;
|
||||
sample_size: number;
|
||||
}
|
||||
|
||||
export interface MTTRMetric {
|
||||
mean_hours: number;
|
||||
median_hours: number;
|
||||
min_hours: number;
|
||||
max_hours: number;
|
||||
sample_size: number;
|
||||
}
|
||||
|
||||
export interface DetectionEfficacy {
|
||||
percentage: number;
|
||||
detected: number;
|
||||
partially: number;
|
||||
not_detected: number;
|
||||
total: number;
|
||||
}
|
||||
|
||||
export interface AlertFidelity {
|
||||
percentage: number;
|
||||
triggered: number;
|
||||
not_triggered: number;
|
||||
total_evaluated: number;
|
||||
}
|
||||
|
||||
export interface CoverageVelocity {
|
||||
techniques_per_week: number;
|
||||
trend: "improving" | "declining" | "stable";
|
||||
}
|
||||
|
||||
export interface ValidationThroughput {
|
||||
tests_per_week: number;
|
||||
trend: "improving" | "declining" | "stable";
|
||||
}
|
||||
|
||||
export interface RejectionRate {
|
||||
percentage: number;
|
||||
by_red_lead: number;
|
||||
by_blue_lead: number;
|
||||
}
|
||||
|
||||
export interface OperationalMetrics {
|
||||
mttd: MTTDMetric | null;
|
||||
mttr: MTTRMetric | null;
|
||||
detection_efficacy: DetectionEfficacy;
|
||||
alert_fidelity: AlertFidelity;
|
||||
coverage_velocity: CoverageVelocity;
|
||||
validation_throughput: ValidationThroughput;
|
||||
rejection_rate: RejectionRate;
|
||||
}
|
||||
|
||||
export interface OperationalTrendPoint {
|
||||
date: string;
|
||||
detection_efficacy: number;
|
||||
validated_tests: number;
|
||||
detected_tests: number;
|
||||
}
|
||||
|
||||
export interface TeamMetrics {
|
||||
red_team: {
|
||||
tests_completed: number;
|
||||
avg_completion_hours: number | null;
|
||||
rejection_rate: number;
|
||||
};
|
||||
blue_team: {
|
||||
tests_completed: number;
|
||||
avg_completion_hours: number | null;
|
||||
rejection_rate: number;
|
||||
};
|
||||
}
|
||||
|
||||
// ── API Functions ────────────────────────────────────────────────────
|
||||
|
||||
export async function getOperationalMetrics(): Promise<OperationalMetrics> {
|
||||
const { data } = await client.get<OperationalMetrics>("/metrics/operational");
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function getOperationalTrend(
|
||||
period: string = "90d",
|
||||
): Promise<OperationalTrendPoint[]> {
|
||||
const { data } = await client.get<OperationalTrendPoint[]>("/metrics/operational/trend", {
|
||||
params: { period },
|
||||
});
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function getMetricsByTeam(): Promise<TeamMetrics> {
|
||||
const { data } = await client.get<TeamMetrics>("/metrics/operational/by-team");
|
||||
return data;
|
||||
}
|
||||
100
frontend/src/api/scores.ts
Normal file
100
frontend/src/api/scores.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import client from "./client";
|
||||
|
||||
// ── Types ────────────────────────────────────────────────────────────
|
||||
|
||||
export interface ScoreBreakdownItem {
|
||||
score: number;
|
||||
max: number;
|
||||
detail: string;
|
||||
}
|
||||
|
||||
export interface TechniqueScore {
|
||||
mitre_id: string;
|
||||
name: string;
|
||||
tactic: string | null;
|
||||
status_global: string | null;
|
||||
total_score: number;
|
||||
breakdown: Record<string, ScoreBreakdownItem>;
|
||||
}
|
||||
|
||||
export interface TacticScore {
|
||||
tactic: string;
|
||||
average_score: number;
|
||||
techniques_count: number;
|
||||
techniques_scored: number;
|
||||
}
|
||||
|
||||
export interface ActorCoverageScore {
|
||||
actor_id: string;
|
||||
actor_name: string;
|
||||
total_score: number;
|
||||
techniques_count: number;
|
||||
techniques_covered: number;
|
||||
techniques_detail: Array<{
|
||||
mitre_id: string;
|
||||
name: string;
|
||||
score: number;
|
||||
breakdown: Record<string, ScoreBreakdownItem>;
|
||||
}>;
|
||||
}
|
||||
|
||||
export interface OrganizationScore {
|
||||
overall_score: number;
|
||||
total_coverage: number;
|
||||
critical_coverage: number;
|
||||
detection_maturity: number;
|
||||
response_readiness: number;
|
||||
techniques_evaluated: number;
|
||||
techniques_total: number;
|
||||
}
|
||||
|
||||
export interface ScoreHistoryPoint {
|
||||
date: string;
|
||||
score: number;
|
||||
validated_tests: number;
|
||||
}
|
||||
|
||||
export interface ScoringConfig {
|
||||
weights: {
|
||||
tests: number;
|
||||
detection_rules: number;
|
||||
d3fend: number;
|
||||
freshness: number;
|
||||
platform_diversity: number;
|
||||
};
|
||||
total: number;
|
||||
}
|
||||
|
||||
// ── API Functions ────────────────────────────────────────────────────
|
||||
|
||||
export async function getTechniqueScore(mitreId: string): Promise<TechniqueScore> {
|
||||
const { data } = await client.get<TechniqueScore>(`/scores/technique/${mitreId}`);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function getTacticScore(tactic: string): Promise<TacticScore> {
|
||||
const { data } = await client.get<TacticScore>(`/scores/tactic/${tactic}`);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function getActorCoverageScore(actorId: string): Promise<ActorCoverageScore> {
|
||||
const { data } = await client.get<ActorCoverageScore>(`/scores/threat-actor/${actorId}`);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function getOrganizationScore(): Promise<OrganizationScore> {
|
||||
const { data } = await client.get<OrganizationScore>("/scores/organization");
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function getScoreHistory(period: string = "90d"): Promise<ScoreHistoryPoint[]> {
|
||||
const { data } = await client.get<ScoreHistoryPoint[]>("/scores/history", {
|
||||
params: { period },
|
||||
});
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function getScoringConfig(): Promise<ScoringConfig> {
|
||||
const { data } = await client.get<ScoringConfig>("/scores/config");
|
||||
return data;
|
||||
}
|
||||
Reference in New Issue
Block a user