Skip to content

Commit

Permalink
[Logs Explorer] Fix privilege checks bug (elastic#198368)
Browse files Browse the repository at this point in the history
## Summary

This PR enhances the privilege checks for Logs Explorer side nav
visibility.
  • Loading branch information
mohamedhamed-ahmed authored Oct 31, 2024
1 parent 750452e commit 76ccc9c
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,19 @@
*/

import { History } from 'history';
import { CoreStart } from '@kbn/core/public';
import React from 'react';
import { AppStatus, CoreStart } from '@kbn/core/public';
import React, { useMemo } from 'react';
import ReactDOM from 'react-dom';
import { Router, Routes, Route } from '@kbn/shared-ux-router';
import { AppMountParameters } from '@kbn/core/public';
import { Storage } from '@kbn/kibana-utils-plugin/public';
import { AllDatasetsLocatorParams, ALL_DATASETS_LOCATOR_ID } from '@kbn/deeplinks-observability';
import {
AllDatasetsLocatorParams,
ALL_DATASETS_LOCATOR_ID,
OBSERVABILITY_LOGS_EXPLORER_APP_ID,
} from '@kbn/deeplinks-observability';
import useObservable from 'react-use/lib/useObservable';
import { map } from 'rxjs';
import { LinkToLogsPage } from '../pages/link_to/link_to_logs';
import { LogsPage } from '../pages/logs';
import { InfraClientStartDeps, InfraClientStartExports } from '../types';
Expand Down Expand Up @@ -57,7 +63,22 @@ const LogsApp: React.FC<{
storage: Storage;
theme$: AppMountParameters['theme$'];
}> = ({ core, history, pluginStart, plugins, setHeaderActionMenu, storage, theme$ }) => {
const { logs, discover, fleet } = core.application.capabilities;
const { logs } = core.application.capabilities;

const isLogsExplorerAppAccessible = useObservable(
useMemo(
() =>
core.application.applications$.pipe(
map(
(apps) =>
(apps.get(OBSERVABILITY_LOGS_EXPLORER_APP_ID)?.status ?? AppStatus.inaccessible) ===
AppStatus.accessible
)
),
[core.application.applications$]
),
false
);

return (
<CoreProviders core={core} pluginStart={pluginStart} plugins={plugins} theme$={theme$}>
Expand All @@ -74,7 +95,7 @@ const LogsApp: React.FC<{
toastsService={core.notifications.toasts}
>
<Routes>
{Boolean(discover?.show && fleet?.read) && (
{isLogsExplorerAppAccessible && (
<Route
path="/"
exact
Expand Down
73 changes: 39 additions & 34 deletions x-pack/plugins/observability_solution/infra/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,15 @@ import {
MetricsExplorerLocatorParams,
ObservabilityTriggerId,
} from '@kbn/observability-shared-plugin/common';
import { BehaviorSubject, combineLatest, from } from 'rxjs';
import { map } from 'rxjs';
import {
BehaviorSubject,
combineLatest,
distinctUntilChanged,
from,
of,
switchMap,
map,
} from 'rxjs';
import type { EmbeddableApiContext } from '@kbn/presentation-publishing';
import { apiCanAddNewPanel } from '@kbn/presentation-containers';
import { IncompatibleActionError, ADD_PANEL_TRIGGER } from '@kbn/ui-actions-plugin/public';
Expand Down Expand Up @@ -132,14 +139,18 @@ export class Plugin implements InfraClientPluginClass {
messageFields: this.config.sources?.default?.fields?.message,
});

const startDep$AndHostViewFlag$ = combineLatest([from(core.getStartServices())]);
const startDep$AndAccessibleFlag$ = from(core.getStartServices()).pipe(
switchMap(([{ application }]) =>
combineLatest([of(application), getLogsExplorerAccessible$(application)])
)
);

const logRoutes = getLogsAppRoutes({ isLogsStreamEnabled });

/** !! Need to be kept in sync with the deepLinks in x-pack/plugins/observability_solution/infra/public/plugin.ts */
pluginsSetup.observabilityShared.navigation.registerSections(
startDep$AndHostViewFlag$.pipe(
map(([[{ application }]]) => {
startDep$AndAccessibleFlag$.pipe(
map(([application, isLogsExplorerAccessible]) => {
const { infrastructure, logs } = application.capabilities;
return [
...(logs.show
Expand All @@ -148,7 +159,7 @@ export class Plugin implements InfraClientPluginClass {
label: logsTitle,
sortKey: 200,
entries: getLogsNavigationEntries({
application,
isLogsExplorerAccessible,
config: this.config,
routes: logRoutes,
}),
Expand Down Expand Up @@ -310,16 +321,13 @@ export class Plugin implements InfraClientPluginClass {
);
},
});

startDep$AndHostViewFlag$.subscribe(
([_startServices]: [[CoreStart, InfraClientStartDeps, InfraClientStartExports]]) => {
this.appUpdater$.next(() => ({
deepLinks: getInfraDeepLinks({
metricsExplorerEnabled: this.config.featureFlags.metricsExplorerEnabled,
}),
}));
}
);
startDep$AndAccessibleFlag$.subscribe(([_applicationStart, _isLogsExplorerAccessible]) => {
this.appUpdater$.next(() => ({
deepLinks: getInfraDeepLinks({
metricsExplorerEnabled: this.config.featureFlags.metricsExplorerEnabled,
}),
}));
});

// Setup telemetry events
this.telemetry.setup({ analytics: core.analytics });
Expand Down Expand Up @@ -382,28 +390,26 @@ export class Plugin implements InfraClientPluginClass {
}

const getLogsNavigationEntries = ({
application,
isLogsExplorerAccessible,
config,
routes,
}: {
application: CoreStart['application'];
isLogsExplorerAccessible: boolean;
config: InfraPublicConfig;
routes: LogsAppRoutes;
}) => {
const entries: NavigationEntry[] = [];

if (!config.featureFlags.logsUIEnabled) return entries;

getLogsExplorerAccessibility$(application).subscribe((isAccessible) => {
if (isAccessible) {
entries.push({
label: 'Explorer',
app: 'observability-logs-explorer',
path: '/',
isBetaFeature: true,
});
}
});
if (isLogsExplorerAccessible) {
entries.push({
label: 'Explorer',
app: 'observability-logs-explorer',
path: '/',
isBetaFeature: true,
});
}

// Display Stream nav entry when Logs Stream is enabled
if (routes.stream) entries.push(createNavEntryFromRoute(routes.stream));
Expand All @@ -416,16 +422,15 @@ const getLogsNavigationEntries = ({
return entries;
};

const getLogsExplorerAccessibility$ = (application: CoreStart['application']) => {
const { capabilities, applications$ } = application;
const getLogsExplorerAccessible$ = (application: CoreStart['application']) => {
const { applications$ } = application;
return applications$.pipe(
map(
(apps) =>
(apps.get(OBSERVABILITY_LOGS_EXPLORER_APP_ID)?.status ?? AppStatus.inaccessible) ===
AppStatus.accessible &&
capabilities.discover?.show &&
capabilities.fleet?.read
)
AppStatus.accessible
),
distinctUntilChanged()
);
};

Expand Down

0 comments on commit 76ccc9c

Please sign in to comment.