refactor(exec): extract RLS/privileges into exec/rls.nim
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user