feat(phase-26): add Campaign models, endpoints, service with kill chain timeline UI (T-217 to T-220)

This commit is contained in:
2026-02-09 16:52:52 +01:00
parent f4de12d8ab
commit 57b47c296d
12 changed files with 2032 additions and 0 deletions

View File

@@ -0,0 +1,153 @@
import client from "./client";
// ── Types ───────────────────────────────────────────────────────────
export interface CampaignTest {
id: string;
test_id: string;
order_index: number;
depends_on: string | null;
phase: string | null;
test_name: string | null;
test_state: string | null;
test_result: string | null;
technique_mitre_id: string | null;
technique_name: string | null;
platform: string | null;
}
export interface CampaignProgress {
total: number;
by_state: Record<string, number>;
completion_pct: number;
}
export interface Campaign {
id: string;
name: string;
description: string | null;
type: string;
status: string;
threat_actor_id: string | null;
threat_actor_name: string | null;
created_by: string | null;
scheduled_at: string | null;
completed_at: string | null;
target_platform: string | null;
tags: string[];
created_at: string | null;
tests: CampaignTest[];
progress: CampaignProgress;
}
export interface CampaignSummary {
id: string;
name: string;
description: string | null;
type: string;
status: string;
threat_actor_id: string | null;
threat_actor_name: string | null;
target_platform: string | null;
tags: string[];
created_at: string | null;
test_count: number;
completion_pct: number;
}
export interface CampaignCreatePayload {
name: string;
description?: string;
type?: string;
threat_actor_id?: string;
target_platform?: string;
tags?: string[];
scheduled_at?: string;
}
export interface AddTestPayload {
test_id: string;
order_index?: number;
depends_on?: string;
phase?: string;
}
// ── API Functions ───────────────────────────────────────────────────
/** List campaigns with optional filters. */
export async function listCampaigns(params?: {
type?: string;
status?: string;
threat_actor_id?: string;
search?: string;
offset?: number;
limit?: number;
}): Promise<{ total: number; items: CampaignSummary[] }> {
const { data } = await client.get("/campaigns", { params });
return data;
}
/** Get a campaign detail with tests and progress. */
export async function getCampaign(campaignId: string): Promise<Campaign> {
const { data } = await client.get<Campaign>(`/campaigns/${campaignId}`);
return data;
}
/** Create a new campaign. */
export async function createCampaign(payload: CampaignCreatePayload): Promise<Campaign> {
const { data } = await client.post<Campaign>("/campaigns", payload);
return data;
}
/** Update a campaign. */
export async function updateCampaign(
campaignId: string,
payload: Partial<CampaignCreatePayload>,
): Promise<Campaign> {
const { data } = await client.patch<Campaign>(`/campaigns/${campaignId}`, payload);
return data;
}
/** Add a test to a campaign. */
export async function addTestToCampaign(
campaignId: string,
payload: AddTestPayload,
): Promise<CampaignTest> {
const { data } = await client.post<CampaignTest>(`/campaigns/${campaignId}/tests`, payload);
return data;
}
/** Remove a test from a campaign. */
export async function removeTestFromCampaign(
campaignId: string,
campaignTestId: string,
): Promise<void> {
await client.delete(`/campaigns/${campaignId}/tests/${campaignTestId}`);
}
/** Activate a campaign. */
export async function activateCampaign(campaignId: string): Promise<Campaign> {
const { data } = await client.post<Campaign>(`/campaigns/${campaignId}/activate`);
return data;
}
/** Mark a campaign as completed. */
export async function completeCampaign(campaignId: string): Promise<Campaign> {
const { data } = await client.post<Campaign>(`/campaigns/${campaignId}/complete`);
return data;
}
/** Get campaign progress. */
export async function getCampaignProgress(campaignId: string): Promise<CampaignProgress & {
campaign_id: string;
campaign_name: string;
}> {
const { data } = await client.get(`/campaigns/${campaignId}/progress`);
return data;
}
/** Generate a campaign from a threat actor. */
export async function generateCampaignFromThreatActor(actorId: string): Promise<Campaign> {
const { data } = await client.post<Campaign>(`/campaigns/from-threat-actor/${actorId}`);
return data;
}