322b6fcb62
- Auto-trigger POST /risk/compute on first load if no profiles exist - Add "Refresh scores" button next to Critical Gaps header (spins while computing) - Add computeRiskScores() to frontend/src/api/risk.ts - After compute, invalidate risk-profiles query so table updates immediately
51 lines
1.7 KiB
TypeScript
51 lines
1.7 KiB
TypeScript
import client from "./client";
|
|
|
|
// ── Types ───────────────────────────────────────────────────────────
|
|
|
|
export interface RiskProfile {
|
|
id: string;
|
|
technique_id: string;
|
|
risk_score: number;
|
|
likelihood: number;
|
|
impact: number;
|
|
risk_level: string;
|
|
detection_gap: number;
|
|
threat_actor_count: number;
|
|
osint_signal_count: number;
|
|
test_fail_count: number;
|
|
test_total_count: number;
|
|
test_failure_rate: number;
|
|
confidence_level: number;
|
|
scoring_breakdown: Record<string, unknown> | null;
|
|
recommendations: string[] | null;
|
|
computed_at: string;
|
|
is_stale: boolean;
|
|
}
|
|
|
|
// ── API Functions ───────────────────────────────────────────────────
|
|
|
|
/** List risk profiles sorted by risk_score DESC. */
|
|
export async function getRiskProfiles(params?: {
|
|
risk_level?: string;
|
|
min_score?: number;
|
|
max_score?: number;
|
|
stale_only?: boolean;
|
|
limit?: number;
|
|
offset?: number;
|
|
}): Promise<RiskProfile[]> {
|
|
const { data } = await client.get<RiskProfile[]>("/risk/profiles", { params });
|
|
return data;
|
|
}
|
|
|
|
/** Get the risk profile for a single technique. */
|
|
export async function getRiskProfile(techniqueId: string): Promise<RiskProfile> {
|
|
const { data } = await client.get<RiskProfile>(`/risk/profiles/${techniqueId}`);
|
|
return data;
|
|
}
|
|
|
|
/** Trigger recomputation of all risk scores. */
|
|
export async function computeRiskScores(): Promise<{ computed: number; skipped: number; errors: number; duration_seconds: number }> {
|
|
const { data } = await client.post("/risk/compute");
|
|
return data;
|
|
}
|