Skip to content

docs: document that Cube Core development mode bypasses authentication - #11805

Open
paveltiunov wants to merge 15 commits into
masterfrom
pavel-claude/serene-mayer-0w8zu0
Open

docs: document that Cube Core development mode bypasses authentication#11805
paveltiunov wants to merge 15 commits into
masterfrom
pavel-claude/serene-mayer-0w8zu0

Conversation

@paveltiunov

@paveltiunov paveltiunov commented Sep 9, 2026

Copy link
Copy Markdown
Member

Check List

  • Tests have been run in packages where changes have been made if available — n/a, documentation-only change (24 files, all .mdx/.md; Codecov reports a zero code diff)
  • Linter has been run for changed code — n/a, only .mdx/.md; verified callout tags balance in every edited page, all 10 snippet imports resolve, and the duplicate page pairs stay byte-identical
  • Tests for the changes have been added if not covered yet — n/a, documentation-only change
  • Docs have been added / updated if required

Description of Changes Made (if issue reference is not provided)

Cube Core development mode was under-documented: admin/deployment/core.mdx said only that it "can lead to security vulnerabilities" and "will expose your data to the internet", and admin/index.mdx listed "Disables authentication checks" as one bullet among nine behavioural changes. Neither conveyed what an exposed dev-mode instance actually gives away.

Every place that documents CUBEJS_DEV_MODE now says that development mode is an authentication bypass, that this is intentional and meant for a developer's local machine, and that using it in the Cube cloud platform is highly discouraged because it bypasses the platform's security model.

Three independent gates

Getting this right took several rounds, because "development mode" is not one switch. The docs now name the applicable condition in each sentence rather than letting a paragraph inherit the section's:

Behaviour Gate
REST/GraphQL JWT verification enforceSecurityChecks = options.enforceSecurityChecks || NODE_ENV === 'production' (gateway.ts:285), and cubejs-server-core never passes the option. Under the cubejs CLI, CUBEJS_DEV_MODE=true forces NODE_ENV=development (container.ts:250-253), so the flag switches verification off
Playground / dev-server mount devServer: this.isDevMode() (OptsHandler.ts:392), where isDevMode() is NODE_ENV !== 'production' || getEnv('devMode') (:485-489)
SQL API password skip skipPasswordCheck: getEnv('devMode') && !allowedPassword (sql-server.ts:371) — the flag alone, no NODE_ENV term, and only when no sqlPassword is configured

What that means in practice:

  • Development mode exposes the Playground endpoints with no authentication at all. GET /playground/context hands out a ready-to-use API-secret-signed JWT (DevServer.ts:52, :116) and POST /playground/token mints further ones from req.body.payload (:607), so anyone who can reach the instance can query every data API as any user, bypassing member-level access control and row-level security. The same endpoints read the data model files (GET /playground/files) and every connected data source's table schema (GET /playground/db-schema, called with securityContext: null), and overwrite the data model (POST /playground/generate-schema) and .env (POST /playground/env).
  • Under the cubejs CLI, the flag also turns off JWT verification outright, because ServerContainer.lookupConfiguration() rewrites NODE_ENV to development before the gateway reads it. start() calls it at :336, ahead of runServerInstance() at :344. Nothing rewrites NODE_ENV if you construct CubejsServer/CubejsServerCore yourself, so the docs scope this to the CLI and the official images (whose CMD is ["cubejs", "server"]).
  • With CUBEJS_DEV_MODE=true and no CUBEJS_SQL_PASSWORD, the SQL API accepts any credentials, allowing arbitrary SQL against connected data sources. Scoped to the flag deliberately: with it unset, sql-server.ts:345-361 forces allowedUser = 'cube' and generates a random password, so credentials are enforced even though the instance may still be in development mode.
  • Turning it off: cubejs server and the official images already set NODE_ENV=production, so leaving CUBEJS_DEV_MODE unset is sufficient there. An unset NODE_ENV only matters when embedding @cubejs-backend/server-core directly, where it puts the instance in development mode whatever the flag says — the warning says so rather than implying everyone must set NODE_ENV.

The pre-existing "Development mode is disabled by default" note held only because the images set ENV NODE_ENV=production (latest.Dockerfile:41); it now explains that.

Structure

The warning lives in two Mintlify snippets — docs-mintlify/snippets/dev-mode-warning.mdx (long) and dev-mode-warning-short.mdx (condensed) — imported by 10 pages. yarn broken-links already runs with --check-snippets. It was originally pasted into every page; extracting it came out of review after an accuracy fix had to be applied 11 times by hand, and every correction since has been a single edit.

The long form goes on the CUBEJS_DEV_MODE reference, the Administration and Cube Core deployment pages, and the Cube Core getting-started guide; the short form on the production/Cube Store pages, Playground, and the SQL API and QuestDB Docker examples. embedding/authentication/jwt.mdx had its "token is not required in development mode" <Info> promoted to a <Warning>. Both production checklists gained NODE_ENV=production with an accurate comment.

Incidental mentions (pre-aggregations, config.mdx, the JavaScript SDK pages) just link "development mode" to the canonical warning rather than carrying a security aside — and those links were repointed from /docs/data-modeling/dev-mode, which documents the cloud platform's branch-based development mode, a different feature. That page now carries a callout distinguishing the two, since several Cube Core pages linked to it as "Development Mode".

The root README.md carries the warning inline next to its docker run -e CUBEJS_DEV_MODE=true snippet, since it can't import a Mintlify snippet. It was also added to the Vertica driver and Cube Store READMEs and then removed as disproportionate for those documents; both are back to their state on master.

Only docs-mintlify is touched; the deprecated /docs Nextra site is left alone per CLAUDE.md.

🤖 Generated with Claude Code

https://claude.ai/code/session_01S7RGv1SFGTWjRUSaarhE88

Every place that documents Cube Core development mode (`CUBEJS_DEV_MODE`) now
states that enabling it disables authentication completely: all data access
endpoints are served without any authentication or authorization verification,
member-level access control is not enforced, and anyone who can reach the
instance can execute arbitrary SQL against connected data sources.

The docs also make clear that this is by design — development mode is meant to
run on a developer's local machine for ease of use and debugging — and that
using it in the Cube cloud platform is highly discouraged because it bypasses
the platform's security model.

Covers the `CUBEJS_DEV_MODE` reference, the Administration and Cube Core
deployment/production pages, the Cube Core getting-started guide, Playground,
JWT authentication, SQL API and QuestDB Docker examples, pre-aggregation and
config references, the JavaScript SDK pages, the Cube cloud platform dev mode
page (disambiguating the two features), and the root, Vertica driver and Cube
Store READMEs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7RGv1SFGTWjRUSaarhE88
@paveltiunov
paveltiunov requested review from a team and keydunov as code owners September 9, 2026 04:01
@mintlify

mintlify Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated
cubed3 🟢 Ready View Preview Sep 9, 2026, 4:02 AM

💡 Tip: Enable Automations to automatically generate PRs for you.

@github-actions github-actions Bot added cube store Issues relating to Cube Store rust Pull requests that update Rust code data source driver labels Sep 9, 2026
@claude

claude Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Claude finished @paveltiunov's task in 4m 1s —— View job


Review complete — request changes: 1 high (factual inaccuracy), 4 medium, 3 low. 8 inline comments posted.

Full review
  • Gather context (read diff)
  • Verify factual accuracy of claims against source code
  • Check Mintlify conventions / link validity
  • Post review

Summary

The intent is right — dev mode's security posture was under-documented, and centralizing a clear warning on CUBEJS_DEV_MODE is worth doing. Two things need attention before merge: the central factual claim doesn't match the implementation, and the warning is copy-pasted into 11 pages plus 3 READMEs.

High — the claim is wrong, in the unsafe direction

docs-mintlify/reference/configuration/environment-variables.mdx:1199 (and the 5 verbatim copies) states that CUBEJS_DEV_MODE "disables authentication completely". For the REST and GraphQL APIs it does not:

// packages/cubejs-api-gateway/src/gateway.ts:285
this.enforceSecurityChecks = options.enforceSecurityChecks || (process.env.NODE_ENV === 'production');

enforceSecurityChecks is the only gate that turns a missing or invalid token into a 403 (gateway.ts:2705-2715), and cubejs-server-core never passes the option. So:

Claim in the PR What the code does
CUBEJS_DEV_MODE=true ⇒ no auth REST/GraphQL auth is gated on NODE_ENV !== 'production', independently of this flag
Disabling dev mode secures the instance CUBEJS_DEV_MODE=false with NODE_ENV unset still accepts requests with no Authorization header — the exact failure this PR targets
No authorization verification A user-supplied checkAuth is always invoked (gateway.ts:2726)
SQL API served without auth Only when creds are unset: skipPasswordCheck: getEnv('devMode') && !allowedPassword (sql-server.ts:371)

Because the block is duplicated, the inaccuracy propagates to every page. The accurate framing: dev mode enables the Playground and the data-model read/write endpoints; NODE_ENV=production is what enforces API authentication — and NODE_ENV=production belongs in the "Disable Development Mode" production checklist next to the flag.

