feat: Rename WAF to Coraza in UI and update related tests

- Updated UI components to reflect the renaming of "WAF (Coraza)" to "Coraza".
- Removed WAF controls from the Security page and adjusted related tests.
- Verified that all frontend tests pass after updating assertions to match the new UI.
- Added a test script to package.json for running tests with Vitest.
- Adjusted imports for jest-dom to be compatible with Vitest.
- Updated TypeScript configuration to include Vitest types for testing.
This commit is contained in:
GitHub Actions
2025-12-12 03:19:27 +00:00
parent 8e09efe548
commit effed44ce8
12 changed files with 358 additions and 1289 deletions
@@ -1,6 +1,6 @@
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { render, screen, waitFor, within } from '@testing-library/react'
import '@testing-library/jest-dom'
import '@testing-library/jest-dom/vitest'
import userEvent from '@testing-library/user-event'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import type { ProxyHost } from '../../api/proxyHosts'
@@ -284,7 +284,7 @@ describe('Security Page - QA Security Audit', () => {
// All 4 cards should be present
expect(screen.getByText('CrowdSec')).toBeInTheDocument()
expect(screen.getByText('Access Control')).toBeInTheDocument()
expect(screen.getByText('WAF (Coraza)')).toBeInTheDocument()
expect(screen.getByText('Coraza')).toBeInTheDocument()
expect(screen.getByText('Rate Limiting')).toBeInTheDocument()
})
})
@@ -303,17 +303,6 @@ describe('Security Page - QA Security Audit', () => {
expect(screen.getByTestId('toggle-rate-limit')).toBeInTheDocument()
})
it('WAF controls have proper test IDs when enabled', async () => {
vi.mocked(securityApi.getSecurityStatus).mockResolvedValue(mockSecurityStatus)
await renderSecurityPage()
await waitFor(() => screen.getByText(/Cerberus Dashboard/i))
expect(screen.getByTestId('waf-mode-select')).toBeInTheDocument()
expect(screen.getByTestId('waf-ruleset-select')).toBeInTheDocument()
})
it('CrowdSec controls surface primary actions when enabled', async () => {
vi.mocked(securityApi.getSecurityStatus).mockResolvedValue(mockSecurityStatus)
vi.mocked(crowdsecApi.statusCrowdsec).mockResolvedValue({ running: false })
@@ -341,7 +330,7 @@ describe('Security Page - QA Security Audit', () => {
const cardNames = cards.map(card => card.textContent)
// Spec requirement from current_spec.md plus Live Security Logs feature
expect(cardNames).toEqual(['CrowdSec', 'Access Control', 'WAF (Coraza)', 'Rate Limiting', 'Live Security Logs'])
expect(cardNames).toEqual(['CrowdSec', 'Access Control', 'Coraza', 'Rate Limiting', 'Live Security Logs'])
})
it('layer indicators match spec descriptions', async () => {
@@ -186,125 +186,6 @@ describe('Security page', () => {
expect(crowdsecToggle).toBeDisabled()
})
it('shows WAF mode selector when WAF is enabled', async () => {
const status: SecurityStatus = {
cerberus: { enabled: true },
crowdsec: { enabled: false, mode: 'disabled' as const, api_url: '' },
waf: { enabled: true, mode: 'enabled' as const },
rate_limit: { enabled: false },
acl: { enabled: false },
}
vi.mocked(api.getSecurityStatus).mockResolvedValue(status as SecurityStatus)
vi.mocked(api.getSecurityConfig).mockResolvedValue(mockSecurityConfig)
vi.mocked(api.getRuleSets).mockResolvedValue(mockRuleSets)
renderWithProviders(<Security />)
await waitFor(() => expect(screen.getByTestId('waf-mode-select')).toBeInTheDocument())
// Check mode selector is present with correct options
const modeSelect = screen.getByTestId('waf-mode-select')
expect(modeSelect).toBeInTheDocument()
expect(modeSelect).toHaveValue('block')
})
it('shows WAF ruleset selector with available rulesets', async () => {
const status: SecurityStatus = {
cerberus: { enabled: true },
crowdsec: { enabled: false, mode: 'disabled' as const, api_url: '' },
waf: { enabled: true, mode: 'enabled' as const },
rate_limit: { enabled: false },
acl: { enabled: false },
}
vi.mocked(api.getSecurityStatus).mockResolvedValue(status as SecurityStatus)
vi.mocked(api.getSecurityConfig).mockResolvedValue(mockSecurityConfig)
vi.mocked(api.getRuleSets).mockResolvedValue(mockRuleSets)
renderWithProviders(<Security />)
await waitFor(() => expect(screen.getByTestId('waf-ruleset-select')).toBeInTheDocument())
// Check ruleset selector shows available rulesets
const rulesetSelect = screen.getByTestId('waf-ruleset-select')
expect(rulesetSelect).toBeInTheDocument()
// Verify options are present
expect(screen.getByText('None (all rule sets)')).toBeInTheDocument()
expect(screen.getByText('OWASP CRS (blocking)')).toBeInTheDocument()
expect(screen.getByText('Custom Rules (detection)')).toBeInTheDocument()
})
it('calls updateSecurityConfig when WAF mode is changed', async () => {
const status: SecurityStatus = {
cerberus: { enabled: true },
crowdsec: { enabled: false, mode: 'disabled' as const, api_url: '' },
waf: { enabled: true, mode: 'enabled' as const },
rate_limit: { enabled: false },
acl: { enabled: false },
}
vi.mocked(api.getSecurityStatus).mockResolvedValue(status as SecurityStatus)
vi.mocked(api.getSecurityConfig).mockResolvedValue(mockSecurityConfig)
vi.mocked(api.getRuleSets).mockResolvedValue(mockRuleSets)
vi.mocked(api.updateSecurityConfig).mockResolvedValue({})
renderWithProviders(<Security />)
await waitFor(() => expect(screen.getByTestId('waf-mode-select')).toBeInTheDocument())
// Change mode to monitor
const modeSelect = screen.getByTestId('waf-mode-select')
await userEvent.selectOptions(modeSelect, 'monitor')
await waitFor(() => {
expect(api.updateSecurityConfig).toHaveBeenCalledWith(
expect.objectContaining({ waf_mode: 'monitor' })
)
})
})
it('calls updateSecurityConfig when WAF ruleset is changed', async () => {
const status: SecurityStatus = {
cerberus: { enabled: true },
crowdsec: { enabled: false, mode: 'disabled' as const, api_url: '' },
waf: { enabled: true, mode: 'enabled' as const },
rate_limit: { enabled: false },
acl: { enabled: false },
}
vi.mocked(api.getSecurityStatus).mockResolvedValue(status as SecurityStatus)
vi.mocked(api.getSecurityConfig).mockResolvedValue(mockSecurityConfig)
vi.mocked(api.getRuleSets).mockResolvedValue(mockRuleSets)
vi.mocked(api.updateSecurityConfig).mockResolvedValue({})
renderWithProviders(<Security />)
await waitFor(() => expect(screen.getByTestId('waf-ruleset-select')).toBeInTheDocument())
// Select a specific ruleset
const rulesetSelect = screen.getByTestId('waf-ruleset-select')
await userEvent.selectOptions(rulesetSelect, 'OWASP CRS')
await waitFor(() => {
expect(api.updateSecurityConfig).toHaveBeenCalledWith(
expect.objectContaining({ waf_rules_source: 'OWASP CRS' })
)
})
})
it('shows warning when no rulesets are configured', async () => {
const status: SecurityStatus = {
cerberus: { enabled: true },
crowdsec: { enabled: false, mode: 'disabled' as const, api_url: '' },
waf: { enabled: true, mode: 'enabled' as const },
rate_limit: { enabled: false },
acl: { enabled: false },
}
vi.mocked(api.getSecurityStatus).mockResolvedValue(status as SecurityStatus)
vi.mocked(api.getSecurityConfig).mockResolvedValue(mockSecurityConfig)
vi.mocked(api.getRuleSets).mockResolvedValue({ rulesets: [] })
renderWithProviders(<Security />)
await waitFor(() => expect(screen.getByTestId('waf-ruleset-select')).toBeInTheDocument())
// Should show warning about no rulesets
expect(screen.getByText('No rule sets configured. Add one below.')).toBeInTheDocument()
})
it('displays correct WAF threat protection summary when enabled', async () => {
const status: SecurityStatus = {
cerberus: { enabled: true },
@@ -323,24 +204,4 @@ describe('Security page', () => {
// WAF now shows threat protection summary instead of mode text
await waitFor(() => expect(screen.getByText(/SQL injection, XSS, RCE/i)).toBeInTheDocument())
})
it('does not show WAF controls when WAF is disabled', async () => {
const status: SecurityStatus = {
cerberus: { enabled: true },
crowdsec: { enabled: false, mode: 'disabled' as const, api_url: '' },
waf: { enabled: false, mode: 'disabled' as const },
rate_limit: { enabled: false },
acl: { enabled: false },
}
vi.mocked(api.getSecurityStatus).mockResolvedValue(status as SecurityStatus)
vi.mocked(api.getSecurityConfig).mockResolvedValue(mockSecurityConfig)
vi.mocked(api.getRuleSets).mockResolvedValue(mockRuleSets)
renderWithProviders(<Security />)
await waitFor(() => expect(screen.getByText('Cerberus Dashboard')).toBeInTheDocument())
// Mode selector and ruleset selector should not be visible
expect(screen.queryByTestId('waf-mode-select')).not.toBeInTheDocument()
expect(screen.queryByTestId('waf-ruleset-select')).not.toBeInTheDocument()
})
})
+3 -35
View File
@@ -232,39 +232,7 @@ describe('Security', () => {
})
describe('WAF Controls', () => {
it('should change WAF mode', async () => {
const user = userEvent.setup()
const { useUpdateSecurityConfig } = await import('../../hooks/useSecurity')
const mockMutate = vi.fn()
vi.mocked(useUpdateSecurityConfig).mockReturnValue({ mutate: mockMutate, isPending: false } as unknown as ReturnType<typeof useUpdateSecurityConfig>)
vi.mocked(securityApi.getSecurityStatus).mockResolvedValue(mockSecurityStatus)
await renderSecurityPage()
await waitFor(() => screen.getByTestId('waf-mode-select'))
const select = screen.getByTestId('waf-mode-select')
await user.selectOptions(select, 'monitor')
await waitFor(() => expect(mockMutate).toHaveBeenCalledWith({ name: 'default', waf_mode: 'monitor' }))
})
it('should change WAF ruleset', async () => {
const user = userEvent.setup()
const { useUpdateSecurityConfig } = await import('../../hooks/useSecurity')
const mockMutate = vi.fn()
vi.mocked(useUpdateSecurityConfig).mockReturnValue({ mutate: mockMutate, isPending: false } as unknown as ReturnType<typeof useUpdateSecurityConfig>)
vi.mocked(securityApi.getSecurityStatus).mockResolvedValue(mockSecurityStatus)
await renderSecurityPage()
await waitFor(() => screen.getByTestId('waf-ruleset-select'))
const select = screen.getByTestId('waf-ruleset-select')
await user.selectOptions(select, 'OWASP CRS')
await waitFor(() => expect(mockMutate).toHaveBeenCalledWith({ name: 'default', waf_rules_source: 'OWASP CRS' }))
})
})
// Note: WAF Controls tests removed - dropdowns moved to dedicated WAF config page (/security/waf)
describe('Card Order (Pipeline Sequence)', () => {
it('should render cards in correct pipeline order: CrowdSec → ACL → WAF → Rate Limiting', async () => {
@@ -277,8 +245,8 @@ describe('Security', () => {
const cards = screen.getAllByRole('heading', { level: 3 })
const cardNames = cards.map(card => card.textContent)
// Verify pipeline order: CrowdSec (Layer 1) → ACL (Layer 2) → WAF (Layer 3) → Rate Limiting (Layer 4) + Live Security Logs
expect(cardNames).toEqual(['CrowdSec', 'Access Control', 'WAF (Coraza)', 'Rate Limiting', 'Live Security Logs'])
// Verify pipeline order: CrowdSec (Layer 1) → ACL (Layer 2) → Coraza (Layer 3) → Rate Limiting (Layer 4) + Live Security Logs
expect(cardNames).toEqual(['CrowdSec', 'Access Control', 'Coraza', 'Rate Limiting', 'Live Security Logs'])
})
it('should display layer indicators on each card', async () => {