From 7f9f93765d8b88c7736a2490cf765086242cfee8 Mon Sep 17 00:00:00 2001 From: Scott Idem Date: Tue, 24 Feb 2026 16:36:27 -0500 Subject: [PATCH] test: modernize v3 API security tests (mock /v3/, deterministic headers); add runnable modern copy --- tests/disabled/v3_api_security.test.ts | 28 ++++++---- tests/v3_api_security.modern.test.ts | 74 ++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 11 deletions(-) create mode 100644 tests/v3_api_security.modern.test.ts diff --git a/tests/disabled/v3_api_security.test.ts b/tests/disabled/v3_api_security.test.ts index 347e80b3..f2946dc2 100644 --- a/tests/disabled/v3_api_security.test.ts +++ b/tests/disabled/v3_api_security.test.ts @@ -13,11 +13,12 @@ test.describe('V3 API Header Integrity', () => { } }); - // Mock all API requests to ensure tests are fast and independent of the network. - await page.route('**/*oneskyit.com/**', async (route) => { - const url = route.request().url(); + // Mock all local /v3/ API requests so tests are deterministic. + await page.route('**/v3/**', async (route) => { + const req = route.request(); + const url = req.url(); - // 1. Handshake Mock: Provide a complete response to allow the app to boot. + // Handshake mock so app boots predictably if (url.includes('site_domain/search')) { return route.fulfill({ status: 200, @@ -26,7 +27,6 @@ test.describe('V3 API Header Integrity', () => { data: [ { id: 'test-site-domain-id', - id_random: 'test-site-domain-id', account_id: 'test-account-id', site_id: 'test-site-id', account_name: 'Test Account', @@ -37,12 +37,18 @@ test.describe('V3 API Header Integrity', () => { }) }); } - // 2. Default Mock: Provide a generic empty success response for all other API calls. - return route.fulfill({ - status: 200, - contentType: 'application/json', - body: JSON.stringify({ data: [] }) - }); + + // 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: [] }) }); }); }); diff --git a/tests/v3_api_security.modern.test.ts b/tests/v3_api_security.modern.test.ts new file mode 100644 index 00000000..18ecd99e --- /dev/null +++ b/tests/v3_api_security.modern.test.ts @@ -0,0 +1,74 @@ +import { test, expect } from '@playwright/test'; +import { ae_app_local_data_defaults } from './_helpers/ae_defaults'; + +test.describe('V3 API Header Integrity (modernized)', () => { + test.setTimeout(10000); + + test.beforeEach(async ({ page }) => { + 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 local /v3/ endpoints used by the app to make the test deterministic. + await page.route('**/v3/**', async (route) => { + const req = route.request(); + const url = req.url(); + + if (url.includes('site_domain/search')) { + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ data: [{ id: 'test-site', account_id: 'test-account-id', site_id: 'test-site-id', cfg_json: {} }] }) + }); + } + + 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: [] }) }); + } + + return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ data: [] }) }); + }); + }); + + test('Verify lookup requests include the unauthenticated bypass header', async ({ page }) => { + 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); + + const requestPromise = page.waitForRequest((request) => request.url().includes('/v3/lookup/country/list')); + + await page.goto('/core/lookups'); + + const request = await requestPromise; + const headers = request.headers(); + + 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'; + + 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 }); + + const requestPromise = page.waitForRequest((request) => request.url().includes('/v3/crud/user/search')); + + await page.goto('/core/users'); + + const request = await requestPromise; + const headers = request.headers(); + + expect(headers['x-account-id']).toBe(testAccountId); + }); +});