- Standardized E2E base URL to 127.0.0.1 to resolve cookie domain 401 errors - Updated playwright config to strictly exclude security tests from main shards - Refactored waitForModal helper to prevent strict mode violations on complex modals - Fixed leak of crowdsec diagnostics tests into standard chromium project
157 lines
5.4 KiB
TypeScript
157 lines
5.4 KiB
TypeScript
/**
|
|
* Admin Whitelist IP Blocking Enforcement Tests
|
|
*
|
|
* CRITICAL: This test MUST run LAST in the security-enforcement suite.
|
|
* Uses 'zzz-' prefix to ensure alphabetical ordering places it at the end.
|
|
*
|
|
* Tests validate that Cerberus admin whitelist correctly blocks non-whitelisted IPs
|
|
* and allows whitelisted IPs or emergency tokens.
|
|
*
|
|
* Recovery: Uses emergency reset in afterAll to unblock test IP.
|
|
*/
|
|
|
|
import { test, expect } from '@playwright/test';
|
|
|
|
test.describe.serial('Admin Whitelist IP Blocking (RUN LAST)', () => {
|
|
const EMERGENCY_TOKEN = process.env.CHARON_EMERGENCY_TOKEN;
|
|
const BASE_URL = process.env.PLAYWRIGHT_BASE_URL || 'http://127.0.0.1:8080';
|
|
|
|
test.beforeAll(() => {
|
|
if (!EMERGENCY_TOKEN) {
|
|
throw new Error(
|
|
'CHARON_EMERGENCY_TOKEN required for admin whitelist tests\n' +
|
|
'Generate with: openssl rand -hex 32'
|
|
);
|
|
}
|
|
});
|
|
|
|
test.afterAll(async ({ request }) => {
|
|
// CRITICAL: Emergency reset to unblock test IP
|
|
console.log('🔧 Emergency reset - cleaning up admin whitelist test');
|
|
|
|
try {
|
|
const response = await request.post('http://localhost:2020/emergency/security-reset', {
|
|
headers: {
|
|
'Authorization': 'Basic ' + Buffer.from('admin:changeme').toString('base64'),
|
|
'X-Emergency-Token': EMERGENCY_TOKEN,
|
|
'Content-Type': 'application/json',
|
|
},
|
|
data: { reason: 'E2E test cleanup - admin whitelist blocking test' },
|
|
});
|
|
|
|
if (response.ok()) {
|
|
console.log('✅ Emergency reset completed - test IP unblocked');
|
|
} else {
|
|
console.error(`❌ Emergency reset failed: ${response.status()}`);
|
|
}
|
|
} catch (error) {
|
|
console.error('Emergency reset error:', error);
|
|
}
|
|
});
|
|
|
|
test('Test 1: should block non-whitelisted IP when Cerberus enabled', async ({ request }) => {
|
|
// Use a fake whitelist IP that will never match the test runner
|
|
const fakeWhitelist = '192.0.2.1/32'; // RFC 5737 TEST-NET-1 (documentation only)
|
|
|
|
await test.step('Configure admin whitelist with non-matching IP', async () => {
|
|
const response = await request.patch(`${BASE_URL}/api/v1/security/acl`, {
|
|
data: {
|
|
enabled: false, // Ensure disabled first
|
|
},
|
|
});
|
|
expect(response.ok()).toBeTruthy();
|
|
|
|
// Set the admin whitelist
|
|
const configResponse = await request.patch(`${BASE_URL}/api/v1/config`, {
|
|
data: {
|
|
security: {
|
|
admin_whitelist: fakeWhitelist,
|
|
},
|
|
},
|
|
});
|
|
expect(configResponse.ok()).toBeTruthy();
|
|
});
|
|
|
|
await test.step('Enable ACL - expect 403 because IP not in whitelist', async () => {
|
|
const response = await request.patch(`${BASE_URL}/api/v1/security/acl`, {
|
|
data: { enabled: true },
|
|
});
|
|
|
|
// Should be blocked because our IP is not in the admin_whitelist
|
|
expect(response.status()).toBe(403);
|
|
|
|
const body = await response.json().catch(() => ({}));
|
|
expect(body.error || '').toMatch(/whitelist|forbidden|access/i);
|
|
});
|
|
});
|
|
|
|
test('Test 2: should allow whitelisted IP to enable Cerberus', async ({ request }) => {
|
|
// Use localhost/Docker network IP that will match test runner
|
|
// In Docker compose, Playwright runs from host connecting to localhost:8080
|
|
const testWhitelist = '127.0.0.1/32,172.16.0.0/12,192.168.0.0/16,10.0.0.0/8';
|
|
|
|
await test.step('Configure admin whitelist with test IP ranges', async () => {
|
|
const response = await request.patch(`${BASE_URL}/api/v1/config`, {
|
|
data: {
|
|
security: {
|
|
admin_whitelist: testWhitelist,
|
|
},
|
|
},
|
|
});
|
|
expect(response.ok()).toBeTruthy();
|
|
});
|
|
|
|
await test.step('Enable ACL with whitelisted IP', async () => {
|
|
const response = await request.patch(`${BASE_URL}/api/v1/security/acl`, {
|
|
data: { enabled: true },
|
|
});
|
|
expect(response.ok()).toBeTruthy();
|
|
|
|
const body = await response.json();
|
|
expect(body.enabled).toBe(true);
|
|
});
|
|
|
|
await test.step('Verify ACL is enforcing', async () => {
|
|
const response = await request.get(`${BASE_URL}/api/v1/security/status`);
|
|
expect(response.ok()).toBeTruthy();
|
|
|
|
const body = await response.json();
|
|
expect(body.acl?.enabled).toBe(true);
|
|
});
|
|
});
|
|
|
|
test('Test 3: should allow emergency token to bypass admin whitelist', async ({ request }) => {
|
|
await test.step('Configure admin whitelist with non-matching IP', async () => {
|
|
// First disable ACL so we can change config
|
|
await request.post('http://localhost:2020/emergency/security-reset', {
|
|
headers: {
|
|
'Authorization': 'Basic ' + Buffer.from('admin:changeme').toString('base64'),
|
|
'X-Emergency-Token': EMERGENCY_TOKEN,
|
|
},
|
|
data: { reason: 'Test setup - reset for emergency token test' },
|
|
});
|
|
|
|
const response = await request.patch(`${BASE_URL}/api/v1/config`, {
|
|
data: {
|
|
security: {
|
|
admin_whitelist: '192.0.2.1/32', // Fake IP
|
|
},
|
|
},
|
|
});
|
|
expect(response.ok()).toBeTruthy();
|
|
});
|
|
|
|
await test.step('Enable ACL using emergency token despite IP mismatch', async () => {
|
|
const response = await request.patch(`${BASE_URL}/api/v1/security/acl`, {
|
|
data: { enabled: true },
|
|
headers: {
|
|
'X-Emergency-Token': EMERGENCY_TOKEN,
|
|
},
|
|
});
|
|
|
|
// Should succeed with valid emergency token even though IP not in whitelist
|
|
expect(response.ok()).toBeTruthy();
|
|
});
|
|
});
|
|
});
|