Files
MineGeo/scripts/test-bug-reports-sql.mjs

387 lines
11 KiB
JavaScript

import assert from "node:assert/strict";
import { randomUUID } from "node:crypto";
import { readFile, readdir } from "node:fs/promises";
import { PGlite } from "../.data/sql-verification/node_modules/@electric-sql/pglite/dist/index.js";
const db = new PGlite();
try {
await db.exec(`create role anon;create role authenticated;create role service_role;
create schema auth;create table auth.users(id uuid primary key);
create function auth.uid() returns uuid language sql as $$select null::uuid$$;
create schema storage;create table storage.buckets(id text primary key,name text,public boolean,file_size_limit bigint);`);
for (const file of (await readdir("supabase/migrations"))
.filter((file) => file.endsWith(".sql"))
.sort())
await db.exec(await readFile(`supabase/migrations/${file}`, "utf8"));
const account = randomUUID();
await db.query("insert into auth.users values($1)", [account]);
await db.query(
"insert into public.profiles(id,display_name) values($1,'Support fixture')",
[account],
);
const hash = "a".repeat(64),
nonce = randomUUID();
const report = (
await db.query(
"insert into public.bug_reports(client_id,access_hash,display_name,title,description,state) values($1,$2,'Guest','Test issue','A valid test bug description.','pending') returning id",
[nonce, hash],
)
).rows[0].id;
assert.notEqual(
report,
nonce,
"Linear issue IDs are server generated, not chosen by the player",
);
const rpc = async (sql, params) => (await db.query(sql, params)).rows[0];
assert.equal(
(await rpc("select public.claim_bug_sync($1,'worker-a') as ok", [report]))
.ok,
true,
);
assert.equal(
(await rpc("select public.claim_bug_sync($1,'worker-b') as ok", [report]))
.ok,
false,
);
await db.query(
"update public.bug_reports set lease_until=now()-interval '1 second' where id=$1",
[report],
);
assert.equal(
(await rpc("select public.claim_bug_sync($1,'worker-b') as ok", [report]))
.ok,
true,
);
const command = randomUUID();
await db.query("select public.receive_bug_reply($1,$2,'Staff','',true)", [
report,
command,
]);
assert.equal(
(
await db.query(
"select glow_requested from public.bug_reports where id=$1",
[report],
)
).rows[0].glow_requested,
true,
);
await assert.rejects(
db.query("select public.claim_bug_report($1,$2,$3)", [
report,
"b".repeat(64),
account,
]),
/Report not found/,
);
await db.query("select public.claim_bug_report($1,$2,$3)", [
report,
hash,
account,
]);
assert.equal(
(
await db.query("select name_glow from public.profiles where id=$1", [
account,
])
).rows[0].name_glow,
true,
);
await db.query("select public.receive_bug_reply($1,$2,'Staff','',false)", [
report,
randomUUID(),
]);
await db.query("select public.receive_bug_reply($1,$2,'Staff','',true)", [
report,
command,
]);
assert.equal(
(
await db.query("select name_glow from public.profiles where id=$1", [
account,
])
).rows[0].name_glow,
false,
"old duplicate grant cannot override a revoke",
);
await db.query(
"select public.receive_bug_reply($1,$2,'Staff','We found the bug.',null)",
[report, randomUUID()],
);
assert.equal(
(
await db.query(
"select count(*)::integer as n from public.bug_report_messages where report_id=$1",
[report],
)
).rows[0].n,
3,
);
for (const role of ["anon", "authenticated"]) {
await db.exec(`set role ${role}`);
for (const table of ["bug_reports", "bug_report_messages"])
await assert.rejects(
db.query(`select * from public.${table}`),
/permission denied/,
);
await assert.rejects(
db.query("select public.receive_bug_reply($1,$2,'Spoof','Fake',true)", [
report,
randomUUID(),
]),
/permission denied/,
);
await assert.rejects(
db.query("select public.claim_bug_report($1,$2,$3)", [
report,
hash,
account,
]),
/permission denied/,
);
await db.exec("reset role");
}
await db.exec(
"create role reward_probe bypassrls;grant update on public.profiles to reward_probe;grant select on public.profiles to reward_probe;set role reward_probe;",
);
await assert.rejects(
db.query("update public.profiles set name_glow=true where id=$1", [
account,
]),
/Reward permission/,
);
await db.exec("reset role");
assert.equal(
(
await db.query("select bug_finder from public.profiles where id=$1", [
account,
])
).rows[0].bug_finder,
true,
"revoking glow keeps the confirmed bug-finder badge",
);
await assert.rejects(
db.query("update public.profiles set glow_color='#123456' where id=$1", [
account,
]),
/Earn a username glow/,
);
const mod = randomUUID();
await db.query("insert into auth.users values($1)", [mod]);
await db.query("insert into public.profiles(id,role) values($1,'admin')", [
mod,
]);
await assert.rejects(
db.query("select public.set_user_prefix($1,$2,'Builder','gem')", [
account,
mod,
]),
/Admin permission/,
);
await db.query("select public.set_user_prefix($1,$2,'Builder','gem')", [
mod,
account,
]);
assert.equal(
(
await db.query("select custom_prefix from public.profiles where id=$1", [
account,
])
).rows[0].custom_prefix,
"Builder",
);
await db.query("select public.set_user_prefix($1,$2,null,'star')", [
mod,
account,
]);
assert.equal(
(
await db.query("select custom_prefix from public.profiles where id=$1", [
account,
])
).rows[0].custom_prefix,
null,
);
await db.exec("set role reward_probe");
for (const column of [
"role='moderator'",
"role='admin'",
"bug_finder=false",
"custom_prefix='Spoof'",
"custom_prefix_icon='crown'",
])
await assert.rejects(
db.query(`update public.profiles set ${column} where id=$1`, [account]),
/Moderator permission/,
);
await assert.rejects(
db.query("select public.set_user_prefix($1,$2,'Spoof','star')", [
mod,
account,
]),
/permission denied/,
);
await db.exec("reset role");
const guest = (
await db.query(
"insert into public.bug_reports(client_id,access_hash,display_name,title,description,state) values($1,$2,'Guest','Guest verification','A guest verification description.','pending') returning id",
[randomUUID(), hash],
)
).rows[0].id;
await db.query("select public.receive_bug_reply($1,$2,'Staff','',true)", [
guest,
randomUUID(),
]);
await db.query("select public.receive_bug_reply($1,$2,'Staff','',false)", [
guest,
randomUUID(),
]);
await db.query("select public.claim_bug_report($1,$2,$3)", [
guest,
hash,
mod,
]);
const claimed = (
await db.query(
"select bug_finder,name_glow from public.profiles where id=$1",
[mod],
)
).rows[0];
assert.equal(claimed.bug_finder, true);
assert.equal(claimed.name_glow, false);
const closeEvent = randomUUID();
await db.query("select public.receive_bug_close($1,$2)", [
report,
closeEvent,
]);
let closed = (
await db.query("select * from public.bug_reports where id=$1", [report])
).rows[0];
assert.equal(closed.state, "done");
assert.equal(
new Date(closed.delete_after) - new Date(closed.closed_at),
3 * 86400000,
);
await db.query("select public.set_bug_report_done($1,true,null)", [report]);
assert.equal(
String(
(
await db.query("select closed_at from public.bug_reports where id=$1", [
report,
])
).rows[0].closed_at,
),
String(closed.closed_at),
"repeat close preserves deadline",
);
assert.equal(
(
await db.query("select public.begin_bug_purge($1,$2) as ok", [
report,
closed.closed_at,
])
).rows[0].ok,
false,
"cannot purge before three days",
);
await assert.rejects(
db.query(
"insert into public.bug_report_messages(report_id,kind,body,author_name) values($1,'user','new message','Guest')",
[report],
),
/Done/,
);
await db.query("select public.set_bug_report_done($1,false,null)", [report]);
assert.equal(
(
await db.query("select public.receive_bug_close($1,$2) as ok", [
report,
closeEvent,
])
).rows[0].ok,
false,
"replayed close command cannot reclose a reopened report",
);
await db.query(
"select public.set_bug_report_done($1,true,clock_timestamp()-interval '4 days')",
[report],
);
closed = (
await db.query("select * from public.bug_reports where id=$1", [report])
).rows[0];
assert.equal(
(
await db.query("select public.begin_bug_purge($1,$2) as ok", [
report,
closed.closed_at,
])
).rows[0].ok,
false,
"Linear completion must be confirmed",
);
await db.query(
"update public.bug_reports set linear_done_synced=true where id=$1",
[report],
);
assert.equal(
(
await db.query("select public.begin_bug_purge($1,$2) as ok", [
report,
closed.closed_at,
])
).rows[0].ok,
true,
);
assert.equal(
(
await db.query("select public.set_bug_report_done($1,false,null) as ok", [
report,
])
).rows[0].ok,
false,
"cannot reopen midway through irreversible purge",
);
await db.query("select public.finish_bug_purge($1,$2)", [
report,
closed.closed_at,
]);
assert.equal(
(
await db.query(
"select count(*)::int as n from public.bug_report_messages where report_id=$1",
[report],
)
).rows[0].n,
0,
"messages cascade on purge",
);
assert.equal(
(
await db.query("select bug_finder from public.profiles where id=$1", [
account,
])
).rows[0].bug_finder,
true,
"account recognition survives report deletion",
);
for (const role of ["anon", "authenticated"]) {
await db.exec(`set role ${role}`);
await assert.rejects(
db.query("select public.set_bug_report_done($1,true,null)", [guest]),
/permission denied/,
);
await assert.rejects(
db.query("select public.finish_bug_purge($1,now())", [guest]),
/permission denied/,
);
await db.exec("reset role");
}
console.log(
"Bug report SQL passed: private tables, lease retries, guest claims, staff reply deduplication, grant/revoke rewards and privilege isolation.",
);
} catch (error) {
console.error(error.message);
process.exitCode = 1;
} finally {
await db.close();
}