@cubejs-backend/testing 1.6.55 → 1.6.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -279,6 +279,44 @@ module.exports = {
|
|
|
279
279
|
},
|
|
280
280
|
};
|
|
281
281
|
}
|
|
282
|
+
// User matching only the full-access policy (with a row filter) on a cube
|
|
283
|
+
// that also has a separate, group-scoped masking policy the user is NOT in.
|
|
284
|
+
if (user === 'single_policy_measure_user') {
|
|
285
|
+
if (password && password !== 'single_policy_measure_password') {
|
|
286
|
+
throw new Error(`Password doesn't match for ${user}`);
|
|
287
|
+
}
|
|
288
|
+
return {
|
|
289
|
+
password,
|
|
290
|
+
superuser: false,
|
|
291
|
+
securityContext: {
|
|
292
|
+
auth: {
|
|
293
|
+
username: 'single_policy_measure_user',
|
|
294
|
+
userAttributes: {},
|
|
295
|
+
roles: [],
|
|
296
|
+
groups: ['spm_full_group'],
|
|
297
|
+
},
|
|
298
|
+
},
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
// User belonging to two groups whose access policies grant different
|
|
302
|
+
// members (member-level union across groups, no row_level filters).
|
|
303
|
+
if (user === 'multi_group_user') {
|
|
304
|
+
if (password && password !== 'multi_group_password') {
|
|
305
|
+
throw new Error(`Password doesn't match for ${user}`);
|
|
306
|
+
}
|
|
307
|
+
return {
|
|
308
|
+
password,
|
|
309
|
+
superuser: false,
|
|
310
|
+
securityContext: {
|
|
311
|
+
auth: {
|
|
312
|
+
username: 'multi_group_user',
|
|
313
|
+
userAttributes: {},
|
|
314
|
+
roles: [],
|
|
315
|
+
groups: ['mg_group_a', 'mg_group_c'],
|
|
316
|
+
},
|
|
317
|
+
},
|
|
318
|
+
};
|
|
319
|
+
}
|
|
282
320
|
throw new Error(`User "${user}" doesn't exist`);
|
|
283
321
|
}
|
|
284
322
|
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Test view for validating multi-group member-level access union (CUB-2758).
|
|
2
|
+
#
|
|
3
|
+
# Two access policies, each matched by a different group, grant member-level
|
|
4
|
+
# access to DIFFERENT members. Neither policy has a row_level filter, so row
|
|
5
|
+
# access defaults to allow-all.
|
|
6
|
+
#
|
|
7
|
+
# A user that belongs to BOTH groups should see the UNION of member access:
|
|
8
|
+
# querying member_a (granted by group mg_group_a) together with member_c
|
|
9
|
+
# (granted by group mg_group_c) must return data.
|
|
10
|
+
#
|
|
11
|
+
# Before the fix, member-level access required a single policy to cover ALL
|
|
12
|
+
# queried members, so a cross-policy query returned an empty (denied) result.
|
|
13
|
+
|
|
14
|
+
cubes:
|
|
15
|
+
- name: multi_group_base
|
|
16
|
+
sql_table: public.line_items
|
|
17
|
+
|
|
18
|
+
dimensions:
|
|
19
|
+
- name: id
|
|
20
|
+
sql: id
|
|
21
|
+
type: number
|
|
22
|
+
primary_key: true
|
|
23
|
+
|
|
24
|
+
# Granted only by group mg_group_a
|
|
25
|
+
- name: member_a
|
|
26
|
+
sql: order_id
|
|
27
|
+
type: number
|
|
28
|
+
|
|
29
|
+
# Granted only by group mg_group_c
|
|
30
|
+
- name: member_c
|
|
31
|
+
sql: quantity
|
|
32
|
+
type: number
|
|
33
|
+
|
|
34
|
+
measures:
|
|
35
|
+
- name: count
|
|
36
|
+
type: count
|
|
37
|
+
|
|
38
|
+
views:
|
|
39
|
+
- name: multi_group_test
|
|
40
|
+
cubes:
|
|
41
|
+
- join_path: multi_group_base
|
|
42
|
+
includes: "*"
|
|
43
|
+
|
|
44
|
+
access_policy:
|
|
45
|
+
# Group A: member_a (no row_level filter => allow-all rows)
|
|
46
|
+
- group: mg_group_a
|
|
47
|
+
member_level:
|
|
48
|
+
includes:
|
|
49
|
+
- id
|
|
50
|
+
- count
|
|
51
|
+
- member_a
|
|
52
|
+
|
|
53
|
+
# Group C: member_c (no row_level filter => allow-all rows)
|
|
54
|
+
- group: mg_group_c
|
|
55
|
+
member_level:
|
|
56
|
+
includes:
|
|
57
|
+
- id
|
|
58
|
+
- count
|
|
59
|
+
- member_c
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Smoke test for: a single matching policy granting full (unmasked) access to a
|
|
2
|
+
# measure, with a row-level filter, and NO group by.
|
|
3
|
+
#
|
|
4
|
+
# Two policies are defined:
|
|
5
|
+
# - spm_mask_group → masks all members (member_masking)
|
|
6
|
+
# - spm_full_group → full member access + row filter product_id <= 3
|
|
7
|
+
#
|
|
8
|
+
# The test user (single_policy_measure_user) belongs ONLY to spm_full_group, so
|
|
9
|
+
# only the full-access policy matches. Because no matching policy masks the
|
|
10
|
+
# measure, the masked measure must render its REAL aggregated value, and the
|
|
11
|
+
# full-access policy's row-level filter must still be applied — even for a
|
|
12
|
+
# measure-only query with no GROUP BY.
|
|
13
|
+
|
|
14
|
+
cubes:
|
|
15
|
+
- name: single_policy_measure_test
|
|
16
|
+
sql_table: public.line_items
|
|
17
|
+
|
|
18
|
+
dimensions:
|
|
19
|
+
- name: id
|
|
20
|
+
sql: id
|
|
21
|
+
type: number
|
|
22
|
+
primary_key: true
|
|
23
|
+
|
|
24
|
+
- name: product_id
|
|
25
|
+
sql: product_id
|
|
26
|
+
type: number
|
|
27
|
+
|
|
28
|
+
measures:
|
|
29
|
+
# Carries a mask, but it is only masked when a masking policy matches.
|
|
30
|
+
- name: total_quantity
|
|
31
|
+
sql: quantity
|
|
32
|
+
type: sum
|
|
33
|
+
mask: -1
|
|
34
|
+
|
|
35
|
+
# Used to assert the row-level filter is applied (max <= 3 when filtered).
|
|
36
|
+
- name: max_product_id
|
|
37
|
+
sql: product_id
|
|
38
|
+
type: max
|
|
39
|
+
|
|
40
|
+
access_policy:
|
|
41
|
+
# Masking policy — targets a group the test user is NOT in.
|
|
42
|
+
- group: spm_mask_group
|
|
43
|
+
member_level:
|
|
44
|
+
includes: []
|
|
45
|
+
member_masking:
|
|
46
|
+
includes: "*"
|
|
47
|
+
|
|
48
|
+
# Full-access policy with a row filter — the test user IS in this group.
|
|
49
|
+
- group: spm_full_group
|
|
50
|
+
member_level:
|
|
51
|
+
includes: "*"
|
|
52
|
+
row_level:
|
|
53
|
+
filters:
|
|
54
|
+
- member: product_id
|
|
55
|
+
operator: lte
|
|
56
|
+
values:
|
|
57
|
+
- "3"
|
|
@@ -35,3 +35,22 @@ views:
|
|
|
35
35
|
includes: "*"
|
|
36
36
|
row_level:
|
|
37
37
|
allow_all: true
|
|
38
|
+
|
|
39
|
+
# Two-layer row-level filtering: the underlying `orders` cube restricts rows
|
|
40
|
+
# to id IN {1, 10, 11} (role "*" → id = 1, role admin → id = 10 OR id = 11),
|
|
41
|
+
# while this view adds its own row filter id < 11. A row must satisfy BOTH
|
|
42
|
+
# the cube policy AND the view policy, so the result is id IN {1, 10}.
|
|
43
|
+
- name: orders_two_layer_test
|
|
44
|
+
cubes:
|
|
45
|
+
- join_path: orders
|
|
46
|
+
includes: "*"
|
|
47
|
+
access_policy:
|
|
48
|
+
- role: "*"
|
|
49
|
+
member_level:
|
|
50
|
+
includes: "*"
|
|
51
|
+
row_level:
|
|
52
|
+
filters:
|
|
53
|
+
- member: id
|
|
54
|
+
operator: lt
|
|
55
|
+
values:
|
|
56
|
+
- "11"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cubejs-backend/testing",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.57",
|
|
4
4
|
"description": "Cube.js e2e tests",
|
|
5
5
|
"author": "Cube Dev, Inc.",
|
|
6
6
|
"repository": {
|
|
@@ -102,15 +102,15 @@
|
|
|
102
102
|
"birdbox-fixtures"
|
|
103
103
|
],
|
|
104
104
|
"dependencies": {
|
|
105
|
-
"@cubejs-backend/cubestore-driver": "1.6.
|
|
105
|
+
"@cubejs-backend/cubestore-driver": "1.6.57",
|
|
106
106
|
"@cubejs-backend/dotenv": "^9.0.2",
|
|
107
|
-
"@cubejs-backend/ksql-driver": "1.6.
|
|
108
|
-
"@cubejs-backend/postgres-driver": "1.6.
|
|
109
|
-
"@cubejs-backend/query-orchestrator": "1.6.
|
|
110
|
-
"@cubejs-backend/schema-compiler": "1.6.
|
|
111
|
-
"@cubejs-backend/shared": "1.6.
|
|
112
|
-
"@cubejs-backend/testing-shared": "1.6.
|
|
113
|
-
"@cubejs-client/ws-transport": "1.6.
|
|
107
|
+
"@cubejs-backend/ksql-driver": "1.6.57",
|
|
108
|
+
"@cubejs-backend/postgres-driver": "1.6.57",
|
|
109
|
+
"@cubejs-backend/query-orchestrator": "1.6.57",
|
|
110
|
+
"@cubejs-backend/schema-compiler": "1.6.57",
|
|
111
|
+
"@cubejs-backend/shared": "1.6.57",
|
|
112
|
+
"@cubejs-backend/testing-shared": "1.6.57",
|
|
113
|
+
"@cubejs-client/ws-transport": "1.6.57",
|
|
114
114
|
"dedent": "^0.7.0",
|
|
115
115
|
"fs-extra": "^8.1.0",
|
|
116
116
|
"http-proxy": "^1.18.1",
|
|
@@ -121,8 +121,8 @@
|
|
|
121
121
|
},
|
|
122
122
|
"devDependencies": {
|
|
123
123
|
"@4tw/cypress-drag-drop": "^1.6.0",
|
|
124
|
-
"@cubejs-backend/linter": "1.6.
|
|
125
|
-
"@cubejs-client/core": "1.6.
|
|
124
|
+
"@cubejs-backend/linter": "1.6.57",
|
|
125
|
+
"@cubejs-client/core": "1.6.57",
|
|
126
126
|
"@jest/globals": "^29",
|
|
127
127
|
"@types/dedent": "^0.7.0",
|
|
128
128
|
"@types/http-proxy": "^1.17.5",
|
|
@@ -148,5 +148,5 @@
|
|
|
148
148
|
"eslintConfig": {
|
|
149
149
|
"extends": "../cubejs-linter"
|
|
150
150
|
},
|
|
151
|
-
"gitHead": "
|
|
151
|
+
"gitHead": "5f4674f6536b0e2e82f4445bfbc5f47450266256"
|
|
152
152
|
}
|