@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.55",
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.55",
105
+ "@cubejs-backend/cubestore-driver": "1.6.57",
106
106
  "@cubejs-backend/dotenv": "^9.0.2",
107
- "@cubejs-backend/ksql-driver": "1.6.55",
108
- "@cubejs-backend/postgres-driver": "1.6.55",
109
- "@cubejs-backend/query-orchestrator": "1.6.55",
110
- "@cubejs-backend/schema-compiler": "1.6.55",
111
- "@cubejs-backend/shared": "1.6.55",
112
- "@cubejs-backend/testing-shared": "1.6.55",
113
- "@cubejs-client/ws-transport": "1.6.55",
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.55",
125
- "@cubejs-client/core": "1.6.55",
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": "0d6393b29b6b348a9ab2527d6c5b72203f14dad1"
151
+ "gitHead": "5f4674f6536b0e2e82f4445bfbc5f47450266256"
152
152
  }