ff5ad26cfc
- Switched to secure httpOnly, SameSite=Strict cookies for JWT authentication. - Refactored backend to use AppState for shared secrets and database pool caching. - Modernized frontend with Svelte 5 runes ($state) and removed localStorage reliance. - Gated destructive test endpoints behind debug_assertions and fixed unsafe test patterns. - Enhanced CI pipeline with cargo clippy, cargo fmt, and pinned pnpm version. - Updated documentation and implementation plans to match the hardened architecture.
61 lines
2.1 KiB
TypeScript
61 lines
2.1 KiB
TypeScript
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
|
|
async function globalSetup() {
|
|
// Read env vars written by scripts/test-env.sh (make test-up calls it first)
|
|
const envFile = path.resolve(__dirname, '../../data/test/.env');
|
|
if (!fs.existsSync(envFile)) {
|
|
throw new Error('data/test/.env not found — run "make test-up" first');
|
|
}
|
|
for (const line of fs.readFileSync(envFile, 'utf-8').split('\n')) {
|
|
const eq = line.indexOf('=');
|
|
if (eq > 0) process.env[line.slice(0, eq).trim()] = line.slice(eq + 1).trim();
|
|
}
|
|
|
|
const baseURL = process.env.TT_BASE_URL!;
|
|
|
|
// Obtain admin JWT via the login API
|
|
const res = await fetch(`${baseURL}/api/auth/login`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ email: 'admin@tutortool.com', password: 'admin' }),
|
|
});
|
|
if (!res.ok) throw new Error(`Login failed: ${res.status} ${await res.text()}`);
|
|
|
|
// Extract token from Set-Cookie header
|
|
const setCookie = res.headers.get('set-cookie');
|
|
const tokenMatch = setCookie?.match(/token=([^;]+)/);
|
|
const token = tokenMatch ? tokenMatch[1] : '';
|
|
|
|
const { is_superadmin } = await res.json() as { is_superadmin: boolean };
|
|
|
|
// Write Playwright storage state with cookies pre-populated
|
|
const authDir = path.resolve(__dirname, '.auth');
|
|
fs.mkdirSync(authDir, { recursive: true });
|
|
const storageState = {
|
|
cookies: [
|
|
{
|
|
name: 'token',
|
|
value: token,
|
|
domain: new URL(baseURL).hostname,
|
|
path: '/',
|
|
httpOnly: true,
|
|
secure: true,
|
|
sameSite: 'Strict' as const,
|
|
}
|
|
],
|
|
origins: [
|
|
{
|
|
origin: baseURL,
|
|
localStorage: [],
|
|
},
|
|
],
|
|
};
|
|
fs.writeFileSync(path.join(authDir, 'admin.json'), JSON.stringify(storageState, null, 2));
|
|
}
|
|
|
|
export default globalSetup;
|