feat(rt-import): import Red Team engagement results as validated tests
Backend — POST /tests/import-rt (red_lead + admin): Accepts engagement JSON with name/date/description/operator and a list of techniques each with mitre_id, result, attack_success, platform, notes. Creates one Test per technique directly in 'validated' state (red + blue validation = approved) bypassing the normal workflow. Recalculates technique.status_global for all affected techniques. Returns created/skipped summary. Frontend — /tests/import-rt (new dedicated page): - Format reference panel (collapsible) with field descriptions - Download template JSON button (generates a filled example) - Paste JSON textarea + file upload (.json) - Live validation + preview table showing what will be imported - Import button with spinner - Success / warning / error result display Accessible to admin and red_lead only. Added to sidebar under Tests > Import RT Results.
This commit is contained in:
@@ -20,6 +20,7 @@ const TestDetailPage = React.lazy(() => import("./pages/TestDetailPage"));
|
||||
const TestCatalogPage = React.lazy(() => import("./pages/TestCatalogPage"));
|
||||
const ValidatedTestsPage = React.lazy(() => import("./pages/ValidatedTestsPage"));
|
||||
const ReviewQueuePage = React.lazy(() => import("./pages/ReviewQueuePage"));
|
||||
const ImportRTPage = React.lazy(() => import("./pages/ImportRTPage"));
|
||||
const ReportsPage = React.lazy(() => import("./pages/ReportsPage"));
|
||||
const SystemPage = React.lazy(() => import("./pages/SystemPage"));
|
||||
const UsersPage = React.lazy(() => import("./pages/UsersPage"));
|
||||
@@ -76,6 +77,14 @@ export default function App() {
|
||||
<Route path="/tests" element={<Suspense fallback={<LoadingSpinner text="Loading…" />}><TestsPage /></Suspense>} />
|
||||
<Route path="/tests/new" element={<Suspense fallback={<LoadingSpinner text="Loading…" />}><TestCreatePage /></Suspense>} />
|
||||
<Route path="/tests/validated" element={<Suspense fallback={<LoadingSpinner text="Loading…" />}><ValidatedTestsPage /></Suspense>} />
|
||||
<Route
|
||||
path="/tests/import-rt"
|
||||
element={
|
||||
<ProtectedRoute roles={["admin", "red_lead"]}>
|
||||
<Suspense fallback={<LoadingSpinner text="Loading…" />}><ImportRTPage /></Suspense>
|
||||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
<Route path="/tests/:testId" element={<Suspense fallback={<LoadingSpinner text="Loading…" />}><TestDetailPage /></Suspense>} />
|
||||
<Route path="/test-catalog" element={<Suspense fallback={<LoadingSpinner text="Loading…" />}><TestCatalogPage /></Suspense>} />
|
||||
<Route path="/test-catalog/:templateId/use" element={<Suspense fallback={<LoadingSpinner text="Loading…" />}><TestCatalogPage /></Suspense>} />
|
||||
|
||||
Reference in New Issue
Block a user