Files
Pavel Tiunov c95317be96 fix: cached GraphQL schema can result in missing members if used with access policies (#10590)
* fix(api-gateway): cache unfiltered GraphQL schema with RBAC enforced at query time

Instead of adding JS-side member validation for GraphQL RBAC enforcement,
rely on the existing Rust-side validation in query_result_transform.rs.

The Rust transform layer already checks if requested members are present
in the RBAC-filtered annotation map and throws 'You requested hidden member'
errors for inaccessible members.

Changes:
- Build GraphQL schema from unfiltered metadata (skipVisibilityPatch) so it
  can be safely cached across security contexts sharing a CompilerApi
- Add skipVisibilityPatch option to CompilerApi.metaConfig() to bypass
  RBAC visibility patching when building the shared GraphQL schema
- Add integration test verifying RBAC enforcement through GraphQL

Co-authored-by: Pavel Tiunov <pavel.tiunov@gmail.com>

* ci: add smoke:rbac-graphql test to CI pipeline

Add the new RBAC GraphQL integration test to:
- packages/cubejs-testing/package.json as smoke:rbac-graphql script
- .github/actions/smoke.sh to run in integration-smoke CI job

Co-authored-by: Pavel Tiunov <pavel.tiunov@gmail.com>

* fix(cubeorchestrator): validate query members against annotation even with empty results

When RBAC denies access to a member, the query gets a '1=0' filter that
returns zero rows. Previously, the Rust get_members() function would
short-circuit on empty columns (derived from zero rows) without checking
if the requested members were actually accessible.

Now validate_query_members_in_annotation() checks the query's measures,
dimensions, segments, and time dimensions against the annotation map
even when db_data.columns is empty. This ensures 'You requested hidden
member' errors are returned for RBAC-denied members regardless of
whether the query returns data.

Also adds a test for the hidden member + empty dataset scenario.

Co-authored-by: Pavel Tiunov <pavel.tiunov@gmail.com>

* fix(cubeorchestrator): exclude segments from empty-result member validation

Segments are not included in the annotation map (which only contains
measures, dimensions, and time dimensions). The rlsAccessDenied
synthetic segment added by RBAC denial would incorrectly trigger the
hidden member error when validated against the annotation.

Co-authored-by: Pavel Tiunov <pavel.tiunov@gmail.com>

* test(testing): update smoke-rbac tests for hidden member error behavior

Now that the Rust transform validates query members against the annotation
even with empty results, RBAC-denied members return 'You requested hidden
member' errors instead of silently returning empty data.

Updated tests:
- line_items hidden price_dim: expect error instead of empty result
- orders_view and cube with default policy: expect error for orders_view.count
  when user has no matching access policy on the view

Co-authored-by: Pavel Tiunov <pavel.tiunov@gmail.com>

* test(testing): remove obsolete orders_view_rest snapshot

The orders_view_rest snapshot is no longer used after updating the test
to expect a hidden member error instead of empty results.

Co-authored-by: Pavel Tiunov <pavel.tiunov@gmail.com>

* refactor(cubeorchestrator): extract ensure_member_in_annotation to deduplicate hidden member checks

The hidden member error was duplicated in three places:
- get_members (column-based check for non-empty results)
- get_vanilla_row (per-row alias check)
- validate_query_members_in_annotation (query member check for empty results)

Extract ensure_member_in_annotation() and use it in all three places.

Co-authored-by: Pavel Tiunov <pavel.tiunov@gmail.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
2026-03-31 20:37:03 -07:00
..