From f97e72314fed9f9991a1653669f0d36b03162bf7 Mon Sep 17 00:00:00 2001 From: dimgigov Date: Thu, 30 Jul 2026 14:11:08 +0300 Subject: [PATCH] refactor(exec): extract RLS/privileges into exec/rls.nim --- src/barabadb/query/exec/rls.nim | 56 +++++++++++++++++++++++++++++++++ src/barabadb/query/executor.nim | 49 +---------------------------- 2 files changed, 57 insertions(+), 48 deletions(-) create mode 100644 src/barabadb/query/exec/rls.nim diff --git a/src/barabadb/query/exec/rls.nim b/src/barabadb/query/exec/rls.nim new file mode 100644 index 0000000..5090ffa --- /dev/null +++ b/src/barabadb/query/exec/rls.nim @@ -0,0 +1,56 @@ +## Row-Level Security — privilege checks and policy evaluation. +## +## Extracted from `executor.nim` (Task 7 of the executor split). +import std/tables +import types +import values +import eval +import lower + +# ---------------------------------------------------------------------- +# Row-Level Security +# ---------------------------------------------------------------------- + +proc hasPrivilege*(ctx: ExecutionContext, tableName, command: string): bool = + if ctx.currentUser.len == 0: return true + let user = ctx.users.getOrDefault(ctx.currentUser) + if user.isSuperuser: return true + # Check table-level policies for user or PUBLIC + # For now: if no policies exist, allow everything (backward compatible) + if tableName notin ctx.policies: return true + let policies = ctx.policies[tableName] + # If RLS is enabled (policies exist), check if user matches any policy + for pol in policies: + if pol.command == "ALL" or pol.command == command: + return true + return false + +proc passesPolicy*(ctx: ExecutionContext, tableName, command: string, row: Row): bool = + if ctx.currentUser.len == 0: return true + let user = ctx.users.getOrDefault(ctx.currentUser) + if user.isSuperuser: return true + if tableName notin ctx.policies: return true + let policies = ctx.policies[tableName] + for pol in policies: + if pol.command != "ALL" and pol.command != command: + continue + if pol.usingExpr != nil: + let expr = lowerExpr(pol.usingExpr) + if valueToString(evalExpr(expr, row, ctx)) != "true": + return false + return true + +proc checkInsertPolicy*(ctx: ExecutionContext, tableName: string, row: Row): bool = + if ctx.currentUser.len == 0: return true + let user = ctx.users.getOrDefault(ctx.currentUser) + if user.isSuperuser: return true + if tableName notin ctx.policies: return true + let policies = ctx.policies[tableName] + for pol in policies: + if pol.command != "ALL" and pol.command != "INSERT": + continue + if pol.withCheckExpr != nil: + let expr = lowerExpr(pol.withCheckExpr) + if valueToString(evalExpr(expr, row, ctx)) != "true": + return false + return true diff --git a/src/barabadb/query/executor.nim b/src/barabadb/query/executor.nim index 743432f..51a45a8 100644 --- a/src/barabadb/query/executor.nim +++ b/src/barabadb/query/executor.nim @@ -48,6 +48,7 @@ import exec/params import exec/migrations # internal — not re-exported import exec/eval import exec/lower +import exec/rls # internal — not re-exported export types export values export schema @@ -66,54 +67,6 @@ proc executePlan*(ctx: ExecutionContext, plan: IRPlan): seq[Row] proc execScan(ctx: ExecutionContext, table: string): seq[Row] proc executeQuery*(ctx: ExecutionContext, astNode: Node, params: seq[WireValue] = @[]): ExecResult -# ---------------------------------------------------------------------- -# Row-Level Security -# ---------------------------------------------------------------------- - -proc hasPrivilege(ctx: ExecutionContext, tableName, command: string): bool = - if ctx.currentUser.len == 0: return true - let user = ctx.users.getOrDefault(ctx.currentUser) - if user.isSuperuser: return true - # Check table-level policies for user or PUBLIC - # For now: if no policies exist, allow everything (backward compatible) - if tableName notin ctx.policies: return true - let policies = ctx.policies[tableName] - # If RLS is enabled (policies exist), check if user matches any policy - for pol in policies: - if pol.command == "ALL" or pol.command == command: - return true - return false - -proc passesPolicy(ctx: ExecutionContext, tableName, command: string, row: Row): bool = - if ctx.currentUser.len == 0: return true - let user = ctx.users.getOrDefault(ctx.currentUser) - if user.isSuperuser: return true - if tableName notin ctx.policies: return true - let policies = ctx.policies[tableName] - for pol in policies: - if pol.command != "ALL" and pol.command != command: - continue - if pol.usingExpr != nil: - let expr = lowerExpr(pol.usingExpr) - if valueToString(evalExpr(expr, row, ctx)) != "true": - return false - return true - -proc checkInsertPolicy(ctx: ExecutionContext, tableName: string, row: Row): bool = - if ctx.currentUser.len == 0: return true - let user = ctx.users.getOrDefault(ctx.currentUser) - if user.isSuperuser: return true - if tableName notin ctx.policies: return true - let policies = ctx.policies[tableName] - for pol in policies: - if pol.command != "ALL" and pol.command != "INSERT": - continue - if pol.withCheckExpr != nil: - let expr = lowerExpr(pol.withCheckExpr) - if valueToString(evalExpr(expr, row, ctx)) != "true": - return false - return true - # ---------------------------------------------------------------------- # Table scan and storage # ----------------------------------------------------------------------