Files
proffesor-for-testing__agen…/tests/e2e/specs/security.spec.ts
Profa 2253d05618 feat: flatten project structure — archive v2, promote v3 to root
Remove the nested v3/ subdirectory by moving all active source code,
tests, configs, and assets directly to the project root. Archive v2/
(dead code, 847MB) to v2-archive.tar.gz.

Key changes:
- Move v3/src/ → src/, v3/tests/ → tests/, v3/packages/ → packages/
- Move v3/tsconfig.json, v3/vitest.config.ts to root
- Merge v3/package.json into root package.json (ESM, scripts, deps, exports)
- Merge v3/scripts/ into scripts/, v3/implementation/ into docs/implementation/
- Update all CI workflows to remove "cd v3 &&" and v3/ path prefixes
- Fix all init installer path resolution (3-level-up → 2-level-up)
- Fix hooks to use "node ./dist/cli/bundle.js" instead of bare "aqe"
- Update settings.json ADR/DDD directories to docs/implementation/
- Fix helper scripts (statusline, adr-compliance, ddd-tracker, guidance-hooks)
- Update 58 agent definitions: aqe/v3/ → aqe/ memory namespaces
- Update 15 guidance shards: v3/src/ → src/ path references
- Fix sync interfaces: remove v3/ and v2/ path references
- Fix test path calculations (process.cwd() + '..' no longer needed)
- Fix flaky perf test threshold (500ms → 1000ms for CI environments)
- Fix complexity-analyzer test to match ADR-051 keyword-based eligibility

Build passes, 17,901 tests pass, CLI and MCP bundles verified.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 11:35:41 +00:00

353 lines
11 KiB
TypeScript

