test: combine and modernize private-network checks; remove legacy disabled variants

This commit is contained in:
Scott Idem
2026-02-24 16:38:36 -05:00
parent 7f9f93765d
commit f2c426b595
14 changed files with 877 additions and 714 deletions

View File

@@ -1,62 +0,0 @@
import { test, expect } from '@playwright/test';
// This test attaches to the Chrome DevTools Protocol to capture low-level
// network events (including those from service workers). Run this with the
// real Chrome binary (channel: 'chrome') to reproduce the exact browser
// behavior that shows the PNA prompt.
test('CDP: detect private/local network requests and PNA preflights', async ({ page }) => {
const privateRequests: Array<any> = [];
function isPrivateHostname(hostname: string) {
if (!hostname) return false;
if (hostname === 'localhost' || hostname.endsWith('.localhost')) return true;
if (/^(127)\.|^(10)\.|^(192\.168)\.|^172\.(1[6-9]|2[0-9]|3[0-1])\./.test(hostname)) return true;
return false;
}
// Create a CDP session for the page to listen to Network events
const client = await page.context().newCDPSession(page);
await client.send('Network.enable');
client.on('Network.requestWillBeSent', (params) => {
try {
const url = params.request.url;
const hostname = new URL(url).hostname;
const headers = params.request.headers || {};
const pna = headers['access-control-request-private-network'] === 'true' || headers['Access-Control-Request-Private-Network'] === 'true';
if (isPrivateHostname(hostname) || pna) {
privateRequests.push({
url,
method: params.request.method,
initiator: params.initiator?.type,
pnaPreflight: pna,
headers
});
}
} catch (e) {}
});
// Also capture console messages to surface the same errors you see in Chrome.
const consoleMessages: string[] = [];
page.on('console', (msg) => {
consoleMessages.push(`${msg.type()}: ${msg.text()}`);
});
// Navigate to the site that triggers the behavior in your environment.
await page.goto('http://demo.localhost:5173/');
await page.waitForLoadState('networkidle');
if (privateRequests.length > 0) {
console.error('CDP detected private/local requests or PNA preflights:');
for (const r of privateRequests) console.error(JSON.stringify(r, null, 2));
}
if (consoleMessages.length) {
console.log('Captured console messages:');
consoleMessages.forEach((m) => console.log(m));
}
expect(privateRequests.length, 'No private/local network requests or PNA preflights should be made').toBe(0);
});

View File

@@ -0,0 +1,84 @@
import { test, expect } from '@playwright/test';
// Combined private-network detection test.
// Keeps both high-level request observation and low-level CDP capture in one
// place so you can run this when troubleshooting PNA / localhost access issues.
function isPrivateHostname(hostname: string) {
if (!hostname) return false;
if (hostname === 'localhost' || hostname.endsWith('.localhost')) return true;
if (/^(127)\.|^(10)\.|^(192\.168)\.|^172\.(1[6-9]|2[0-9]|3[0-1])\./.test(hostname)) return true;
return false;
}
test('detect private/local network requests and PNA preflights (combined)', async ({ page }) => {
const privateRequests: Array<any> = [];
const cdpPrivateRequests: Array<any> = [];
const consoleMessages: string[] = [];
page.on('console', (msg) => consoleMessages.push(`${msg.type()}: ${msg.text()}`));
page.on('request', (request) => {
try {
const url = new URL(request.url());
const headers = request.headers();
const hostname = url.hostname;
const pnaHeader = (headers['access-control-request-private-network'] || headers['Access-Control-Request-Private-Network']);
if (isPrivateHostname(hostname) || pnaHeader === 'true') {
privateRequests.push({ url: request.url(), method: request.method(), resourceType: request.resourceType(), pnaPreflight: pnaHeader === 'true', headers });
}
} catch (e) {
// ignore parse errors
}
});
page.on('requestfailed', (r) => {
try {
const url = new URL(r.url());
if (isPrivateHostname(url.hostname)) {
privateRequests.push({ url: r.url(), method: r.method(), failure: r.failure() });
}
} catch (e) {}
});
// CDP capture (may not be available in some browser channels)
try {
const client = await page.context().newCDPSession(page);
await client.send('Network.enable');
client.on('Network.requestWillBeSent', (params) => {
try {
const url = params.request.url;
const hostname = new URL(url).hostname;
const headers = params.request.headers || {};
const pna = headers['access-control-request-private-network'] === 'true' || headers['Access-Control-Request-Private-Network'] === 'true';
if (isPrivateHostname(hostname) || pna) {
cdpPrivateRequests.push({ url, method: params.request.method, initiator: params.initiator?.type, pnaPreflight: pna, headers });
}
} catch (e) {}
});
} catch (e) {
// CDP not available in this context; continue with high-level capture
}
await page.goto('http://demo.localhost:5173/');
await page.waitForLoadState('networkidle');
// Report findings for easier debugging
if (privateRequests.length > 0 || cdpPrivateRequests.length > 0 || consoleMessages.length > 0) {
if (consoleMessages.length) {
console.log('Console messages:');
consoleMessages.forEach((m) => console.log(m));
}
if (privateRequests.length) {
console.error('Detected private/local requests or PNA preflights (high-level):');
for (const r of privateRequests) console.error(JSON.stringify(r, null, 2));
}
if (cdpPrivateRequests.length) {
console.error('Detected private/local requests or PNA preflights (CDP):');
for (const r of cdpPrivateRequests) console.error(JSON.stringify(r, null, 2));
}
}
expect(privateRequests.length + cdpPrivateRequests.length, 'No private/local network requests or PNA preflights should be made').toBe(0);
});

