Commit 1f755a1
fix: Support not in access policy conditions (cube-js#10767)
* feat: add RBAC smoke test for group-based conditional region row filtering
Add a test that verifies group-based conditional row filtering:
- region_test cube backed by users table (id, city, count)
- region_test_view with an access policy for user_group that
conditionally applies a row filter based on region_group membership
- region_user (user_group + region_group): sees only San Francisco rows
- region_user_no_filter (user_group only): sees all rows
The access policy checks security_context.auth.groups for region_group
membership. If present, it filters rows by the user's region attribute.
If absent, it grants allow_all (no row filter).
Co-authored-by: Pavel Tiunov <pavel.tiunov@gmail.com>
* fix: use line_items table, group-based conditions, and MEASURE syntax
- Switch region_test cube to use public.line_items table to avoid
cross-contamination from the users cube's RBAC city filter
- Add cube-level allowAll access policy so view policies can layer
on top correctly
- Use group-based (user_group) policies with conditions to check
hasRegionFilter user attribute for conditional row filtering
- Use MEASURE() syntax for aggregate count queries
- Both users have groups only (no roles needed) — view policy uses
group: 'user_group' with conditions for mutual exclusivity
Co-authored-by: Pavel Tiunov <pavel.tiunov@gmail.com>
* feat: allow security_context evaluation at rowLevel in access policies
Enable security_context to be used directly at the rowLevel property
of access policies, allowing the entire filter structure to be
controlled dynamically based on the user's security context.
Changes:
- CubePropContextTranspiler: add special handling to transpile
rowLevel/row_level when its value is an expression (not an object
literal), wrapping it in an arrow function with securityContext
- CubeValidator: accept Joi.func() as alternative for rowLevel,
alongside the existing RowLevelPolicySchema object
- CompilerApi: resolve rowLevel via evaluateContextFunction when it
is a function, and process the returned raw filters through a new
evaluateRawFilter method that handles uncompiled member references
- Update test to use the cleaner syntax where security_context
controls the rowLevel structure directly via groups.includes()
This enables patterns like:
rowLevel: security_context.auth?.groups?.includes('region_group')
? { filters: [{ member: 'col', operator: 'equals', values: ... }] }
: { allowAll: true }
Co-authored-by: Pavel Tiunov <pavel.tiunov@gmail.com>
* refactor: convert region_test_view from JS to YAML
Replace the JS view with a YAML view that uses two mutually exclusive
conditions on the user_group access policy:
- hasRegionFilter (truthy) -> filters by allowedProductIds
- noRegionFilter (truthy) -> allow_all
Users carry complementary boolean attributes so the YAML conditions
(which only support truthy checks, not comparisons or negation) can
distinguish the two cases without policy overlap.
Co-authored-by: Pavel Tiunov <pavel.tiunov@gmail.com>
* refactor: use group-based policies instead of attribute-based conditions
Replace attribute-based conditions (hasRegionFilter/noRegionFilter) with
pure group-based policy scoping:
- group: region_group — row filter by allowedProductIds
- group: user_group — allow_all
Each user belongs to exactly one group so only one policy matches,
avoiding the union overlap problem without needing conditions.
Co-authored-by: Pavel Tiunov <pavel.tiunov@gmail.com>
* refactor: revert core changes, use conditions with groups.includes() check
Revert all changes to cubejs-schema-compiler and cubejs-server-core.
Use standard access policy conditions to check security context groups:
- Two mutually exclusive user_group policies with conditions:
- if: security_context.auth?.groups?.includes('region_group')
→ filters by allowedProductIds
- if: !security_context.auth?.groups?.includes('region_group')
→ allowAll
- region_user has both ['user_group', 'region_group'] and is
correctly filtered because the condition routes to the filter
policy, not the allowAll policy.
Co-authored-by: Pavel Tiunov <pavel.tiunov@gmail.com>
* refactor: convert region_test_view to YAML with group-scoped policies
Replace JS view with YAML view using two group-scoped policies:
- group: region_group — filters by allowedProductIds
- group: user_group — allow_all
Users belong to exactly one group to avoid the union-overlap problem
where allow_all would override the filter. No core changes.
Co-authored-by: Pavel Tiunov <pavel.tiunov@gmail.com>
* fix: use JS view with groups.includes() conditions for both-groups support
A user with both user_group and region_group must be filtered by
region_group. This requires mutually exclusive conditions checking
groups.includes('region_group') — which needs JS (not YAML, since
the YAML Python parser cannot express negation).
Single user_group policy with two condition branches:
- groups.includes('region_group') → filter by allowedProductIds
- !groups.includes('region_group') → allowAll
No core changes. region_user now has ['user_group', 'region_group']
and is correctly filtered.
Co-authored-by: Pavel Tiunov <pavel.tiunov@gmail.com>
* feat: add not/and/or support to YAML Python parser, convert view to YAML
Add support for Python boolean operators in the YAML expression parser:
- not → JS ! (unary negation)
- and → JS && (logical AND)
- or → JS || (logical OR)
This enables YAML access policy conditions like:
if: "{ not (security_context.auth.groups and security_context.auth.groups.includes('region_group')) }"
Convert region_test_view from JS to YAML using the new operators
for null-safe group membership checks in conditions.
Co-authored-by: Pavel Tiunov <pavel.tiunov@gmail.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>1 parent d9fa353 commit 1f755a1
5 files changed
Lines changed: 176 additions & 0 deletions
File tree
- packages
- cubejs-schema-compiler/src/parser
- cubejs-testing
- birdbox-fixtures/rbac
- model
- cubes
- views
- test
Lines changed: 21 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
21 | 27 | | |
22 | 28 | | |
23 | 29 | | |
| |||
223 | 229 | | |
224 | 230 | | |
225 | 231 | | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
226 | 247 | | |
227 | 248 | | |
228 | 249 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
186 | 186 | | |
187 | 187 | | |
188 | 188 | | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
189 | 225 | | |
190 | 226 | | |
191 | 227 | | |
| |||
Lines changed: 24 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
Lines changed: 24 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1059 | 1059 | | |
1060 | 1060 | | |
1061 | 1061 | | |
| 1062 | + | |
| 1063 | + | |
| 1064 | + | |
| 1065 | + | |
| 1066 | + | |
| 1067 | + | |
| 1068 | + | |
| 1069 | + | |
| 1070 | + | |
| 1071 | + | |
| 1072 | + | |
| 1073 | + | |
| 1074 | + | |
| 1075 | + | |
| 1076 | + | |
| 1077 | + | |
| 1078 | + | |
| 1079 | + | |
| 1080 | + | |
| 1081 | + | |
| 1082 | + | |
| 1083 | + | |
| 1084 | + | |
| 1085 | + | |
| 1086 | + | |
| 1087 | + | |
| 1088 | + | |
| 1089 | + | |
| 1090 | + | |
| 1091 | + | |
| 1092 | + | |
| 1093 | + | |
| 1094 | + | |
| 1095 | + | |
| 1096 | + | |
| 1097 | + | |
| 1098 | + | |
| 1099 | + | |
| 1100 | + | |
| 1101 | + | |
| 1102 | + | |
| 1103 | + | |
| 1104 | + | |
| 1105 | + | |
| 1106 | + | |
| 1107 | + | |
| 1108 | + | |
| 1109 | + | |
| 1110 | + | |
| 1111 | + | |
| 1112 | + | |
| 1113 | + | |
| 1114 | + | |
| 1115 | + | |
| 1116 | + | |
| 1117 | + | |
| 1118 | + | |
| 1119 | + | |
| 1120 | + | |
| 1121 | + | |
| 1122 | + | |
| 1123 | + | |
| 1124 | + | |
| 1125 | + | |
| 1126 | + | |
| 1127 | + | |
| 1128 | + | |
| 1129 | + | |
| 1130 | + | |
| 1131 | + | |
| 1132 | + | |
1062 | 1133 | | |
1063 | 1134 | | |
1064 | 1135 | | |
| |||
0 commit comments