@@ -152,22 +152,6 @@ test.serial("Rule-based: glob pattern on table name", async (t) => {
152152 } ) ;
153153} ) ;
154154
155- test . serial ( "Rule-based: regex pattern on table name" , async ( t ) => {
156- const db = t . context . db ;
157-
158- db . authorizer ( {
159- rules : [
160- { action : Action . READ , table : / ^ u s e r s $ / , policy : Authorization . ALLOW } ,
161- { action : Action . SELECT , policy : Authorization . ALLOW } ,
162- ] ,
163- defaultPolicy : Authorization . DENY ,
164- } ) ;
165-
166- const stmt = db . prepare ( "SELECT * FROM users" ) ;
167- const users = stmt . all ( ) ;
168- t . is ( users . length , 2 ) ;
169- } ) ;
170-
171155test . serial ( "Rule-based: IGNORE returns NULL for READ columns" , async ( t ) => {
172156 const db = t . context . db ;
173157
@@ -192,7 +176,7 @@ test.serial("Rule-based: entity pattern for functions", async (t) => {
192176
193177 db . authorizer ( {
194178 rules : [
195- { action : Action . FUNCTION , entity : / ^ ( l o w e r | u p p e r | l e n g t h ) $ / , policy : Authorization . ALLOW } ,
179+ { action : Action . FUNCTION , entity : " upper" , policy : Authorization . ALLOW } ,
196180 { action : Action . READ , policy : Authorization . ALLOW } ,
197181 { action : Action . SELECT , policy : Authorization . ALLOW } ,
198182 ] ,
@@ -430,193 +414,13 @@ test.serial("Glob: exact string without wildcards is exact match", async (t) =>
430414 t . is ( rows . length , 2 ) ;
431415} ) ;
432416
433- // ---- Regex pattern tests ----
434-
435- test . serial ( "Regex: case-insensitive flag" , async ( t ) => {
436- const db = t . context . db ;
437-
438- db . exec ( "CREATE TABLE IF NOT EXISTS Users_CI (id INTEGER PRIMARY KEY, val TEXT)" ) ;
439- db . exec ( "INSERT INTO Users_CI (id, val) VALUES (1, 'test')" ) ;
440-
441- db . authorizer ( {
442- rules : [
443- { action : Action . READ , table : / ^ u s e r s _ c i $ / i, policy : Authorization . ALLOW } ,
444- { action : Action . SELECT , policy : Authorization . ALLOW } ,
445- ] ,
446- defaultPolicy : Authorization . DENY ,
447- } ) ;
448-
449- const rows = db . prepare ( "SELECT * FROM Users_CI" ) . all ( ) ;
450- t . is ( rows . length , 1 ) ;
451- } ) ;
452-
453- test . serial ( "Regex: partial match (no anchors)" , async ( t ) => {
454- const db = t . context . db ;
455-
456- // /user/ without anchors should match "users" (partial match)
457- db . authorizer ( {
458- rules : [
459- { action : Action . READ , table : / u s e r / , policy : Authorization . ALLOW } ,
460- { action : Action . SELECT , policy : Authorization . ALLOW } ,
461- ] ,
462- defaultPolicy : Authorization . DENY ,
463- } ) ;
464-
465- const rows = db . prepare ( "SELECT * FROM users" ) . all ( ) ;
466- t . is ( rows . length , 2 ) ;
467- } ) ;
468-
469- test . serial ( "Regex: anchored pattern rejects partial matches" , async ( t ) => {
470- const db = t . context . db ;
471-
472- // /^user$/ should NOT match "users" (has trailing s)
473- db . authorizer ( {
474- rules : [
475- { action : Action . READ , table : / ^ u s e r $ / , policy : Authorization . ALLOW } ,
476- { action : Action . SELECT , policy : Authorization . ALLOW } ,
477- ] ,
478- defaultPolicy : Authorization . DENY ,
479- } ) ;
480-
481- await t . throwsAsync ( async ( ) => {
482- return await db . prepare ( "SELECT * FROM users" ) ;
483- } , { instanceOf : t . context . errorType , code : "SQLITE_AUTH" } ) ;
484- } ) ;
485-
486- test . serial ( "Regex: alternation pattern" , async ( t ) => {
487- const db = t . context . db ;
488-
489- db . exec ( "CREATE TABLE IF NOT EXISTS products (id INTEGER PRIMARY KEY, pname TEXT)" ) ;
490- db . exec ( "INSERT INTO products (id, pname) VALUES (1, 'Widget')" ) ;
491-
492- db . authorizer ( {
493- rules : [
494- { action : Action . READ , table : / ^ ( u s e r s | p r o d u c t s ) $ / , policy : Authorization . ALLOW } ,
495- { action : Action . SELECT , policy : Authorization . ALLOW } ,
496- ] ,
497- defaultPolicy : Authorization . DENY ,
498- } ) ;
499-
500- const u = db . prepare ( "SELECT * FROM users" ) . all ( ) ;
501- t . is ( u . length , 2 ) ;
502- const p = db . prepare ( "SELECT * FROM products" ) . all ( ) ;
503- t . is ( p . length , 1 ) ;
504- } ) ;
505-
506- test . serial ( "Regex: character class pattern" , async ( t ) => {
507- const db = t . context . db ;
508-
509- db . exec ( "CREATE TABLE IF NOT EXISTS t1_data (id INTEGER PRIMARY KEY)" ) ;
510- db . exec ( "CREATE TABLE IF NOT EXISTS t2_data (id INTEGER PRIMARY KEY)" ) ;
511- db . exec ( "INSERT INTO t1_data (id) VALUES (1)" ) ;
512- db . exec ( "INSERT INTO t2_data (id) VALUES (1)" ) ;
513-
514- db . authorizer ( {
515- rules : [
516- { action : Action . READ , table : / ^ t [ 0 - 9 ] _ d a t a $ / , policy : Authorization . ALLOW } ,
517- { action : Action . SELECT , policy : Authorization . ALLOW } ,
518- ] ,
519- defaultPolicy : Authorization . DENY ,
520- } ) ;
521-
522- const r1 = db . prepare ( "SELECT * FROM t1_data" ) . all ( ) ;
523- t . is ( r1 . length , 1 ) ;
524- const r2 = db . prepare ( "SELECT * FROM t2_data" ) . all ( ) ;
525- t . is ( r2 . length , 1 ) ;
526-
527- // users shouldn't match
528- await t . throwsAsync ( async ( ) => {
529- return await db . prepare ( "SELECT * FROM users" ) ;
530- } , { instanceOf : t . context . errorType , code : "SQLITE_AUTH" } ) ;
531- } ) ;
532-
533- test . serial ( "Regex: on column name with IGNORE" , async ( t ) => {
534- const db = t . context . db ;
535-
536- // IGNORE any column ending in "il" → email gets NULL
537- db . authorizer ( {
538- rules : [
539- { action : Action . READ , table : "users" , column : / i l $ / , policy : Authorization . IGNORE } ,
540- { action : Action . READ , policy : Authorization . ALLOW } ,
541- { action : Action . SELECT , policy : Authorization . ALLOW } ,
542- ] ,
543- defaultPolicy : Authorization . DENY ,
544- } ) ;
545-
546- const row = db . prepare ( "SELECT id, name, email FROM users WHERE id = 1" ) . get ( ) ;
547- t . is ( row . id , 1 ) ;
548- t . is ( row . name , "Alice" ) ;
549- t . is ( row . email , null ) ; // "email" ends in "il"
550- } ) ;
551-
552- test . serial ( "Regex: on entity name for allowed functions" , async ( t ) => {
417+ test . serial ( "Glob: table + column combo" , async ( t ) => {
553418 const db = t . context . db ;
554419
555- // Allow only functions starting with lowercase letters
420+ // For any table matching user*, IGNORE columns matching e*
556421 db . authorizer ( {
557422 rules : [
558- { action : Action . FUNCTION , entity : / ^ [ a - z ] / , policy : Authorization . ALLOW } ,
559- { action : Action . READ , policy : Authorization . ALLOW } ,
560- { action : Action . SELECT , policy : Authorization . ALLOW } ,
561- ] ,
562- defaultPolicy : Authorization . DENY ,
563- } ) ;
564-
565- const row = db . prepare ( "SELECT length(name) as len FROM users WHERE id = 1" ) . get ( ) ;
566- t . is ( row . len , 5 ) ; // "Alice" = 5 chars
567- } ) ;
568-
569- test . serial ( "Regex: non-matching regex denies correctly" , async ( t ) => {
570- const db = t . context . db ;
571-
572- // Only allow tables starting with "archive_"
573- db . authorizer ( {
574- rules : [
575- { action : Action . READ , table : / ^ a r c h i v e _ / , policy : Authorization . ALLOW } ,
576- { action : Action . SELECT , policy : Authorization . ALLOW } ,
577- ] ,
578- defaultPolicy : Authorization . DENY ,
579- } ) ;
580-
581- // users doesn't start with archive_
582- await t . throwsAsync ( async ( ) => {
583- return await db . prepare ( "SELECT * FROM users" ) ;
584- } , { instanceOf : t . context . errorType , code : "SQLITE_AUTH" } ) ;
585- } ) ;
586-
587- test . serial ( "Regex: complex pattern with quantifiers" , async ( t ) => {
588- const db = t . context . db ;
589-
590- db . exec ( "CREATE TABLE IF NOT EXISTS logs_2024_01 (id INTEGER PRIMARY KEY, msg TEXT)" ) ;
591- db . exec ( "INSERT INTO logs_2024_01 (id, msg) VALUES (1, 'jan')" ) ;
592-
593- // Match logs_YYYY_MM pattern
594- db . authorizer ( {
595- rules : [
596- { action : Action . READ , table : / ^ l o g s _ \d { 4 } _ \d { 2 } $ / , policy : Authorization . ALLOW } ,
597- { action : Action . SELECT , policy : Authorization . ALLOW } ,
598- ] ,
599- defaultPolicy : Authorization . DENY ,
600- } ) ;
601-
602- const rows = db . prepare ( "SELECT * FROM logs_2024_01" ) . all ( ) ;
603- t . is ( rows . length , 1 ) ;
604-
605- // users doesn't match the date pattern
606- await t . throwsAsync ( async ( ) => {
607- return await db . prepare ( "SELECT * FROM users" ) ;
608- } , { instanceOf : t . context . errorType , code : "SQLITE_AUTH" } ) ;
609- } ) ;
610-
611- // ---- Combined glob/regex with multiple fields ----
612-
613- test . serial ( "Glob table + regex column combo" , async ( t ) => {
614- const db = t . context . db ;
615-
616- // For any table matching user*, IGNORE columns matching a secret-ish pattern
617- db . authorizer ( {
618- rules : [
619- { action : Action . READ , table : "user*" , column : / ^ ( e m a i l | p a s s w o r d | s s n ) $ / , policy : Authorization . IGNORE } ,
423+ { action : Action . READ , table : "user*" , column : "e*" , policy : Authorization . IGNORE } ,
620424 { action : Action . READ , policy : Authorization . ALLOW } ,
621425 { action : Action . SELECT , policy : Authorization . ALLOW } ,
622426 ] ,
@@ -626,26 +430,7 @@ test.serial("Glob table + regex column combo", async (t) => {
626430 const row = db . prepare ( "SELECT id, name, email FROM users WHERE id = 2" ) . get ( ) ;
627431 t . is ( row . id , 2 ) ;
628432 t . is ( row . name , "Bob" ) ;
629- t . is ( row . email , null ) ; // email matched the regex, users matched user*
630- } ) ;
631-
632- test . serial ( "Regex table + glob column combo" , async ( t ) => {
633- const db = t . context . db ;
634-
635- // For tables matching /^users$/, IGNORE columns matching e*
636- db . authorizer ( {
637- rules : [
638- { action : Action . READ , table : / ^ u s e r s $ / , column : "e*" , policy : Authorization . IGNORE } ,
639- { action : Action . READ , policy : Authorization . ALLOW } ,
640- { action : Action . SELECT , policy : Authorization . ALLOW } ,
641- ] ,
642- defaultPolicy : Authorization . DENY ,
643- } ) ;
644-
645- const row = db . prepare ( "SELECT id, name, email FROM users WHERE id = 1" ) . get ( ) ;
646- t . is ( row . id , 1 ) ;
647- t . is ( row . name , "Alice" ) ;
648- t . is ( row . email , null ) ;
433+ t . is ( row . email , null ) ; // email matches e*, users matches user*
649434} ) ;
650435
651436test . serial ( "Glob: wildcard-only pattern * matches everything" , async ( t ) => {
@@ -700,11 +485,7 @@ test.beforeEach(async (t) => {
700485 DROP TABLE IF EXISTS audit_users;
701486 DROP TABLE IF EXISTS app_prod_logs;
702487 DROP TABLE IF EXISTS x_data_y;
703- DROP TABLE IF EXISTS Users_CI;
704488 DROP TABLE IF EXISTS products;
705- DROP TABLE IF EXISTS t1_data;
706- DROP TABLE IF EXISTS t2_data;
707- DROP TABLE IF EXISTS logs_2024_01;
708489 CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)
709490 ` ) ;
710491 db . exec (
0 commit comments