Spaces:
Runtime error
Runtime error
File size: 4,907 Bytes
1804b24 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | import postgres from 'postgres';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const envPath = path.join(__dirname, '../artifacts/api-server/.env');
let connectionString = process.env.DATABASE_URL;
if (!connectionString && fs.existsSync(envPath)) {
const envContent = fs.readFileSync(envPath, 'utf8');
const match = envContent.match(/DATABASE_URL=(.*)/);
if (match) connectionString = match[1].trim();
}
if (!connectionString) {
console.error("DATABASE_URL is not set");
process.exit(1);
}
const sql = postgres(connectionString);
const USER_A = '00000000-0000-0000-0000-000000000001';
const USER_B = '00000000-0000-0000-0000-000000000002';
async function runTest() {
try {
console.log("--- Starting Comprehensive RLS Verification Test ---");
const tables = ['clients', 'projects', 'tasks', 'time_entries', 'briefs'];
// 1. Clean up
for (const table of tables) {
await sql.unsafe(`DELETE FROM ${table} WHERE user_id IN ('${USER_A}', '${USER_B}')`);
}
console.log("✓ Cleaned up old test data for all tables.");
const runAsUser = async (userId, queryFn) => {
return await sql.begin(async (tx) => {
await tx.unsafe(`SET LOCAL role TO authenticated`);
await tx.unsafe(`SET LOCAL "request.jwt.claims" TO '{"sub": "${userId}"}'`);
return await queryFn(tx);
});
};
// Test each table
for (const table of tables) {
console.log(`\n--- Testing Table: ${table} ---`);
// Prepare dummy data for insertion
let data = { user_id: USER_A };
if (table === 'clients') { data.name = 'Test Client A'; data.email = 'a@test.com'; }
if (table === 'projects') { data.title = 'Test Project A'; }
if (table === 'tasks') {
// Need a project first
const p = await runAsUser(USER_A, tx => tx`INSERT INTO projects (title, user_id) VALUES ('Project for Task', ${USER_A}) RETURNING id`);
data.title = 'Test Task A'; data.project_id = p[0].id;
}
if (table === 'time_entries') {
const p = await runAsUser(USER_A, tx => tx`INSERT INTO projects (title, user_id) VALUES ('Project for Time', ${USER_A}) RETURNING id`);
data.hours = 1.5; data.date = '2024-01-01'; data.project_id = p[0].id;
}
if (table === 'briefs') { data.title = 'Test Brief A'; data.content = 'Content A'; }
// 2. Insert
console.log(`Testing: User A inserts into ${table}...`);
await runAsUser(USER_A, async (tx) => {
await tx.unsafe(`INSERT INTO ${table} (${Object.keys(data).join(',')}) VALUES (${Object.values(data).map(v => typeof v === 'string' ? `'${v}'` : v).join(',')})`);
});
console.log(`✓ User A successfully inserted into ${table}.`);
// 3. Select (Self)
const rowsA = await runAsUser(USER_A, async (tx) => {
return await tx.unsafe(`SELECT * FROM ${table} WHERE user_id = '${USER_A}'`);
});
if (rowsA.length > 0) {
console.log(`✓ User A successfully read their own data from ${table}.`);
} else {
throw new Error(`User A could not read their own data from ${table}!`);
}
// 4. Select (Other)
const rowsB = await runAsUser(USER_B, async (tx) => {
return await tx.unsafe(`SELECT * FROM ${table} WHERE user_id = '${USER_A}'`);
});
if (rowsB.length === 0) {
console.log(`✓ User B cannot see User A's data in ${table} (RLS Working).`);
} else {
throw new Error(`CRITICAL: User B can see User A's data in ${table}!`);
}
// 5. Update (Other)
const updateCol = (table === 'clients' ? 'name' : (table === 'time_entries' ? 'description' : 'title'));
const updateResult = await runAsUser(USER_B, async (tx) => {
return await tx.unsafe(`UPDATE ${table} SET ${updateCol} = 'Hacked' WHERE user_id = '${USER_A}'`);
});
if (updateResult.count === 0) {
console.log(`✓ User B cannot update User A's data in ${table} (RLS Working).`);
} else {
throw new Error(`CRITICAL: User B updated User A's data in ${table}!`);
}
// 6. Delete (Other)
const deleteResult = await runAsUser(USER_B, async (tx) => {
return await tx.unsafe(`DELETE FROM ${table} WHERE user_id = '${USER_A}'`);
});
if (deleteResult.count === 0) {
console.log(`✓ User B cannot delete User A's data in ${table} (RLS Working).`);
} else {
throw new Error(`CRITICAL: User B deleted User A's data in ${table}!`);
}
}
console.log("\n--- All Comprehensive RLS Verification Tests Passed Successfully! ---");
} catch (err) {
console.error("\nFAIL: RLS Verification Failed!");
console.error(err.stack || err.message);
process.exit(1);
} finally {
await sql.end();
}
}
runTest();
|