@@ -137,7 +237,15 @@ export default function Security() {
Access Control
-
+
+ toggleServiceMutation.mutate({ key: 'security.acl.enabled', enabled: e.target.checked })}
+ data-testid="toggle-acl"
+ />
+
+
@@ -158,6 +266,11 @@ export default function Security() {
)}
+ {!status.acl.enabled && (
+
+
+
+ )}
@@ -165,7 +278,15 @@ export default function Security() {
Rate Limiting
-
+
+
toggleServiceMutation.mutate({ key: 'security.rate_limit.enabled', enabled: e.target.checked })}
+ data-testid="toggle-rate-limit"
+ />
+
+
@@ -181,6 +302,11 @@ export default function Security() {
)}
+ {!status.rate_limit.enabled && (
+
+
+
+ )}
diff --git a/frontend/src/pages/SystemSettings.tsx b/frontend/src/pages/SystemSettings.tsx
index d5494773..bc2780bf 100644
--- a/frontend/src/pages/SystemSettings.tsx
+++ b/frontend/src/pages/SystemSettings.tsx
@@ -8,7 +8,7 @@ import { toast } from '../utils/toast'
import { getSettings, updateSetting } from '../api/settings'
import { getFeatureFlags, updateFeatureFlags } from '../api/featureFlags'
import client from '../api/client'
-import { startCrowdsec, stopCrowdsec, statusCrowdsec, importCrowdsecConfig } from '../api/crowdsec'
+import { startCrowdsec, stopCrowdsec, statusCrowdsec, importCrowdsecConfig, exportCrowdsecConfig } from '../api/crowdsec'
import { Loader2, Server, RefreshCw, Save, Activity } from 'lucide-react'
interface HealthResponse {
@@ -356,6 +356,22 @@ export default function SystemSettings() {
+
diff --git a/frontend/src/pages/__tests__/CrowdSecConfig.spec.tsx b/frontend/src/pages/__tests__/CrowdSecConfig.spec.tsx
new file mode 100644
index 00000000..6e5f9b97
--- /dev/null
+++ b/frontend/src/pages/__tests__/CrowdSecConfig.spec.tsx
@@ -0,0 +1,101 @@
+import { describe, it, expect, vi, beforeEach } from 'vitest'
+import { render, screen, waitFor } from '@testing-library/react'
+import userEvent from '@testing-library/user-event'
+import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
+import { BrowserRouter } from 'react-router-dom'
+import CrowdSecConfig from '../CrowdSecConfig'
+import * as api from '../../api/security'
+import * as crowdsecApi from '../../api/crowdsec'
+import * as backupsApi from '../../api/backups'
+import * as settingsApi from '../../api/settings'
+
+vi.mock('../../api/security')
+vi.mock('../../api/crowdsec')
+vi.mock('../../api/backups')
+vi.mock('../../api/settings')
+
+const createQueryClient = () => new QueryClient({ defaultOptions: { queries: { retry: false }, mutations: { retry: false } } })
+const renderWithProviders = (ui: React.ReactNode) => {
+ const qc = createQueryClient()
+ return render(
+