View File

@@ -1,62 +0,0 @@
import { test, expect } from '@playwright/test';
// Detect requests to private/local address space or PNA preflight headers.
test('detect private/local network requests and PNA preflights', async ({ page }) => {
const privateRequests: Array<any> = [];
function isPrivateHostname(hostname: string) {
if (!hostname) return false;
// hostnames that resolve to local addresses or explicitly localhost
if (hostname === 'localhost' || hostname.endsWith('.localhost')) return true;
// IPv4 private ranges
if (/^(127)\.|^(10)\.|^(192\.168)\.|^172\.(1[6-9]|2[0-9]|3[0-1])\./.test(hostname)) return true;
return false;
}
page.on('request', (request) => {
try {
const url = new URL(request.url());
const headers = request.headers();
const hostname = url.hostname;
const pnaHeader = (headers['access-control-request-private-network'] || headers['Access-Control-Request-Private-Network']);
if (isPrivateHostname(hostname) || pnaHeader === 'true') {
privateRequests.push({
url: request.url(),
method: request.method(),
resourceType: request.resourceType(),
pnaPreflight: pnaHeader === 'true',
headers
});
}
} catch (e) {
// ignore parse errors
}
});
page.on('requestfailed', (r) => {
// capture failed requests that might be private and blocked
try {
const url = new URL(r.url());
if (isPrivateHostname(url.hostname)) {
privateRequests.push({ url: r.url(), method: r.method(), failure: r.failure() });
}
} catch (e) {}
});
// Navigate to the dev site used in other tests.
await page.goto('http://demo.localhost:5173/');
// Wait for network to settle.
await page.waitForLoadState('networkidle');
if (privateRequests.length > 0) {
console.error('Detected private/local requests or PNA preflights:');
for (const r of privateRequests) {
console.error(JSON.stringify(r, null, 2));
}
}
expect(privateRequests.length, 'No private/local network requests or PNA preflights should be made').toBe(0);
});

View File

@@ -1,105 +0,0 @@
import { test, expect } from '@playwright/test';
import { ae_app_local_data_defaults } from '../_helpers/ae_defaults';
test.describe('V3 API Header Integrity', () => {
test.setTimeout(7000);
test.beforeEach(async ({ page }) => {
// Log browser console errors to the terminal for easier debugging.
page.on('pageerror', (err) => console.error(`BROWSER ERROR: ${err.message}`));
page.on('console', (msg) => {
if (msg.type() === 'error' || msg.type() === 'warn') {
console.error(`BROWSER [${msg.type().toUpperCase()}]: ${msg.text()}`);
}
});
// Mock all local /v3/ API requests so tests are deterministic.
await page.route('**/v3/**', async (route) => {
const req = route.request();
const url = req.url();
// Handshake mock so app boots predictably
if (url.includes('site_domain/search')) {
return route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify({
data: [
{
id: 'test-site-domain-id',
account_id: 'test-account-id',
site_id: 'test-site-id',
account_name: 'Test Account',
enable: '1',
cfg_json: {}
}
]
})
});
}
// Provide lightweight responses for endpoints we assert on
if (url.includes('/v3/lookup/country/list')) {
return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ data: [] }) });
}
if (url.includes('/v3/crud/user/search')) {
return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ data: [] }) });
}
// Default handler
return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ data: [] }) });
});
});
test('Verify lookup requests include the unauthenticated bypass header', async ({ page }) => {
// Prepare the browser's localStorage with the necessary state for this test.
await page.addInitScript((defaults) => {
const testData = { ...defaults, account_id: 'test-account-id', manager_access: true };
window.localStorage.setItem('ae_loc', JSON.stringify(testData));
}, ae_app_local_data_defaults);
// Start waiting for the lookup request *before* navigating.
const requestPromise = page.waitForRequest((request) =>
request.url().includes('/v3/lookup/country/list')
);
// Navigate to the page that triggers the lookup.
await page.goto('/core/lookups');
// Wait for the request to be captured.
const request = await requestPromise;
const headers = request.headers();
// Assert that the correct bypass headers were used.
expect(headers['x-no-account-id']).toBe('Nothing to See Here');
expect(headers['x-aether-api-key']).toBeDefined();
});
test('Verify Account ID Scavenging from localStorage on CRUD requests', async ({ page }) => {
const testAccountId = 'scavenged-account-id-123';
// Prepare the browser's localStorage with a specific account ID.
await page.addInitScript(({ defaults, id }) => {
const testData = { ...defaults, account_id: id, manager_access: true };
window.localStorage.setItem('ae_loc', JSON.stringify(testData));
},{ defaults: ae_app_local_data_defaults, id: testAccountId });
// Start waiting for the CRUD request.
const requestPromise = page.waitForRequest((request) => {
const url = request.url();
// The /core/users page triggers a 'user' search on load.
return url.includes('/v3/crud/user/search');
});
// Navigate to a page that is guaranteed to make a standard CRUD call.
await page.goto('/core/users');
// Wait for the request to be captured.
const request = await requestPromise;
const headers = request.headers();
// Assert that the scavenged account ID was correctly included in the header.
expect(headers['x-account-id']).toBe(testAccountId);
});
});