From b81b24ebcc54ea5b769a2d4dc285e1fa924b7a10 Mon Sep 17 00:00:00 2001 From: Kevin Delemme Date: Thu, 5 Oct 2023 09:17:32 -0400 Subject: [PATCH] fix(slo): handle permission error (#167933) (cherry picked from commit 335fc9b2409855f4aeebf360c0747141b2fcf03b) --- .../public/hooks/slo/use_clone_slo.ts | 16 ++++++++++------ .../public/hooks/slo/use_create_slo.ts | 7 +++++-- .../public/hooks/slo/use_delete_slo.ts | 15 +++++++++------ .../public/hooks/slo/use_update_slo.ts | 7 +++++-- .../observability/server/errors/errors.ts | 2 ++ .../observability/server/errors/handler.ts | 5 +++++ .../server/services/slo/transform_manager.ts | 5 +++++ 7 files changed, 41 insertions(+), 16 deletions(-) diff --git a/x-pack/plugins/observability/public/hooks/slo/use_clone_slo.ts b/x-pack/plugins/observability/public/hooks/slo/use_clone_slo.ts index 08a3c0520ca18..ac7f1ce0659f5 100644 --- a/x-pack/plugins/observability/public/hooks/slo/use_clone_slo.ts +++ b/x-pack/plugins/observability/public/hooks/slo/use_clone_slo.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { IHttpFetchError, ResponseErrorBody } from '@kbn/core/public'; import { i18n } from '@kbn/i18n'; import type { CreateSLOInput, CreateSLOResponse, FindSLOResponse } from '@kbn/slo-schema'; import { QueryKey, useMutation, useQueryClient } from '@tanstack/react-query'; @@ -12,6 +13,8 @@ import { v1 as uuidv1 } from 'uuid'; import { useKibana } from '../../utils/kibana_react'; import { sloKeys } from './query_key_factory'; +type ServerError = IHttpFetchError; + export function useCloneSlo() { const { http, @@ -21,7 +24,7 @@ export function useCloneSlo() { return useMutation< CreateSLOResponse, - string, + ServerError, { slo: CreateSLOInput; originalSloId?: string }, { previousData?: FindSLOResponse; queryKey?: QueryKey } >( @@ -58,16 +61,17 @@ export function useCloneSlo() { return { queryKey, previousData }; }, // If the mutation fails, use the context returned from onMutate to roll back - onError: (_err, { slo }, context) => { + onError: (error, { slo }, context) => { if (context?.previousData && context?.queryKey) { queryClient.setQueryData(context.queryKey, context.previousData); } - toasts.addDanger( - i18n.translate('xpack.observability.slo.clone.errorNotification', { + + toasts.addError(new Error(error.body?.message ?? error.message), { + title: i18n.translate('xpack.observability.slo.clone.errorNotification', { defaultMessage: 'Failed to clone {name}', values: { name: slo.name }, - }) - ); + }), + }); }, onSuccess: (_data, { slo }) => { toasts.addSuccess( diff --git a/x-pack/plugins/observability/public/hooks/slo/use_create_slo.ts b/x-pack/plugins/observability/public/hooks/slo/use_create_slo.ts index ca2a0435b741f..a1a79d51f5af5 100644 --- a/x-pack/plugins/observability/public/hooks/slo/use_create_slo.ts +++ b/x-pack/plugins/observability/public/hooks/slo/use_create_slo.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { IHttpFetchError, ResponseErrorBody } from '@kbn/core/public'; import { i18n } from '@kbn/i18n'; import { encode } from '@kbn/rison'; import type { CreateSLOInput, CreateSLOResponse, FindSLOResponse } from '@kbn/slo-schema'; @@ -14,6 +15,8 @@ import { paths } from '../../../common/locators/paths'; import { useKibana } from '../../utils/kibana_react'; import { sloKeys } from './query_key_factory'; +type ServerError = IHttpFetchError; + export function useCreateSlo() { const { application: { navigateToUrl }, @@ -24,7 +27,7 @@ export function useCreateSlo() { return useMutation< CreateSLOResponse, - string, + ServerError, { slo: CreateSLOInput }, { previousData?: FindSLOResponse; queryKey?: QueryKey } >( @@ -72,7 +75,7 @@ export function useCreateSlo() { queryClient.setQueryData(context.queryKey, context.previousData); } - toasts.addError(new Error(String(error)), { + toasts.addError(new Error(error.body?.message ?? error.message), { title: i18n.translate('xpack.observability.slo.create.errorNotification', { defaultMessage: 'Something went wrong while creating {name}', values: { name: slo.name }, diff --git a/x-pack/plugins/observability/public/hooks/slo/use_delete_slo.ts b/x-pack/plugins/observability/public/hooks/slo/use_delete_slo.ts index 6857609500f92..0ba0c93266bda 100644 --- a/x-pack/plugins/observability/public/hooks/slo/use_delete_slo.ts +++ b/x-pack/plugins/observability/public/hooks/slo/use_delete_slo.ts @@ -8,9 +8,12 @@ import { QueryKey, useMutation, useQueryClient } from '@tanstack/react-query'; import { i18n } from '@kbn/i18n'; import { FindSLOResponse } from '@kbn/slo-schema'; +import { IHttpFetchError, ResponseErrorBody } from '@kbn/core/public'; import { useKibana } from '../../utils/kibana_react'; import { sloKeys } from './query_key_factory'; +type ServerError = IHttpFetchError; + export function useDeleteSlo() { const { http, @@ -20,7 +23,7 @@ export function useDeleteSlo() { return useMutation< string, - string, + ServerError, { id: string; name: string }, { previousData?: FindSLOResponse; queryKey?: QueryKey } >( @@ -60,17 +63,17 @@ export function useDeleteSlo() { return { previousData, queryKey }; }, // If the mutation fails, use the context returned from onMutate to roll back - onError: (_err, { name }, context) => { + onError: (error, { name }, context) => { if (context?.previousData && context?.queryKey) { queryClient.setQueryData(context.queryKey, context.previousData); } - toasts.addDanger( - i18n.translate('xpack.observability.slo.slo.delete.errorNotification', { + toasts.addError(new Error(error.body?.message ?? error.message), { + title: i18n.translate('xpack.observability.slo.slo.delete.errorNotification', { defaultMessage: 'Failed to delete {name}', values: { name }, - }) - ); + }), + }); }, onSuccess: (_data, { name }) => { toasts.addSuccess( diff --git a/x-pack/plugins/observability/public/hooks/slo/use_update_slo.ts b/x-pack/plugins/observability/public/hooks/slo/use_update_slo.ts index c158fa3f31f5e..07f6991b9e82b 100644 --- a/x-pack/plugins/observability/public/hooks/slo/use_update_slo.ts +++ b/x-pack/plugins/observability/public/hooks/slo/use_update_slo.ts @@ -5,12 +5,15 @@ * 2.0. */ +import { IHttpFetchError, ResponseErrorBody } from '@kbn/core/public'; import { i18n } from '@kbn/i18n'; import type { FindSLOResponse, UpdateSLOInput, UpdateSLOResponse } from '@kbn/slo-schema'; import { QueryKey, useMutation, useQueryClient } from '@tanstack/react-query'; import { useKibana } from '../../utils/kibana_react'; import { sloKeys } from './query_key_factory'; +type ServerError = IHttpFetchError; + export function useUpdateSlo() { const { http, @@ -20,7 +23,7 @@ export function useUpdateSlo() { return useMutation< UpdateSLOResponse, - string, + ServerError, { sloId: string; slo: UpdateSLOInput }, { previousData?: FindSLOResponse; queryKey?: QueryKey } >( @@ -69,7 +72,7 @@ export function useUpdateSlo() { queryClient.setQueryData(context.queryKey, context.previousData); } - toasts.addError(new Error(String(error)), { + toasts.addError(new Error(error.body?.message ?? error.message), { title: i18n.translate('xpack.observability.slo.update.errorNotification', { defaultMessage: 'Something went wrong when updating {name}', values: { name }, diff --git a/x-pack/plugins/observability/server/errors/errors.ts b/x-pack/plugins/observability/server/errors/errors.ts index dbbb873925636..cbecb88d9ce05 100644 --- a/x-pack/plugins/observability/server/errors/errors.ts +++ b/x-pack/plugins/observability/server/errors/errors.ts @@ -25,3 +25,5 @@ export class InternalQueryError extends ObservabilityError {} export class NotSupportedError extends ObservabilityError {} export class IllegalArgumentError extends ObservabilityError {} export class InvalidTransformError extends ObservabilityError {} + +export class SecurityException extends ObservabilityError {} diff --git a/x-pack/plugins/observability/server/errors/handler.ts b/x-pack/plugins/observability/server/errors/handler.ts index 943983439ca60..2898e53624832 100644 --- a/x-pack/plugins/observability/server/errors/handler.ts +++ b/x-pack/plugins/observability/server/errors/handler.ts @@ -9,6 +9,7 @@ import { CompositeSLOIdConflict, CompositeSLONotFound, ObservabilityError, + SecurityException, SLOIdConflict, SLONotFound, } from './errors'; @@ -22,5 +23,9 @@ export function getHTTPResponseCode(error: ObservabilityError): number { return 409; } + if (error instanceof SecurityException) { + return 403; + } + return 400; } diff --git a/x-pack/plugins/observability/server/services/slo/transform_manager.ts b/x-pack/plugins/observability/server/services/slo/transform_manager.ts index e195b683e1892..ed35512c03b65 100644 --- a/x-pack/plugins/observability/server/services/slo/transform_manager.ts +++ b/x-pack/plugins/observability/server/services/slo/transform_manager.ts @@ -8,6 +8,7 @@ import { ElasticsearchClient, Logger } from '@kbn/core/server'; import { SLO, IndicatorTypes } from '../../domain/models'; +import { SecurityException } from '../../errors'; import { retryTransientEsErrors } from '../../utils/retry'; import { TransformGenerator } from './transform_generators'; @@ -42,6 +43,10 @@ export class DefaultTransformManager implements TransformManager { }); } catch (err) { this.logger.error(`Cannot create SLO transform for indicator type [${slo.indicator.type}]`); + if (err.meta?.body?.error?.type === 'security_exception') { + throw new SecurityException(err.meta.body.error.reason); + } + throw err; }