Skip to content

Add opt-in config to allow read-only users to access Discover and Visualize#2416

Open
seanthegeek wants to merge 4 commits into
opensearch-project:mainfrom
seanthegeek:feature/readonly-discover-opt-in
Open

Add opt-in config to allow read-only users to access Discover and Visualize#2416
seanthegeek wants to merge 4 commits into
opensearch-project:mainfrom
seanthegeek:feature/readonly-discover-opt-in

Conversation

@seanthegeek

@seanthegeek seanthegeek commented Apr 21, 2026

Copy link
Copy Markdown
Contributor

Description

Adds two new opt-in configuration options (both defaulting to false) that extend the read-only app allowlist with apps that are natural fits for a read-only audience:

  • opensearch_security.readonly_mode.allow_discover — when enabled, adds Discover to the read-only allowlist.
  • opensearch_security.readonly_mode.allow_visualize — when enabled, adds Visualize to the read-only allowlist.

Default behavior is unchanged — read-only users continue to be blocked from both apps unless an operator explicitly opts in. The flags are independent.

Because modern OSD hosts Discover inside the data-explorer app at /app/data-explorer/discover while the legacy discover app is still registered as a thin redirect shim, the Discover allowlist extension covers both ids. Visualize has no such shim and only requires its single visualize app id. The reasoning for the Discover/data-explorer pairing is documented inline at the declaration site so a future reader doesn't try to consolidate them.

Category

Enhancement

Why these changes are required?

Discover and Visualize are view-oriented applications that align naturally with the semantics of the read-only role. Discover exposes saved-search and ad-hoc query views; Visualize exposes saved-visualization views. Operators running read-only tenants for analyst or client-facing use cases currently have no supported way to expose either app to those users, even though doing so does not grant any write capability — the saved-object write paths remain blocked by the OpenSearch role.

However, some existing deployments may rely on the current blocking behavior as a form of informal data isolation — keeping read-only users confined to curated dashboards rather than browsing indices or composing charts directly. Flipping this behavior by default would break those deployments. Each app is therefore gated behind an explicit opt-in flag so existing installations see zero behavior change on upgrade, and operators can opt into Discover, Visualize, both, or neither.

For operators who want real data confinement (not just UI hiding), the correct tool remains document-level and field-level security on the OpenSearch role — UI allowlisting has never been a security boundary. This PR does not change that; it only exposes a supported way to surface Discover and Visualize when it is appropriate.

What is the old behavior before changes and new behavior after changes?

Old behavior: Read-only users are always blocked from Discover and Visualize. Neither app appears in the navigation; direct URL access returns an "Application not found" error.

New behavior: Default is unchanged. Operators can opt in per-app in opensearch_dashboards.yml:

  • opensearch_security.readonly_mode.allow_discover: true adds both the discover and data-explorer app ids to the read-only allowlist. Users holding the read-only role can access Discover via the nav menu, /app/discover (legacy URL that redirects), and /app/data-explorer/discover (the modern URL).
  • opensearch_security.readonly_mode.allow_visualize: true adds the visualize app id to the read-only allowlist. Users holding the read-only role can access Visualize via the nav menu and /app/visualize.

All other read-only restrictions (no saved-object writes, no index management, etc.) remain enforced.

Issues Resolved

Enhancement follow-up to the UX improvements explored in #2415. Not a backport.

Testing

Unit tests. public/test/plugin.test.ts has a readonly app allowlist — opt-in flags describe block with parallel allow_discover flag and allow_visualize flag sub-blocks, plus a shared baseline check. Coverage:

  • allow_discover: flag unset → both discover and data-explorer blocked; flag false → both blocked; flag true → both allowed; flag true → other non-allowlisted apps (e.g. visualize, management) still blocked.
  • allow_visualize: flag unset → visualize blocked; flag false → blocked; flag true → allowed; flag true → other non-allowlisted apps (e.g. discover, data-explorer, management) still blocked.
  • Independence: allow_discover: true alone does not unblock Visualize; allow_visualize: true alone does not unblock Discover; both true together unblocks all three ids.
  • Baseline: home and dashboards are accessible across every combination of the two flags.

All 14 tests in plugin.test pass locally (yarn test:jest_ui --testPathPattern=plugin.test).