Medium

  1. Duplication. The long warning appears verbatim in 6 files, a condensed variant in 5 more, inline sentences in 8. Any fix must be applied 11×. Use a Mintlify snippet (docs-mintlify/snippets/), or keep the long form only on CUBEJS_DEV_MODE + the production checklist and link to it elsewhere. docs-mintlify/CLAUDE.md explicitly asks for concise, surgical edits.
  2. rest-api/reference.mdx:62 — security paragraph buried inside a <Note> about the usedPreAggregations response field. Wrong audience, wrong moment.
  3. packages/cubejs-vertica-driver/README.md:29 — that README never sets CUBEJS_DEV_MODE; the warning is unrelated to the driver.
  4. config.mdx:1515 and docs/pre-aggregations/index.mdx:25 — auth asides wedged into paragraphs about telemetry and about resetting the in-memory cache. Non sequiturs that dilute both facts.

Low

  • Placementquestdb.mdx:46, sql-api/index.mdx, create-a-project.mdx: callouts sit mid-procedure, between a compose file and the next step.
  • cube-core/deployment.mdx:393 — the rewritten "read more" sentence still resolves link-cubejs-dev-vs-prod to /docs/data-modeling/dev-mode, the cloud feature this PR itself flags as different. Worth repointing while the line is being touched.
  • cubejs-client-core.mdx:55 — looks like a generated typedoc table; confirm it's hand-maintained before adding prose.

Verified as fine

  • All new link targets exist on disk: reference/core-data-apis/{rest-api,graphql-api,sql-api}, docs/data-modeling/access-control/member-level-security.mdx, docs/explore-analyze/playground.mdx. Reference-link definitions ([ref-development-mode], [link-cubejs-dev-vs-prod]) are present in each file that newly uses them.
  • <Warning> / <Note> tags are balanced, with the blank lines Mintlify needs.
  • Naming follows docs-mintlify/CLAUDE.md: "Cube cloud platform", not the deprecated "Cube Cloud".
  • Only the active docs site is touched; the deprecated /docs Nextra tree is untouched.
  • The two duplicate page pairs (admin/deployment/core.mdxcube-core/deployment.mdx, cube-core/running-in-production.mdxdocs/pre-aggregations/running-in-production.mdx) were kept byte-identical.
  • Adding the disambiguation callout to docs/data-modeling/dev-mode.mdx is a good call — that page/feature collision was a real trap.

I could not run docs-mintlify/scripts/check_links.py (command not permitted in this environment), so link validation above is by manual file-existence check rather than the repo's checker.

· branch `pavel-claude/serene-mayer-0w8zu0`

Name the mechanisms verified in the source instead of asserting arbitrary
SQL as a consequence of data model writes:

- REST/GraphQL: `enforceSecurityChecks` is only on when NODE_ENV=production,
  so a missing *or invalid* token is accepted (ApiGateway.createDefaultCheckAuth).
- SQL API: the default `checkSqlAuth` skips the password check in dev mode when
  no CUBEJS_SQL_PASSWORD is set, and leaves the user name unconstrained, so any
  credentials connect and pushdown reaches the data source with arbitrary SQL.
- Playground endpoints are unauthenticated: /playground/files and
  /playground/generate-schema read and rewrite the data model, /playground/env
  rewrites .env, and /playground/token signs any payload with the API secret.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7RGv1SFGTWjRUSaarhE88
@claude

claude Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Claude finished @paveltiunov's task in 3m 13s —— View job


Re-review after 6ffe339 — the central factual issue is still open. 1 high, 3 medium, 5 low (all 9 prior threads re-affirmed, no new inline comments)

Full review
  • Gather context (read diff)
  • Verify factual accuracy of claims against source code
  • Check Mintlify conventions / link validity
  • Post review

What the new commit changed

6ffe339 added a Playground paragraph to the long-form warning ("Playground's own endpoints are unauthenticated as well: they read and write your data model files and .env, and mint tokens carrying any security context, signed with your API secret").

That paragraph is accurate, and it's the strongest thing in the PR. Verified against the code:

Claim Verdict Evidence
Playground/dev-server mounted when dev mode is on OptsHandler.ts:392 devServer: this.isDevMode(); server.ts:444
/playground/* routes carry no auth middleware DevServer.ts:112-616, handlers wrapped only in catchErrors
Writes .env and the data model DevServer.ts:585 fs.writeFileSync(path.join(process.cwd(), '.env'), …); :161 generate-schema
Mints tokens with any security context, signed with the API secret DevServer.ts:607-611 jwt.sign(payload, options.apiSecret, …) from unauthenticated req.body.payload
SQL API skips the password check ⚠️ conditional sql-server.ts:371 skipPasswordCheck: getEnv('devMode') && !allowedPassword — only when no sqlPassword; CUBEJS_SQL_USER still constrains the user name (:364)
REST/GraphQL served without any authentication verification gated on NODE_ENV, not CUBEJS_DEV_MODE — see below

The unresolved high finding (thread on environment-variables.mdx:1210)

Nothing in 6ffe339 addressed it. gateway.ts:285:

this.enforceSecurityChecks = options.enforceSecurityChecks || (process.env.NODE_ENV === 'production');

enforceSecurityChecks is the only thing that turns a missing/invalid token into a 403 (gateway.ts:2705-2715), and cubejs-server-core never passes the option (server.ts:464-495). The code says so itself, in DevServer.ts:54:

🔓 Authentication checks are disabled in developer mode. Please use NODE_ENV=production to enable it.

This matters most exactly where the PR puts the warning: the official images set ENV NODE_ENV=production (packages/cubejs-docker/latest.Dockerfile:41), so a docker run … -e CUBEJS_DEV_MODE=true — the snippet in the root README.md, create-a-project.mdx, questdb.mdx and sql-api/index.mdxstill verifies JWTs on the REST API. And the converse is the dangerous half: running cubejs-server locally with CUBEJS_DEV_MODE=false and NODE_ENV unset accepts requests with no Authorization header at all, so a reader who follows the new "Disable Development Mode" checklist item and nothing else is still unauthenticated.

The outcome the warning describes is reachable under CUBEJS_DEV_MODE=true even with NODE_ENV=production — via the unauthenticated /playground/token route — but through the Playground, not through "the REST API accepts missing tokens." Restructuring the warning around the mechanism that actually holds would make it both correct and shorter:

  1. Dev mode exposes the unauthenticated Playground/dev-server endpoints, which write .env and mint API-secret-signed tokens for any security context — full data access regardless of NODE_ENV.
  2. Dev mode skips the SQL API password check when no CUBEJS_SQL_PASSWORD is set.
  3. Separately, NODE_ENV=production is what enforces API authentication — add it to the production checklist next to disabling dev mode.

Other prior threads, all still applicable

Verified against the current tree; none are outdated:

  • rest-api/reference.mdx:65 — warning buried inside a <Note> about the usedPreAggregations response field.
  • config.mdx:1519 — security aside inside the anonymous-telemetry paragraph (and the dev_pre_aggregations default at ~630).
  • docs/pre-aggregations/index.mdx:27 — non sequitur in the caching intro.
  • packages/cubejs-vertica-driver/README.md:37 — that snippet never sets CUBEJS_DEV_MODE.
  • cube-core/deployment.mdx:393link-cubejs-dev-vs-prod still points at the Cloud dev-mode page.
  • questdb.mdx:55 — callout splits "create docker-compose.yml" from "create an .env file".
  • admin/index.mdx:195 — the 15-line block is duplicated verbatim in 6 files; a fix to the item above has to be applied 11 times.
  • cubejs-client-core.mdx:55 — generated-looking typedoc table.

One addition to the config.mdx thread, folded in here rather than posted separately: the rewritten telemetry sentence turns plain text into [development mode][ref-development-mode], and that reference resolves to /docs/data-modeling/dev-mode (config.mdx:1550) — the Cloud feature — while the surrounding new clause asserts Cube Core semantics. Same pattern in the new sentence at docs/pre-aggregations/index.mdx:26 (:297). These are new mislinks introduced by this PR, not pre-existing ones.

Nits verified clean

Callout tags balance in every edited file; /reference/core-data-apis/rest-api, /graphql-api, /sql-api, /docs/data-modeling/access-control/member-level-security and the #cubejs_sql_password anchor all resolve; only .mdx/.md touched, so no build or test impact.

• branch `pavel-claude/serene-mayer-0w8zu0`

Comment thread docs-mintlify/reference/configuration/environment-variables.mdx Outdated
Comment thread docs-mintlify/reference/core-data-apis/rest-api/reference.mdx Outdated
Comment thread docs-mintlify/reference/configuration/config.mdx Outdated
Comment thread docs-mintlify/docs/pre-aggregations/index.mdx Outdated
Comment thread packages/cubejs-vertica-driver/README.md Outdated
Comment thread docs-mintlify/cube-core/deployment.mdx Outdated
Comment thread docs-mintlify/admin/connect-to-data/data-sources/questdb.mdx Outdated
Comment thread docs-mintlify/admin/index.mdx Outdated
Comment thread docs-mintlify/reference/javascript-sdk/reference/cubejs-client-core.mdx Outdated
Review on #11805 was right that the warning attached the whole story to
CUBEJS_DEV_MODE while REST/GraphQL auth enforcement is keyed on NODE_ENV.
Verified in the source and reworked:

- `enforceSecurityChecks` is `options.enforceSecurityChecks || NODE_ENV ===
  'production'` (gateway.ts:285) and server-core never passes the option, so
  JWT verification on the REST (JSON) and GraphQL APIs follows NODE_ENV, not
  dev mode. With NODE_ENV unset those APIs accept untokened requests even when
  CUBEJS_DEV_MODE=false — so the production checklist now sets NODE_ENV too,
  and the callout says disabling dev mode is necessary but not sufficient.
- A custom checkAuth is invoked unconditionally (gateway.ts:2726, wrapCheckAuth
  has no enforceSecurityChecks branch), so "no authorization verification" was
  wrong for that configuration.
- What dev mode does gate is the DevServer: Playground's endpoints are mounted
  unauthenticated, and /playground/token signs any payload with the API secret.
  That is a full bypass even under NODE_ENV=production, so the warning now
  leads with it rather than with unverified JWTs.
- isDevMode() ORs `NODE_ENV !== 'production'` with CUBEJS_DEV_MODE, so
  "development mode is disabled by default" only held because the official
  Docker images set NODE_ENV=production; the callout now says so.

Also dropped the security paragraph from the `usedPreAggregations` note in the
REST API reference, per review: a reader looking up a JSON field would not read
it there. It keeps a short cross-reference to CUBEJS_DEV_MODE instead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7RGv1SFGTWjRUSaarhE88
@claude

claude Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Claude finished @paveltiunov's task in 2m 16s —— View job


Re-review after 43bb0ff — the high finding is resolved. Remaining: 2 medium accuracy nits (1 new inline comment), 7 prior threads re-affirmed

Full review
  • Gather context (read new diff)
  • Verify the reworked claims against source code
  • Resolve stale threads / dedupe against prior comments
  • Post review

43bb0ff fixes the high finding

The warning no longer claims CUBEJS_DEV_MODE disables JWT verification. It now leads with the DevServer bypass and states that NODE_ENV=production is what enforces REST/GraphQL auth, with NODE_ENV=production added to the production checklist and a "necessary but not sufficient" clause. That matches the code. Re-verified line by line:

Claim Verdict Evidence
Playground + supporting endpoints mounted with no auth OptsHandler.ts:392 devServer: this.isDevMode(); every /playground/* handler in DevServer.ts:112-616 is wrapped only in catchErrors
Anyone reachable can mint a token with any security context, signed with the API secret DevServer.ts:607-611 jwt.sign(req.body.payload, options.apiSecret, …)
Reads data model files GET /playground/filesdataSchemaFiles() (:150)
Overwrites data model POST /playground/generate-schema (:161)
Reads table schema of every connected data source GET /playground/db-schemadriver.tablesSchema() with securityContext: null (:132)
SQL API accepts any credentials unless CUBEJS_SQL_PASSWORD set sql-server.ts:371 skipPasswordCheck: getEnv('devMode') && !allowedPassword (the CUBEJS_SQL_USER caveat at :364 is elided, acceptable)
NODE_ENV=production (or a custom check_auth) is what enforces JWT verification ✅ with a caveat gateway.ts:285, :2709-2715; see inline comment — a check_auth that doesn't throw enforces nothing
Cube treats any non-production NODE_ENV as dev mode; images set NODE_ENV=production OptsHandler.ts:485-489; packages/cubejs-docker/latest.Dockerfile:41
"Disables member-level access control when listing the data model" gateway.ts:716-720 filterVisibleItemsInMeta — the narrowed wording is now correct; the old unqualified bullet was not
Reads your .env only POST /playground/env exists (:558, writes at :585); no read route — see inline comment

The usedPreAggregations <Note> was trimmed per review — thread resolved. Minor leftover there: the sentence now links the same #cubejs_dev_mode anchor twice back to back ("stay behind CUBEJS_DEV_MODE (a local-development-only setting that bypasses authentication)"); one link is enough.

New (1 inline comment, on environment-variables.mdx:1208)

  1. .env read claim is unsupported, and the stronger fact is missing: GET /playground/context returns cubejsToken, a ready-to-use API-secret-signed JWT (DevServer.ts:52, :116), unauthenticated — an attacker doesn't even need /playground/token.
  2. "or by a custom check_auth" enforces only if that function throws (wrapCheckAuth, gateway.ts:2553, has no enforceSecurityChecks branch). A check_auth that just derives a security context leaves the instance open with NODE_ENV unset.

Prior threads re-affirmed (no new comments posted)

Verified against the current tree; all still apply:

  • admin/index.mdx:195duplication got worse, not better: the long block is now ~24 lines and appears in 14 files (git grep -l "authentication bypass"). Both accuracy nits above have to be fixed 14×. A docs-mintlify/snippets/ include, or long-form on CUBEJS_DEV_MODE + checklist only with one-line pointers elsewhere, still applies.
  • questdb.mdx:46 — callout still splits "create docker-compose.yml" from "create an .env file". Same in sql-api/index.mdx and create-a-project.mdx.
  • cube-core/deployment.mdx:393link-cubejs-dev-vs-prod still resolves to /docs/data-modeling/dev-mode, the cloud feature. Same in admin/deployment/core.mdx.
  • config.mdx:1519 (telemetry) and ~630 (dev_pre_aggregations) — security asides still wedged into unrelated paragraphs; the reword changed only the phrasing.
  • docs/pre-aggregations/index.mdx:26 and ~191 — same non sequitur.
  • packages/cubejs-vertica-driver/README.md:29 — that snippet still never sets CUBEJS_DEV_MODE.
  • cubejs-client-core.mdx:55 — generated-looking typedoc table.

Two threads resolved as addressed: the environment-variables.mdx:1210 high finding and the rest-api/reference.mdx <Note> insertion.

Clean

Callout tags balance in every edited file; all link targets and the #cubejs_sql_password / #check_auth anchors resolve; only .mdx/.md touched, so no build or test impact. docs-mintlify/scripts/check_links.py could not be run in this environment, so link validation is by file-existence check.

· branch `pavel-claude/serene-mayer-0w8zu0`

Comment thread docs-mintlify/reference/configuration/environment-variables.mdx Outdated
Addresses the remaining review threads on #11805:

- The warning was pasted verbatim into 6 files with a condensed variant in 5
  more, so every wording fix had to be applied 11 times. It now lives in
  docs-mintlify/snippets/dev-mode-warning.mdx and -short.mdx and is imported;
  `yarn broken-links` already runs with --check-snippets. Net -184 lines.
- Moved the QuestDB callout out of the middle of the setup walkthrough to
  after it, so the procedure reads uninterrupted.
- Dropped the security asides from the `telemetry` and `pre_aggregations_schema`
  notes and from the caching intro, where they were off-topic; those places now
  just link "development mode" to the canonical warning, and the link targets
  were repointed from /docs/data-modeling/dev-mode (the cloud platform's
  branch-based dev mode) to #cubejs_dev_mode. Same repointing for
  link-cubejs-dev-vs-prod on both production checklists and for the
  getting-started page.
- Shortened the apiToken row in the JS SDK reference to a linked qualifier.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7RGv1SFGTWjRUSaarhE88
@claude

claude Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Claude finished @paveltiunov's task in 2m 31s —— View job


Re-review after 7fe1d04 — snippet extraction resolves the duplication and 5 other threads. Remaining: 2 low accuracy nits (2 inline comments), 2 prior threads re-affirmed

Full review
  • Read the new diff
  • Verify the snippet content against source code
  • Resolve stale threads / dedupe
  • Post review

What 7fe1d04 fixed

The warning now lives in docs-mintlify/snippets/dev-mode-warning.mdx (long) and dev-mode-warning-short.mdx (condensed), imported into 10 pages. That's the right mechanism, and it collapses the 14-copy problem to two files. Several other threads went away with it:

Prior finding Status
15-line block duplicated 14× (admin/index.mdx) ✅ snippets
link-cubejs-dev-vs-prod → cloud dev-mode page ✅ repointed to #cubejs_dev_mode in cube-core/deployment.mdx:530, admin/deployment/core.mdx, plus [ref-development-mode] in config.mdx, pre-aggregations/index.mdx, playground.mdx
Security aside wedged into the telemetry paragraph (config.mdx) ✅ reverted to a plain link
Non sequitur in the caching intro (pre-aggregations/index.mdx) ✅ reverted to a plain link
Callout mid-procedure (questdb.mdx) ✅ moved after "Access Cube at localhost:4000"; sql-api/index.mdx likewise now sits after docker compose up
rest-api/reference.mdx <Note> insertion ✅ trimmed to a parenthetical (still links the same anchor twice back to back — one link is enough)

Also good: NODE_ENV=production is now in the production-checklist .dotenv block with an accurate comment, and the <Info> above it explains that CUBEJS_DEV_MODE defaulting to false isn't the whole story.

Snippet content re-verified against source

Claim Verdict Evidence
Playground + supporting endpoints mounted with no auth every /playground/* route in DevServer.ts:112-616 is wrapped only in catchErrors; OptsHandler.ts:392
Anyone reachable can mint a token with any security context, signed with the API secret DevServer.ts:607-611 jwt.sign(req.body.payload, options.apiSecret, …)
Overwrites data model files POST /playground/generate-schema (:161)
Reads table schema of every data source GET /playground/db-schemadriver.tablesSchema() with securityContext: null (:132)
SQL API accepts any credentials unless CUBEJS_SQL_PASSWORD set sql-server.ts:371 skipPasswordCheck: getEnv('devMode') && !allowedPassword
NODE_ENV=production — not CUBEJS_DEV_MODE — enforces REST/GraphQL JWT verification gateway.ts:285, :2709-2715; official images set it (cubejs-docker/latest.Dockerfile:41)
Reads your .env POST /playground/env parses it server-side and rewrites it (:568, :585); no route returns it — see inline comment
"or by a custom check_auth" ⚠️ conditional wrapCheckAuth (gateway.ts:2553) has no enforceSecurityChecks branch — enforces only if the function throws; see inline comment

New inline comments (2, both low, both on the snippet)

  1. snippets/dev-mode-warning.mdx:10 — drop the .env read claim; add the stronger unmentioned fact that GET /playground/context hands out a signed cubejsToken (DevServer.ts:52, :116) with no auth at all. Same wording in the short snippet, docs/data-modeling/dev-mode.mdx, admin/index.mdx:190, and the three READMEs.
  2. snippets/dev-mode-warning.mdx:24 — qualify the check_auth clause ("that itself rejects unauthenticated requests"); embedding/authentication/jwt.mdx:45 repeats it in hand-written form.

I resolved the superseded thread on environment-variables.mdx — that text now lives in the snippet, so the discussion belongs there.

Prior threads re-affirmed (no new comments)

  • packages/cubejs-vertica-driver/README.md:29 — that README still never sets CUBEJS_DEV_MODE; a 10-line dev-mode warning under a Vertica connection config is unrelated to the driver. The root README.md and rust/cubestore/README.md additions do sit next to a CUBEJS_DEV_MODE=true snippet and are justified.
  • reference/javascript-sdk/reference/cubejs-client-core.mdx:55 — still a typedoc-shaped table; worth confirming it's hand-maintained before adding prose to the apiToken cell.

Minor, not worth a thread

  • admin/index.mdx:186-196 — the snippet is immediately followed by three bullets restating the same three facts (token minting, SQL password skip, member-level control). docs-mintlify/CLAUDE.md says "say it once"; the bullet list could stay behavioral (Cube Store single instance, background refresh, …) and let the callout carry the security story.
  • The hand-wrapped READMEs and dev-mode.mdx have one over-long line each ("… through the SQL API. This is intentional — development mode is designed to run on a developer's"); cosmetic.

Clean

Callout tags balance in every edited file; snippet import paths (/snippets/…) follow the Mintlify convention and snippets/ is excluded from navigation, so no docs.json change is needed; all link targets and the #cubejs_sql_password / #check_auth anchors resolve; only .mdx/.md touched, so no build or test impact. docs-mintlify/scripts/check_links.py isn't runnable in this environment, so link validation is by file-existence check.

· branch `pavel-claude/serene-mayer-0w8zu0`

Copy link
Copy Markdown
Member Author

Correction: disabling development mode is sufficient to enforce API authentication

Pushed in b306b65. My earlier claim on the environment-variables.mdx thread — that disabling development mode is "necessary but not sufficient" — was wrong, and since it's a security statement it's worth correcting in the open rather than only in the diff.

OptsHandler.ts:485-490:

private isDevMode(): boolean {
  return (
    process.env.NODE_ENV !== 'production' ||
    getEnv('devMode')
  );
}

Development mode is on iff NODE_ENV !== 'production' or CUBEJS_DEV_MODE=true. By contraposition it is off only when NODE_ENV === 'production' — and enforceSecurityChecks is options.enforceSecurityChecks || (process.env.NODE_ENV === 'production') (gateway.ts:285). So development mode being off implies JWT verification is enforced. There is no configuration in which the instance is out of development mode and still accepting untokened requests.

What I'd conflated was setting the flag with disabling the mode. The genuine trap is the narrower one: CUBEJS_DEV_MODE=false on its own does not disable development mode, because a non-production NODE_ENV keeps it on whatever the flag says. That's still worth warning about — a reader who sets only the flag is still unauthenticated — but the reason is that they haven't actually left development mode, not that leaving it is insufficient.

The warning now says that, and that NODE_ENV=production both takes the instance out of development mode and is what turns verification on. The production checklist's dotenv comments had the same conflation ("set this to false … to disable development mode" against the flag alone) and are fixed too.

Everything else stands: dev mode does bypass authentication even under NODE_ENV=production, via the unauthenticated Playground endpoints that hand out and mint API-secret-signed tokens.


Generated by Claude Code

@claude

claude Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Claude finished @paveltiunov's task in 1m 7s —— View job


Re-review after b306b65 — the reframing is correct; 1 low wording contradiction (1 inline comment)

Full review
  • Read the new diff (241870b..b306b65)
  • Verify the reframed claims against source code
  • Resolve stale threads / dedupe
  • Post review

What b306b65 changed

It flips the framing from "disabling dev mode is necessary but not sufficient" to "disabling dev mode is sufficient — but CUBEJS_DEV_MODE=false alone doesn't disable it." That's the more accurate reading, and it removes the awkwardness of the previous wording:

OptsHandler.ts:485-489

private isDevMode(): boolean {
  return (
    process.env.NODE_ENV !== 'production' ||
    getEnv('devMode')
  );
}

Dev mode being genuinely off means NODE_ENV === 'production' and the flag not true — and NODE_ENV === 'production' is exactly what sets enforceSecurityChecks (gateway.ts:285). So "once development mode is genuinely off, JWT verification is enforced" holds, and the new .dotenv comments ("Both are required: Cube is in development mode unless NODE_ENV is production AND this flag is not true") are accurate. getEnv('devMode') defaults to false (env.ts:212-214), so the flag can only push dev mode on, never off — which is what the snippet now says.

The check_auth clause kept its "that rejects unauthenticated requests" qualifier, correctly (wrapCheckAuth, gateway.ts:2553, has no enforceSecurityChecks branch).

Low — one inline comment, on embedding/authentication/jwt.mdx:50

The hand-written copy in jwt.mdx now contradicts itself across two adjacent paragraphs: line 50 says NODE_ENV=production "both takes the instance out of development mode and turns JWT verification on", while line 55 says "Enabling CUBEJS_DEV_MODE bypasses authentication even under NODE_ENV=production". Given the ||, the first clause needs an "unless CUBEJS_DEV_MODE=true" qualifier. Suggestion posted inline. The snippet itself doesn't have this problem — it says "whatever the flag is set to" only in the direction that's true.

Threads

All 12 of my prior threads are resolved; nothing to re-affirm. No other new findings.

Clean

Both snippets' <Warning> tags balance and keep the blank lines Mintlify needs; the two deployment pages remain byte-identical (admin/deployment/core.mdxcube-core/deployment.mdx, same blob SHA 922c739), as do the two running-in-production pages. Only .mdx touched in this commit, so no build or test impact — consistent with Codecov reporting a zero code diff.

CI: I did not re-check the three red jobs; per @paveltiunov's notes they are the data.wprdc.org 403 fixture in cubestore, an sa login race in the mssql matrix, and a shared dev_pre_aggregations collision in the BigQuery GCS variant — none reachable from a docs-only diff. docs-mintlify/scripts/check_links.py / yarn broken-links aren't runnable in this environment, so link validation is by file-existence check.

· branch `pavel-claude/serene-mayer-0w8zu0`

Comment thread docs-mintlify/embedding/authentication/jwt.mdx Outdated
…e flag

The reframing in b306b65 left jwt.mdx contradicting itself one paragraph
later: it said NODE_ENV=production "takes the instance out of development
mode", while the next paragraph correctly says dev mode is still on under
NODE_ENV=production when CUBEJS_DEV_MODE=true. isDevMode() ORs the two
(OptsHandler.ts:485-490), so NODE_ENV=production exits dev mode only when the
flag isn't true. Added that qualifier.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7RGv1SFGTWjRUSaarhE88
@claude

claude Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Claude finished @paveltiunov's task in 1m 19s —— View job


Re-review after f6f0c70 — the jwt.mdx contradiction is fixed. 1 low finding (1 inline comment); all 13 prior threads resolved

Full review
  • Read the new diff (241870b..f6f0c70)
  • Verify the corrected wording against source code
  • Resolve stale threads / dedupe
  • Post review

f6f0c70 closes the open thread

embedding/authentication/jwt.mdx:47 now reads "NODE_ENV=production turns JWT verification on, and — unless CUBEJS_DEV_MODE=true — also takes the instance out of development mode", which removes the contradiction with the paragraph below it. That matches isDevMode() = NODE_ENV !== 'production' || getEnv('devMode') (OptsHandler.ts:485-489).

The reworked .dotenv comments in both deployment pages are accurate too:

# Both are required: Cube is in development mode unless NODE_ENV is
# production AND this flag is not true, so setting this alone is not enough
CUBEJS_DEV_MODE=false

getEnv('devMode') defaults to false (env.ts:212-214), so strictly the flag line is belt-and-braces rather than required — but stating both explicitly in a production checklist is the right call, and the <Info> above already says the flag defaults to false.

Low — one inline comment, on snippets/dev-mode-warning.mdx:3

The snippet's opening clause still scopes the bypass to CUBEJS_DEV_MODE=true, but the dev-server mount follows isDevMode() (OptsHandler.ts:392 devServer: this.isDevMode()), so the Playground endpoints are live with CUBEJS_DEV_MODE=false and NODE_ENV unset as well — the exact configuration the snippet's third paragraph warns about. Paragraph 3 recovers it, but a reader who stops after paragraph 1 concludes the bypass doesn't apply to them. Same opening in dev-mode-warning-short.mdx:3 and the three READMEs. Suggestion posted inline; this is a wording scope issue, not a factual error elsewhere in the text.

Everything else re-verified against the tree at f6f0c70

Claim Evidence
Anyone reachable is handed a ready-to-use API token GET /playground/contextcubejsToken (DevServer.ts:52, :116), no auth
…and can mint others with any security context POST /playground/tokenjwt.sign(req.body.payload, options.apiSecret, …) (:607)
Reads data model files and every data source's table schema GET /playground/files (:150); GET /playground/db-schematablesSchema() with securityContext: null (:132)
Overwrites data model and .env (read claim correctly dropped) POST /playground/generate-schema (:161); POST /playground/envfs.writeFileSync (:585)
SQL API accepts any credentials unless CUBEJS_SQL_PASSWORD set sql-server.ts:371 skipPasswordCheck: getEnv('devMode') && !allowedPassword
"Once development mode is genuinely off, JWT verification is enforced, because NODE_ENV=production is exactly what enables it" gateway.ts:285; 403 paths at :2709-2715
A check_auth "that rejects unauthenticated requests" enforces it whatever NODE_ENV is wrapCheckAuth (:2553) has no enforceSecurityChecks branch — the qualifier is exactly the missing condition
Official Docker images set NODE_ENV=production packages/cubejs-docker/latest.Dockerfile:41
Dev mode disables member-level access control when listing the data model gateway.ts:716-720 visibilityFilter

Threads

All 13 of my prior threads are resolved — nothing to re-affirm. The one new comment above is on a line no prior thread covered.

Clean

<Warning> tags balance in both snippets and in jwt.mdx, with the blank lines Mintlify needs; admin/deployment/core.mdxcube-core/deployment.mdx remain byte-identical (blob 922c739), as do the two running-in-production pages; all 10 snippet imports resolve and snippets/ needs no docs.json entry. Only .mdx touched in these two commits, so no build or test impact — consistent with Codecov reporting a zero code diff.

CI: I did not re-check the red jobs; per @paveltiunov's notes they are the data.wprdc.org 403 fixture in cubestore, an sa login race in the mssql matrix, and a shared dev_pre_aggregations collision in the BigQuery GCS variant — none reachable from a docs-only diff. docs-mintlify/scripts/check_links.py / yarn broken-links aren't runnable in this environment, so link validation is by file-existence check.

· branch `pavel-claude/serene-mayer-0w8zu0`

Comment thread docs-mintlify/snippets/dev-mode-warning.mdx Outdated
The warning opened with "With CUBEJS_DEV_MODE=true, Cube mounts Playground …",
but the mount is `devServer: this.isDevMode()` (OptsHandler.ts:392) and
isDevMode() ORs `NODE_ENV !== 'production'` with the flag (:485-490). So the
whole bypass is equally live with CUBEJS_DEV_MODE=false and NODE_ENV unset —
the configuration the last paragraph already warned about. Attributing it to
the flag understated the exposure, and a reader setting only the flag could
read the opening as "this doesn't apply to me".

Both snippets now state the condition up front, and the last paragraph drops
the now-duplicated explanation and just gives the remedy (both variables). Same
fix in the dev-mode disambiguation callout and the three plain-Markdown
READMEs, which named the flag too.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7RGv1SFGTWjRUSaarhE88
@claude

claude Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Claude finished @paveltiunov's task in 1m 43s —— View job


Re-review after 33854e6 — the scope fix is right, but it over-broadened one sentence. 1 low finding (1 inline comment); all 14 prior threads resolved

Full review
  • Read the new diff (f6f0c70..33854e6)
  • Verify the reworded scope claims against source
  • Resolve stale threads / dedupe
  • Post review

33854e6 closes the open thread

Both snippets and the three READMEs now open with "Cube is in development mode whenever NODE_ENV is not production or CUBEJS_DEV_MODE=true" instead of scoping the bypass to the flag. docs/data-modeling/dev-mode.mdx got the same treatment, and the closing paragraph was tightened to "turning development mode off takes both". That matches isDevMode() = NODE_ENV !== 'production' || getEnv('devMode') (OptsHandler.ts:485-489), which is exactly what gates devServer (:392).

Low — one inline comment, on snippets/dev-mode-warning.mdx:3-15

The rescope is correct for everything the DevServer does, but the paragraph's last sentence — the SQL API password skip — is gated on the flag alone, with no NODE_ENV term:

// packages/cubejs-api-gateway/src/sql-server.ts:371
skipPasswordCheck: getEnv('devMode') && !allowedPassword

getEnv('devMode') reads CUBEJS_DEV_MODE and nothing else (env.ts:212), and when skip_password_check is false the Rust side verifies the password (pg_auth_service.rs:101). So a plain cubejs-server run with neither variable set is in development mode — the Playground bypass applies — but the SQL API still checks credentials. Folding that sentence under the broadened condition overstates it. Suggested rewording posted inline; the same sentence appears in the short snippet, docs/data-modeling/dev-mode.mdx and the three READMEs.

Same class of issue as the previous round, opposite direction: last time the scope was too narrow, this time one clause got carried along into a scope it doesn't hold in. The other getEnv('devMode')-only behaviors (member-level visibility at gateway.ts:717, trace log level, memory cache engine) are correctly kept under the flag-scoped bullet list in admin/index.mdx:187-192.

Everything else re-verified at 33854e6

Claim Evidence
Playground + supporting endpoints mounted with no auth, on isDevMode() OptsHandler.ts:392, :485-489; every /playground/* handler in DevServer.ts:112-616 wrapped only in catchErrors
Anyone reachable is handed a ready-to-use API token GET /playground/contextcubejsToken (DevServer.ts:52, :116)
…and can mint others with any security context POST /playground/tokenjwt.sign(req.body.payload, options.apiSecret, …) (:607)
Reads data model files and every data source's table schema GET /playground/files (:150); GET /playground/db-schematablesSchema() with securityContext: null (:132)
Overwrites data model and .env POST /playground/generate-schema (:161); POST /playground/envfs.writeFileSync (:585)
"Turning development mode off takes both … setting the flag alone leaves you in development mode" getEnv('devMode') defaults to false (env.ts:212-214), so the flag can only push dev mode on
Once off, JWT verification is enforced because NODE_ENV=production is what enables it gateway.ts:285; 403 paths at :2709-2715
A check_auth "that rejects unauthenticated requests" enforces it whatever NODE_ENV is wrapCheckAuth (:2553) has no enforceSecurityChecks branch
Official Docker images set NODE_ENV=production packages/cubejs-docker/latest.Dockerfile:41

Threads

All 14 of my prior threads are resolved — nothing to re-affirm. The one new comment is on a scope introduced by this commit.

Clean

<Warning> tags balance in both snippets and in the edited pages, with the blank lines Mintlify needs; the two deployment pages remain byte-identical (admin/deployment/core.mdxcube-core/deployment.mdx, blob 922c739), as do the two running-in-production pages; all 10 snippet imports resolve and snippets/ needs no docs.json entry. Only .mdx/.md touched, so no build or test impact — consistent with Codecov reporting a zero code diff.

CI: I did not re-check the red jobs; per @paveltiunov's notes they are the data.wprdc.org 403 fixture in cubestore, an sa login race in the mssql matrix, and a shared dev_pre_aggregations collision in the BigQuery GCS variant — none reachable from a docs-only diff. docs-mintlify/scripts/check_links.py / yarn broken-links aren't runnable in this environment, so link validation is by file-existence check.

· branch `pavel-claude/serene-mayer-0w8zu0`

Comment thread docs-mintlify/snippets/dev-mode-warning.mdx Outdated
Rescoping paragraph 1 to isDevMode() in 33854e6 was right for the Playground
mount but swept in the SQL API sentence, which is gated differently:

    // sql-server.ts:371
    skipPasswordCheck: getEnv('devMode') && !allowedPassword

`getEnv('devMode')` reads CUBEJS_DEV_MODE only (env.ts:210-213) — no NODE_ENV
term — and with the flag unset the `if (!getEnv('devMode'))` branch at :345
forces allowedUser to 'cube' and generates a random password. So on a plain
`cubejs-server` run (NODE_ENV unset, flag unset) the instance IS in development
mode and the Playground bypass is live, but the SQL API still enforces
credentials. The text said it accepted any.

Scoped just that sentence back to CUBEJS_DEV_MODE=true across both snippets,
the dev-mode disambiguation callout and the three READMEs, and noted that this
gate follows the flag rather than NODE_ENV. Also rewrote the short snippet,
whose wrapping and subject/verb agreement had degraded over successive edits.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7RGv1SFGTWjRUSaarhE88
@claude

claude Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Claude finished @paveltiunov's task in 1m 12s —— View job


Re-review after 00adafd — the SQL API rescope is correct. No open findings; LGTM

Full review
  • Read the new diff (33854e6..00adafd)
  • Verify the rescoped SQL API claim against source
  • Resolve stale threads / dedupe
  • Post review

00adafd closes the last open thread

The SQL API sentence is now scoped to the flag alone in all six copies (both snippets, docs/data-modeling/dev-mode.mdx, and the three READMEs). Re-verified:

// packages/cubejs-api-gateway/src/sql-server.ts:371
skipPasswordCheck: getEnv('devMode') && !allowedPassword

getEnv('devMode') reads CUBEJS_DEV_MODE and nothing else (env.ts:212-214), so there is no NODE_ENV term — "with CUBEJS_DEV_MODE=true specifically … the SQL API accepts any credentials" is exactly right, and the rest of the paragraph correctly stays scoped to isDevMode(). One nuance the wording elides harmlessly: allowedPassword is options.sqlPassword || getEnv('sqlPassword') (:343), so a sql_password set in cube.js also defeats the skip, not only the env var — the env var is the form a reader of this warning will be using.

Also worth noting the adjacent behavior the docs don't need to spell out: outside dev mode, :345-360 generates a random sqlPassword when none is configured, so the "accepts any credentials" state is genuinely unreachable with the flag off.

Confirmed embedding/authentication/jwt.mdx carries no SQL clause, so it needed no change — the rescope reached every copy that had one.

Threads

All 15 of my prior threads are resolved; nothing to re-affirm and no new inline comments this round.

Final accuracy state

Every claim in the two snippets, re-confirmed against the tree at 00adafd:

Claim Evidence
Playground + supporting endpoints mounted with no auth, on isDevMode() OptsHandler.ts:392, :485-489; every /playground/* handler in DevServer.ts:112-616 wrapped only in catchErrors
Anyone reachable is handed a ready-to-use API token GET /playground/contextcubejsToken (DevServer.ts:52, :116)
…and can mint others with any security context POST /playground/tokenjwt.sign(req.body.payload, options.apiSecret, …) (:607)
Reads data model files and every data source's table schema GET /playground/files (:150); GET /playground/db-schematablesSchema() with securityContext: null (:132)
Overwrites data model and .env POST /playground/generate-schema (:161); POST /playground/envfs.writeFileSync (:585)
SQL API accepts any credentials with CUBEJS_DEV_MODE=true and no password set sql-server.ts:343-371
Turning dev mode off takes the flag not true and NODE_ENV=production; once off, JWT verification is enforced OptsHandler.ts:485-489; gateway.ts:285, 403 paths at :2709-2715; getEnv('devMode') defaults to false
A check_auth "that rejects unauthenticated requests" enforces it whatever NODE_ENV is wrapCheckAuth (gateway.ts:2553) has no enforceSecurityChecks branch
Official Docker images set NODE_ENV=production packages/cubejs-docker/latest.Dockerfile:41
Dev mode disables member-level access control when listing the data model gateway.ts:716-720 visibilityFilter

Minor, not worth a thread

  • snippets/dev-mode-warning.mdx:12-13 — the mid-sentence aside "the SQL API's password check follows that flag alone, not NODE_ENV" explains Cube's internals to justify the scope change. The short snippet says the same thing with just "With CUBEJS_DEV_MODE=true specifically and no CUBEJS_SQL_PASSWORD set"; the reader doesn't need the mechanism. Dropping the aside would read better and is purely editorial.
  • The three READMEs each picked up an unwrapped ~110-char line again ("… arbitrary SQL against connected data sources. This is intentional — development mode is designed to run on a"), re-introducing the wrap 241870b had fixed. Cosmetic.

Clean

<Warning> tags balance in both snippets and every edited page, with the blank lines Mintlify needs; the two deployment pages remain byte-identical (admin/deployment/core.mdxcube-core/deployment.mdx, blob 922c739), as do the two running-in-production pages (8d80ad2); all 10 snippet imports resolve and snippets/ needs no docs.json entry. Only .mdx/.md touched, so no build or test impact — consistent with Codecov reporting a zero code diff.

CI: I did not re-check the red jobs; per @paveltiunov's notes they are the data.wprdc.org 403 fixture in cubestore, an sa login race in the mssql matrix, and a shared dev_pre_aggregations collision in the BigQuery GCS variant — none reachable from a docs-only diff. docs-mintlify/scripts/check_links.py / yarn broken-links aren't runnable in this environment, so link validation is by file-existence check.

· branch `pavel-claude/serene-mayer-0w8zu0`

I had missed the only place that writes NODE_ENV from the flag. In
ServerContainer.lookupConfiguration():

    // packages/cubejs-server/src/server/container.ts:250-253
    const devMode = getEnv('devMode');
    if (devMode) {
      process.env.NODE_ENV = 'development';
    }

start() calls lookupConfiguration() before runServerInstance(), so the rewrite
lands before the gateway computes `enforceSecurityChecks` from NODE_ENV
(gateway.ts:285). CUBEJS_DEV_MODE=true therefore switches JWT verification off
on the REST (JSON) and GraphQL APIs outright — not merely, as the text said,
exposing Playground endpoints that mint tokens.

The converse also matters for the production checklist. `cubejs server` sets
NODE_ENV=production (command/server.ts:19) and both Dockerfiles set it as an
ENV, with CMD ["cubejs","server"] — so on any Docker or CLI deployment
CUBEJS_DEV_MODE alone controls development mode, and leaving it unset IS
sufficient. The earlier "both are required / setting this alone is not enough"
framing was wrong for exactly the deployments that page documents. An unset
NODE_ENV only bites when embedding @cubejs-backend/server-core directly,
bypassing the CLI and ServerContainer; the warning now says so.

Rewrote both snippets, jwt.mdx, the dev-mode disambiguation callout, the two
production checklists and the three READMEs around this. Also dropped the
mid-sentence aside about the SQL gate and re-fixed the README line wraps my
last commit had re-broken.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7RGv1SFGTWjRUSaarhE88

Copy link
Copy Markdown
Member Author

Correction: CUBEJS_DEV_MODE=true forces NODE_ENV=development

Pushed in 7aaa209. This supersedes part of both my earlier correction and the original high-severity finding on the environment-variables.mdx thread. I had verified every reader of NODE_ENV and never checked who writes it. There is exactly one place, and it changes the conclusion:

// packages/cubejs-server/src/server/container.ts:250-253
const devMode = getEnv('devMode');
if (devMode) {
  process.env.NODE_ENV = 'development';
}

ServerContainer.start() calls lookupConfiguration() before runServerInstance() (:334-345), so this rewrite lands before the gateway computes enforceSecurityChecks from NODE_ENV (gateway.ts:285).

So CUBEJS_DEV_MODE=true does switch JWT verification off on the REST (JSON) and GraphQL APIs. The review thread's point 2 — "CUBEJS_DEV_MODE=true does not, by itself, disable JWT verification; with NODE_ENV=production dev mode is on but tokens are still verified" — does not hold on the CLI/Docker path, because the flag overwrites NODE_ENV first. I accepted that point without checking, and the text has been understating this ever since.

The converse matters more for the production checklist. cubejs server sets NODE_ENV=production (command/server.ts:19), and both Dockerfiles set it as an ENV with CMD ["cubejs", "server"] (latest.Dockerfile:41,59). So on any Docker or CLI deployment, CUBEJS_DEV_MODE alone controls development mode and leaving it unset is sufficient — which is what @paveltiunov said at the outset. My "both are required / setting this alone is not enough" wording was wrong for precisely the deployments that page documents.

An unset NODE_ENV only bites when embedding @cubejs-backend/server-core directly, bypassing the CLI and ServerContainer. The warning now says that explicitly instead of implying every reader needs to set NODE_ENV.

Corrected wording of the three gates:

Behaviour Gate
REST/GraphQL JWT verification NODE_ENV === 'production' (gateway.ts:285) — and CUBEJS_DEV_MODE=true forces NODE_ENV=development, so the flag turns it off
Playground / dev-server mount isDevMode()NODE_ENV !== 'production' or the flag (OptsHandler.ts:392, :485-489)
SQL API password skip getEnv('devMode') — the flag alone, with no sqlPassword set (sql-server.ts:343-371)

Also dropped the mid-sentence aside about the SQL gate, and re-fixed the README line wraps my previous commit had re-broken — both editorial notes from the last review.


Generated by Claude Code

@claude

claude Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Claude finished @paveltiunov's task in 2m 18s —— View job


Re-review after 7aaa209 — the new NODE_ENV finding is real and verified. 1 low scope nit (1 inline comment); all 15 prior threads resolved

Full review
  • Read the new diff (00adafd..7aaa209)
  • Verify the new NODE_ENV=development claim against source
  • Resolve stale threads / dedupe
  • Post review

The 7aaa209 finding holds

I'd missed this too across five rounds. Verified end to end:

// packages/cubejs-server/src/server/container.ts:250-253
const devMode = getEnv('devMode');
if (devMode) {
  process.env.NODE_ENV = 'development';
}

start() calls lookupConfiguration() at :336 and runServerInstance() at :344, so the rewrite lands before gateway.ts:285 reads process.env.NODE_ENV to compute enforceSecurityChecks. And grep -rn "NODE_ENV *=" packages/cubejs-server-core/src packages/cubejs-backend-shared/src turns up no other writer — ServerContainer is the only one. So on the CLI path CUBEJS_DEV_MODE=true does switch REST/GraphQL JWT verification off outright, which is stronger than what the text said before.

The converse checks out too, and it's the part that matters for the checklist:

Claim Evidence
cubejs server sets NODE_ENV=production packages/cubejs-server/src/command/server.ts:19, before container.start()
Official images set it as an ENV, with CMD ["cubejs","server"] cubejs-docker/latest.Dockerfile:41, :59
⇒ on Docker/CLI, leaving the flag unset is sufficient follows from the two above; getEnv('devMode') defaults to false (env.ts:212-214)
An unset NODE_ENV only bites when embedding server-core directly OptsHandler.isDevMode() :485-489 ORs, and nothing rewrites NODE_ENV off the CLI path

So the "both are required / setting this alone is not enough" framing the last few commits carried was indeed wrong for exactly the deployments cube-core/deployment.mdx documents. The rewritten <Info> and .dotenv comments are accurate, and cubejs dev-server setting NODE_ENV=development (command/dev-server.ts:19) is consistent with the story.

Low — one inline comment, on snippets/dev-mode-warning.mdx:3-8

The forcing is stated unconditionally, but it only happens via ServerContainer. Embed CubejsServer/CubeServerCore directly with NODE_ENV=production and CUBEJS_DEV_MODE=true, and JWT verification stays on — the opposite of what paragraph 1 says. It over-warns rather than under-warns, and paragraph 2 still holds there since devServer follows isDevMode() (OptsHandler.ts:392), so it's minor — but the last paragraph already draws the CLI-vs-embedded line, so scoping the sentence costs one clause. Same phrasing in the short snippet, dev-mode.mdx, jwt.mdx, the two .dotenv comments and the three READMEs.

Minor, not worth a thread

The short snippet dropped the SQL API sentence in this commit. It's imported by reference/core-data-apis/sql-api/index.mdx:183 and admin/connect-to-data/data-sources/questdb.mdx:67 — the two places where "unless CUBEJS_SQL_PASSWORD is set, the SQL API accepts any credentials" is the single most relevant fact on the page. Worth keeping one clause of it there even in the condensed form.

Threads

All 15 prior threads are resolved; nothing to re-affirm. The inline comment above is on a claim introduced by this commit.

Clean

<Warning> tags balance in both snippets and every edited page, with the blank lines Mintlify needs; the two deployment pages remain byte-identical (admin/deployment/core.mdxcube-core/deployment.mdx, blob f5800b1), as do the two running-in-production pages (8d80ad2); all 10 snippet imports resolve. The four JavaScript SDK pages weren't touched by this commit and their wording is still consistent with it. Only .mdx/.md touched, so no build or test impact — consistent with Codecov's zero code diff.

CI: not re-checked; per @paveltiunov's notes the three red jobs are the data.wprdc.org 403 fixture in cubestore, an sa login race in the mssql matrix, and a shared dev_pre_aggregations collision in the BigQuery GCS variant — none reachable from a docs-only diff. yarn broken-links isn't runnable in this environment, so link validation is by file-existence check.

· branch `pavel-claude/serene-mayer-0w8zu0`

Comment thread docs-mintlify/snippets/dev-mode-warning.mdx
Seventeen lines of security warning under a Vertica connection snippet, and
again under a Cube Store version note, is out of proportion to those documents.
Both files are back to their state on master. The root README keeps its notice,
since its `docker run -e CUBEJS_DEV_MODE=true` is the snippet people actually
copy to start Cube, and docs-mintlify carries the full warning.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7RGv1SFGTWjRUSaarhE88
@claude

claude Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Claude finished @paveltiunov's task in 1m 47s —— View job


Re-review after 0192bcf — narrowing the README copies is fine; no new findings. 1 prior thread still open (low)

Full review
  • Read the new diff (7aaa209..0192bcf)
  • Verify the current claims against source
  • Resolve stale threads / dedupe
  • Post review

What 0192bcf changed

It removes the inline dev-mode notice from packages/cubejs-vertica-driver/README.md and rust/cubestore/README.md, keeping it only in the root README.md. Nothing else moved — git diff 7aaa209..0192bcf touches those two files only, and both are back to their origin/master contents (git diff origin/master...HEAD no longer lists them).

That's a defensible line to draw, and it's the right one of the three to keep:

File Context Kept?
README.md:39-44 docker run … -e CUBEJS_DEV_MODE=true cubejs/cube — the first thing a new user copies, and the container runs cubejs server, so the NODE_ENV=development forcing genuinely applies
packages/cubejs-vertica-driver/README.md:25 - CUBEJS_DEV_MODE=true #if running locally inside a fragment of a compose environment: block, on a driver page ✅ dropped
rust/cubestore/README.md:72 a prose sentence noting Cube Store ships enabled when the flag is set — not an instruction to set it ✅ dropped

Fewer hand-maintained copies is straightforwardly better: those two were the ones that couldn't import the Mintlify snippet and would have drifted. Minor: the PR description still says "The three plain-Markdown READMEs … carry the same warning inline" and lists all three — worth updating before merge, since it's now one.

One prior thread still open (low) — re-affirmed, no new comment

snippets/dev-mode-warning.mdx:8: the snippet states the NODE_ENV=development forcing unconditionally, but process.env.NODE_ENV = 'development' is written in exactly one place — ServerContainer.lookupConfiguration() (packages/cubejs-server/src/server/container.ts:250-253), reached from start() at :336 before runServerInstance() at :344. Embed CubejsServer/CubeServerCore directly with NODE_ENV=production and CUBEJS_DEV_MODE=true and JWT verification stays on. It over-warns rather than under-warns, and the snippet's last paragraph already draws the CLI-vs-embedded line for the converse, so scoping the sentence costs one clause. Same phrasing in dev-mode-warning-short.mdx:4, docs/data-modeling/dev-mode.mdx:14-16, embedding/authentication/jwt.mdx:47-51, and the two deployment-page .dotenv comments. README.md doesn't need it — the docker path is the CLI path.

All 15 other threads are resolved.

Re-verified at 0192bcf

Nothing in the snippets or the remaining hand-written copies changed, and the claims still hold:

Claim Evidence
Dev mode is CUBEJS_DEV_MODE=true or NODE_ENV !== 'production' OptsHandler.ts:485-489
The flag forces NODE_ENV=development (CLI/container path) container.ts:250-253, before gateway.ts:285 reads it
cubejs server and the images set NODE_ENV=production command/server.ts:19; cubejs-docker/latest.Dockerfile:41,59
Playground + supporting endpoints mounted with no auth OptsHandler.ts:392; every /playground/* handler in DevServer.ts:112-616 wrapped only in catchErrors
Ready-to-use token handed out; further ones mintable with any security context DevServer.ts:52, :116; :607 jwt.sign(req.body.payload, options.apiSecret, …)
Reads data model files and every data source's table schema; overwrites data model and .env :150, :132, :161, :585
SQL API accepts any credentials with the flag set and no password sql-server.ts:343-371
check_auth "that rejects unauthenticated requests" wrapCheckAuth (gateway.ts:2553) has no enforceSecurityChecks branch

Minor, not worth a thread

  • snippets/dev-mode-warning-short.mdx still carries no SQL API clause, and it's the variant imported by reference/core-data-apis/sql-api/index.mdx:183 and admin/connect-to-data/data-sources/questdb.mdx:67. Low impact on the SQL API page specifically, since the compose block right above it sets CUBEJS_SQL_PASSWORD (:175), so that reader isn't in the exposed configuration — but the QuestDB page doesn't.

Clean

<Warning> tags balance in both snippets and every edited page, with the blank lines Mintlify needs; all 10 DevModeWarning/DevModeWarningShort imports resolve to the two files in snippets/, which needs no docs.json entry; admin/deployment/core.mdxcube-core/deployment.mdx remain byte-identical (blob f5800b1), as do the two running-in-production pages (8d80ad2). The diff is now 24 files, +204/−39, all .mdx/.md — no build or test impact, consistent with Codecov's zero code diff.

CI: not re-checked this round; per @paveltiunov's notes the red jobs are the data.wprdc.org 403 fixture in cubestore, an sa login race in the mssql matrix, and a shared dev_pre_aggregations collision in the BigQuery GCS variant — none reachable from a docs-only diff. yarn broken-links isn't runnable in this environment, so link validation is by file-existence check.

· branch `pavel-claude/serene-mayer-0w8zu0`

The `NODE_ENV=development` rewrite lives in ServerContainer.lookupConfiguration()
(packages/cubejs-server/src/server/container.ts:250-253), and ServerContainer is
only constructed by the `cubejs server` and `cubejs dev-server` commands. Nothing
rewrites NODE_ENV when you construct CubejsServer or CubejsServerCore yourself,
so with embedded usage, NODE_ENV=production and CUBEJS_DEV_MODE=true, JWT
verification stays on — the opposite of what the warning claimed
unconditionally.

Scoped that sentence to "the `cubejs` CLI and the official Docker images" (whose
CMD is `cubejs server`) in both snippets, jwt.mdx, the dev-mode callout, the two
production checklists and the root README. The Playground half is unaffected:
`devServer` follows isDevMode() (OptsHandler.ts:392), which holds either way.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7RGv1SFGTWjRUSaarhE88
@claude

claude Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Claude finished @paveltiunov's task in 1m 9s —— View job


Re-review after aff9d83 — the CLI scoping is correct and closes the last thread. No open findings; LGTM

Full review
  • Read the new diff (0192bcf..aff9d83)
  • Verify the scoped claims against source
  • Resolve stale threads / dedupe
  • Post review

aff9d83 closes the last open thread

The NODE_ENV=development forcing is now scoped to the CLI/container path in all six copies (both snippets, docs/data-modeling/dev-mode.mdx, embedding/authentication/jwt.mdx, the two deployment-page .dotenv comments, and the root README.md). Re-verified that this is exactly the right scope:

// packages/cubejs-server/src/server/container.ts:250-253
const devMode = getEnv('devMode');
if (devMode) {
  process.env.NODE_ENV = 'development';
}

grep -rn "NODE_ENV *=" packages/cubejs-server/src packages/cubejs-server-core/src packages/cubejs-backend-shared/src returns exactly three writers, all on the CLI path — command/server.ts:19 (production), command/dev-server.ts:19 (development), and container.ts:252. Nothing in server-core or backend-shared writes it, so an embedded CubejsServer/CubeServerCore with NODE_ENV=production and the flag set keeps JWT verification on, which the text no longer contradicts.

Worth noting the ordering holds in the direction the docs claim: cubejs server sets NODE_ENV=production at command/server.ts:19, then container.start()lookupConfiguration() overwrites it back to development when the flag is set. So on the Docker path the flag genuinely wins over the image's ENV NODE_ENV=production.

The README's "In the official images — whose entrypoint is the cubejs CLI" is accurate (cubejs-docker/latest.Dockerfile:59 CMD ["cubejs","server"]), and it's the only phrasing of the six that needed the docker-specific framing rather than the CLI one.

Threads

All 16 of my prior threads are resolved — nothing to re-affirm, and no new inline comments this round.

Final accuracy state

Every claim in the two snippets, re-confirmed at aff9d83:

Claim Evidence
Dev mode is CUBEJS_DEV_MODE=true or NODE_ENV !== 'production' OptsHandler.ts:485-489
Under the CLI/images, the flag forces NODE_ENV=development and so switches off REST/GraphQL JWT verification container.ts:250-253 before gateway.ts:285; 403 paths at :2709-2715
Playground + supporting endpoints mounted with no auth, on isDevMode() OptsHandler.ts:392; every /playground/* handler in DevServer.ts:112-616 wrapped only in catchErrors
Ready-to-use token handed out; further ones mintable with any security context DevServer.ts:52, :116; :607 jwt.sign(req.body.payload, options.apiSecret, …)
Reads data model files and every data source's table schema; overwrites data model and .env :150, :132, :161, :585
SQL API accepts any credentials with CUBEJS_DEV_MODE=true and no password set sql-server.ts:343-371
A check_auth "that rejects unauthenticated requests" enforces it whatever NODE_ENV is wrapCheckAuth (gateway.ts:2553) has no enforceSecurityChecks branch
cubejs server and the official images set NODE_ENV=production command/server.ts:19; cubejs-docker/latest.Dockerfile:41, :59
Dev mode disables member-level access control when listing the data model gateway.ts:716-720 visibilityFilter

Minor, not worth a thread

  • snippets/dev-mode-warning-short.mdx still carries no SQL API clause, and it's the variant imported by reference/core-data-apis/sql-api/index.mdx and admin/connect-to-data/data-sources/questdb.mdx — the two pages where "with CUBEJS_DEV_MODE=true and no CUBEJS_SQL_PASSWORD, the SQL API accepts any credentials" is the most relevant fact. Low impact on the SQL API page (its compose block sets CUBEJS_SQL_PASSWORD), less so on QuestDB's.
  • The PR description still says "The three plain-Markdown READMEs … carry the same warning inline" and lists all three; 0192bcf narrowed that to the root README.md only. Worth updating before merge.

Clean

<Warning> tags balance in both snippets and every edited page, with the blank lines Mintlify needs; all 10 DevModeWarning/DevModeWarningShort imports resolve to the two files in snippets/, which needs no docs.json entry; admin/deployment/core.mdxcube-core/deployment.mdx remain byte-identical, as do the two running-in-production pages. The diff is 24 files, +212/−39, all .mdx/.md — no build or test impact, consistent with Codecov's zero code diff.

CI: not re-checked this round; per @paveltiunov's notes the red jobs are the data.wprdc.org 403 fixture in cubestore, an sa login race in the mssql matrix, and a shared dev_pre_aggregations collision in the BigQuery GCS variant — none reachable from a docs-only diff. yarn broken-links isn't runnable in this environment, so link validation is by file-existence check.

· branch `pavel-claude/serene-mayer-0w8zu0`

The short snippet is the variant imported by the SQL API and QuestDB
pages, where "with CUBEJS_DEV_MODE=true and no CUBEJS_SQL_PASSWORD set,
the SQL API accepts any credentials" is the most relevant fact, but it
carried no SQL API clause at all. Scoped to the flag alone, matching the
long snippet, since skipPasswordCheck follows getEnv('devMode') with no
NODE_ENV term.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S7RGv1SFGTWjRUSaarhE88
@claude

claude Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Claude finished @paveltiunov's task in 45s —— View job


Re-review after db39d2a — the added SQL API clause is accurate. No open findings; LGTM

Full review
  • Read the new diff (aff9d83..db39d2a)
  • Verify the added clause against source
  • Resolve stale threads / dedupe
  • Post review

What db39d2a changed

One hunk, in docs-mintlify/snippets/dev-mode-warning-short.mdx only — it restores the SQL API sentence to the condensed form, which was the "minor, not worth a thread" note from the last two rounds:

With CUBEJS_DEV_MODE=true and no CUBEJS_SQL_PASSWORD set, the SQL API accepts any credentials as well, allowing arbitrary SQL against connected data sources.

That's exactly the right scope, and it matches the long snippet's wording rather than re-widening it to isDevMode():

// packages/cubejs-api-gateway/src/sql-server.ts:341-371
let allowedPassword = options.sqlPassword || getEnv('sqlPassword');
if (!getEnv('devMode')) {
  
  if (!allowedPassword) { allowedPassword = crypto.randomBytes(16).toString('hex');  }
}

skipPasswordCheck: getEnv('devMode') && !allowedPassword

getEnv('devMode') reads CUBEJS_DEV_MODE alone (env.ts:212-214) — no NODE_ENV term — so the flag-scoped phrasing is correct, and with the flag unset the !getEnv('devMode') branch generates a password, making the "accepts any credentials" state unreachable. The CUBEJS_SQL_PASSWORD half is likewise right (sqlPassword from config also defeats the skip, but the env var is the form a reader of this callout is using).

The two pages where this fact matters most both import the short snippet — reference/core-data-apis/sql-api/index.mdx:183 and admin/connect-to-data/data-sources/questdb.mdx:67 — plus the three running-in-production/Playground pages, all of which are fine to carry it.

Threads

All 17 of my prior threads are resolved. No new inline comments this round.

Minor, not worth a thread

dev-mode-warning-short.mdx:3-7 — the opening sentence now runs "Cube is in development mode when CUBEJS_DEV_MODE=true — which, under the cubejs CLI and the official Docker images, also forces NODE_ENV=development and so switches off JWT verification on the REST (JSON) and GraphQL APIs — and whenever NODE_ENV is not production." The 30-word dash aside separates "when" from its second branch, so the NODE_ENV-is-not-production condition reads as an afterthought. Splitting into two sentences would read better in the condensed variant especially. Purely editorial; the content is correct.

Clean

<Warning> tags balance in both snippets with the blank lines Mintlify needs; all 10 imports resolve and snippets/ needs no docs.json entry; the two deployment pages and the two running-in-production pages remain byte-identical to their duplicates. Diff is 24 files, +216/−39, all .mdx/.md — no build or test impact, consistent with Codecov's zero code diff. The PR description was updated to match 0192bcf (root README.md only), so my prior note on that is closed.

CI: not re-checked; per @paveltiunov's notes the red jobs are the data.wprdc.org 403 fixture in cubestore, an sa login race in the mssql matrix, and a shared dev_pre_aggregations collision in the BigQuery GCS variant — none reachable from a docs-only diff. yarn broken-links isn't runnable in this environment, so link validation is by file-existence check.

· branch `pavel-claude/serene-mayer-0w8zu0`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cube store Issues relating to Cube Store data source driver rust Pull requests that update Rust code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants