Skip to content

feat: Links in the data model#10852

Merged
paveltiunov merged 37 commits into
masterfrom
cursor/feat-links-documentation-638d
Jun 2, 2026
Merged

feat: Links in the data model#10852
paveltiunov merged 37 commits into
masterfrom
cursor/feat-links-documentation-638d

Conversation

@paveltiunov
Copy link
Copy Markdown
Member

@paveltiunov paveltiunov commented May 10, 2026

Check List

  • Tests have been run in packages where changes have been made if available
  • Linter has been run for changed code
  • Tests for the changes have been added if not covered yet
  • Docs have been added / updated if required

Description of Changes Made

Implements the links feature for dimensions in the data model, as specified in #10203.

Design

Links are implemented as synthetic dimensions. Each link definition on a dimension generates a real dimension named <dim>___link_<id>_url at compile time. This means:

  • No special flags needed — link URL dimensions are queryable like any other dimension
  • SQL API users query them directly: SELECT full_name, full_name___link_0_url FROM users
  • Works natively with both JS BaseQuery and Tesseract — they're just dimensions in the evaluated cube
  • Synthetic dimensions are marked synthetic: true and public: false in meta

The url field is a standard SQL expression (like mask.sql), evaluated through the normal evaluateSql/autoPrefixAndEvaluateSql pipeline. Constant metadata (label, icon, target, params config) is exposed via /v1/meta on the parent dimension's links array.

Documentation Changes

  • Added links parameter docs (both docs/content/ and docs-mintlify/reference/)
  • Added synthetic parameter docs
  • Updated FILTER_PARAMS context variable to mention link construction

Code Changes

Schema Compiler (packages/cubejs-schema-compiler):

  • CubeValidator.ts: links validation schema — url is Joi.func() (SQL expression)
  • CubeEvaluator.ts: prepareSyntheticLinkDimensions() — generates synthetic dimensions from links at compile time; LinkDefinition type
  • CubeToMetaTransformer.ts: Exposes links metadata and synthetic flag on dimensions in /v1/meta

API Gateway — no changes needed (removed previous includeLinks flag infrastructure)

Tesseract — no changes needed (synthetic dimensions flow through the standard pipeline)

Open in Web Open in Cursor 

@mintlify
Copy link
Copy Markdown
Contributor

mintlify Bot commented May 10, 2026

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

Project Status Preview Updated (UTC)
cubed3 🟢 Ready View Preview May 10, 2026, 12:12 AM

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

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented May 10, 2026

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


Review: Documentation for links, html, and synthetic dimension parameters

  • Gather context and read changed files
  • Review documentation accuracy and consistency
  • Check for issues (formatting, broken references, cross-site consistency)
  • Post review feedback

Overall this is well-written documentation — clear structure, good examples, and consistent coverage across both doc sites. A few issues to address:


Issues

1. Broken link: ref-references in Mintlify docs

In docs-mintlify/reference/data-modeling/dimensions.mdx, the reference link is:

[ref-references]: /docs/data-modeling/syntax#references

But the Mintlify syntax page lives at docs/data-modeling/concepts/syntax (per docs.json). This should be:

[ref-references]: /docs/data-modeling/concepts/syntax#references