Manual testing. On a local docker-compose stack (OpenSearch + OpenSearch Dashboards 3.6.0, Security plugin built from this branch with temporary manifest retarget for local build since the 3.7.0 image is not yet published):

  • Created an internal user readonly_test mapped to kibana_read_only.
  • With both flags unset: nav "Discover" and "Visualize" entries absent; direct navigation to /app/data-explorer/discover, /app/discover, and /app/visualize all return "Application not found". ✅
  • With allow_discover: true, allow_visualize: false: Discover accessible (nav + both URLs); Visualize still blocked. ✅
  • With allow_discover: false, allow_visualize: true: Visualize accessible (nav + /app/visualize); Discover still blocked. ✅
  • With both flags true: both apps accessible; queries against sample indices return data in Discover; saved visualizations load in Visualize; Save controls on saved searches and saved visualizations are disabled. ✅
  • Confirmed Stack Management and Dev Tools remain blocked in every combination.

Check List

  • New functionality includes testing
  • New functionality has been documented
  • Commits are signed per the DCO using --signoff

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.

Adds opensearch_security.readonly_mode.allow_discover (default false).
When enabled, Discover is added to the read-only app allowlist so
operators can surface it to users mapped to the read-only role. Default
behavior is unchanged; existing deployments that rely on the current
blocking behavior as informal data isolation see no change on upgrade.

- server/index.ts: extend readonly_mode config schema with the flag.
- public/types.ts: expose allow_discover on ClientConfigType.
- public/plugin.ts: compute the readonly app allowlist from the flag.
- public/test/plugin.test.ts: cover both states of the flag.
- DEVELOPER_GUIDE.md: document the new option near readonly_mode.roles.

Signed-off-by: Sean Whalen <seanthegeek@users.noreply.github.com>
Importing AppStatus from src/core/public pulls monaco-editor into the
test at module-load time, which crashes under jsdom before any test
runs. Assert on the shape of the updater's return value instead, so the
test only needs the mocks module.

Signed-off-by: Sean Whalen <seanthegeek@users.noreply.github.com>
Modern OSD hosts Discover inside the data-explorer app at
/app/data-explorer/discover. The legacy `discover` app is still
registered but only as a thin shim that client-side redirects to
data-explorer. The AppUpdater status check runs before mount, so
blocking either id produces a broken UX for read-only users even with
allow_discover: true — "Application not found" on the legacy URL, or a
dead nav-menu "Discover" entry (the nav link references `discover`, not
`data-explorer`). Allowlist both together and document the reasoning.

Also avoid importing AppStatus from src/core/public in the test; that
pulls in monaco-editor which crashes under jsdom at module-load time.
Assert on the shape of the updater's return value instead.

Signed-off-by: Sean Whalen <seanthegeek@users.noreply.github.com>
@cwperks

cwperks commented Apr 21, 2026

Copy link
Copy Markdown
Member

Thank you @seanthegeek. This really underscores the need for better tools for admins to select what different sets of users can see in the menus. I'm not opposed to adding a new setting in the interim while better organizational tools are built for admins.

@seanthegeek

Copy link
Copy Markdown
Contributor Author

@cwperks Agreed, and to ensure that other applications only show what a user has access to do. For example, "add data", "manage", "dev tools", "app directory". So users don't end up with "application not found" errors.

Mirrors the existing opensearch_security.readonly_mode.allow_discover
flag with opensearch_security.readonly_mode.allow_visualize (default
false). When enabled, the Visualize app id is added to the read-only
app allowlist so operators can surface it to users mapped to the
read-only role. Default behavior is unchanged; existing deployments
that rely on the current blocking behavior see no change on upgrade.

Unlike Discover, Visualize is registered under a single app id, so
only `visualize` needs to be allowlisted — no second shim id the way
`data-explorer` shadows `discover`.

- server/index.ts: extend readonly_mode config schema with the flag.
- public/types.ts: expose allow_visualize on ClientConfigType.
- public/plugin.ts: reshape the allowlist as a spread so each opt-in
  flag contributes independently without nested conditionals.
- public/test/plugin.test.ts: add a parallel describe block for the
  flag (unset/false/true, independence from allow_discover, combined
  both-flags-true case); also fix runAndGetUpdater to read the
  current setup's BehaviorSubject rather than the first one, which
  matters once a test calls it more than once.
- DEVELOPER_GUIDE.md: document the new option alongside allow_discover.

Signed-off-by: Sean Whalen <seanthegeek@users.noreply.github.com>
@seanthegeek seanthegeek changed the title Add opt-in config to allow read-only users to access Discover Add opt-in config to allow read-only users to access Discover and Visualize Apr 24, 2026
@codecov

codecov Bot commented Apr 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 71.69%. Comparing base (7088895) to head (8642359).
⚠️ Report is 4 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2416      +/-   ##
==========================================
+ Coverage   71.59%   71.69%   +0.09%     
==========================================
  Files         101      101              
  Lines        3010     3017       +7     
  Branches      511      531      +20     
==========================================
+ Hits         2155     2163       +8     
  Misses        699      699              
+ Partials      156      155       -1     

☔ 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.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants