e2861a08bc
- Capture Step.Description (HTML stripped), step name/number, substep ref, criteria, and data sources from MITRE ATT&CK Evaluations API - _aggregate_by_technique() now accumulates ALL occurrences per technique (multiple substep refs, criteria, step contexts) instead of keeping only the best-scoring one - New helper functions _build_procedure_text(), _build_description(), _build_red_summary() generate rich narratives from accumulated occurrences - New re_enrich_evaluation_round() service function + POST endpoint /system/attck-evaluations/re-enrich to update already-imported tests without changing detection results or validation state - Frontend: Re-enrich button per imported round + result banner in SystemPage
141 lines
4.1 KiB
TypeScript
141 lines
4.1 KiB
TypeScript
import client from "./client";
|
|
|
|
export interface SyncMitreResponse {
|
|
message: string;
|
|
status?: string;
|
|
new?: number;
|
|
updated?: number;
|
|
}
|
|
|
|
export interface IntelScanResponse {
|
|
message: string;
|
|
new_items: number;
|
|
}
|
|
|
|
export interface SchedulerJob {
|
|
id: string;
|
|
name: string;
|
|
next_run_time: string | null;
|
|
}
|
|
|
|
export interface SchedulerStatusResponse {
|
|
running: boolean;
|
|
jobs: SchedulerJob[];
|
|
}
|
|
|
|
/** Manually trigger MITRE ATT&CK sync. */
|
|
export async function triggerMitreSync(): Promise<SyncMitreResponse> {
|
|
const { data } = await client.post<SyncMitreResponse>("/system/sync-mitre");
|
|
return data;
|
|
}
|
|
|
|
/** Manually trigger threat intelligence scan. */
|
|
export async function triggerIntelScan(): Promise<IntelScanResponse> {
|
|
const { data } = await client.post<IntelScanResponse>("/system/run-intel-scan");
|
|
return data;
|
|
}
|
|
|
|
/** Get scheduler status. */
|
|
export async function getSchedulerStatus(): Promise<SchedulerStatusResponse> {
|
|
const { data } = await client.get<SchedulerStatusResponse>("/system/scheduler-status");
|
|
return data;
|
|
}
|
|
|
|
// ── ATT&CK Evaluations ─────────────────────────────────────────────
|
|
|
|
export interface EvaluationRound {
|
|
name: string;
|
|
display_name: string;
|
|
eval_round: number;
|
|
imported: boolean;
|
|
imported_at: string | null;
|
|
tests_created: number | null;
|
|
techniques_covered: number | null;
|
|
}
|
|
|
|
export interface EvaluationRoundsResponse {
|
|
rounds: EvaluationRound[];
|
|
api_reachable: boolean;
|
|
api_error: string | null;
|
|
}
|
|
|
|
export interface EvaluationImportResult {
|
|
message: string;
|
|
created: number;
|
|
skipped: number;
|
|
techniques_covered: number;
|
|
adversary: string;
|
|
eval_round: number;
|
|
}
|
|
|
|
export interface NewRoundCheckResult {
|
|
new_round_available: boolean;
|
|
already_imported: boolean;
|
|
latest_round: { name: string; display_name: string; eval_round: number } | null;
|
|
error?: string;
|
|
}
|
|
|
|
/** List all public CrowdStrike evaluation rounds with import status. */
|
|
export async function listEvaluationRounds(): Promise<EvaluationRoundsResponse> {
|
|
const { data } = await client.get<EvaluationRoundsResponse>("/system/attck-evaluations/rounds");
|
|
return data;
|
|
}
|
|
|
|
/** Import a specific evaluation round. */
|
|
export async function importEvaluationRound(payload: {
|
|
adversary_name: string;
|
|
adversary_display: string;
|
|
eval_round: number;
|
|
}): Promise<EvaluationImportResult> {
|
|
const { data } = await client.post<EvaluationImportResult>("/system/attck-evaluations/import", payload);
|
|
return data;
|
|
}
|
|
|
|
/** Import the latest available round automatically. */
|
|
export async function importLatestEvaluation(): Promise<EvaluationImportResult> {
|
|
const { data } = await client.post<EvaluationImportResult>("/system/attck-evaluations/import-latest");
|
|
return data;
|
|
}
|
|
|
|
/** Check if a new round is available. */
|
|
export async function checkNewEvaluationRound(): Promise<NewRoundCheckResult> {
|
|
const { data } = await client.get<NewRoundCheckResult>("/system/attck-evaluations/check-new");
|
|
return data;
|
|
}
|
|
|
|
export interface BulkApproveResult {
|
|
approved: number;
|
|
techniques_recalculated: number;
|
|
message: string;
|
|
}
|
|
|
|
export interface ReEnrichResult {
|
|
updated: number;
|
|
skipped: number;
|
|
adversary: string;
|
|
eval_round: number;
|
|
message: string;
|
|
}
|
|
|
|
/** Bulk-approve all in-review evaluation tests (Blue Team side). */
|
|
export async function bulkApproveEvaluationTests(): Promise<BulkApproveResult> {
|
|
const { data } = await client.post<BulkApproveResult>("/system/attck-evaluations/bulk-approve");
|
|
return data;
|
|
}
|
|
|
|
/** Get the count of evaluation tests still awaiting Blue approval. */
|
|
export async function getEvalPendingCount(): Promise<{ pending: number }> {
|
|
const { data } = await client.get<{ pending: number }>("/system/attck-evaluations/pending-count");
|
|
return data;
|
|
}
|
|
|
|
/** Re-enrich an already-imported round with attack path, criteria and data sources. */
|
|
export async function reEnrichEvaluationRound(payload: {
|
|
adversary_name: string;
|
|
adversary_display: string;
|
|
eval_round: number;
|
|
}): Promise<ReEnrichResult> {
|
|
const { data } = await client.post<ReEnrichResult>("/system/attck-evaluations/re-enrich", payload);
|
|
return data;
|
|
}
|