From 7312f9664bdbc188a38d26ee676de9c23cd85f78 Mon Sep 17 00:00:00 2001 From: kitos Date: Tue, 19 May 2026 12:53:02 +0200 Subject: [PATCH] fix(qa): CSP hash, remove pencil icon, fetch full template on modal open MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - nginx.conf: add new CSP script-src hash (sha256-Yvj83pg...) alongside previous one - SystemPage: remove pencil icon from template name button, keep cyan underline style - SystemPage: switch from selectedTemplate state to selectedTemplateId + useQuery for getTemplateById() — ensures full template data (description, attack_procedure, expected_detection, tool_suggested etc.) loads before modal opens - DB backfill already applied via SQL: UPDATE audit_logs SET timestamp = NOW() WHERE timestamp IS NULL (358 rows fixed) Co-Authored-By: Claude Sonnet 4.6 --- frontend/nginx.conf | 2 +- frontend/src/pages/SystemPage.tsx | 48 ++++++++++++++++++++----------- 2 files changed, 32 insertions(+), 18 deletions(-) diff --git a/frontend/nginx.conf b/frontend/nginx.conf index 7f8b2f8..286279b 100644 --- a/frontend/nginx.conf +++ b/frontend/nginx.conf @@ -14,7 +14,7 @@ server { # add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; # CSP: allow self + inline styles (React build) + data: URIs for fonts/images - add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'sha256-31OgE8E9uFi947Hj0TYz0o9NSyrQOewgXrj1ZPfYDaY='; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self' ws: wss:; frame-ancestors 'none'; base-uri 'self'; form-action 'self';" always; + add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'sha256-31OgE8E9uFi947Hj0TYz0o9NSyrQOewgXrj1ZPfYDaY=' 'sha256-Yvj83pg9TGSmhZQWii1NGmFCIaX9trnlTFVkemiMlS8='; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self' ws: wss:; frame-ancestors 'none'; base-uri 'self'; form-action 'self';" always; # Hide Nginx version server_tokens off; diff --git a/frontend/src/pages/SystemPage.tsx b/frontend/src/pages/SystemPage.tsx index 567851f..eb8d5df 100644 --- a/frontend/src/pages/SystemPage.tsx +++ b/frontend/src/pages/SystemPage.tsx @@ -18,7 +18,6 @@ import { ToggleRight, BarChart3, X, - Pencil, } from "lucide-react"; import { triggerMitreSync, @@ -30,6 +29,7 @@ import { import { getTemplateStats, getAllTemplates, + getTemplateById, createTemplate, updateTemplate, toggleTemplateActive, @@ -45,7 +45,7 @@ export default function SystemPage() { const [intelResult, setIntelResult] = useState(null); const [showCreateForm, setShowCreateForm] = useState(false); const [bulkConfirm, setBulkConfirm] = useState<"activate" | "deactivate" | null>(null); - const [selectedTemplate, setSelectedTemplate] = useState(null); + const [selectedTemplateId, setSelectedTemplateId] = useState(null); // ── Existing queries ───────────────────────────────────────────── const { @@ -75,6 +75,15 @@ export default function SystemPage() { queryFn: () => getAllTemplates({ limit: 200 }), }); + const { + data: selectedTemplate, + isLoading: selectedTemplateLoading, + } = useQuery({ + queryKey: ["template-detail", selectedTemplateId], + queryFn: () => getTemplateById(selectedTemplateId!), + enabled: !!selectedTemplateId, + }); + // ── Mutations ──────────────────────────────────────────────────── const mitreSyncMutation = useMutation({ mutationFn: triggerMitreSync, @@ -125,10 +134,10 @@ export default function SystemPage() { const updateTemplateMutation = useMutation({ mutationFn: ({ id, payload }: { id: string; payload: Partial }) => updateTemplate(id, payload), - onSuccess: (updated) => { - setSelectedTemplate(updated); + onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["templates-admin"] }); queryClient.invalidateQueries({ queryKey: ["test-templates"] }); + queryClient.invalidateQueries({ queryKey: ["template-detail", selectedTemplateId] }); }, }); @@ -481,12 +490,11 @@ export default function SystemPage() { > @@ -704,15 +712,21 @@ export default function SystemPage() { {/* Template Detail Modal */} - {selectedTemplate && ( - setSelectedTemplate(null)} - onSave={(id, payload) => updateTemplateMutation.mutate({ id, payload })} - onToggleActive={(id) => toggleActiveMutation.mutate(id)} - isSaving={updateTemplateMutation.isPending} - isToggling={toggleActiveMutation.isPending} - /> + {selectedTemplateId && ( + selectedTemplateLoading ? ( +
+ +
+ ) : selectedTemplate ? ( + setSelectedTemplateId(null)} + onSave={(id, payload) => updateTemplateMutation.mutate({ id, payload })} + onToggleActive={(id) => toggleActiveMutation.mutate(id)} + isSaving={updateTemplateMutation.isPending} + isToggling={toggleActiveMutation.isPending} + /> + ) : null )} );