4.2 KiB
4.2 KiB
Security Test Helpers
Helper utilities for managing security module state during E2E tests.
Overview
The security helpers module (tests/utils/security-helpers.ts) provides utilities for:
- Capturing and restoring security module state
- Toggling individual security modules (ACL, WAF, Rate Limiting, CrowdSec)
- Ensuring test isolation without ACL deadlock
Problem Solved
During E2E testing, if ACL is left enabled from a previous test run (e.g., due to test failure), it creates a deadlock:
- ACL blocks API requests → returns 403 Forbidden
- Global cleanup can't run → API blocked
- Auth setup fails → tests skip
- Manual intervention required to reset volumes
The security helpers solve this by using Playwright's test.afterAll() fixture to guarantee cleanup even when tests fail.
Usage
Capture and Restore Pattern
import { captureSecurityState, restoreSecurityState } from '../utils/security-helpers';
import { request } from '@playwright/test';
let originalState;
test.beforeAll(async ({ request: reqFixture }) => {
originalState = await captureSecurityState(reqFixture);
});
test.afterAll(async () => {
const cleanup = await request.newContext({ baseURL: '...' });
try {
await restoreSecurityState(cleanup, originalState);
} finally {
await cleanup.dispose();
}
});
Toggle Security Module
import { setSecurityModuleEnabled } from '../utils/security-helpers';
await setSecurityModuleEnabled(request, 'acl', true);
await setSecurityModuleEnabled(request, 'waf', false);
With Guaranteed Cleanup
import { withSecurityEnabled } from '../utils/security-helpers';
test.describe('ACL Tests', () => {
let cleanup: () => Promise<void>;
test.beforeAll(async ({ request }) => {
cleanup = await withSecurityEnabled(request, { acl: true, cerberus: true });
});
test.afterAll(async () => {
await cleanup();
});
test('should enforce ACL', async ({ page }) => {
// ACL is now enabled, test enforcement
});
});
Functions
| Function | Purpose |
|---|---|
getSecurityStatus |
Fetch current security module states |
setSecurityModuleEnabled |
Toggle a specific module on/off |
captureSecurityState |
Snapshot all module states |
restoreSecurityState |
Restore to captured snapshot |
withSecurityEnabled |
Enable modules with guaranteed cleanup |
disableAllSecurityModules |
Emergency reset |
API Endpoints Used
| Endpoint | Method | Purpose |
|---|---|---|
/api/v1/security/status |
GET | Returns current state of all security modules |
/api/v1/settings |
POST | Toggle settings with { key: "...", value: "true/false" } |
Settings Keys
| Key | Values | Description |
|---|---|---|
security.acl.enabled |
"true" / "false" |
Toggle ACL enforcement |
security.waf.enabled |
"true" / "false" |
Toggle WAF enforcement |
security.rate_limit.enabled |
"true" / "false" |
Toggle Rate Limiting |
security.crowdsec.enabled |
"true" / "false" |
Toggle CrowdSec |
feature.cerberus.enabled |
"true" / "false" |
Master toggle for all security |
Best Practices
- Always use
test.afterAllfor cleanup - it runs even when tests fail - Capture state before modifying - enables precise restoration
- Enable Cerberus first - it's the master toggle for all security modules
- Don't toggle back in individual tests - let
afterAllhandle cleanup - Use
withSecurityEnabledfor the cleanest pattern
Troubleshooting
ACL Deadlock Recovery
If the test suite is stuck due to ACL deadlock:
# Check current security status
curl http://localhost:8080/api/v1/security/status
# Manually disable ACL (requires auth)
curl -X POST http://localhost:8080/api/v1/settings \
-H "Content-Type: application/json" \
-d '{"key": "security.acl.enabled", "value": "false"}'
Complete Reset
Use disableAllSecurityModules in global setup to ensure clean slate:
import { disableAllSecurityModules } from './utils/security-helpers';
async function globalSetup() {
const context = await request.newContext({ baseURL: '...' });
await disableAllSecurityModules(context);
await context.dispose();
}