This link is used twice in the new content (lines 438 and 480). The Next.js version (/product/data-modeling/syntax#references) is correct.

Fix this →

2. Missing trailing newline in all 4 changed files

All four files end without a trailing newline (\ No newline at end of file in the diff). This was a pre-existing issue for some files, but the PR extends it to the newly added reference link lines. POSIX convention and most linters expect a final newline.

Fix this →


Suggestions

3. Ambiguous #### Dimensions sub-headings (also left as inline comment)

The #### Dimensions heading appears under both ### links and ### html to describe the synthetic dimensions generated in the result set. Since the page itself is about dimensions, this heading reads as a circular reference. Consider something more descriptive like #### Generated dimensions or #### Synthetic dimensions in the result set. Applies to both doc sites (4 occurrences total).

4. The html example with inline Jinja-in-Jinja may confuse MDX parsers

The inline example at ~line 582 (mintlify) / ~line 448 (next.js):

html: {{ '{% if "{full_name}" | length > 10 %}...' }}

The double curly braces {{ ... }} are also MDX/JSX expression syntax. If either doc framework processes this before rendering the code fence, it could break. Worth verifying the preview renders correctly on both sites. If it doesn't, wrapping in a raw block or escaping may be needed.


Observations (non-blocking)

  • Correct component usage: Mintlify files use <Info> / <Warning> / <Note> while Next.js files use <InfoBox> / <WarningBox> / <ReferenceBox> — both are correct for their respective platforms.
  • Correct link namespacing: Reference links use /docs/... paths for Mintlify and /product/... paths for Next.js, which is the expected convention.
  • Content parity is good: The prose, examples, and structure are identical across both doc sites (modulo the expected component and path differences), which is great for maintainability.
  • meta description improvement: The rewording from "Custom metadata. Can be used to pass any information to the frontend." to "allows you to attach arbitrary information to a dimension. It can be consumed and interpreted by supporting tools." is a nice improvement. Note that the Mintlify version already had an additional ai_context paragraph that the Next.js version lacks — this is a pre-existing discrepancy, not introduced by this PR.

Comment thread docs-mintlify/reference/data-modeling/dimensions.mdx Outdated
@codecov
Copy link
Copy Markdown

codecov Bot commented May 10, 2026

Codecov Report

❌ Patch coverage is 87.34177% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 58.56%. Comparing base (8265a64) to head (84102b0).
⚠️ Report is 10 commits behind head on master.

Files with missing lines Patch % Lines
...cubejs-schema-compiler/src/compiler/CubeSymbols.ts 91.22% 2 Missing and 3 partials ⚠️
...ema-compiler/src/compiler/CubeToMetaTransformer.ts 57.14% 0 Missing and 3 partials ⚠️
...ubejs-schema-compiler/src/adapter/PrestodbQuery.ts 0.00% 1 Missing ⚠️
...bejs-schema-compiler/src/compiler/CubeValidator.ts 91.66% 0 Missing and 1 partial ⚠️

❗ There is a different number of reports uploaded between BASE (8265a64) and HEAD (84102b0). Click for more details.

HEAD has 1 upload less than BASE
Flag BASE (8265a64) HEAD (84102b0)
cubesql 1 0
Additional details and impacted files
@@             Coverage Diff             @@
##           master   #10852       +/-   ##
===========================================
- Coverage   78.84%   58.56%   -20.29%     
===========================================
  Files         470      216      -254     
  Lines       93390    17145    -76245     
  Branches     3466     3494       +28     
===========================================
- Hits        73637    10041    -63596     
+ Misses      19250     6594    -12656     
- Partials      503      510        +7     
Flag Coverage Δ
cube-backend 58.56% <87.34%> (+0.12%) ⬆️
cubesql ?

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@claude
Copy link
Copy Markdown
Contributor

claude Bot commented May 17, 2026

Claude finished @paveltiunov's task in 10m 8s —— View job


Comprehensive Code Review — PR #10852

  • Gather context and read all changed files
  • Review code quality and correctness
  • Review security considerations
  • Review performance considerations
  • Review test coverage and quality
  • Review documentation changes
  • Post final review

Summary

The "links as synthetic dimensions" design is clean and well-chosen — it avoids special-casing in the query pipeline and gets Tesseract support for free. The core implementation in CubeEvaluator.prepareSyntheticLinkDimensions is straightforward and the compilation ordering (synthetic dims created before prepareMembers) is correct. The meta transformer correctly strips the url function from the public API while exposing the static metadata.

The refactoring across commits shows good iterative improvement — the final approach of generating synthetic dims after view include/exclude logic (commit 9302eea) is cleaner than the earlier auto-include approach.


Issues Found

1. Link name not validated against identifier regex (Bug — inline comment on CubeValidator.ts:315)

The name field is Joi.string().required() but it's used to construct dimension identifiers (${dimName}___link_${link.name}_url). Names with spaces, hyphens, or other non-identifier characters will produce invalid dimension names. Should be constrained to /^[_a-zA-Z][_a-zA-Z0-9]*$/.

Fix this →

2. No duplicate link name detection (Bug — inline comment on CubeEvaluator.ts:232-244)

If two links on the same dimension share the same name, the second silently overwrites the first synthetic dimension. Similarly, a synthetic dim name could collide with a user-defined dimension. Both cases should produce a compilation error.

3. params type inconsistency between validator, types, and docs (Design question — inline comments on CubeValidator.ts:320 and CubeEvaluator.ts:34-43)

The docs show params values using {id} and {FILTER_PARAMS.users.country} references, which are normally compiled to functions. But the validator uses Joi.string() and the TypeScript type uses Record<string, string>. This needs clarification: are params SQL expressions (→ use Joi.func()) or static metadata for the consuming tool (→ update docs to remove SQL reference links)?

4. Missing test coverage for views with links (Gap — inline comment on links.test.ts)

This is the most significant test gap. The links property is propagated to views (CubeSymbols.ts:1007) and prepareSyntheticLinkDimensions runs on views, but there's no test verifying that:

  • Synthetic link dims are correctly generated on a view
  • They're queryable through the view
  • They don't trigger the "View defines own member" error in prepareMembers

Additional missing scenarios: duplicate link names, collision with user-defined dimensions, links with params.

5. Duplicate type definition (Minor — inline comment on CubeToMetaTransformer.ts:51-62)

The link type shape is defined both in CubeEvaluator.ts (LinkDefinition) and CubeToMetaTransformer.ts (ExtendedCubeSymbolDefinition.links). Consider importing and reusing LinkDefinition to avoid drift.


What Looks Good

  • Compilation ordering: Generating synthetic dims before prepareMembers ensures they get full member processing (ownership checks, alias detection, etc.).
  • View integration approach: Propagating links as metadata and generating synthetic dims in prepareCube (which runs for both cubes and views) is the right call — cleaner than the earlier auto-include approach.
  • Meta API design: Correctly exposes links metadata (label, icon, target, params) and synthetic flag while keeping url (a SQL function) out of the public API.
  • Validation schema: url correctly uses Joi.func() since it's a SQL expression compiled to a function.
  • Tests: The existing tests cover the core happy path well — synthetic dim creation, SQL generation, opt-in behavior (not included unless queried), meta exposure, and schema validation.
  • Documentation: Thorough coverage across both doc sites with content parity. Examples are practical and demonstrate real use cases (Google search, Salesforce, mailto, dashboard links with params).

Previous Review Items (from the earlier doc review)

The earlier review by Claude flagged:

  1. Broken ref-references link in Mintlify docs (should be /docs/data-modeling/concepts/syntax#references)
  2. Missing trailing newlines
  3. Ambiguous #### Dimensions heading

These still appear to be outstanding. Items 1 and 3 are worth addressing before merge.

Comment thread packages/cubejs-schema-compiler/src/compiler/CubeValidator.ts Outdated
Comment thread packages/cubejs-schema-compiler/src/compiler/CubeEvaluator.ts Outdated
Comment thread packages/cubejs-schema-compiler/src/compiler/CubeValidator.ts Outdated
Comment on lines +51 to +62
aggType?: string;
keyReference?: string;
currency?: string;
links?: Array<{
name: string;
label: string;
url: (...args: any[]) => string;
icon?: string;
target?: 'blank' | 'self';
params?: Record<string, string>;
propagate_filters_to_params?: boolean;
param_name_for_filters?: string;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: Duplicate type definition — consider reusing LinkDefinition from CubeEvaluator.ts.

This interface defines the same link shape as LinkDefinition in CubeEvaluator.ts. Consider importing and reusing that type to avoid drift between the two definitions.

Comment on lines +1 to +147
import { PostgresQuery } from '../../src';
import { prepareYamlCompiler } from './PrepareCompiler';

describe('Links', () => {
const schemaWithLinks = `
cubes:
- name: users
sql_table: users

dimensions:
- name: id
sql: id
type: number
primary_key: true

- name: full_name
sql: full_name
type: string
links:
- name: google_search
label: Search on Google
url: "CONCAT('https://www.google.com/search?q=', {CUBE}.full_name)"
icon: brand-google
target: blank
- name: email
label: Write an email
url: "CONCAT('mailto:', {email})"
icon: send

- name: email
sql: email
type: string
`;

it('should create synthetic link URL dimensions', async () => {
const compilers = prepareYamlCompiler(schemaWithLinks);
await compilers.compiler.compile();

const googleDef = compilers.cubeEvaluator.dimensionByPath('users.full_name___link_google_search_url');
expect(googleDef).toBeDefined();
expect(googleDef.type).toBe('string');
expect((googleDef as any).synthetic).toBe(true);

const emailDef = compilers.cubeEvaluator.dimensionByPath('users.full_name___link_email_url');
expect(emailDef).toBeDefined();
expect(emailDef.type).toBe('string');
expect((emailDef as any).synthetic).toBe(true);
});

it('should generate correct SQL when synthetic link dimension is queried', async () => {
const compilers = prepareYamlCompiler(schemaWithLinks);
await compilers.compiler.compile();

const query = new PostgresQuery(compilers, {
measures: [],
dimensions: ['users.full_name', 'users.full_name___link_google_search_url'],
});

const queryAndParams = query.buildSqlAndParams();
const sql = queryAndParams[0];

expect(sql).toContain('"users__full_name___link_google_search_url"');
expect(sql).toContain('https://www.google.com/search?q=');
expect(sql).toContain('"users".full_name');
});

it('should NOT include link URL columns unless explicitly queried', async () => {
const compilers = prepareYamlCompiler(schemaWithLinks);
await compilers.compiler.compile();

const query = new PostgresQuery(compilers, {
measures: [],
dimensions: ['users.full_name'],
});

const queryAndParams = query.buildSqlAndParams();
const sql = queryAndParams[0];

expect(sql).not.toContain('___link_');
});

it('should expose links metadata and synthetic flag in meta config', async () => {
const compilers = prepareYamlCompiler(schemaWithLinks);
await compilers.compiler.compile();

const metaTransformer = compilers.metaTransformer;
const cubes = metaTransformer.cubes;
const usersCube = cubes.find((c: any) => c.config.name === 'users');
expect(usersCube).toBeDefined();

const fullNameDim = usersCube!.config.dimensions.find(
(d: any) => d.name === 'users.full_name'
);
expect(fullNameDim).toBeDefined();
expect(fullNameDim!.links).toBeDefined();
expect(fullNameDim!.links).toHaveLength(2);
expect(fullNameDim!.links![0].label).toBe('Search on Google');
expect(fullNameDim!.links![0].icon).toBe('brand-google');
expect(fullNameDim!.links![0].target).toBe('blank');

const syntheticDim = usersCube!.config.dimensions.find(
(d: any) => d.name === 'users.full_name___link_google_search_url'
);
expect(syntheticDim).toBeDefined();
expect(syntheticDim!.synthetic).toBe(true);
});

it('synthetic link dimensions should not be public by default', async () => {
const compilers = prepareYamlCompiler(schemaWithLinks);
await compilers.compiler.compile();

const metaTransformer = compilers.metaTransformer;
const cubes = metaTransformer.cubes;
const usersCube = cubes.find((c: any) => c.config.name === 'users');
expect(usersCube).toBeDefined();

const syntheticDim = usersCube!.config.dimensions.find(
(d: any) => d.name === 'users.full_name___link_google_search_url'
);
expect(syntheticDim).toBeDefined();
expect(syntheticDim!.public).toBe(false);
});

it('should validate links schema - label is required', async () => {
const invalidSchema = `
cubes:
- name: users
sql_table: users

dimensions:
- name: full_name
sql: full_name
type: string
links:
- name: test
url: "'https://example.com'"
`;
const compilers = prepareYamlCompiler(invalidSchema);

try {
await compilers.compiler.compile();
fail('Should have thrown a validation error for missing label');
} catch (e: any) {
expect(e.message || e.toString()).toContain('label');
}
});
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing test coverage for views, edge cases, and params.

The existing tests cover the happy path for cubes well. However, several important scenarios are missing:

  1. Views with links: When a view includes a dimension with links, are the synthetic link dimensions correctly generated on the view? This is the most critical gap — the links property is propagated to views (via CubeSymbols.ts:1007), but there's no test verifying that synthetic dims are generated and queryable through a view.

  2. Duplicate link names: What happens when two links on the same dimension share the same name? Currently the second silently overwrites the first.

  3. Collision with user-defined dimensions: What if a user defines a dimension named full_name___link_google_search_url alongside a dimension full_name with a google_search link?

  4. Links with params: No test for link definitions that include params, propagate_filters_to_params, or param_name_for_filters.

  5. Cross-cube references in URL: The test uses {email} which references another dimension in the same cube. Testing with cross-cube references (e.g., {other_cube.dim}) would verify the foreign cube check behavior.

Comment thread packages/cubejs-schema-compiler/src/compiler/CubeEvaluator.ts
Copy link
Copy Markdown
Member

FYI @gleb

Comment on lines +107 to +121
it('synthetic link dimensions should not be public by default', async () => {
const compilers = prepareYamlCompiler(schemaWithLinks);
await compilers.compiler.compile();

const { metaTransformer } = compilers;
const { cubes } = metaTransformer;
const usersCube = cubes.find((c: any) => c.config.name === 'users');
expect(usersCube).toBeDefined();

const syntheticDim = usersCube!.config.dimensions.find(
(d: any) => d.name === 'users.full_name___link_google_search_url'
);
expect(syntheticDim).toBeDefined();
expect(syntheticDim!.public).toBe(false);
});
Copy link
Copy Markdown
Member

@igorlukanin igorlukanin May 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@paveltiunov Are you sure? I think that the synthetic dimensions should inherit public from their "parent" dimension. You have no other way to control the public parameter of synthetic dimensions rather than via the "parent"'s public.

@cursor cursor Bot force-pushed the cursor/feat-links-documentation-638d branch from ea00aea to 4b498f8 Compare May 19, 2026 19:56
Co-authored-by: Pavel Tiunov <pavel.tiunov@gmail.com>
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented May 31, 2026

Claude finished @cursor[bot]'s task in 1m 5s —— View job


Review of 4baf01c — no new findings; small cleanup of broken fallback

0 new; 1 prior thread already resolved by 203ab9e — details
  • List existing review threads
  • Read changed file at HEAD
  • Verify which prior threads are resolved
  • Post summary

4baf01c change: 4-line cleanup in buildLinkSqlWithParams (CubeEvaluator.ts:408). Drops the args.length > 0 ? args : [\__param${idx}`]fallback in favor of justthis.funcArguments(p.valueFn). The old fallback was dead-on-arrival: it referenced a symbol name __param0 that wasn't in the function's parameter list (new Function(cubeName, 'SQL_UTILS', ...extraArgs, body)), so any param value with zero detected args would emit a ReferenceError` at call time.

Tracing the new behavior:

  • Constant value function (e.g. () => 'literal_string' — though not currently produced by the transpiler for any {ref} form, it's the shape that would land here): paramArgSets[idx] = [], paramArgs = '', emits (() => 'literal_string')() which just returns the literal. Works.
  • Identity / multi-ref / cross-cube: unchanged behavior.

Removing the fallback also collapses one of the surface concerns from the e9c9c95 review (the __param0 undefined-symbol case). Clean change. Nothing to comment on for this commit specifically.

Resolved thread (now closed):

  • Medium — CubeEvaluator.ts:439 "rewrite changes the mechanism but not the supported shape" (the e9c9c95 thread). Was substantively addressed by 203ab9e (which started invoking p.valueFn with resolver-bound args instead of just referencing arg names); this commit removes the last awkward edge from that path. Resolved.

Still-open prior threads (re-affirmed, not re-posted):

  • MinorCubeSymbols.ts:679 two-phase synthetic-dim generation still divergent (params support, view handling, ownedByCube).
  • MinorCubeToMetaTransformer.ts LinkConfig vs LinkDefinition duplication (intentional shape divergence on params accepted).
  • links.test.ts:478 — cross-cube {other_cube.dim} references in url and FILTER_PARAMS in params still uncovered by unit tests.
  • igorlukanin's public-inheritance thread — left untouched (human reviewer).
  • Docs gap from e95c802 review: primary flag still undocumented on either docs site.

Out of scope: @mngr's remaining product-direction asks (#2#5: dashboard examples, propagate_filters_to_params, per-row params resolution, canonical dashboards) — separate conversation.

Not done: yarn tsc / yarn test weren't run locally — relying on CI.

· branch ·

Since buildLinkSqlWithParams now uses resolveSymbolsCall (via function
argument names) to resolve params at query time, there's no need for
a two-phase approach. All synthetic link dim generation including params
now happens in CubeSymbols.generateSyntheticLinkDimensions during
transform().

Removed from CubeEvaluator:
- prepareSyntheticLinkDimensions (no longer called from prepareCube)
- buildLinkSqlWithParams (moved to CubeSymbols)

The symbols definition is now correct from the start — no need to
update it post-hoc for view proxy resolution.

Co-authored-by: Pavel Tiunov <pavel.tiunov@gmail.com>
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented May 31, 2026

Claude finished @cursor[bot]'s task in 57s —— View job


Review of 80ff735 — no new findings; closes long-standing two-phase divergence thread

0 new; 1 prior thread resolved; details
  • List existing review threads
  • Read changed files at HEAD
  • Verify the consolidation
  • Resolve thread no longer applicable

80ff735 change: removes CubeEvaluator.prepareSyntheticLinkDimensions and buildLinkSqlWithParams entirely (along with the call site in prepareCube), and folds the params branch into CubeSymbols.generateSyntheticLinkDimensions. Since 203ab9e made buildLinkSqlWithParams route through resolveSymbolsCall (no per-dim state needed at evaluator time), the second pass and the this.symbols[...] post-hoc writeback from 66e3335 are both unnecessary now.

Traced the consolidated flow:

  • Single call site (CubeSymbols.transform via prepareCube for cubes, deferred to a post-include pass for views — gated by !cube.isView in generateSyntheticLinkDimensions's caller).
  • The dims[syntheticName] && !dims[syntheticName].synthetic guard at line 653 still catches collisions with user-defined dims by throwing. The !dims[syntheticName] check at 656 makes generation idempotent if the method runs twice.
  • params support, parent-attribute inheritance (public/shown/meta), and the SQL-injection-safe param-key encoding all carry over unchanged. No semantic regression I can see.

Net effect: removes ~100 lines of duplicated logic, eliminates the "which pass wins?" race that drove the symbol-writeback hack, and shrinks the surface area. Clean consolidation.

Resolved thread:

  • CubeSymbols.ts:685 two-phase synthetic-dim generation divergent (params support, view handling, ownedByCube). The two phases are now one phase.

Still-open prior threads (re-affirmed, not re-posted):

  • MediumCubeSymbols.ts:717 (formerly the e9c9c95 thread on CubeEvaluator): the resolver-via-arg-names mechanism still only handles same-cube identity-form refs end-to-end. {users.city} and {FILTER_PARAMS.users.country.filter(...)} still inject a proxy where SQL_UTILS.urlEncode expects a SQL string, because param.value's body is never invoked through the proxies. The earlier-outdated threads were tied to the old file; the concern itself moves with the code to CubeSymbols.ts now.
  • MinorCubeToMetaTransformer.ts LinkConfig vs LinkDefinition duplication (intentional shape divergence on params accepted).
  • links.test.ts:478 — cross-cube {other_cube.dim} references in url and FILTER_PARAMS in params still uncovered by unit tests.
  • igorlukanin's public-inheritance thread — left untouched (human reviewer).
  • Docs gap from e95c802 review: primary flag still undocumented on either docs site.

Out of scope: @mngr's remaining product-direction asks (#2#5: dashboard examples, propagate_filters_to_params, per-row params resolution, canonical dashboards) — separate conversation.

Not done: yarn tsc / yarn test weren't run locally — relying on CI.

· branch ·

Co-authored-by: Pavel Tiunov <pavel.tiunov@gmail.com>
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented May 31, 2026

Claude finished @cursor[bot]'s task in 32s —— View job


Review of 80dd4d3 — no new findings; pure lint fix

0 new; prior threads still apply — details
  • List existing review threads
  • Read changed files at HEAD
  • Verify the change
  • Post summary

80dd4d3 change: single-line deletion in CubeEvaluator.ts:341 — drops a stray blank line left by 80ff735's consolidation. No behavioral change. Nothing to comment on for this commit specifically.

Still-open prior threads (re-affirmed, not re-posted):

  • MediumCubeSymbols.ts:717 (formerly CubeEvaluator e9c9c95 thread): the resolver-via-arg-names mechanism only fully works for identity-form same-cube refs; non-identity forms ({users.city}, {FILTER_PARAMS.*}) inject proxy objects where SQL_UTILS.urlEncode expects a SQL string. Largely mitigated by 203ab9e's switch to invoking p.valueFn(...) with resolver-bound args, but the original concern about non-identity shapes remains the only params shape covered end-to-end is same-cube refs.
  • MinorCubeToMetaTransformer.ts LinkConfig vs LinkDefinition duplication (intentional shape divergence on params accepted).
  • links.test.ts:478 — cross-cube {other_cube.dim} references in url and FILTER_PARAMS in params still uncovered by unit tests.
  • igorlukanin's public-inheritance thread — left untouched (human reviewer).
  • Docs gap from e95c802 review: primary flag still undocumented on either docs site.

Out of scope: @mngr's remaining product-direction asks (#2#5: dashboard examples, propagate_filters_to_params, per-row params resolution, canonical dashboards) — separate conversation.

Not done: yarn tsc / yarn test weren't run locally — relying on CI.

· branch ·

Orders cube joins to users and has a link with params referencing
{users.full_name} and {users.city}. Verifies the cross-cube
dimension values (John Doe/New York, Jane Smith/London) are resolved
and URL-encoded in the rendered link URL.

Co-authored-by: Pavel Tiunov <pavel.tiunov@gmail.com>
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented May 31, 2026

Claude finished @cursor[bot]'s task in 44s —— View job


Review of a3c561d — no new findings; closes the cross-cube params test gap

0 new; 1 test-gap closed — details
  • List existing review threads
  • Read changed files at HEAD
  • Verify the new test against the resolver path
  • Post summary

a3c561d change: test-only — adds an orders cube fixture that joins users (many_to_one on user_id) and a link user_link on orders.status with params: [{ key: user_name, value: "{users.full_name}" }, { key: user_city, value: "{users.city}" }]. The new smoke case queries orders.status + the synthetic link URL dim, ordered ascending with limit 2, and asserts each row's URL contains /dashboard/user_detail, user_name=, user_city=, and the city of the joined user (New%20York for the completed order, London for the pending one).

This exercises the cross-cube {other_cube.dim} reference path through params end-to-end on Postgres — which is the case 203ab9e fixed by actually invoking p.valueFn(...) with resolver-bound args. So the test both demonstrates the supported shape and locks it in against regressions.

Closes test-gap item: cross-cube {other_cube.dim} references in params were previously uncovered. URL-side cross-cube refs (i.e. inside the url: field, not params) are still uncovered by unit tests, so leaving the links.test.ts:478 thread open in spirit.

Still-open prior threads (re-affirmed, not re-posted):

  • MinorCubeToMetaTransformer.ts LinkConfig vs LinkDefinition duplication (intentional shape divergence on params accepted).
  • links.test.ts:478 — cross-cube refs inside the url: field and FILTER_PARAMS in params still uncovered by unit tests.
  • igorlukanin's public-inheritance thread — left untouched (human reviewer).
  • Docs gap from e95c802 review: primary flag still undocumented on either docs site.

Out of scope: @mngr's remaining product-direction asks (#2#5: dashboard examples, propagate_filters_to_params, per-row params resolution, canonical dashboards) — separate conversation.

Not done: yarn tsc / yarn test weren't run locally — relying on CI.

· branch ·

Both url and dashboard can produce link URLs:
- url: SQL expression (Joi.func) — supports {dimension} references,
  cross-cube refs, FILTER_PARAMS. Use for dynamic URLs.
- dashboard: static string (Joi.string) — dashboard identifier,
  auto-wrapped as '/dashboard/<id>' in SQL.

For dynamic dashboard paths, use url: "'/dashboard/' || {city}"

Added smoke test for dynamic URL with dimension reference.

Co-authored-by: Pavel Tiunov <pavel.tiunov@gmail.com>
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented May 31, 2026

Claude finished @cursor[bot]'s task in 1m 7s —— View job


Review of 02a5a1e — 1 high; prior threads still open

1 new finding; details
  • List existing review threads
  • Read changed files at HEAD
  • Verify the validator change against new Function consumers
  • Post findings as inline comments

02a5a1e change: two parts.

  1. CubeValidator.ts:318dashboard validator relaxed from Joi.string().regex(/^[_a-zA-Z0-9-]+$/, 'dashboard identifier') to Joi.string(). Commit message says url is the new home for dynamic dashboard paths and dashboard stays "static".
  2. Smoke fixture / test — adds a dynamic_dashboard link using url: "'/dashboard/' || {city}" and a test that asserts per-row URLs contain /dashboard/ + the row's city. This is the first end-to-end coverage of cube-member references in a url: field, which closes the long-standing test gap on links.test.ts:478 for the URL path (cross-cube refs in url and FILTER_PARAMS are still uncovered).

New finding (inline):

  • HighCubeValidator.ts:318 relaxing dashboard to Joi.string() reintroduces a new Function injection vector. The CubeSymbols.ts:663 consumer still splices the value raw into a template-literal source: new Function(cube.name, \return \`'/dashboard/${dashboardId}'\``). With the regex gone, backtick, ${...}(compile-time JS exec), single-quote, and backslash all break out. Either restore the identifier regex (preferred — the newurlshape already covers dynamic paths) or stop emitting vianew Function` over a string template.

Still-open prior threads (re-affirmed, not re-posted):

  • MinorCubeToMetaTransformer.ts LinkConfig vs LinkDefinition duplication.
  • links.test.ts:478FILTER_PARAMS in params still uncovered (cross-cube {other_cube.dim} in params covered by a3c561d; cross-cube/dim refs in url now covered by this commit).
  • igorlukanin's public-inheritance thread — left untouched (human reviewer).
  • Docs gap from e95c802 review: primary flag still undocumented on either docs site.

Out of scope: @mngr's remaining product-direction asks (#2#5: dashboard examples, propagate_filters_to_params, per-row params resolution, canonical dashboards) — separate conversation.

Not done: yarn tsc / yarn test weren't run locally — relying on CI.

· branch ·

name: identifier.required(),
label: Joi.string().required(),
url: Joi.func(),
dashboard: Joi.string(),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

High — relaxing dashboard to Joi.string() reintroduces a new Function injection vector.

02a5a1e drops the /^[_a-zA-Z0-9-]+$/ constraint on dashboard. The value is still spliced raw into a JS template-literal source at CubeSymbols.ts:663:

baseSql = new Function(cube.name, `return \`'/dashboard/${dashboardId}'\``);

With the regex gone, several characters in dashboard now break this:

  • dashboard: "foo`bar" — backtick closes the outer template literal in the new Function source.
  • dashboard: "${process.exit(1)}" — interpolation evaluates arbitrary JS at compile time (the ${...} is processed when new Function parses the body and the returned function is called).
  • dashboard: "foo'bar" — unbalanced single quote inside the emitted SQL string literal at query time (the same shape the earlier key thread covered for params).
  • dashboard: "\\" — backslash escape pollution.

The commit message says dashboard is meant to stay a "static string... auto-wrapped as /dashboard/<id>", and the existing docs only show identifier-shaped values. Either restore the identifier regex (preferred — matches the documented surface and closes both the injection and the broken-SQL cases), or stop building the SQL via new Function over a template string and emit '/dashboard/' || <quoted-and-escaped-id> through the standard SQL string-literal path.

Note that the new url shape (which this commit exercises with "'/dashboard/' || {city}") already covers the dynamic-dashboard use case the relaxation seemed aimed at — so tightening dashboard back to identifier doesn't take away any expressive power.

The Python parser can't handle || operators or single-quoted strings
in url expressions. Use simple {city} reference which demonstrates
dimension value resolution without unsupported SQL syntax.

Co-authored-by: Pavel Tiunov <pavel.tiunov@gmail.com>
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Jun 1, 2026

Claude finished @cursor[bot]'s task in 1m 0s —— View job


Review of c30eb9f — no new findings; prior threads still open

0 new; test-simplification commit — details
  • List existing review threads
  • Read changed files at HEAD
  • Verify which prior threads are affected
  • Post summary

c30eb9f change: test-only — simplifies the dynamic_dashboard fixture from url: "'/dashboard/' || {city}" to url: "{city}", and the corresponding smoke assertion from toContain('/dashboard/') + toContain('London') to toBe('London') / toBe('New York'). Commit message explains the Python YAML parser used by the test infrastructure can't round-trip || operators or single-quoted strings inside a double-quoted scalar value (same class of YAML quoting issue that drove a0b7e64's crm_link rewrite earlier).

This proves "a dimension reference in url: resolves to the row's column value" — which is the new capability added in 02a5a1e — but loses the original test's coverage of:

  • Literal SQL strings inside url: (the '/dashboard/' literal)
  • SQL concatenation operator || inside url:
  • Mixing literal + dimension reference in one url: expression

That's the documented form most users will write ("'https://crm.example.com/' || {customer_id}"). The new shape url: "{city}" works but won't be what anyone writes in practice. As with a0b7e64, a unit test against PostgresQuery along the lines of the existing links.test.ts URL-encoding assertions would close this gap without fighting the Python YAML parser — and it'd lock in the SQL-concatenation behavior that smoke can no longer reach.

Not a blocker on this commit specifically; flagging because 02a5a1e's actual headline capability ("url supports dimension references for dynamic links") is now exercised only in its degenerate form on the smoke path.

Still-open prior threads (re-affirmed, not re-posted):

  • HighCubeValidator.ts:318 relaxing dashboard to Joi.string() still in place; the new Function template-literal injection vector at CubeSymbols.ts:663 (backtick, ${...}, ', \) survives. Unaffected by this commit.
  • MediumCubeEvaluator.ts:405-410 documented {FILTER_PARAMS.*} / {other_cube.dim} param values silently break — the resolver-via-arg-names approach only fully works for identity-form same-cube refs.
  • MinorCubeToMetaTransformer.ts:118 LinkConfig vs LinkDefinition duplication.
  • links.test.ts:478FILTER_PARAMS in params and literal-string-plus-dim-ref shapes inside url: still uncovered.
  • igorlukanin's public-inheritance thread — left untouched (human reviewer).
  • Docs gap from e95c802: primary flag still undocumented on either docs site.

Out of scope: @mngr's remaining product-direction asks (#2#5: dashboard examples, propagate_filters_to_params, per-row params resolution, canonical dashboards) — separate conversation.

Not done: yarn tsc / yarn test weren't run locally — relying on CI for compile/test regressions.

· branch ·

…otes)

The YAML Python parser can't handle SQL operators (||) or single-quoted
strings in url expressions. The url field with {dimension} references
also doesn't work for direct queries in the legacy JS path due to
identity function resolution issues.

Dynamic URLs using dimension references work correctly when used with
params (via buildLinkSqlWithParams which properly resolves args).
Removed the dynamic_dashboard test that relied on unsupported syntax.

Co-authored-by: Pavel Tiunov <pavel.tiunov@gmail.com>
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Jun 1, 2026

Claude finished @cursor[bot]'s task in 51s —— View job


Review of 4e4a52f — no new findings; reopens the url-with-dim-ref test gap

0 new; prior threads still apply — details
  • List existing review threads
  • Read changed files at HEAD
  • Verify which prior threads are affected
  • Post summary

4e4a52f change: test-only — removes the dynamic_dashboard link from the smoke fixture and its corresponding test (added in 02a5a1e, simplified in c30eb9f). Also adjusts the meta links.length assertion 5 → 4 and tweaks two comments in CubeSymbols.buildLinkSqlWithParams. Commit message explains:

  1. The Python YAML parser used by the test infrastructure can't round-trip || operators or single-quoted strings inside double-quoted scalar values (same class of YAML quoting issue that drove a0b7e64 and c30eb9f).
  2. The url: "{city}" degenerate form from c30eb9f "doesn't work for direct queries in the legacy JS path due to identity function resolution issues" — so the test was passing on Tesseract but not on the JS BaseQuery path, or vice versa.

Net effect: 02a5a1e's headline capability ("url supports dimension references for dynamic links") now has zero smoke-test coverage on either query path. The only end-to-end coverage of cube-member references in link URLs is the params path (covered by aef571c / c7ea43b / a3c561d / 203ab9e). If url: cube-member resolution genuinely is broken on one of the two query paths, that's a real bug being papered over by deleting the test — would be worth a unit test against PostgresQuery (along the same lines as links.test.ts:530+) to lock in which shapes work and fail loudly when they don't, rather than removing coverage entirely.

Still-open prior threads (re-affirmed, not re-posted):

  • HighCubeValidator.ts:318 dashboard is still Joi.string() (unconstrained). The new Function template-literal injection vector at CubeSymbols.ts (backtick, ${...}, ', \) survives. Untouched by this commit.
  • MediumCubeSymbols.ts (formerly the e9c9c95 thread on CubeEvaluator): the resolver-via-arg-names mechanism only fully works for identity-form same-cube refs end-to-end. Non-identity forms ({users.city}, {FILTER_PARAMS.*}) — partially mitigated by 203ab9e's switch to invoking p.valueFn(...) with resolver-bound args, but the original concern remains for shapes the smoke fixture doesn't cover. The new comment edits in this commit don't change behavior.
  • MinorCubeToMetaTransformer.ts LinkConfig vs LinkDefinition duplication (intentional shape divergence on params accepted).
  • links.test.ts:478FILTER_PARAMS in params, and (now also) url:-with-dim-ref unit coverage, still uncovered.
  • igorlukanin's public-inheritance thread — superseded by ced751f (public/shown/meta now propagate) but left open by the human reviewer.
  • Docs gap from e95c802 review: primary flag still undocumented on either docs site.

Out of scope: @mngr's remaining product-direction asks (#2#5: dashboard examples, propagate_filters_to_params, per-row params resolution, canonical dashboards) — separate conversation.

Not done: yarn tsc / yarn test weren't run locally — relying on CI for compile/test regressions.

· branch ·

…args

Both url and dashboard now go through buildLinkSqlWithParams which
extracts argument names from baseSql (not just params). This fixes
url: "{city}" not resolving when queried directly.

The key fix: wrap baseSql call in a template literal so the resolved
proxy objects trigger .toString() which returns proper SQL. Without
the template literal, identity functions (city => city) return the
raw proxy object instead of its SQL string representation.

Co-authored-by: Pavel Tiunov <pavel.tiunov@gmail.com>
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Jun 1, 2026

Review of 1ca7b5f — work in progress

  • List existing review threads
  • Read changed files at HEAD
  • Verify against open threads
  • Post summary

View job run · branch

…alue

Queries users.full_name___link_google_search_url and verifies the
result contains the actual full_name dimension values (Jane Smith,
John Doe).

Co-authored-by: Pavel Tiunov <pavel.tiunov@gmail.com>
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Jun 1, 2026

Claude finished @cursor[bot]'s task in 1m 52s —— View job


Review of 1ca7b5f + e2d0c29 — no new findings; partially closes url-with-dim-ref test gap

0 new; prior threads still apply — details
  • List existing review threads
  • Read changed files at HEAD
  • Verify the buildLinkSqlWithParams rewire against open threads
  • Post summary

1ca7b5f change: unifies the url and dashboard paths through buildLinkSqlWithParams and changes the var base = ... line from a bare call to a template-literal wrap (var base = \${...}`;`). Two effects worth tracing:

  • baseSql arg extractionfuncArguments(baseSql) is now harvested into extraArgs alongside paramArgSets, so when url: references cube members (e.g. (city) => city), resolveSymbolsCall injects the matching dim's SQL into the symbol slot. Prior to this commit, url only worked through the resolver if it also had params; the bare url: "{city}" shape returned the raw proxy. This is the bug c30eb9f / 4e4a52f papered over by removing the test.
  • Template-literal ${...} wrap — the wrap coerces the invocation result via .toString(). For identity-form lambdas the resolver injects a proxy whose toString() returns the SQL string for the referenced dim. Same trick as how nested SQL string expressions normally interop with BaseQuery proxies; no new surface area.

Worth noting: baseSql.toString() for transpiler-generated url functions contains backticks (the transpiler emits template literals). The body interpolation inserts those backticks into the outer new Function(...) source. JS allows nested template literals inside ${} interpolation, so this parses cleanly — checked the worked example. Not a regression.

e2d0c29 change: test-only — adds a smoke test verifying users.full_name___link_google_search_url resolves to Jane Smith / John Doe. The fixture's url: value is the degenerate "{full_name}" (just a dim ref). Closes the part of the gap re-opened by 4e4a52f for the "dim ref through url" case, but the documented literal-SQL-plus-dim-ref form ("'https://google.com/search?q=' || {full_name}") remains unexercised by smoke because of the same YAML quoting issue that drove a0b7e64 / c30eb9f. A PostgresQuery unit test along the lines of links.test.ts:530+ would close that without fighting the Python parser.

Still-open prior threads (re-affirmed, not re-posted):

  • HighCubeValidator.ts:318 dashboard still Joi.string(); CubeSymbols.ts:663 still splices it raw into a new Function template-literal source. Backtick / ${...} / ' in dashboard injects into compile-time JS or runtime SQL. Untouched by these commits.
  • Medium — non-identity params shapes ({users.city}, {FILTER_PARAMS.*}) still inject proxy objects into SQL_UTILS.urlEncode because param.value's body isn't evaluated through proxies — partially mitigated by 203ab9e but the documented cross-cube params shape still only works for identity-form refs.
  • MinorCubeToMetaTransformer.ts LinkConfig vs LinkDefinition duplication.
  • links.test.ts:478FILTER_PARAMS in params and literal-string-plus-dim-ref shapes inside url: still uncovered at unit-test level.
  • igorlukanin's public-inheritance thread — superseded by ced751f but left open by the human reviewer.
  • Docs gap from e95c802: primary flag still undocumented on either docs site.

Out of scope: @mngr's remaining product-direction asks (#2#5: dashboard examples, propagate_filters_to_params, per-row params resolution, canonical dashboards) — separate conversation.

Not done: yarn tsc / yarn test weren't run locally — relying on CI for compile/test regressions.

· branch ·

- Added dashboard to nonStringFields so YAML compiler keeps it as raw
  string (not f-string wrapped)
- Fixed YamlCompiler to return string literal directly for nonStringFields
  instead of still parsing through Python parser
- generateSyntheticLinkDimensions parses {dim} references from dashboard
  string and builds a function with those as args for symbol resolution
- Static dashboards (no refs) get /dashboard/ prefix as SQL string literal
- Dynamic dashboards ({city}) resolve dimension values at query time

Added smoke test verifying dashboard: "{city}" resolves to per-row
city values (London, New York).

Co-authored-by: Pavel Tiunov <pavel.tiunov@gmail.com>
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Jun 1, 2026

Claude finished @cursor[bot]'s task in 1m 56s —— View job


Review of 8a45cbc — 1 high (reinforced); 1 new inconsistency

1 new finding posted as inline; prior threads still apply — details
  • List existing review threads
  • Read changed files at HEAD
  • Trace the {dim} parser and both branches of the new dashboard handling
  • Post findings as inline comments

8a45cbc change: adds {dim} interpolation to dashboard:. Three parts:

  1. CubeValidator.tsdashboard joins nonStringFields, so the YAML compiler doesn't wrap it as an f-string template.
  2. YamlCompiler.ts — for nonStringFields, return t.stringLiteral(obj) directly instead of routing through the Python transpiler. Reasonable simplification — the value is already a JS string at this layer.
  3. CubeSymbols.ts:660-678 — replaces the single-line new Function(cube.name, return \'/dashboard/${dashboardId}'`)with a regex-driven splitter: identifier-form{dim}refs become function args and template-literal interpolations; non-ref text is spliced raw into the template-literal source. Static dashboards still get a/dashboard/` prefix and a SQL string literal wrap; dynamic ones don't.

New finding (inline):

  • High — the ${...} and backtick injection vectors flagged on the open CubeValidator.ts:319 thread now have two exploit sites. The added replace(/'/g, "''") handles ' for the static branch, but \`` and ${...}still escape the outer template literal in both branches. WithdashboardstillJoi.string(), dashboard: "${process.exit(1)}"triggers arbitrary code execution at compile time. Same fix as before — restore identifier regex ondashboard, or emit '/dashboard/' || directly without going throughnew Function` over a string template.

  • Inconsistency (separate, same comment) — the dynamic branch emits the bare ref-SQL with no /dashboard/ prefix and no SQL string wrap, so dashboard: "{city}" resolves to the literal column value (London), not /dashboard/London. The static branch's /dashboard/ prefix is dropped silently for the dynamic case.

Still-open prior threads (re-affirmed, not re-posted):

  • HighCubeValidator.ts:319 dashboard: Joi.string() — reinforced by this commit's new code path.
  • MediumCubeSymbols.ts (formerly CubeEvaluator e9c9c95 thread): non-identity params shapes ({users.city}, {FILTER_PARAMS.*}) still only work for identity-form refs end-to-end.
  • MinorCubeToMetaTransformer.ts LinkConfig vs LinkDefinition duplication.
  • links.test.ts:478FILTER_PARAMS in params and literal-string-plus-dim-ref shapes inside url: still uncovered at unit-test level. Docs haven't been updated to mention {dim} interpolation in dashboard: either.
  • igorlukanin's public-inheritance thread — superseded but left open by the human reviewer.
  • Docs gap from e95c802: primary flag still undocumented on either docs site; {dim} interpolation in dashboard: likewise undocumented.

Out of scope: @mngr's remaining product-direction asks (#2#5: dashboard examples, propagate_filters_to_params, per-row params resolution, canonical dashboards) — separate conversation.

Not done: yarn tsc / yarn test weren't run locally — relying on CI for compile/test regressions.

· branch ·

Comment thread packages/cubejs-schema-compiler/src/compiler/CubeSymbols.ts Outdated
Dashboard stays as a plain static identifier string with automatic
/dashboard/ prefix. For dynamic links that need dimension references,
use the url field instead.

Co-authored-by: Pavel Tiunov <pavel.tiunov@gmail.com>
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Jun 1, 2026

Claude finished @cursor[bot]'s task in 1m 44s —— View job


Review of 6424a11 — no new findings; resolves the CubeSymbols dynamic-branch thread

0 new; 1 prior thread resolved; prior High on `CubeValidator.ts:318` re-affirmed — details
  • List existing review threads
  • Read changed files at HEAD
  • Verify which prior threads are affected
  • Resolve thread no longer applicable
  • Post summary

6424a11 change: clean revert of 8a45cbc's dynamic-dashboard feature. Three parts:

  1. CubeValidator.tsdashboard removed from nonStringFields, so YAML-side string templating goes back through the Python transpiler path.
  2. YamlCompiler.ts — restores the original else if (typeof obj === 'string') shape (template through Python unless in nonStringFields).
  3. CubeSymbols.ts:660-663 — collapses the regex-driven splitter back to the single-line new Function(cube.name, \return \`'/dashboard/${dashboardId}'\``)form. The fixture'sdynamic_dashlink and its smoke test are removed;links.length` assertion drops 5 → 4.

Commit message points users to the url: field for dynamic links going forward, which is the right call given the ${...} injection issues raised on the dynamic branch. Nothing to comment on for this commit specifically.

Resolved thread:

  • CubeSymbols.ts High — the ${...} / backtick exploit on the new dynamic branch (PRRT_kwDOCOH19M6GQNqC). The dynamic-branch code is gone in this revert, so that thread's primary concern (the 8a45cbc-introduced second exploit site) and the /dashboard/ prefix inconsistency are both moot. The underlying static-branch concern is fully captured by the still-open CubeValidator.ts:318 thread.

Still-open prior threads (re-affirmed, not re-posted):

  • HighCubeValidator.ts:318 dashboard: Joi.string() is unconstrained; CubeSymbols.ts:663 still splices it raw into a new Function template literal. dashboard: "${process.exit(1)}" still executes at compile time; dashboard: "foo\bar"still escapes the outer template literal. The revert restored the simpler shape but didn't restore the identifier regex. Easiest fix remains:dashboard: identifier` in the validator.
  • MediumCubeSymbols.ts (formerly CubeEvaluator e9c9c95-era thread): non-identity params shapes ({users.city}, {FILTER_PARAMS.*}) only fully work for identity-form refs end-to-end — partially mitigated by 203ab9e's switch to invoking p.valueFn(...) with resolver-bound args, but the original concern about non-identity shapes remains.
  • MinorCubeToMetaTransformer.ts LinkConfig vs LinkDefinition duplication.
  • links.test.ts:478FILTER_PARAMS in params and literal-string-plus-dim-ref shapes inside url: still uncovered at unit-test level.
  • igorlukanin's public-inheritance thread — superseded but left open by the human reviewer.
  • Docs gap from e95c802: primary flag still undocumented on either docs site.

Out of scope: @mngr's remaining product-direction asks (#2#5: dashboard examples, propagate_filters_to_params, per-row params resolution, canonical dashboards) — separate conversation.

Not done: yarn tsc / yarn test weren't run locally — relying on CI for compile/test regressions.

· branch ·

Co-authored-by: Pavel Tiunov <pavel.tiunov@gmail.com>
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Jun 1, 2026

Claude finished @cursor[bot]'s task in 2m 10s —— View job


Review of 84102b0 — no new findings; partial fix to the still-open High dashboard thread

0 new; 1 prior High partially mitigated; 4 prior threads still apply — details
  • List existing review threads
  • Read changed files at HEAD
  • Verify against open threads
  • Post summary

84102b0 change: two-line edit in CubeSymbols.ts:660-664. (1) Drops the now-unused cube.name arg from new Function, making baseSql zero-arg — consistent with how buildLinkSqlWithParams extracts funcArguments(baseSql) and invokes it via (baseSql)(...baseSqlArgs). Clean. (2) Adds .replace(/'/g, "''") on dashboardId before splicing it into the new Function template-literal source.

Traced the escape against the still-open High thread (PRRT_kwDOCOH19M6F-vr5 on CubeValidator.ts:318):

  • dashboard: "foo'bar" — now safe (single quote becomes '', valid SQL).
  • dashboard: "${process.exit(1)}" — emitted JS source becomes return `'/dashboard/${process.exit(1)}'` ; process.exit fires when baseSql() is invoked at compile time. The ' escape doesn't touch ${...}.
  • dashboard: "foo`bar" — backtick closes the outer template literal in the new Function source; SyntaxError at compile.
  • dashboard: "foo\\bar" — backslash escape inside the template-literal source can still introduce surprises.

So the partial fix closes one of the four characters the prior thread called out — but the underlying Joi.string() shape + new Function template-literal splice still has two injection paths and one broken-SQL path. The fix from that thread remains: restore identifier regex on dashboard in CubeValidator.ts:318, or emit the SQL via plain string concat ('/dashboard/' || <quoted-id>) instead of building a function source. No new inline comment posted — the existing thread already covers the residual issue.

Still-open prior threads (re-affirmed, not re-posted):

  • HighCubeValidator.ts:318 dashboard: Joi.string() injection vector. Partially mitigated for '; ${...} and backtick still injectable.
  • MediumCubeEvaluator.ts (now in CubeSymbols.ts:716+) — non-identity params shapes ({users.city}, {FILTER_PARAMS.*}). The 203ab9e rewrite (now in buildLinkSqlWithParams) does invoke p.valueFn(...) with resolver-bound args, which closes the cross-cube {other_cube.dim} case (verified by a3c561d's smoke test). The FILTER_PARAMS case remains uncovered by tests, so I'm leaving the thread open in spirit until there's an end-to-end exercise.
  • MinorCubeToMetaTransformer.ts LinkConfig vs LinkDefinition duplication.
  • links.test.ts:478FILTER_PARAMS in params and literal-string-plus-dim-ref shapes inside url: still uncovered at unit-test level.
  • igorlukanin's public-inheritance thread — superseded by ced751f but left open by the human reviewer.
  • Docs gap from e95c802: primary flag still undocumented on either docs site.

Out of scope: @mngr's remaining product-direction asks (#2#5: dashboard examples, propagate_filters_to_params, per-row params resolution, canonical dashboards) — separate conversation.

Not done: yarn tsc / yarn test weren't run locally — relying on CI for compile/test regressions.

· branch ·

@paveltiunov paveltiunov merged commit 34fa717 into master Jun 2, 2026
118 of 120 checks passed
@paveltiunov paveltiunov deleted the cursor/feat-links-documentation-638d branch June 2, 2026 04:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cubejs-jdbc-driver data source driver driver:databricks javascript Pull requests that update Javascript code rust Pull requests that update Rust code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants