From 4692a8b93e8dad967ba2c66bd7dbfc65b56e7d51 Mon Sep 17 00:00:00 2001 From: kitos Date: Tue, 14 Jul 2026 15:30:47 +0200 Subject: [PATCH] feat(tests): add Detect Procedure UI, template suggested-procedure editing, lead review panel Blue Team gets a Detect Procedure textarea in the test detail view, mirroring Red's Attack Procedure field. Template create/edit forms gain a Detect Suggested Procedure field for leads to curate directly. Leads also get a Procedure Suggestions panel on the Tests page, scoped to their own team by the backend, to approve or reject suggestions extracted from submitted rounds. --- frontend/src/api/procedure-suggestions.ts | 20 +++++ frontend/src/api/test-templates.ts | 1 + frontend/src/api/tests.ts | 1 + .../src/components/test-detail/TeamTabs.tsx | 21 +++++ frontend/src/pages/SystemPage.tsx | 26 ++++++ frontend/src/pages/TestDetailPage.tsx | 4 + frontend/src/pages/TestsPage.tsx | 84 ++++++++++++++++++- frontend/src/types/models.ts | 21 +++++ 8 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 frontend/src/api/procedure-suggestions.ts diff --git a/frontend/src/api/procedure-suggestions.ts b/frontend/src/api/procedure-suggestions.ts new file mode 100644 index 0000000..6977d23 --- /dev/null +++ b/frontend/src/api/procedure-suggestions.ts @@ -0,0 +1,20 @@ +import client from "./client"; +import type { ProcedureSuggestion } from "../types/models"; + +/** List pending procedure suggestions, scoped to the caller's team (admins see both). */ +export async function getProcedureSuggestions(): Promise { + const { data } = await client.get("/procedure-suggestions"); + return data; +} + +/** Approve a suggestion — writes it into the template's suggested-procedure field. */ +export async function approveProcedureSuggestion(id: string): Promise { + const { data } = await client.post(`/procedure-suggestions/${id}/approve`); + return data; +} + +/** Reject a suggestion — the template is left untouched. */ +export async function rejectProcedureSuggestion(id: string): Promise { + const { data } = await client.post(`/procedure-suggestions/${id}/reject`); + return data; +} diff --git a/frontend/src/api/test-templates.ts b/frontend/src/api/test-templates.ts index 6d5fea5..3ad7acd 100644 --- a/frontend/src/api/test-templates.ts +++ b/frontend/src/api/test-templates.ts @@ -24,6 +24,7 @@ export interface CreateTemplatePayload { source_url?: string; attack_procedure?: string; expected_detection?: string; + detect_suggested_procedure?: string; platform?: string; tool_suggested?: string; severity?: string; diff --git a/frontend/src/api/tests.ts b/frontend/src/api/tests.ts index b3355d0..e85dcd3 100644 --- a/frontend/src/api/tests.ts +++ b/frontend/src/api/tests.ts @@ -46,6 +46,7 @@ export interface BlueUpdatePayload { detection_time?: string; containment_time?: string; blue_summary?: string; + detect_procedure?: string; } export interface RedValidationPayload { diff --git a/frontend/src/components/test-detail/TeamTabs.tsx b/frontend/src/components/test-detail/TeamTabs.tsx index 7633a76..9e5091c 100644 --- a/frontend/src/components/test-detail/TeamTabs.tsx +++ b/frontend/src/components/test-detail/TeamTabs.tsx @@ -114,6 +114,7 @@ interface TeamTabsProps { detection_time: string; containment_time: string; blue_summary: string; + detect_procedure: string; }; // Evidence @@ -411,6 +412,26 @@ export default function TeamTabs({ {blueLockedHint} )} + {/* Detect Procedure */} +
+ + {canEditBlue ? ( +