Access control that compiles to native where it can.
The AccessModel is an AST — ReadFilter, InsertCheck, UpdateTargetFilter, UpdateResultCheck, DeleteFilter, FieldRules, RelationshipRules, Bypass. Vadyl reads provider SecurityCapabilities, compiles to native RLS where supported, falls back to runtime predicate evaluation where not. The policy is the same. The outcome is the same. The execution path is whatever the provider permits.
Native, runtime, hybrid. Vadyl picks per facet.
Native enforcement
PostgreSQL row-level security, SQL Server security predicates, native session context. Vadyl compiles row filters into the provider's enforcement layer — zero runtime cost on the read path.
Runtime enforcement
MongoDB, Redis, providers without native RLS — Vadyl injects the resolved predicate into the query AST before it reaches the provider. SecurityPredicateResolver replaces scope-dependent nodes with concrete literals upstream.
Hybrid mode
Some facets land natively (read filters), others stay runtime (field masking with redaction). AccessPlanBuilder reduces capabilities + AccessModel into per-facet enforcement modes.
Field masks
Omit / Null / Redacted. FieldProjectionBuilder applies post-evaluation. Combined with CanRead via OR(CanRead, NOT(MaskWhen)) — masking only when read is denied AND mask condition holds.
Relationship rules
Cross-relation invariants. The order's customer must be read-allowed before the order is read. Cascading access checks across relation expansion, capability-aware.
Bypass auditing
FullBypass / ReadBypass / WriteBypass conditions are typed. Every bypass invocation lands in AccessEnforcementDiagnostics.Bypasses — auditable, reviewable, alarmable.
Resolve before render. Document providers get the same semantics.
HasRole, HasClaim, InContextSet, ContextValue, AuthStrengthAtLeast, AuthenticatedVia, SubjectTypeIs, SessionAgeLt — auth-aware BoolExpr nodes. SecurityPredicateResolver walks the tree and replaces scope-dependent nodes with concrete BoolLiteral / Literal before the predicate reaches a renderer that can't handle them natively.
Anti-pattern #45 codified: scope-dependent BoolExpr nodes never reach a document or KV provider unresolved. The runtime predicate resolver handles the gap so MongoDB / Redis / Cassandra get the same semantics PostgreSQL gets natively.
Read / Insert / UpdateTarget / UpdateResult / Delete / Field
Native / Runtime / Hybrid / Inactive
Typed, surfaced, alarmable
Across every storage model
Express access policy once.
Vadyl picks the enforcement mode per provider, per facet. The policy is the same across Postgres, Mongo, Redis, Neo4j, Cassandra. Your code does not branch.