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/migrations # internal — not re-exported
|
||||||
import exec/eval
|
import exec/eval
|
||||||
import exec/lower
|
import exec/lower
|
||||||
|
import exec/rls # internal — not re-exported
|
||||||
export types
|
export types
|
||||||
export values
|
export values
|
||||||
export schema
|
export schema
|
||||||
@@ -66,54 +67,6 @@ proc executePlan*(ctx: ExecutionContext, plan: IRPlan): seq[Row]
|
|||||||
proc execScan(ctx: ExecutionContext, table: string): seq[Row]
|
proc execScan(ctx: ExecutionContext, table: string): seq[Row]
|
||||||
proc executeQuery*(ctx: ExecutionContext, astNode: Node, params: seq[WireValue] = @[]): ExecResult
|
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
|
# Table scan and storage
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user