@cubejs-backend/testing 1.6.66 → 1.7.0
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.
- package/birdbox-fixtures/lambda/cube.js +6 -15
- package/birdbox-fixtures/multidb/cube.js +15 -20
- package/birdbox-fixtures/rbac/cube.js +10 -27
- package/birdbox-fixtures/rbac/model/cubes/conditional_masking_test.yaml +3 -3
- package/birdbox-fixtures/rbac/model/cubes/line_items.js +4 -4
- package/birdbox-fixtures/rbac/model/cubes/masking_test.yaml +13 -13
- package/birdbox-fixtures/rbac/model/cubes/orders.js +2 -2
- package/birdbox-fixtures/rbac/model/cubes/policy_overlap_test.yaml +2 -2
- package/birdbox-fixtures/rbac/model/cubes/products.yaml +1 -1
- package/birdbox-fixtures/rbac/model/cubes/region_test.yaml +1 -1
- package/birdbox-fixtures/rbac/model/cubes/security_context_test.js +4 -4
- package/birdbox-fixtures/rbac/model/cubes/users.yaml +2 -2
- package/birdbox-fixtures/rbac/model/views/users.js +1 -1
- package/birdbox-fixtures/rbac/model/views/views.yaml +4 -4
- package/birdbox-fixtures/rbac-graphql/cube.js +1 -1
- package/birdbox-fixtures/rbac-graphql/model/Orders.js +3 -3
- package/birdbox-fixtures/rbac-python/cube.py +4 -4
- package/birdbox-fixtures/rbac-python/model/cubes/products.yaml +1 -1
- package/birdbox-fixtures/rbac-python/model/cubes/users.yaml +2 -2
- package/birdbox-fixtures/rbac-python/model/views/users_view.yaml +1 -1
- package/package.json +14 -14
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
const PostgresDriver = require("@cubejs-backend/postgres-driver");
|
|
2
|
-
const KsqlDriver = require("@cubejs-backend/ksql-driver");
|
|
3
|
-
|
|
4
1
|
module.exports = {
|
|
5
2
|
orchestratorOptions: {
|
|
6
3
|
preAggregationsOptions: {
|
|
@@ -10,22 +7,16 @@ module.exports = {
|
|
|
10
7
|
contextToApiScopes: async () => new Promise((resolve) => {
|
|
11
8
|
resolve(['graphql', 'meta', 'data', 'jobs']);
|
|
12
9
|
}),
|
|
13
|
-
|
|
14
|
-
if (dataSource === '
|
|
15
|
-
return
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
return dataSource || 'postgres';
|
|
19
|
-
},
|
|
20
|
-
driverFactory: async ({ dataSource }) => {
|
|
21
|
-
if (dataSource === "ksql") {
|
|
22
|
-
return new KsqlDriver({
|
|
10
|
+
driverFactory: ({ dataSource }) => {
|
|
11
|
+
if (dataSource === 'ksql') {
|
|
12
|
+
return {
|
|
13
|
+
type: 'ksql',
|
|
23
14
|
url: process.env.KSQL_URL,
|
|
24
15
|
kafkaHost: process.env.KSQL_KAFKA_HOST,
|
|
25
16
|
kafkaUseSsl: false,
|
|
26
|
-
}
|
|
17
|
+
};
|
|
27
18
|
}
|
|
28
19
|
|
|
29
|
-
return
|
|
20
|
+
return { type: 'postgres' };
|
|
30
21
|
}
|
|
31
22
|
};
|
|
@@ -1,26 +1,21 @@
|
|
|
1
|
-
const PostgresDriver = require('@cubejs-backend/postgres-driver');
|
|
2
|
-
const MySqlDriver = require("@cubejs-backend/mysql-driver");
|
|
3
|
-
|
|
4
1
|
module.exports = {
|
|
5
|
-
dbType: ({ dataSource }) => {
|
|
6
|
-
switch (dataSource) {
|
|
7
|
-
case 'suppliers': return 'postgres';
|
|
8
|
-
case 'products': return 'mysql';
|
|
9
|
-
default: return 'postgres';
|
|
10
|
-
}
|
|
11
|
-
},
|
|
12
|
-
|
|
13
2
|
driverFactory: ({ dataSource }) => {
|
|
14
3
|
switch (dataSource) {
|
|
15
|
-
case 'suppliers':
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
4
|
+
case 'suppliers':
|
|
5
|
+
return { type: 'postgres' };
|
|
6
|
+
case 'products':
|
|
7
|
+
return {
|
|
8
|
+
type: 'mysql',
|
|
9
|
+
host: process.env.CUBEJS_DB_HOST2,
|
|
10
|
+
port: process.env.CUBEJS_DB_PORT2,
|
|
11
|
+
database: process.env.CUBEJS_DB_NAME2,
|
|
12
|
+
user: process.env.CUBEJS_DB_USER2,
|
|
13
|
+
password: process.env.CUBEJS_DB_PASS2,
|
|
14
|
+
};
|
|
15
|
+
case 'default':
|
|
16
|
+
return { type: 'postgres' };
|
|
17
|
+
default:
|
|
18
|
+
throw new Error(`driverFactory: Invalid dataSource '${dataSource}'`);
|
|
24
19
|
}
|
|
25
20
|
},
|
|
26
21
|
};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
module.exports = {
|
|
2
|
-
contextToRoles: async (context) => context.securityContext.auth?.roles || [],
|
|
3
2
|
contextToGroups: async (context) => context.securityContext.auth?.groups || [],
|
|
4
3
|
canSwitchSqlUser: async () => true,
|
|
5
4
|
checkSqlAuth: async (req, user, password) => {
|
|
@@ -19,8 +18,7 @@ module.exports = {
|
|
|
19
18
|
canHaveAdmin: true,
|
|
20
19
|
minDefaultId: 10000,
|
|
21
20
|
},
|
|
22
|
-
|
|
23
|
-
groups: ['leadership', 'hr'],
|
|
21
|
+
groups: ['leadership', 'hr', 'admin'],
|
|
24
22
|
},
|
|
25
23
|
},
|
|
26
24
|
};
|
|
@@ -41,8 +39,7 @@ module.exports = {
|
|
|
41
39
|
canHaveAdmin: false,
|
|
42
40
|
minDefaultId: 10000,
|
|
43
41
|
},
|
|
44
|
-
|
|
45
|
-
groups: ['management'],
|
|
42
|
+
groups: ['management', 'manager'],
|
|
46
43
|
},
|
|
47
44
|
},
|
|
48
45
|
};
|
|
@@ -63,7 +60,6 @@ module.exports = {
|
|
|
63
60
|
canHaveAdmin: false,
|
|
64
61
|
minDefaultId: 20000,
|
|
65
62
|
},
|
|
66
|
-
roles: [],
|
|
67
63
|
groups: ['general'],
|
|
68
64
|
},
|
|
69
65
|
},
|
|
@@ -85,7 +81,6 @@ module.exports = {
|
|
|
85
81
|
canHaveAdmin: true,
|
|
86
82
|
minDefaultId: 20000,
|
|
87
83
|
},
|
|
88
|
-
roles: ['restricted'],
|
|
89
84
|
groups: ['restricted'],
|
|
90
85
|
},
|
|
91
86
|
},
|
|
@@ -107,14 +102,13 @@ module.exports = {
|
|
|
107
102
|
region: 'CA',
|
|
108
103
|
allowedCities: ['Los Angeles', 'New York'],
|
|
109
104
|
},
|
|
110
|
-
roles: [],
|
|
111
105
|
groups: ['developer'],
|
|
112
106
|
},
|
|
113
107
|
},
|
|
114
108
|
};
|
|
115
109
|
}
|
|
116
110
|
// User for testing two-dimensional policy overlap (matches diagram in CompilerApi.ts)
|
|
117
|
-
// Has
|
|
111
|
+
// Has policy2_group, so both Policy 1 (*) and Policy 2 (policy2_group) apply
|
|
118
112
|
if (user === 'policy_test') {
|
|
119
113
|
if (password && password !== 'policy_test_password') {
|
|
120
114
|
throw new Error(`Password doesn't match for ${user}`);
|
|
@@ -126,13 +120,12 @@ module.exports = {
|
|
|
126
120
|
auth: {
|
|
127
121
|
username: 'policy_test',
|
|
128
122
|
userAttributes: {},
|
|
129
|
-
|
|
130
|
-
groups: [],
|
|
123
|
+
groups: ['policy2_group'],
|
|
131
124
|
},
|
|
132
125
|
},
|
|
133
126
|
};
|
|
134
127
|
}
|
|
135
|
-
// User for masking tests - no special
|
|
128
|
+
// User for masking tests - no special groups, sees only masked values
|
|
136
129
|
if (user === 'masking_viewer') {
|
|
137
130
|
if (password && password !== 'masking_viewer_password') {
|
|
138
131
|
throw new Error(`Password doesn't match for ${user}`);
|
|
@@ -144,13 +137,12 @@ module.exports = {
|
|
|
144
137
|
auth: {
|
|
145
138
|
username: 'masking_viewer',
|
|
146
139
|
userAttributes: {},
|
|
147
|
-
roles: [],
|
|
148
140
|
groups: [],
|
|
149
141
|
},
|
|
150
142
|
},
|
|
151
143
|
};
|
|
152
144
|
}
|
|
153
|
-
// User for masking tests - has full access
|
|
145
|
+
// User for masking tests - has full access group
|
|
154
146
|
if (user === 'masking_full') {
|
|
155
147
|
if (password && password !== 'masking_full_password') {
|
|
156
148
|
throw new Error(`Password doesn't match for ${user}`);
|
|
@@ -162,8 +154,7 @@ module.exports = {
|
|
|
162
154
|
auth: {
|
|
163
155
|
username: 'masking_full',
|
|
164
156
|
userAttributes: {},
|
|
165
|
-
|
|
166
|
-
groups: [],
|
|
157
|
+
groups: ['masking_full_access'],
|
|
167
158
|
},
|
|
168
159
|
},
|
|
169
160
|
};
|
|
@@ -180,8 +171,7 @@ module.exports = {
|
|
|
180
171
|
auth: {
|
|
181
172
|
username: 'masking_partial',
|
|
182
173
|
userAttributes: {},
|
|
183
|
-
|
|
184
|
-
groups: [],
|
|
174
|
+
groups: ['masking_partial'],
|
|
185
175
|
},
|
|
186
176
|
},
|
|
187
177
|
};
|
|
@@ -199,7 +189,6 @@ module.exports = {
|
|
|
199
189
|
userAttributes: {
|
|
200
190
|
allowedProductIds: [1, 2],
|
|
201
191
|
},
|
|
202
|
-
roles: [],
|
|
203
192
|
groups: ['user_group', 'region_group'],
|
|
204
193
|
},
|
|
205
194
|
},
|
|
@@ -216,7 +205,6 @@ module.exports = {
|
|
|
216
205
|
auth: {
|
|
217
206
|
username: 'region_user_no_filter',
|
|
218
207
|
userAttributes: {},
|
|
219
|
-
roles: [],
|
|
220
208
|
groups: ['user_group'],
|
|
221
209
|
},
|
|
222
210
|
},
|
|
@@ -239,7 +227,6 @@ module.exports = {
|
|
|
239
227
|
auth: {
|
|
240
228
|
username: 'sc_test',
|
|
241
229
|
userAttributes: {},
|
|
242
|
-
roles: [],
|
|
243
230
|
groups: [],
|
|
244
231
|
},
|
|
245
232
|
},
|
|
@@ -256,8 +243,7 @@ module.exports = {
|
|
|
256
243
|
auth: {
|
|
257
244
|
username: 'conditional_mask_user',
|
|
258
245
|
userAttributes: {},
|
|
259
|
-
|
|
260
|
-
groups: [],
|
|
246
|
+
groups: ['conditional_mask_group'],
|
|
261
247
|
},
|
|
262
248
|
},
|
|
263
249
|
};
|
|
@@ -273,8 +259,7 @@ module.exports = {
|
|
|
273
259
|
auth: {
|
|
274
260
|
username: 'conditional_mask_multi_user',
|
|
275
261
|
userAttributes: {},
|
|
276
|
-
|
|
277
|
-
groups: [],
|
|
262
|
+
groups: ['conditional_mask_group', 'conditional_mask_group_extra'],
|
|
278
263
|
},
|
|
279
264
|
},
|
|
280
265
|
};
|
|
@@ -292,7 +277,6 @@ module.exports = {
|
|
|
292
277
|
auth: {
|
|
293
278
|
username: 'single_policy_measure_user',
|
|
294
279
|
userAttributes: {},
|
|
295
|
-
roles: [],
|
|
296
280
|
groups: ['spm_full_group'],
|
|
297
281
|
},
|
|
298
282
|
},
|
|
@@ -311,7 +295,6 @@ module.exports = {
|
|
|
311
295
|
auth: {
|
|
312
296
|
username: 'multi_group_user',
|
|
313
297
|
userAttributes: {},
|
|
314
|
-
roles: [],
|
|
315
298
|
groups: ['mg_group_a', 'mg_group_c'],
|
|
316
299
|
},
|
|
317
300
|
},
|
|
@@ -26,13 +26,13 @@ cubes:
|
|
|
26
26
|
type: sum
|
|
27
27
|
|
|
28
28
|
access_policy:
|
|
29
|
-
-
|
|
29
|
+
- group: "*"
|
|
30
30
|
member_level:
|
|
31
31
|
includes: []
|
|
32
32
|
member_masking:
|
|
33
33
|
includes: "*"
|
|
34
34
|
|
|
35
|
-
-
|
|
35
|
+
- group: "conditional_mask_group"
|
|
36
36
|
member_level:
|
|
37
37
|
includes: "*"
|
|
38
38
|
row_level:
|
|
@@ -42,7 +42,7 @@ cubes:
|
|
|
42
42
|
values:
|
|
43
43
|
- "3"
|
|
44
44
|
|
|
45
|
-
-
|
|
45
|
+
- group: "conditional_mask_group_extra"
|
|
46
46
|
member_level:
|
|
47
47
|
includes: "*"
|
|
48
48
|
row_level:
|
|
@@ -47,7 +47,7 @@ cube('line_items', {
|
|
|
47
47
|
|
|
48
48
|
accessPolicy: [
|
|
49
49
|
{
|
|
50
|
-
|
|
50
|
+
group: '*',
|
|
51
51
|
rowLevel: {
|
|
52
52
|
filters: [{
|
|
53
53
|
member: 'id',
|
|
@@ -61,13 +61,13 @@ cube('line_items', {
|
|
|
61
61
|
},
|
|
62
62
|
},
|
|
63
63
|
{
|
|
64
|
-
|
|
64
|
+
group: 'restricted',
|
|
65
65
|
memberLevel: {
|
|
66
66
|
excludes: ['count', 'price', 'price_dim'],
|
|
67
67
|
},
|
|
68
68
|
},
|
|
69
69
|
{
|
|
70
|
-
|
|
70
|
+
group: 'admin',
|
|
71
71
|
conditions: [
|
|
72
72
|
{
|
|
73
73
|
if: security_context.auth?.userAttributes?.region === 'CA',
|
|
@@ -82,7 +82,7 @@ cube('line_items', {
|
|
|
82
82
|
},
|
|
83
83
|
},
|
|
84
84
|
{
|
|
85
|
-
|
|
85
|
+
group: 'manager',
|
|
86
86
|
conditions: [
|
|
87
87
|
{
|
|
88
88
|
if: security_context.auth?.userAttributes?.region === 'CA',
|
|
@@ -43,19 +43,19 @@ cubes:
|
|
|
43
43
|
type: sum
|
|
44
44
|
|
|
45
45
|
access_policy:
|
|
46
|
-
-
|
|
46
|
+
- group: "*"
|
|
47
47
|
member_level:
|
|
48
48
|
includes: []
|
|
49
49
|
member_masking:
|
|
50
50
|
includes: "*"
|
|
51
51
|
|
|
52
|
-
-
|
|
52
|
+
- group: "masking_full_access"
|
|
53
53
|
member_level:
|
|
54
54
|
includes: "*"
|
|
55
55
|
row_level:
|
|
56
56
|
allow_all: true
|
|
57
57
|
|
|
58
|
-
-
|
|
58
|
+
- group: "masking_partial"
|
|
59
59
|
member_level:
|
|
60
60
|
includes:
|
|
61
61
|
- id
|
|
@@ -102,7 +102,7 @@ cubes:
|
|
|
102
102
|
type: sum
|
|
103
103
|
|
|
104
104
|
access_policy:
|
|
105
|
-
-
|
|
105
|
+
- group: "*"
|
|
106
106
|
member_level:
|
|
107
107
|
includes: []
|
|
108
108
|
|
|
@@ -126,7 +126,7 @@ cubes:
|
|
|
126
126
|
type: count
|
|
127
127
|
|
|
128
128
|
access_policy:
|
|
129
|
-
-
|
|
129
|
+
- group: "*"
|
|
130
130
|
member_level:
|
|
131
131
|
includes: []
|
|
132
132
|
member_masking:
|
|
@@ -205,7 +205,7 @@ cubes:
|
|
|
205
205
|
type: count
|
|
206
206
|
|
|
207
207
|
access_policy:
|
|
208
|
-
-
|
|
208
|
+
- group: "*"
|
|
209
209
|
member_level:
|
|
210
210
|
includes:
|
|
211
211
|
- id
|
|
@@ -231,7 +231,7 @@ views:
|
|
|
231
231
|
- count_d
|
|
232
232
|
- total_quantity
|
|
233
233
|
access_policy:
|
|
234
|
-
-
|
|
234
|
+
- group: "*"
|
|
235
235
|
member_level:
|
|
236
236
|
includes: "*"
|
|
237
237
|
row_level:
|
|
@@ -249,14 +249,14 @@ views:
|
|
|
249
249
|
- count_d
|
|
250
250
|
- total_quantity
|
|
251
251
|
access_policy:
|
|
252
|
-
-
|
|
252
|
+
- group: "*"
|
|
253
253
|
member_level:
|
|
254
254
|
includes: []
|
|
255
255
|
member_masking:
|
|
256
256
|
includes: "*"
|
|
257
257
|
row_level:
|
|
258
258
|
allow_all: true
|
|
259
|
-
-
|
|
259
|
+
- group: "masking_full_access"
|
|
260
260
|
member_level:
|
|
261
261
|
includes: "*"
|
|
262
262
|
row_level:
|
|
@@ -274,7 +274,7 @@ views:
|
|
|
274
274
|
- count_d
|
|
275
275
|
- total_quantity
|
|
276
276
|
access_policy:
|
|
277
|
-
-
|
|
277
|
+
- group: "*"
|
|
278
278
|
member_level:
|
|
279
279
|
includes:
|
|
280
280
|
- public_dim
|
|
@@ -304,7 +304,7 @@ views:
|
|
|
304
304
|
- count
|
|
305
305
|
|
|
306
306
|
access_policy:
|
|
307
|
-
-
|
|
307
|
+
- group: "*"
|
|
308
308
|
member_level:
|
|
309
309
|
includes:
|
|
310
310
|
- view_mask_base_id
|
|
@@ -330,7 +330,7 @@ views:
|
|
|
330
330
|
- count
|
|
331
331
|
- total_quantity
|
|
332
332
|
access_policy:
|
|
333
|
-
-
|
|
333
|
+
- group: "*"
|
|
334
334
|
member_level:
|
|
335
335
|
includes:
|
|
336
336
|
- public_dim
|
|
@@ -339,7 +339,7 @@ views:
|
|
|
339
339
|
includes: "*"
|
|
340
340
|
row_level:
|
|
341
341
|
allow_all: true
|
|
342
|
-
-
|
|
342
|
+
- group: "masking_full_access"
|
|
343
343
|
member_level:
|
|
344
344
|
includes: "*"
|
|
345
345
|
row_level:
|
|
@@ -31,7 +31,7 @@ cube('orders', {
|
|
|
31
31
|
|
|
32
32
|
access_policy: [
|
|
33
33
|
{
|
|
34
|
-
|
|
34
|
+
group: '*',
|
|
35
35
|
memberLevel: {
|
|
36
36
|
// This cube is "private" by default and only accessible via views
|
|
37
37
|
includes: [],
|
|
@@ -47,7 +47,7 @@ cube('orders', {
|
|
|
47
47
|
},
|
|
48
48
|
},
|
|
49
49
|
{
|
|
50
|
-
|
|
50
|
+
group: 'admin',
|
|
51
51
|
memberLevel: {
|
|
52
52
|
// This cube is "private" by default and only accessible via views
|
|
53
53
|
includes: [],
|
|
@@ -51,7 +51,7 @@ views:
|
|
|
51
51
|
|
|
52
52
|
access_policy:
|
|
53
53
|
# Policy 1: covers members a, b (and count, id for filtering) with row filter R1 (id < 500)
|
|
54
|
-
-
|
|
54
|
+
- group: "*"
|
|
55
55
|
member_level:
|
|
56
56
|
includes:
|
|
57
57
|
- id
|
|
@@ -66,7 +66,7 @@ views:
|
|
|
66
66
|
- "500"
|
|
67
67
|
|
|
68
68
|
# Policy 2: covers members b, c (and count, id for filtering) with row filter R2 (id >= 500)
|
|
69
|
-
-
|
|
69
|
+
- group: "policy2_group"
|
|
70
70
|
member_level:
|
|
71
71
|
includes:
|
|
72
72
|
- id
|
|
@@ -96,7 +96,7 @@ cube('sc_ua_mask_test', {
|
|
|
96
96
|
|
|
97
97
|
accessPolicy: [
|
|
98
98
|
{
|
|
99
|
-
|
|
99
|
+
group: '*',
|
|
100
100
|
memberLevel: {
|
|
101
101
|
includes: [],
|
|
102
102
|
},
|
|
@@ -133,7 +133,7 @@ cube('sc_cube_mask_test', {
|
|
|
133
133
|
|
|
134
134
|
accessPolicy: [
|
|
135
135
|
{
|
|
136
|
-
|
|
136
|
+
group: '*',
|
|
137
137
|
memberLevel: {
|
|
138
138
|
includes: [],
|
|
139
139
|
},
|
|
@@ -181,7 +181,7 @@ cube('sc_joined_mask_test', {
|
|
|
181
181
|
|
|
182
182
|
accessPolicy: [
|
|
183
183
|
{
|
|
184
|
-
|
|
184
|
+
group: '*',
|
|
185
185
|
memberLevel: {
|
|
186
186
|
includes: [],
|
|
187
187
|
},
|
|
@@ -215,7 +215,7 @@ cube('sc_groups_shorthand_test', {
|
|
|
215
215
|
|
|
216
216
|
accessPolicy: [
|
|
217
217
|
{
|
|
218
|
-
|
|
218
|
+
group: '*',
|
|
219
219
|
rowLevel: {
|
|
220
220
|
filters: [{
|
|
221
221
|
member: 'product_id',
|
|
@@ -18,13 +18,13 @@ cubes:
|
|
|
18
18
|
primary_key: true
|
|
19
19
|
|
|
20
20
|
access_policy:
|
|
21
|
-
-
|
|
21
|
+
- group: "*"
|
|
22
22
|
row_level:
|
|
23
23
|
filters:
|
|
24
24
|
- member: "{CUBE}.city"
|
|
25
25
|
operator: equals
|
|
26
26
|
values: ["{ security_context.auth.userAttributes.city }"]
|
|
27
|
-
-
|
|
27
|
+
- group: admin
|
|
28
28
|
conditions:
|
|
29
29
|
# This thing will fail if there's no auth info in the context
|
|
30
30
|
# Unfortunately, as of now, there's no way to write more complex expressions
|
|
@@ -4,7 +4,7 @@ views:
|
|
|
4
4
|
- join_path: line_items
|
|
5
5
|
includes: "*"
|
|
6
6
|
access_policy:
|
|
7
|
-
-
|
|
7
|
+
- group: "*"
|
|
8
8
|
row_level:
|
|
9
9
|
filters:
|
|
10
10
|
- member: "${CUBE}.price_dim"
|
|
@@ -30,14 +30,14 @@ views:
|
|
|
30
30
|
- join_path: orders
|
|
31
31
|
includes: "*"
|
|
32
32
|
access_policy:
|
|
33
|
-
-
|
|
33
|
+
- group: admin
|
|
34
34
|
member_level:
|
|
35
35
|
includes: "*"
|
|
36
36
|
row_level:
|
|
37
37
|
allow_all: true
|
|
38
38
|
|
|
39
39
|
# Two-layer row-level filtering: the underlying `orders` cube restricts rows
|
|
40
|
-
# to id IN {1, 10, 11} (
|
|
40
|
+
# to id IN {1, 10, 11} (group "*" → id = 1, group admin → id = 10 OR id = 11),
|
|
41
41
|
# while this view adds its own row filter id < 11. A row must satisfy BOTH
|
|
42
42
|
# the cube policy AND the view policy, so the result is id IN {1, 10}.
|
|
43
43
|
- name: orders_two_layer_test
|
|
@@ -45,7 +45,7 @@ views:
|
|
|
45
45
|
- join_path: orders
|
|
46
46
|
includes: "*"
|
|
47
47
|
access_policy:
|
|
48
|
-
-
|
|
48
|
+
- group: "*"
|
|
49
49
|
member_level:
|
|
50
50
|
includes: "*"
|
|
51
51
|
row_level:
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
module.exports = {
|
|
2
|
-
|
|
2
|
+
contextToGroups: ({ securityContext }) => securityContext?.auth?.groups || ['*'],
|
|
3
3
|
|
|
4
4
|
// Same app ID for all tenants so they share a CompilerApi instance
|
|
5
5
|
contextToAppId: () => 'CUBEJS_APP_shared',
|
|
@@ -33,20 +33,20 @@ cube('Orders', {
|
|
|
33
33
|
|
|
34
34
|
accessPolicy: [
|
|
35
35
|
{
|
|
36
|
-
|
|
36
|
+
group: '*',
|
|
37
37
|
memberLevel: {
|
|
38
38
|
includes: [],
|
|
39
39
|
},
|
|
40
40
|
},
|
|
41
41
|
{
|
|
42
|
-
|
|
42
|
+
group: 'tenant-a',
|
|
43
43
|
memberLevel: {
|
|
44
44
|
includes: '*',
|
|
45
45
|
excludes: ['tier'],
|
|
46
46
|
},
|
|
47
47
|
},
|
|
48
48
|
{
|
|
49
|
-
|
|
49
|
+
group: 'tenant-b',
|
|
50
50
|
memberLevel: {
|
|
51
51
|
includes: '*',
|
|
52
52
|
excludes: ['internalCode'],
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
from cube import config
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
@config('
|
|
7
|
-
def
|
|
8
|
-
return context.get("securityContext", {}).get("auth", {}).get("
|
|
6
|
+
@config('context_to_groups')
|
|
7
|
+
def context_to_groups(context):
|
|
8
|
+
return context.get("securityContext", {}).get("auth", {}).get("groups", [])
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def extract_matching_dicts(data):
|
|
@@ -55,7 +55,7 @@ def check_sql_auth(query: dict, username: str, password: str) -> dict:
|
|
|
55
55
|
'canHaveAdmin': True,
|
|
56
56
|
'city': 'New York'
|
|
57
57
|
},
|
|
58
|
-
'
|
|
58
|
+
'groups': ['admin']
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
}
|
|
@@ -18,13 +18,13 @@ cubes:
|
|
|
18
18
|
primary_key: true
|
|
19
19
|
|
|
20
20
|
access_policy:
|
|
21
|
-
-
|
|
21
|
+
- group: "*"
|
|
22
22
|
row_level:
|
|
23
23
|
filters:
|
|
24
24
|
- member: "{CUBE}.city"
|
|
25
25
|
operator: equals
|
|
26
26
|
values: ["{ security_context.auth.userAttributes.city }"]
|
|
27
|
-
-
|
|
27
|
+
- group: admin
|
|
28
28
|
conditions:
|
|
29
29
|
# This thing will fail if there's no auth info in the context
|
|
30
30
|
# Unfortunately, as of now, there's no way to write more complex expressions
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cubejs-backend/testing",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "Cube.js e2e tests",
|
|
5
5
|
"author": "Cube Dev, Inc.",
|
|
6
6
|
"repository": {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"main": "dist/src/index.js",
|
|
13
13
|
"typings": "dist/src/index.d.ts",
|
|
14
14
|
"engines": {
|
|
15
|
-
"node": "
|
|
15
|
+
"node": ">=20.0.0"
|
|
16
16
|
},
|
|
17
17
|
"scripts": {
|
|
18
18
|
"cypress:open": "kill-port 4000 && TEST_PLAYGROUND_PORT=3080 yarn cypress:birdbox",
|
|
@@ -100,15 +100,15 @@
|
|
|
100
100
|
"birdbox-fixtures"
|
|
101
101
|
],
|
|
102
102
|
"dependencies": {
|
|
103
|
-
"@cubejs-backend/cubestore-driver": "1.
|
|
103
|
+
"@cubejs-backend/cubestore-driver": "1.7.0",
|
|
104
104
|
"@cubejs-backend/dotenv": "^9.0.2",
|
|
105
|
-
"@cubejs-backend/ksql-driver": "1.
|
|
106
|
-
"@cubejs-backend/postgres-driver": "1.
|
|
107
|
-
"@cubejs-backend/query-orchestrator": "1.
|
|
108
|
-
"@cubejs-backend/schema-compiler": "1.
|
|
109
|
-
"@cubejs-backend/shared": "1.
|
|
110
|
-
"@cubejs-backend/testing-shared": "1.
|
|
111
|
-
"@cubejs-client/ws-transport": "1.
|
|
105
|
+
"@cubejs-backend/ksql-driver": "1.7.0",
|
|
106
|
+
"@cubejs-backend/postgres-driver": "1.7.0",
|
|
107
|
+
"@cubejs-backend/query-orchestrator": "1.7.0",
|
|
108
|
+
"@cubejs-backend/schema-compiler": "1.7.0",
|
|
109
|
+
"@cubejs-backend/shared": "1.7.0",
|
|
110
|
+
"@cubejs-backend/testing-shared": "1.7.0",
|
|
111
|
+
"@cubejs-client/ws-transport": "1.7.0",
|
|
112
112
|
"dedent": "^0.7.0",
|
|
113
113
|
"fs-extra": "^8.1.0",
|
|
114
114
|
"http-proxy": "^1.18.1",
|
|
@@ -119,13 +119,13 @@
|
|
|
119
119
|
},
|
|
120
120
|
"devDependencies": {
|
|
121
121
|
"@4tw/cypress-drag-drop": "^1.6.0",
|
|
122
|
-
"@cubejs-backend/linter": "1.
|
|
123
|
-
"@cubejs-client/core": "1.
|
|
122
|
+
"@cubejs-backend/linter": "1.7.0",
|
|
123
|
+
"@cubejs-client/core": "1.7.0",
|
|
124
124
|
"@jest/globals": "^29",
|
|
125
125
|
"@types/dedent": "^0.7.0",
|
|
126
126
|
"@types/http-proxy": "^1.17.5",
|
|
127
127
|
"@types/jest": "^29",
|
|
128
|
-
"@types/node": "^
|
|
128
|
+
"@types/node": "^22",
|
|
129
129
|
"cypress": "14.0.0",
|
|
130
130
|
"cypress-image-snapshot": "^4.0.1",
|
|
131
131
|
"cypress-localstorage-commands": "^1.4.5",
|
|
@@ -146,5 +146,5 @@
|
|
|
146
146
|
"eslintConfig": {
|
|
147
147
|
"extends": "../cubejs-linter"
|
|
148
148
|
},
|
|
149
|
-
"gitHead": "
|
|
149
|
+
"gitHead": "1635ffd9dc3bf1de886bd6de6a1ab86068918942"
|
|
150
150
|
}
|