import { test, expect } from '@playwright/test';
import { SearchPage, LoginPage, RegisterPage, CartPage, ProductPage } from '../pages';
import { testData } from '../fixtures/test-data';
/**
* Security E2E Tests
* Tests for XSS, CSRF, and other security vulnerabilities
*
* Generated by: qe-queen-coordinator
* Priority: P0 (Security Critical)
*/
test.describe('Security Tests @security @critical', () => {
test.describe('XSS Prevention - Search', () => {
test('should sanitize script tags in search query', async ({ page }) => {
const searchPage = new SearchPage(page);
await searchPage.navigate();
await searchPage.search(testData.securityPayloads.xss.scriptTag);
// Verify no script execution
const alertTriggered = await page.evaluate(() => {
return (window as any).__xss_triggered || false;
});
expect(alertTriggered).toBe(false);
// Page should still be functional
await expect(searchPage.searchInput).toBeVisible();
});
test('should sanitize img onerror XSS in search', async ({ page }) => {
const searchPage = new SearchPage(page);
await searchPage.navigate();
await searchPage.search(testData.securityPayloads.xss.imgOnerror);
// Verify no script execution
const alertTriggered = await page.evaluate(() => {
return (window as any).__xss_triggered || false;
});
expect(alertTriggered).toBe(false);
});
test('should sanitize svg onload XSS in search', async ({ page }) => {
const searchPage = new SearchPage(page);
await searchPage.navigate();
await searchPage.search(testData.securityPayloads.xss.svgOnload);
const alertTriggered = await page.evaluate(() => {
return (window as any).__xss_triggered || false;
});
expect(alertTriggered).toBe(false);
});
test('should sanitize event handler XSS in search', async ({ page }) => {
const searchPage = new SearchPage(page);
await searchPage.navigate();
await searchPage.search(testData.securityPayloads.xss.eventHandler);
const alertTriggered = await page.evaluate(() => {
return (window as any).__xss_triggered || false;
});
expect(alertTriggered).toBe(false);
});
test('should handle URL-encoded XSS in search', async ({ page }) => {
const searchPage = new SearchPage(page);
await searchPage.navigateWithQuery(testData.securityPayloads.xss.urlEncodedScript);
const alertTriggered = await page.evaluate(() => {
return (window as any).__xss_triggered || false;
});
expect(alertTriggered).toBe(false);
});
});
test.describe('XSS Prevention - Forms', () => {
test('should sanitize XSS in login email field', async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.navigate();
await loginPage.login(
testData.securityPayloads.xss.scriptTag,
'password123'
);
const alertTriggered = await page.evaluate(() => {
return (window as any).__xss_triggered || false;
});
expect(alertTriggered).toBe(false);
});
test('should sanitize XSS in registration fields', async ({ page }) => {
const registerPage = new RegisterPage(page);
await registerPage.navigate();
await registerPage.register({
firstName: testData.securityPayloads.xss.scriptTag,
lastName: testData.securityPayloads.xss.imgOnerror,
email: 'test@example.com',
password: 'ValidPassword123!'
});
const alertTriggered = await page.evaluate(() => {
return (window as any).__xss_triggered || false;
});
expect(alertTriggered).toBe(false);
});
});
test.describe('SQL Injection Prevention', () => {
test('should handle SQL injection in search', async ({ page }) => {
const searchPage = new SearchPage(page);
await searchPage.navigate();
await searchPage.search(testData.securityPayloads.sqlInjection.basic);
// Page should not crash or show database errors
await expect(searchPage.searchInput).toBeVisible();
// Check for database error messages
const pageContent = await page.content();
expect(pageContent).not.toContain('SQL');
expect(pageContent).not.toContain('syntax error');
expect(pageContent).not.toContain('mysql');
expect(pageContent).not.toContain('postgresql');
});
test('should handle UNION injection attempt', async ({ page }) => {
const searchPage = new SearchPage(page);
await searchPage.navigate();
await searchPage.search(testData.securityPayloads.sqlInjection.union);
// Page should not crash
await expect(searchPage.searchInput).toBeVisible();
});
test('should handle DROP TABLE injection attempt', async ({ page }) => {
const searchPage = new SearchPage(page);
await searchPage.navigate();
await searchPage.search(testData.securityPayloads.sqlInjection.dropTable);
// Page should not crash
await expect(searchPage.searchInput).toBeVisible();
});
});
test.describe('HTTPS Enforcement', () => {
test('should use HTTPS on all pages', async ({ page }) => {
const pages = [
'/',
'/collections/all',
'/account/login',
'/account/register',
'/cart',
'/search'
];
for (const path of pages) {
await page.goto(path);
expect(page.url()).toMatch(/^https:\/\//);
}
});
test('should not expose sensitive data in URL', async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.navigate();
await loginPage.login('test@example.com', 'SecretPassword123!');
// Password should never appear in URL
expect(page.url()).not.toContain('SecretPassword');
expect(page.url()).not.toContain('password');
});
});
test.describe('Cookie Security', () => {
test('should set secure cookies', async ({ page, context }) => {
await page.goto('/');
const cookies = await context.cookies();
// Check Shopify session cookies
const sessionCookies = cookies.filter(c =>
c.name.includes('_shopify') || c.name.includes('cart')
);
for (const cookie of sessionCookies) {
// On HTTPS, secure flag should be set
// Note: This may vary based on environment
expect(cookie.path).toBeDefined();
}
});
});
test.describe('Price Manipulation Prevention', () => {
test('should not allow client-side price changes to affect checkout', async ({ page }) => {
const productPage = new ProductPage(page);
const cartPage = new CartPage(page);
await productPage.navigate(testData.products.greyJacket.slug);
if (await productPage.isInStock()) {
await productPage.addToCart();
await productPage.goToCart();
// Try to manipulate price via console
await page.evaluate(() => {
// Attempt to change price elements
const priceElements = document.querySelectorAll('[data-price], .price');
priceElements.forEach(el => {
el.textContent = '0.01';
});
});
// Proceed to checkout
if (!(await cartPage.isCartEmpty())) {
await cartPage.proceedToCheckout();
// Server should have correct price, not manipulated price
// Checkout should show actual product price
expect(page.url()).toContain('checkout');
}
} else {
test.skip();
}
});
});
test.describe('Input Length Limits', () => {
test('should handle extremely long input in search', async ({ page }) => {
const searchPage = new SearchPage(page);
const longInput = 'a'.repeat(10000);
await searchPage.navigate();
// Should not crash with very long input
await searchPage.searchInput.fill(longInput);
await searchPage.searchButton.click();
// Page should remain functional
await expect(searchPage.searchInput).toBeVisible();
});
test('should handle extremely long email in login', async ({ page }) => {
const loginPage = new LoginPage(page);
const longEmail = 'a'.repeat(1000) + '@example.com';
await loginPage.navigate();
await loginPage.emailInput.fill(longEmail);
await loginPage.passwordInput.fill('password123');
await loginPage.loginButton.click();
// Should not crash, should show validation error
await expect(loginPage.emailInput).toBeVisible();
});
});
test.describe('Error Message Security', () => {
test('should not expose stack traces in error messages', async ({ page }) => {
await page.goto('/nonexistent-page-12345');
const pageContent = await page.content();
// Should not contain stack trace indicators
expect(pageContent).not.toContain('at Function');
expect(pageContent).not.toContain('at Module');
expect(pageContent).not.toContain('.js:');
expect(pageContent).not.toContain('node_modules');
});
test('should not expose database information in errors', async ({ page }) => {
const searchPage = new SearchPage(page);
await searchPage.navigate();
await searchPage.search("'");
const pageContent = await page.content();
// Should not contain database error information
expect(pageContent).not.toContain('mysql');
expect(pageContent).not.toContain('postgresql');
expect(pageContent).not.toContain('mongodb');
expect(pageContent).not.toContain('database');
});
});
test.describe('CAPTCHA Protection', () => {
test('should have CAPTCHA on login page', async ({ page }) => {
const loginPage = new LoginPage(page);
await loginPage.navigate();
const hasCaptcha = await loginPage.hasCaptcha();
// CAPTCHA presence indicates bot protection
// Log result for awareness
console.log(`Login page CAPTCHA present: ${hasCaptcha}`);
});
test('should have CAPTCHA on registration page', async ({ page }) => {
const registerPage = new RegisterPage(page);
await registerPage.navigate();
const hasCaptcha = await registerPage.hasCaptcha();
console.log(`Registration page CAPTCHA present: ${hasCaptcha}`);
});
});
test.describe('Content Security', () => {
test('should not load external scripts from untrusted sources', async ({ page }) => {
await page.goto('/');
// Get all script sources
const scripts = await page.evaluate(() => {
const scriptElements = document.querySelectorAll('script[src]');
return Array.from(scriptElements).map(s => s.getAttribute('src'));
});
// All scripts should be from trusted sources
const trustedDomains = [
'shopify.com',
'cloudflare',
'facebook.net',
'hcaptcha.com',
'adroll',
'googleapis'
];
for (const src of scripts) {
if (src && src.startsWith('http')) {
const isFromTrustedSource = trustedDomains.some(domain =>
src.includes(domain)
);
// External scripts should be from known sources
expect(isFromTrustedSource || src.includes(page.url())).toBe(true);
}
}
});
});
});