Skip to content

Latest commit

 

History

History
283 lines (172 loc) · 8.59 KB

File metadata and controls

283 lines (172 loc) · 8.59 KB
title Rls
description Rls protocol schemas

{/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs go in content/docs/guides/. */}

Row-Level Security (RLS) Protocol

Implements fine-grained record-level access control inspired by PostgreSQL RLS

and Salesforce Criteria-Based Sharing Rules.

Overview

Row-Level Security (RLS) allows you to control which rows users can access

in database tables based on their identity and role. Unlike object-level

permissions (CRUD), RLS provides record-level filtering.

Use Cases

  1. Multi-Tenant Data Isolation
  • Users only see records from their organization

  • using: "organization_id == current_user.organization_id"

  1. Ownership-Based Access
  • Users only see records they own

  • using: "owner_id == current_user.id"

  1. Organization Member Visibility
  • Users see fellow members of their active organization

  • using: "id in current_user.org_user_ids"

(org_user_ids is pre-resolved by the runtime)

  1. Territory / Regional Access (§7.3.1 dynamic membership)
  • Sales reps only see accounts in their assigned territories

  • using: "account_id in current_user.territory_account_ids"

(the runtime stages territory_account_ids in ExecutionContext.rlsMembership)

  1. Manager / Hierarchy Access (§7.3.1 dynamic membership)
  • Managers see records assigned to anyone they manage

  • using: "assigned_to_id in current_user.team_member_ids"

(the runtime pre-resolves team_member_ids, no subquery needed)

PostgreSQL RLS Comparison

PostgreSQL RLS Example:

CREATE POLICY tenant_isolation ON accounts

FOR SELECT

USING (tenant_id = current_setting('app.current_tenant_id')::uuid);

CREATE POLICY account_insert ON accounts

FOR INSERT

WITH CHECK (tenant_id = current_setting('app.current_tenant_id')::uuid);

ObjectStack RLS Equivalent:

\{

name: 'tenant_isolation',

object: 'account',

operation: 'select',

using: 'organization_id == current_user.organization_id'

\}

Salesforce Sharing Rules Comparison

Salesforce uses "Sharing Rules" and "Role Hierarchy" for record-level access.

ObjectStack RLS provides similar functionality with more flexibility.

Salesforce:

  • Criteria-Based Sharing: Share records matching criteria with users/roles

  • Owner-Based Sharing: Share records based on owner's role

  • Manual Sharing: Individual record sharing

ObjectStack RLS:

  • A small, fixed expression grammar (equality, set-membership, always-true)

  • Subquery-shaped needs are pre-resolved by the runtime (§7.3.1)

  • Multiple policies OR-combine for union (any-match-allows) semantics

Best Practices

  1. Always Define SELECT Policy: Control what users can view

  2. Define INSERT/UPDATE CHECK Policies: Prevent data leakage

  3. Use Role-Based Policies: Apply different rules to different roles

  4. Test Thoroughly: RLS can have complex interactions

  5. Monitor Performance: Complex RLS policies can impact query performance

Security Considerations

  1. Defense in Depth: RLS is one layer; use with object permissions

  2. Default Deny: If no policy matches, access is denied

  3. Policy Precedence: More permissive policy wins (OR logic)

  4. Context Variables: Ensure current_user context is always set

@see https://www.postgresql.org/docs/current/ddl-rowsecurity.html

@see https://help.salesforce.com/s/articleView?id=sf.security_sharing_rules.htm

**Source:** `packages/spec/src/security/rls.zod.ts`

TypeScript Usage

import { RLSAuditConfig, RLSAuditEvent, RLSConfig, RLSEvaluationResult, RLSOperation, RLSUserContext, RowLevelSecurityPolicy } from '@objectstack/spec/security';
import type { RLSAuditConfig, RLSAuditEvent, RLSConfig, RLSEvaluationResult, RLSOperation, RLSUserContext, RowLevelSecurityPolicy } from '@objectstack/spec/security';

// Validate data
const result = RLSAuditConfig.parse(data);

RLSAuditConfig

Properties

Property Type Required Description
enabled boolean Enable RLS audit logging
logLevel Enum<'all' | 'denied_only' | 'granted_only' | 'none'> Which evaluations to log
destination Enum<'system_log' | 'audit_trail' | 'external'> Audit log destination
sampleRate number Sampling rate (0-1) for high-traffic environments
retentionDays integer Audit log retention period in days
includeRowData boolean Include row data in audit logs (security-sensitive)
alertOnDenied boolean Send alerts when access is denied

RLSAuditEvent

Properties

Property Type Required Description
timestamp string ISO 8601 timestamp of the evaluation
userId string User ID whose access was evaluated
operation Enum<'select' | 'insert' | 'update' | 'delete'> Database operation being performed
object string Target object name
policyName string Name of the RLS policy evaluated
granted boolean Whether access was granted
evaluationDurationMs number Policy evaluation duration in milliseconds
matchedCondition string optional Which USING/CHECK clause matched
rowCount number optional Number of rows affected
metadata Record<string, any> optional Additional audit event metadata

RLSConfig

Properties

Property Type Required Description
enabled boolean Enable RLS enforcement globally
defaultPolicy Enum<'deny' | 'allow'> Default action when no policies match
allowSuperuserBypass boolean Allow superusers to bypass RLS
bypassRoles string[] optional Roles that bypass RLS (see all data)
logEvaluations boolean Log RLS policy evaluations for debugging
cacheResults boolean Cache RLS evaluation results
cacheTtlSeconds integer Cache TTL in seconds
prefetchUserContext boolean Pre-fetch user context for performance
audit Object optional RLS audit logging configuration

RLSEvaluationResult

Properties

Property Type Required Description
policyName string Policy name
granted boolean Whether access was granted
durationMs number optional Evaluation duration in milliseconds
error string optional Error message if evaluation failed
usingResult boolean optional USING clause evaluation result
checkResult boolean optional CHECK clause evaluation result

RLSOperation

Allowed Values

  • select
  • insert
  • update
  • delete
  • all

RLSUserContext

Properties

Property Type Required Description
id string User ID
email string optional User email
tenantId string optional Tenant/Organization ID
role string | string[] optional User role(s)
department string optional User department
attributes Record<string, any> optional Additional custom user attributes

RowLevelSecurityPolicy

Properties

Property Type Required Description
name string Policy unique identifier (snake_case)
label string optional Human-readable policy label
description string optional Policy description and business justification
object string Target object name
operation Enum<'select' | 'insert' | 'update' | 'delete' | 'all'> Database operation this policy applies to
using string optional Filter condition for SELECT/UPDATE/DELETE. One of the four compiler-supported forms: field = current_user.<prop>, field = 'literal', field IN (current_user.<array>), or 1 = 1. Optional for INSERT-only policies.
check string optional Validation condition for INSERT/UPDATE (defaults to USING clause if not specified - enforced at application level)
roles string[] optional Roles this policy applies to (omit for all roles)
enabled boolean Whether this policy is active
priority integer Policy evaluation priority (higher = evaluated first)
tags string[] optional Policy categorization tags