Skip to content

Commit 10e47fc

Browse files
feat(server-core): Support for scheduledRefreshTimeZones as function, passing securityContext (#9002)
* feat(server-core): Support for scheduledRefreshTimeZones as function, passing securityContext * add scheduledRefreshTimeZones schema validation * fix context passing * add tests * fix * fix lint warnings * docs: Cross-links between env vars and config options + clean-up * docs: Multi-tenant scheduled_refresh_time_zones * Fix * add scheduledRefreshTimeZones func support to python cover with tests * add and debug tests * add test for string config option ScheduledRefreshTimeZones * make linter happy * add building backend-native for running unit tests * fix jest multiple config in client-dx * add python for unit tests in backend-native --------- Co-authored-by: Igor Lukanin <[email protected]>
1 parent 0e6ecd9 commit 10e47fc

File tree

22 files changed

+431
-108
lines changed

22 files changed

+431
-108
lines changed

.github/workflows/push.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ jobs:
4242
matrix:
4343
# Current docker version + next LTS
4444
node-version: [20.x, 22.x]
45+
python-version: [3.11]
4546
fail-fast: false
4647

4748
steps:
@@ -65,6 +66,10 @@ jobs:
6566
uses: actions/setup-node@v4
6667
with:
6768
node-version: ${{ matrix.node-version }}
69+
- name: Install Python
70+
uses: actions/setup-python@v5
71+
with:
72+
python-version: ${{ matrix.python-version }}
6873
- name: Get yarn cache directory path
6974
id: yarn-cache-dir-path
7075
run: echo "dir=$(yarn cache dir)" >> "$GITHUB_OUTPUT"
@@ -92,6 +97,12 @@ jobs:
9297
run: yarn tsc
9398
- name: Build client
9499
run: yarn build
100+
- name: Build cubejs-backend-native (with Python)
101+
run: yarn run native:build-release-python
102+
working-directory: ./packages/cubejs-backend-native
103+
env:
104+
PYO3_PYTHON: python${{ matrix.python-version }}
105+
95106
- name: Lerna test
96107
run: yarn lerna run --concurrency 1 --stream --no-prefix unit
97108
# - uses: codecov/codecov-action@v1

docs/pages/product/configuration/advanced/multitenancy.mdx

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,22 @@ Cube supports multitenancy out of the box, both on database and data model
99
levels. Multiple drivers are also supported, meaning that you can have one
1010
customer’s data in MongoDB and others in Postgres with one Cube instance.
1111

12-
There are 6 [configuration options][ref-config-opts] you can leverage to make
12+
There are several [configuration options][ref-config-opts] you can leverage for
1313
your multitenancy setup. You can use all of them or just a couple, depending on
1414
your specific case. The options are:
1515

16-
- `contextToAppId`
17-
- `contextToOrchestratorId`
18-
- `driverFactory`
19-
- `repositoryFactory`
20-
- `preAggregationsSchema`
21-
- `queryRewrite`
22-
23-
All of the above options are functions, which you provide to Cube in the
24-
[`cube.js` configuration file][ref-config]. The functions accept one argument -
16+
- `context_to_app_id`
17+
- `schema_version`
18+
- `repository_factory`
19+
- `driver_factory`
20+
- `context_to_orchestrator_id`
21+
- `pre_aggregations_schema`
22+
- `query_rewrite`
23+
- `scheduled_refresh_contexts`
24+
- `scheduled_refresh_time_zones`
25+
26+
All of the above options are functions, which you provide in the
27+
[configuration file][ref-config]. The functions accept one argument:
2528
a context object, which has a [`securityContext`][ref-config-security-ctx]
2629
property where you can provide all the necessary data to identify a user e.g.,
2730
organization, app, etc. By default, the
@@ -360,19 +363,19 @@ module.exports = {
360363

361364
If you need scheduled refreshes for your pre-aggregations in a multi-tenant
362365
deployment, ensure you have configured
363-
[`scheduledRefreshContexts`][ref-config-refresh-ctx] correctly. You may also
364-
need to configure [`scheduledRefreshTimeZones`][ref-config-refresh-tz].
366+
[`scheduled_refresh_contexts`][ref-config-refresh-ctx] correctly. You may also
367+
need to configure [`scheduled_refresh_time_zones`][ref-config-refresh-tz].
365368

366369
<WarningBox>
367370

368-
Leaving [`scheduledRefreshContexts`][ref-config-refresh-ctx] unconfigured will
371+
Leaving [`scheduled_refresh_contexts`][ref-config-refresh-ctx] unconfigured will
369372
lead to issues where the security context will be `undefined`. This is because
370373
there is no way for Cube to know how to generate a context without the required
371374
input.
372375

373376
</WarningBox>
374377

375-
[ref-config]: /reference/configuration/config
378+
[ref-config]: /product/configuration#configuration-options
376379
[ref-config-opts]: /reference/configuration/config
377380
[ref-config-db]: /product/configuration/data-sources
378381
[ref-config-driverfactory]: /reference/configuration/config#driver_factory

docs/pages/reference/configuration/config.mdx

Lines changed: 76 additions & 48 deletions
Large diffs are not rendered by default.

docs/pages/reference/configuration/environment-variables.mdx

Lines changed: 67 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ The secret key used to sign and verify JWTs. Generated on project scaffold with
2121
| --------------- | ---------------------- | --------------------- |
2222
| A valid string | N/A | N/A |
2323

24+
See also the [`check_auth` configuration
25+
option](/reference/configuration/config#check_auth).
26+
2427
## `CUBEJS_APP`
2528

2629
An application ID used to uniquely identify the Cube deployment. Can be
@@ -96,6 +99,9 @@ The cache and queue driver to use for the Cube deployment.
9699
| --------------------- | ---------------------- | --------------------- |
97100
| `cubestore`, `memory` | `memory` | `cubestore` |
98101

102+
It can be also set using the [`cache_and_queue_driver` configuration
103+
option](/reference/configuration/config#cache_and_queue_driver).
104+
99105
## `CUBEJS_CONCURRENCY`
100106

101107
The number of concurrent connections each query queue has to the database.
@@ -104,6 +110,9 @@ The number of concurrent connections each query queue has to the database.
104110
| --------------- | ------------------------------------------- | ------------------------------------------- |
105111
| A valid number | [See database-specific page][ref-config-db] | [See database-specific page][ref-config-db] |
106112

113+
It can be also set as `concurrency` in the [`orchestrator_options` configuration
114+
option](/reference/configuration/config#orchestrator_options).
115+
107116
## `CUBEJS_CUBESTORE_HOST`
108117

109118
The hostname of the Cube Store deployment
@@ -726,6 +735,9 @@ endpoints.
726735
| ------------------------------------------------------------------------------ | ---------------------- | --------------------- |
727736
| A comma-delimited string with any combination of [API scopes][ref-rest-scopes] | `meta,data,graphql` | `meta,data,graphql` |
728737

738+
See also the [`context_to_api_scopes` configuration
739+
option](/reference/configuration/config#context_to_api_scopes).
740+
729741
## `CUBEJS_DEV_MODE`
730742

731743
If `true`, enables [development mode](/product/configuration#development-mode).
@@ -790,6 +802,9 @@ Enables [JSON Web Key (JWK)][ietf-jwk-ref]-based authentication in Cube.
790802
| --------------------------------- | ---------------------- | --------------------- |
791803
| A valid URL to a JSON Web Key Set | N/A | N/A |
792804

805+
It can be also set as `jwkUrl` in the [`jwt` configuration
806+
option](/reference/configuration/config#jwt).
807+
793808
## `CUBEJS_JWT_ALGS`
794809

795810
[Any supported algorithm for decoding JWTs][gh-jsonwebtoken-algs].
@@ -798,6 +813,9 @@ Enables [JSON Web Key (JWK)][ietf-jwk-ref]-based authentication in Cube.
798813
| ---------------- | ---------------------- | --------------------- |
799814
| `HS256`, `RS256` | N/A | N/A |
800815

816+
It can be also set as `algorithms` in the [`jwt` configuration
817+
option](/reference/configuration/config#jwt).
818+
801819
## `CUBEJS_JWT_AUDIENCE`
802820

803821
An audience value which will be used to enforce the [`aud` claim from inbound
@@ -807,6 +825,9 @@ JWTs][ietf-jwt-ref-aud].
807825
| ------------------- | ---------------------- | --------------------- |
808826
| A valid `aud` claim | N/A | N/A |
809827

828+
It can be also set as `audience` in the [`jwt` configuration
829+
option](/reference/configuration/config#jwt).
830+
810831
## `CUBEJS_JWT_CLAIMS_NAMESPACE`
811832

812833
A namespace within the decoded JWT under which any custom claims can be found.
@@ -815,6 +836,9 @@ A namespace within the decoded JWT under which any custom claims can be found.
815836
| --------------- | ---------------------- | --------------------- |
816837
| A valid string | N/A | N/A |
817838

839+
It can be also set as `claimsNamespace` in the [`jwt` configuration
840+
option](/reference/configuration/config#jwt).
841+
818842
## `CUBEJS_JWT_ISSUER`
819843

820844
An issuer value which will be used to enforce the [`iss` claim from inbound
@@ -824,6 +848,9 @@ JWTs][ietf-jwt-ref-iss].
824848
| ------------------- | ---------------------- | --------------------- |
825849
| A valid `iss` claim | N/A | N/A |
826850

851+
It can be also set as `issuer` in the [`jwt` configuration
852+
option](/reference/configuration/config#jwt).
853+
827854
## `CUBEJS_JWT_KEY`
828855

829856
The secret key used to sign and verify JWTs. Similar to
@@ -833,6 +860,9 @@ The secret key used to sign and verify JWTs. Similar to
833860
| --------------- | ---------------------- | --------------------- |
834861
| A valid string | N/A | N/A |
835862

863+
It can be also set as `key` in the [`jwt` configuration
864+
option](/reference/configuration/config#jwt).
865+
836866
## `CUBEJS_JWT_SUBJECT`
837867

838868
A subject value which will be used to enforce the [`sub` claim from inbound
@@ -842,6 +872,9 @@ JWTs][ietf-jwt-ref-sub].
842872
| ------------------- | ---------------------- | --------------------- |
843873
| A valid `sub` claim | N/A | N/A |
844874

875+
It can be also set as `subject` in the [`jwt` configuration
876+
option](/reference/configuration/config#jwt).
877+
845878
## `CUBEJS_LOG_LEVEL`
846879

847880
The logging level for Cube.
@@ -850,6 +883,9 @@ The logging level for Cube.
850883
| -------------------------------- | ---------------------- | --------------------- |
851884
| `error`, `info`, `trace`, `warn` | `warn` | `warn` |
852885

886+
See also `CUBESTORE_LOG_LEVEL`.
887+
See also the [`logger` configuration option](/reference/configuration/config#logger).
888+
853889
## `CUBEJS_MAX_PARTITIONS_PER_CUBE`
854890

855891
The maximum number of partitions each pre-aggregation in a cube can use.
@@ -891,6 +927,9 @@ to use for storing pre-aggregations.
891927
| --------------- | ---------------------- | ----------------------- |
892928
| A valid string | `dev_pre_aggregations` | `prod_pre_aggregations` |
893929

930+
It can be also set using the [`pre_aggregations_schema` configuration
931+
option](/reference/configuration/config#pre_aggregations_schema).
932+
894933
## `CUBEJS_REFRESH_WORKER`
895934

896935
If `true`, this instance of Cube will **only** refresh pre-aggregations.
@@ -909,6 +948,9 @@ mode](/product/caching/using-pre-aggregations#rollup-only-mode) for details.
909948
| --------------- | ---------------------- | --------------------- |
910949
| `true`, `false` | `false` | `false` |
911950

951+
It can be also set using the [`orchestrator_options.rollupOnlyMode` configuration
952+
option](/reference/configuration/config#orchestrator_options).
953+
912954
## `CUBEJS_SCHEDULED_REFRESH_CONCURRENCY`
913955

914956
How many pre-aggregations refresh worker will build in parallel. Please note
@@ -928,6 +970,9 @@ for][ref-config-sched-refresh-timer].
928970
| --------------------------------------------------------- | ---------------------- | --------------------- |
929971
| [A valid timezone from the tz database][wiki-tz-database] | N/A | N/A |
930972

973+
It can be also set using the [`scheduled_refresh_time_zones` configuration
974+
option](/reference/configuration/config#scheduled_refresh_time_zones).
975+
931976
## `CUBEJS_SCHEMA_PATH`
932977

933978
The path where Cube loads data models from.
@@ -936,38 +981,49 @@ The path where Cube loads data models from.
936981
| ---------------------------------------- | ---------------------- | --------------------- |
937982
| A valid path containing Cube data models | `model` | `model` |
938983

939-
<WarningBox>
984+
<InfoBox>
940985

941986
Until v0.35, the default value was `schema`.
942987

943-
</WarningBox>
988+
</InfoBox>
944989

945-
{/* TODO: https://cubedevinc.atlassian.net/browse/CC-3095 */}
990+
It can be also set using the [`schema_path` configuration
991+
option](/reference/configuration/config#schema_path).
946992

947-
## `CUBEJS_SQL_PASSWORD`
993+
## `CUBEJS_SQL_USER`
948994

949-
A password required to access the [SQL API][ref-sql-api].
995+
A username required to access the [SQL API][ref-sql-api].
950996

951997
| Possible Values | Default in Development | Default in Production |
952998
| --------------- | ---------------------- | --------------------- |
953999
| A valid string | N/A | N/A |
9541000

955-
## `CUBEJS_SQL_SUPER_USER`
1001+
See also the [`check_sql_auth` configuration
1002+
option](/reference/configuration/config#check_sql_auth).
1003+
1004+
## `CUBEJS_SQL_PASSWORD`
9561005

957-
A name of specific user who will be allowed to change security context.
1006+
A password required to access the [SQL API][ref-sql-api].
9581007

9591008
| Possible Values | Default in Development | Default in Production |
9601009
| --------------- | ---------------------- | --------------------- |
9611010
| A valid string | N/A | N/A |
9621011

963-
## `CUBEJS_SQL_USER`
1012+
See also the [`check_sql_auth` configuration
1013+
option](/reference/configuration/config#check_sql_auth).
9641014

965-
A username required to access the [SQL API][ref-sql-api].
1015+
## `CUBEJS_SQL_SUPER_USER`
1016+
1017+
A name of specific user who will be allowed to change the user during the SQL API
1018+
session.
9661019

9671020
| Possible Values | Default in Development | Default in Production |
9681021
| --------------- | ---------------------- | --------------------- |
9691022
| A valid string | N/A | N/A |
9701023

1024+
See also the [`can_switch_sql_user` configuration
1025+
option](/reference/configuration/config#can_switch_sql_user).
1026+
9711027
## `CUBEJS_ALLOW_UNGROUPED_WITHOUT_PRIMARY_KEY`
9721028

9731029
If `true`, disables the primary key inclusion check for
@@ -1228,6 +1284,8 @@ The logging level for Cube Store.
12281284
| ----------------------------------------- | ---------------------- | --------------------- |
12291285
| `error`, `warn`, `info`, `debug`, `trace` | `error` | `error` |
12301286

1287+
See also `CUBEJS_LOG_LEVEL`.
1288+
12311289
## `CUBESTORE_META_ADDR`
12321290

12331291
The address/port pair for the Cube Store **router** node in the cluster.

packages/cubejs-api-gateway/src/gateway.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ class ApiGateway {
456456

457457
app.get('/cubejs-system/v1/pre-aggregations/timezones', systemMiddlewares, systemAsyncHandler(async (req, res) => {
458458
this.resToResultFn(res)({
459-
timezones: this.scheduledRefreshTimeZones || []
459+
timezones: this.scheduledRefreshTimeZones ? this.scheduledRefreshTimeZones(req.context) : []
460460
});
461461
}));
462462

@@ -625,12 +625,13 @@ class ApiGateway {
625625
const compilerApi = await this.getCompilerApi(context);
626626
const preAggregations = await compilerApi.preAggregations();
627627

628+
const refreshTimezones = this.scheduledRefreshTimeZones ? await this.scheduledRefreshTimeZones(context) : [];
628629
const preAggregationPartitions = await this.refreshScheduler()
629630
.preAggregationPartitions(
630631
context,
631632
normalizeQueryPreAggregations(
632633
{
633-
timezones: this.scheduledRefreshTimeZones,
634+
timezones: refreshTimezones.length > 0 ? refreshTimezones : undefined,
634635
preAggregations: preAggregations.map(p => ({
635636
id: p.id,
636637
cacheOnly,
@@ -652,9 +653,10 @@ class ApiGateway {
652653
) {
653654
const requestStarted = new Date();
654655
try {
656+
const refreshTimezones = this.scheduledRefreshTimeZones ? await this.scheduledRefreshTimeZones(context) : [];
655657
query = normalizeQueryPreAggregations(
656658
this.parseQueryParam(query),
657-
{ timezones: this.scheduledRefreshTimeZones }
659+
{ timezones: refreshTimezones.length > 0 ? refreshTimezones : undefined }
658660
);
659661
const orchestratorApi = await this.getAdapterApi(context);
660662
const compilerApi = await this.getCompilerApi(context);

packages/cubejs-api-gateway/src/types/gateway.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,24 @@ type UserBackgroundContext = {
3434
authInfo?: any;
3535
};
3636

37+
type RequestContext = {
38+
// @deprecated Renamed to securityContext, please use securityContext.
39+
authInfo?: any;
40+
securityContext: any;
41+
requestId: string;
42+
};
43+
3744
/**
38-
* Function that should provides a logic of scheduled returning of
45+
* Function that should provide a logic of scheduled returning of
3946
* the user background context. Used as a part of a main
4047
* configuration object of the Gateway to provide extendability to
4148
* this logic.
4249
*/
4350
type ScheduledRefreshContextsFn =
4451
() => Promise<UserBackgroundContext[]>;
4552

53+
type ScheduledRefreshTimeZonesFn = (context: RequestContext) => string[] | Promise<string[]>;
54+
4655
/**
4756
* Gateway configuration options interface.
4857
*/
@@ -52,7 +61,7 @@ interface ApiGatewayOptions {
5261
dataSourceStorage: any;
5362
refreshScheduler: any;
5463
scheduledRefreshContexts?: ScheduledRefreshContextsFn;
55-
scheduledRefreshTimeZones?: String[];
64+
scheduledRefreshTimeZones?: ScheduledRefreshTimeZonesFn;
5665
basePath: string;
5766
extendContext?: ExtendContextFn;
5867
jwt?: JWTOptions;

packages/cubejs-api-gateway/test/auth.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ describe('test authorization', () => {
323323

324324
const { app } = createApiGateway(handlerMock, loggerMock, {
325325
playgroundAuthSecret,
326-
checkAuth: async (req: Request, auth?: string) => {
326+
checkAuth: async (_req: Request, _auth?: string) => {
327327
throw new CubejsHandlerError(409, 'Error', 'Custom error');
328328
}
329329
});

packages/cubejs-api-gateway/test/index.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -849,7 +849,7 @@ describe('API Gateway', () => {
849849
playgroundAuthSecret,
850850
refreshScheduler: () => new RefreshSchedulerMock(),
851851
scheduledRefreshContexts: () => Promise.resolve(scheduledRefreshContextsFactory()),
852-
scheduledRefreshTimeZones: scheduledRefreshTimeZonesFactory()
852+
scheduledRefreshTimeZones: scheduledRefreshTimeZonesFactory
853853
}
854854
);
855855
const token = generateAuthToken({ uid: 5, scope }, {}, playgroundAuthSecret);

0 commit comments

Comments
 (0)