@@ -84,27 +84,59 @@ describe("row level security", () => {
8484 expect ( notesB ) . toMatchObject ( [ { note : "Hello from Person B" } ] ) ;
8585 } ) ;
8686
87- test ( "cannot delete someone else's note" , async ( ) => {
88- const t = convexTest ( schema , modules ) ;
89- const noteId = await t . run ( async ( ctx ) => {
90- const aId = await ctx . db . insert ( "users" , { tokenIdentifier : "Person A" } ) ;
91- await ctx . db . insert ( "users" , { tokenIdentifier : "Person B" } ) ;
92- return ctx . db . insert ( "notes" , {
93- note : "Hello from Person A" ,
94- userId : aId ,
87+ describe ( "cannot delete someone else's note" , ( ) => {
88+ test ( "implicit table names" , async ( ) => {
89+ const t = convexTest ( schema , modules ) ;
90+ const noteId = await t . run ( async ( ctx ) => {
91+ const aId = await ctx . db . insert ( "users" , {
92+ tokenIdentifier : "Person A" ,
93+ } ) ;
94+ await ctx . db . insert ( "users" , { tokenIdentifier : "Person B" } ) ;
95+ return ctx . db . insert ( "notes" , {
96+ note : "Hello from Person A" ,
97+ userId : aId ,
98+ } ) ;
9599 } ) ;
96- } ) ;
97- const asA = t . withIdentity ( { tokenIdentifier : "Person A" } ) ;
98- const asB = t . withIdentity ( { tokenIdentifier : "Person B" } ) ;
99- await expect ( ( ) =>
100- asB . run ( async ( ctx ) => {
100+ const asA = t . withIdentity ( { tokenIdentifier : "Person A" } ) ;
101+ const asB = t . withIdentity ( { tokenIdentifier : "Person B" } ) ;
102+ await expect ( ( ) =>
103+ asB . run ( async ( ctx ) => {
104+ const rls = await withRLS ( ctx ) ;
105+ return rls . db . delete ( noteId ) ;
106+ } ) ,
107+ ) . rejects . toThrow ( / n o r e a d a c c e s s / ) ;
108+ await asA . run ( async ( ctx ) => {
101109 const rls = await withRLS ( ctx ) ;
102110 return rls . db . delete ( noteId ) ;
103- } ) ,
104- ) . rejects . toThrow ( / n o r e a d a c c e s s / ) ;
105- await asA . run ( async ( ctx ) => {
106- const rls = await withRLS ( ctx ) ;
107- return rls . db . delete ( noteId ) ;
111+ } ) ;
112+ } ) ;
113+
114+ test ( "explicit table names" , async ( ) => {
115+ const t = convexTest ( schema , modules ) ;
116+ const noteId = await t . run ( async ( ctx ) => {
117+ const aId = await ctx . db . insert ( "users" , {
118+ tokenIdentifier : "Person A" ,
119+ } ) ;
120+ await ctx . db . insert ( "users" , { tokenIdentifier : "Person B" } ) ;
121+ return ctx . db . insert ( "notes" , {
122+ note : "Hello from Person A" ,
123+ userId : aId ,
124+ } ) ;
125+ } ) ;
126+ const asA = t . withIdentity ( { tokenIdentifier : "Person A" } ) ;
127+ const asB = t . withIdentity ( { tokenIdentifier : "Person B" } ) ;
128+ await expect ( ( ) =>
129+ asB . run ( async ( ctx ) => {
130+ const rls = await withRLS ( ctx ) ;
131+ // @ts -expect-error - testing new explicit table name API
132+ return rls . db . delete ( "notes" , noteId ) ;
133+ } ) ,
134+ ) . rejects . toThrow ( / n o r e a d a c c e s s / ) ;
135+ await asA . run ( async ( ctx ) => {
136+ const rls = await withRLS ( ctx ) ;
137+ // @ts -expect-error - testing new explicit table name API
138+ return rls . db . delete ( "notes" , noteId ) ;
139+ } ) ;
108140 } ) ;
109141 } ) ;
110142
@@ -244,39 +276,72 @@ describe("row level security", () => {
244276 ) . rejects . toThrow ( / i n s e r t a c c e s s n o t a l l o w e d / ) ;
245277 } ) ;
246278
247- test ( "default deny policy blocks modifications to tables without rules" , async ( ) => {
248- const t = convexTest ( schema , modules ) ;
249- const docId = await t . run ( async ( ctx ) => {
250- await ctx . db . insert ( "users" , { tokenIdentifier : "Person A" } ) ;
251- return ctx . db . insert ( "publicData" , { content : "Initial content" } ) ;
252- } ) ;
279+ describe ( "default deny policy blocks modifications to tables without rules" , ( ) => {
280+ test ( "implicit table names" , async ( ) => {
281+ const t = convexTest ( schema , modules ) ;
282+ const docId = await t . run ( async ( ctx ) => {
283+ await ctx . db . insert ( "users" , { tokenIdentifier : "Person A" } ) ;
284+ return ctx . db . insert ( "publicData" , { content : "Initial content" } ) ;
285+ } ) ;
253286
254- const asA = t . withIdentity ( { tokenIdentifier : "Person A" } ) ;
287+ const asA = t . withIdentity ( { tokenIdentifier : "Person A" } ) ;
255288
256- // Test with default allow
257- await asA . run ( async ( ctx ) => {
258- const tokenIdentifier = ( await ctx . auth . getUserIdentity ( ) )
259- ?. tokenIdentifier ;
260- if ( ! tokenIdentifier ) throw new Error ( "Unauthenticated" ) ;
289+ // Test with default allow
290+ await asA . run ( async ( ctx ) => {
291+ const tokenIdentifier = ( await ctx . auth . getUserIdentity ( ) )
292+ ?. tokenIdentifier ;
293+ if ( ! tokenIdentifier ) throw new Error ( "Unauthenticated" ) ;
261294
262- const db = wrapDatabaseWriter (
263- { tokenIdentifier } ,
264- ctx . db ,
265- {
266- publicData : {
267- read : async ( ) => true , // Allow reads
295+ const db = wrapDatabaseWriter (
296+ { tokenIdentifier } ,
297+ ctx . db ,
298+ {
299+ publicData : {
300+ read : async ( ) => true , // Allow reads
301+ } ,
268302 } ,
269- } ,
270- { defaultPolicy : "allow" } ,
271- ) ;
303+ { defaultPolicy : "allow" } ,
304+ ) ;
305+
306+ // Should be able to modify (no modify rule, default allow)
307+ await db . patch ( docId , { content : "Modified content" } ) ;
308+ } ) ;
309+
310+ // Test with default deny
311+ await expect ( ( ) =>
312+ asA . run ( async ( ctx ) => {
313+ const tokenIdentifier = ( await ctx . auth . getUserIdentity ( ) )
314+ ?. tokenIdentifier ;
315+ if ( ! tokenIdentifier ) throw new Error ( "Unauthenticated" ) ;
316+
317+ const db = wrapDatabaseWriter (
318+ { tokenIdentifier } ,
319+ ctx . db ,
320+ {
321+ publicData : {
322+ read : async ( ) => true , // Allow reads but no modify rule
323+ } ,
324+ } ,
325+ { defaultPolicy : "deny" } ,
326+ ) ;
272327
273- // Should be able to modify (no modify rule, default allow)
274- await db . patch ( docId , { content : "Modified content" } ) ;
328+ // Should NOT be able to modify (no modify rule, default deny)
329+ await db . patch ( docId , { content : "Blocked modification" } ) ;
330+ } ) ,
331+ ) . rejects . toThrow ( / w r i t e a c c e s s n o t a l l o w e d / ) ;
275332 } ) ;
276333
277- // Test with default deny
278- await expect ( ( ) =>
279- asA . run ( async ( ctx ) => {
334+ test ( "explicit table names" , async ( ) => {
335+ const t = convexTest ( schema , modules ) ;
336+ const docId = await t . run ( async ( ctx ) => {
337+ await ctx . db . insert ( "users" , { tokenIdentifier : "Person A" } ) ;
338+ return ctx . db . insert ( "publicData" , { content : "Initial content" } ) ;
339+ } ) ;
340+
341+ const asA = t . withIdentity ( { tokenIdentifier : "Person A" } ) ;
342+
343+ // Test with default allow
344+ await asA . run ( async ( ctx ) => {
280345 const tokenIdentifier = ( await ctx . auth . getUserIdentity ( ) )
281346 ?. tokenIdentifier ;
282347 if ( ! tokenIdentifier ) throw new Error ( "Unauthenticated" ) ;
@@ -286,16 +351,43 @@ describe("row level security", () => {
286351 ctx . db ,
287352 {
288353 publicData : {
289- read : async ( ) => true , // Allow reads but no modify rule
354+ read : async ( ) => true , // Allow reads
290355 } ,
291356 } ,
292- { defaultPolicy : "deny " } ,
357+ { defaultPolicy : "allow " } ,
293358 ) ;
294359
295- // Should NOT be able to modify (no modify rule, default deny)
296- await db . patch ( docId , { content : "Blocked modification" } ) ;
297- } ) ,
298- ) . rejects . toThrow ( / w r i t e a c c e s s n o t a l l o w e d / ) ;
360+ // Should be able to modify (no modify rule, default allow)
361+ // @ts -expect-error - testing new explicit table name API
362+ await db . patch ( "publicData" , docId , { content : "Modified content" } ) ;
363+ } ) ;
364+
365+ // Test with default deny
366+ await expect ( ( ) =>
367+ asA . run ( async ( ctx ) => {
368+ const tokenIdentifier = ( await ctx . auth . getUserIdentity ( ) )
369+ ?. tokenIdentifier ;
370+ if ( ! tokenIdentifier ) throw new Error ( "Unauthenticated" ) ;
371+
372+ const db = wrapDatabaseWriter (
373+ { tokenIdentifier } ,
374+ ctx . db ,
375+ {
376+ publicData : {
377+ read : async ( ) => true , // Allow reads but no modify rule
378+ } ,
379+ } ,
380+ { defaultPolicy : "deny" } ,
381+ ) ;
382+
383+ // Should NOT be able to modify (no modify rule, default deny)
384+ // @ts -expect-error - testing new explicit table name API
385+ await db . patch ( "publicData" , docId , {
386+ content : "Blocked modification" ,
387+ } ) ;
388+ } ) ,
389+ ) . rejects . toThrow ( / w r i t e a c c e s s n o t a l l o w e d / ) ;
390+ } ) ;
299391 } ) ;
300392} ) ;
301393
0 commit comments