Substitutes the real admin UID everywhere the placeholder appeared, points the Edge Functions base URL at the deployed project, and adds production JWT verification: trigger functions now send the anon key as a bearer token so verify_jwt can stay enabled instead of leaving the functions open to unauthenticated calls from the public internet. Also adds scripts/create-admin.ts (one-off helper used to create Mira's admin auth user), documents the seed script's non-VITE env vars in .env.example, and closes a gitignore gap where plain .env wasn't excluded alongside .env.local. Claude-Session: https://claude.ai/code/session_01NhxA4npAXAxmCDEJt6kxSH
106 lines
3.3 KiB
PL/PgSQL
106 lines
3.3 KiB
PL/PgSQL
begin;
|
|
select plan(12);
|
|
|
|
-- Seed reference data as service_role (bypasses RLS)
|
|
set local role service_role;
|
|
insert into public.services (id, name, duration_minutes, price_from, description, image)
|
|
values ('knotless', 'Knotless Braids', 240, 150, 'Tension-free braids.', 'styles/knotless.jpg');
|
|
insert into public.products (id, name, category, price, image, description, in_stock)
|
|
values ('edge-control', 'Silk Edge Control', 'hair-care', 12, 'products/edge-control.jpg', 'Hold with shine.', true);
|
|
reset role;
|
|
|
|
-- Anyone can read services
|
|
set local role anon;
|
|
select isnt_empty(
|
|
$$ select * from public.services $$,
|
|
'anon can read services'
|
|
);
|
|
|
|
-- Anyone can read products
|
|
select isnt_empty(
|
|
$$ select * from public.products $$,
|
|
'anon can read products'
|
|
);
|
|
|
|
-- Anon cannot write to services
|
|
select throws_ok(
|
|
$$ insert into public.services (id, name, duration_minutes, price_from, description, image)
|
|
values ('hack', 'Hack', 1, 1, 'x', 'x') $$,
|
|
'42501',
|
|
null,
|
|
'anon cannot insert into services'
|
|
);
|
|
|
|
-- Anyone can create a booking
|
|
select lives_ok(
|
|
$$ insert into public.bookings (service_id, date, time, contact_name, contact_phone, contact_email, contact_notes)
|
|
values ('knotless', '2026-09-15', '10:00 AM', 'Jane Doe', '555-0100', 'jane@example.com', '') $$,
|
|
'anon can create a booking'
|
|
);
|
|
|
|
-- Anon cannot read bookings (PII protection). No SELECT privilege is granted
|
|
-- to anon on this table at all now, so this is blocked at the grant layer
|
|
-- (permission denied) rather than merely filtered to empty rows by RLS.
|
|
select throws_ok(
|
|
$$ select * from public.bookings $$,
|
|
'42501',
|
|
null,
|
|
'anon cannot read bookings'
|
|
);
|
|
|
|
-- Anon cannot update bookings (no UPDATE privilege granted, regardless of RLS)
|
|
select throws_ok(
|
|
$$ update public.bookings set contact_notes = 'hacked' $$,
|
|
'42501',
|
|
null,
|
|
'anon cannot update bookings'
|
|
);
|
|
|
|
-- Anyone can create an inquiry
|
|
select lives_ok(
|
|
$$ insert into public.inquiries (product_id, contact_name, contact_email, contact_notes)
|
|
values ('edge-control', 'Jane Doe', 'jane@example.com', 'Is this in stock?') $$,
|
|
'anon can create an inquiry'
|
|
);
|
|
|
|
-- Anon cannot read inquiries (PII protection). Same as bookings above: no
|
|
-- SELECT privilege is granted, so this fails at the grant layer.
|
|
select throws_ok(
|
|
$$ select * from public.inquiries $$,
|
|
'42501',
|
|
null,
|
|
'anon cannot read inquiries'
|
|
);
|
|
|
|
-- Anyone can read booked_slots (no PII there)
|
|
select isnt_empty(
|
|
$$ select * from public.booked_slots $$,
|
|
'anon can read booked_slots (populated by the trigger from the booking above)'
|
|
);
|
|
|
|
-- Anon cannot write booked_slots directly
|
|
select throws_ok(
|
|
$$ insert into public.booked_slots (date, time) values ('2026-09-16', '1:00 PM') $$,
|
|
'42501',
|
|
null,
|
|
'anon cannot insert into booked_slots directly'
|
|
);
|
|
|
|
-- The admin (matching UID) can read bookings
|
|
set local role authenticated;
|
|
set local request.jwt.claim.sub = '21c90224-e0b2-412e-a431-8e7f097c1cef';
|
|
select isnt_empty(
|
|
$$ select * from public.bookings $$,
|
|
'admin can read bookings'
|
|
);
|
|
|
|
-- The admin can write to services
|
|
select lives_ok(
|
|
$$ insert into public.services (id, name, duration_minutes, price_from, description, image)
|
|
values ('cornrows', 'Cornrows', 120, 90, 'Classic style.', 'styles/cornrows.jpg') $$,
|
|
'admin can insert into services'
|
|
);
|
|
|
|
select * from finish();
|
|
rollback;
|