mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[Entity Analytics] Remove nested message.message
property from risk engine API error responses (#170645)
## Summary **TLDR:** change risk engine API error response bodies from `{ message : { message : 'blah', full_error : 'something'}}` to `{ message : 'blah', full_error : 'something'}` I noticed a UI bug when the risk engine "init" call returns an error, this was because the UI was expecting `error.message` to be a string but it was an object with another nested message property. This lead me to investigate why this was the case, turns out our error wrapper was always putting things under a `message` key which in our case we do not want. ### UI crash before ``` Uncaught Error: Objects are not valid as a React child (found: object with keys {message}). If you meant to render a collection of children, use an array instead. ``` <img width="806" alt="Screenshot 2023-11-06 at 14 02 17" src="25066a14
-dabf-46a0-9741-a81f886f64fb"> ### Correct error display after <img width="1171" alt="Screenshot 2023-11-06 at 13 51 04" src="af8db564
-a119-4fc8-9821-bafcfe19b421"> ### Checklist Delete any items that are not applicable to this PR. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios
This commit is contained in:
parent
5fab32d28f
commit
71f1dc7bd5
12 changed files with 51 additions and 40 deletions
|
@ -49,7 +49,7 @@ export class SiemResponseFactory {
|
|||
constructor(private response: KibanaResponseFactory) {}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||
error<T>({ statusCode, body, headers }: CustomHttpResponseOptions<T>) {
|
||||
error<T>({ statusCode, body, headers, bypassErrorFormat }: CustomHttpResponseOptions<T>) {
|
||||
// KibanaResponse is not exported so we cannot use a return type here and that is why the linter is turned off above
|
||||
const contentType: CustomHttpResponseOptions<T>['headers'] = {
|
||||
'content-type': 'application/json',
|
||||
|
@ -59,10 +59,14 @@ export class SiemResponseFactory {
|
|||
...(headers ?? {}),
|
||||
};
|
||||
|
||||
const formattedBody = bypassErrorFormat
|
||||
? body
|
||||
: { message: body ?? statusToErrorMessage(statusCode) };
|
||||
|
||||
return this.response.custom({
|
||||
body: Buffer.from(
|
||||
JSON.stringify({
|
||||
message: body ?? statusToErrorMessage(statusCode),
|
||||
...formattedBody,
|
||||
status_code: statusCode,
|
||||
})
|
||||
),
|
||||
|
|
|
@ -235,11 +235,11 @@ export const RiskScoreEnableSection = () => {
|
|||
let initRiskEngineErrors: string[] = [];
|
||||
|
||||
if (initRiskEngineMutation.isError) {
|
||||
const errorBody = initRiskEngineMutation.error.body.message;
|
||||
const errorBody = initRiskEngineMutation.error.body;
|
||||
if (errorBody?.full_error?.errors) {
|
||||
initRiskEngineErrors = errorBody.full_error?.errors;
|
||||
} else {
|
||||
initRiskEngineErrors = [errorBody];
|
||||
initRiskEngineErrors = [errorBody.message];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -266,10 +266,10 @@ export const RiskScoreEnableSection = () => {
|
|||
</EuiTitle>
|
||||
{initRiskEngineMutation.isError && <RiskScoreErrorPanel errors={initRiskEngineErrors} />}
|
||||
{disableRiskEngineMutation.isError && (
|
||||
<RiskScoreErrorPanel errors={[disableRiskEngineMutation.error.body.message.message]} />
|
||||
<RiskScoreErrorPanel errors={[disableRiskEngineMutation.error.body.message]} />
|
||||
)}
|
||||
{enableRiskEngineMutation.isError && (
|
||||
<RiskScoreErrorPanel errors={[enableRiskEngineMutation.error.body.message.message]} />
|
||||
<RiskScoreErrorPanel errors={[enableRiskEngineMutation.error.body.message]} />
|
||||
)}
|
||||
|
||||
<EuiSpacer size="m" />
|
||||
|
|
|
@ -16,7 +16,7 @@ import {
|
|||
} from '../../detection_engine/routes/__mocks__';
|
||||
import { riskEngineDataClientMock } from '../risk_engine_data_client.mock';
|
||||
|
||||
describe('risk score calculation route', () => {
|
||||
describe('risk score disable route', () => {
|
||||
let server: ReturnType<typeof serverMock.create>;
|
||||
let context: ReturnType<typeof requestContextMock.convertContext>;
|
||||
let mockTaskManagerStart: ReturnType<typeof taskManagerMock.createStart>;
|
||||
|
@ -78,7 +78,7 @@ describe('risk score calculation route', () => {
|
|||
const response = await server.inject(request, context);
|
||||
|
||||
expect(response.status).toEqual(500);
|
||||
expect(response.body.message.message).toEqual('something went wrong');
|
||||
expect(response.body.message).toEqual('something went wrong');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -94,10 +94,8 @@ describe('risk score calculation route', () => {
|
|||
|
||||
expect(response.status).toEqual(400);
|
||||
expect(response.body).toEqual({
|
||||
message: {
|
||||
message:
|
||||
'Task Manager is unavailable, but is required to disable the risk engine. Please enable the taskManager plugin and try again.',
|
||||
},
|
||||
message:
|
||||
'Task Manager is unavailable, but is required by the risk engine. Please enable the taskManager plugin and try again.',
|
||||
status_code: 400,
|
||||
});
|
||||
});
|
||||
|
|
|
@ -9,6 +9,7 @@ import type { StartServicesAccessor } from '@kbn/core/server';
|
|||
import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils';
|
||||
import { transformError } from '@kbn/securitysolution-es-utils';
|
||||
import { RISK_ENGINE_DISABLE_URL, APP_ID } from '../../../../common/constants';
|
||||
import { TASK_MANAGER_UNAVAILABLE_ERROR } from './translations';
|
||||
import type { StartPlugins } from '../../../plugin';
|
||||
import type { SecuritySolutionPluginRouter } from '../../../types';
|
||||
|
||||
|
@ -34,10 +35,7 @@ export const riskEngineDisableRoute = (
|
|||
if (!taskManager) {
|
||||
return siemResponse.error({
|
||||
statusCode: 400,
|
||||
body: {
|
||||
message:
|
||||
'Task Manager is unavailable, but is required to disable the risk engine. Please enable the taskManager plugin and try again.',
|
||||
},
|
||||
body: TASK_MANAGER_UNAVAILABLE_ERROR,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -50,6 +48,7 @@ export const riskEngineDisableRoute = (
|
|||
return siemResponse.error({
|
||||
statusCode: error.statusCode,
|
||||
body: { message: error.message, full_error: JSON.stringify(e) },
|
||||
bypassErrorFormat: true,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -16,7 +16,7 @@ import {
|
|||
} from '../../detection_engine/routes/__mocks__';
|
||||
import { riskEngineDataClientMock } from '../risk_engine_data_client.mock';
|
||||
|
||||
describe('risk score calculation route', () => {
|
||||
describe('risk score enable route', () => {
|
||||
let server: ReturnType<typeof serverMock.create>;
|
||||
let context: ReturnType<typeof requestContextMock.convertContext>;
|
||||
let mockTaskManagerStart: ReturnType<typeof taskManagerMock.createStart>;
|
||||
|
@ -78,7 +78,7 @@ describe('risk score calculation route', () => {
|
|||
const response = await server.inject(request, context);
|
||||
|
||||
expect(response.status).toEqual(500);
|
||||
expect(response.body.message.message).toEqual('something went wrong');
|
||||
expect(response.body.message).toEqual('something went wrong');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -94,10 +94,8 @@ describe('risk score calculation route', () => {
|
|||
|
||||
expect(response.status).toEqual(400);
|
||||
expect(response.body).toEqual({
|
||||
message: {
|
||||
message:
|
||||
'Task Manager is unavailable, but is required to enable the risk engine. Please enable the taskManager plugin and try again.',
|
||||
},
|
||||
message:
|
||||
'Task Manager is unavailable, but is required by the risk engine. Please enable the taskManager plugin and try again.',
|
||||
status_code: 400,
|
||||
});
|
||||
});
|
||||
|
|
|
@ -9,6 +9,7 @@ import type { StartServicesAccessor } from '@kbn/core/server';
|
|||
import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils';
|
||||
import { transformError } from '@kbn/securitysolution-es-utils';
|
||||
import { RISK_ENGINE_ENABLE_URL, APP_ID } from '../../../../common/constants';
|
||||
import { TASK_MANAGER_UNAVAILABLE_ERROR } from './translations';
|
||||
import type { StartPlugins } from '../../../plugin';
|
||||
import type { SecuritySolutionPluginRouter } from '../../../types';
|
||||
|
||||
|
@ -29,14 +30,10 @@ export const riskEngineEnableRoute = (
|
|||
const [_, { taskManager }] = await getStartServices();
|
||||
const securitySolution = await context.securitySolution;
|
||||
const riskEngineClient = securitySolution.getRiskEngineDataClient();
|
||||
|
||||
if (!taskManager) {
|
||||
return siemResponse.error({
|
||||
statusCode: 400,
|
||||
body: {
|
||||
message:
|
||||
'Task Manager is unavailable, but is required to enable the risk engine. Please enable the taskManager plugin and try again.',
|
||||
},
|
||||
body: TASK_MANAGER_UNAVAILABLE_ERROR,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -49,6 +46,7 @@ export const riskEngineEnableRoute = (
|
|||
return siemResponse.error({
|
||||
statusCode: error.statusCode,
|
||||
body: { message: error.message, full_error: JSON.stringify(e) },
|
||||
bypassErrorFormat: true,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -10,7 +10,7 @@ import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils';
|
|||
import { transformError } from '@kbn/securitysolution-es-utils';
|
||||
import { RISK_ENGINE_INIT_URL, APP_ID } from '../../../../common/constants';
|
||||
import type { StartPlugins } from '../../../plugin';
|
||||
|
||||
import { TASK_MANAGER_UNAVAILABLE_ERROR } from './translations';
|
||||
import type { SecuritySolutionPluginRouter } from '../../../types';
|
||||
|
||||
export const riskEngineInitRoute = (
|
||||
|
@ -36,10 +36,7 @@ export const riskEngineInitRoute = (
|
|||
if (!taskManager) {
|
||||
return siemResponse.error({
|
||||
statusCode: 400,
|
||||
body: {
|
||||
message:
|
||||
'Task Manager is unavailable, but is required to initialize the risk engine. Please enable the taskManager plugin and try again.',
|
||||
},
|
||||
body: TASK_MANAGER_UNAVAILABLE_ERROR,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -67,6 +64,7 @@ export const riskEngineInitRoute = (
|
|||
message: initResultResponse.errors.join('\n'),
|
||||
full_error: initResultResponse,
|
||||
},
|
||||
bypassErrorFormat: true,
|
||||
});
|
||||
}
|
||||
return response.ok({ body: { result: initResultResponse } });
|
||||
|
@ -76,6 +74,7 @@ export const riskEngineInitRoute = (
|
|||
return siemResponse.error({
|
||||
statusCode: error.statusCode,
|
||||
body: { message: error.message, full_error: JSON.stringify(e) },
|
||||
bypassErrorFormat: true,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -44,6 +44,7 @@ export const riskEngineStatusRoute = (router: SecuritySolutionPluginRouter) => {
|
|||
return siemResponse.error({
|
||||
statusCode: error.statusCode,
|
||||
body: { message: error.message, full_error: JSON.stringify(e) },
|
||||
bypassErrorFormat: true,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -89,6 +89,7 @@ export const riskScoreCalculationRoute = (router: SecuritySolutionPluginRouter,
|
|||
return siemResponse.error({
|
||||
statusCode: error.statusCode,
|
||||
body: { message: error.message, full_error: JSON.stringify(e) },
|
||||
bypassErrorFormat: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,6 +91,7 @@ export const riskScorePreviewRoute = (router: SecuritySolutionPluginRouter, logg
|
|||
return siemResponse.error({
|
||||
statusCode: error.statusCode,
|
||||
body: { message: error.message, full_error: JSON.stringify(e) },
|
||||
bypassErrorFormat: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export const TASK_MANAGER_UNAVAILABLE_ERROR = i18n.translate(
|
||||
'xpack.securitySolution.api.riskEngine.taskManagerUnavailable',
|
||||
{
|
||||
defaultMessage:
|
||||
'Task Manager is unavailable, but is required by the risk engine. Please enable the taskManager plugin and try again.',
|
||||
}
|
||||
);
|
|
@ -78,19 +78,15 @@ export interface InitRiskEngineResponse {
|
|||
|
||||
export interface InitRiskEngineError {
|
||||
body: {
|
||||
message: {
|
||||
message: string;
|
||||
full_error: InitRiskEngineResultResponse | undefined;
|
||||
} & string;
|
||||
message: string;
|
||||
full_error: InitRiskEngineResultResponse | undefined;
|
||||
};
|
||||
}
|
||||
|
||||
export interface EnableDisableRiskEngineErrorResponse {
|
||||
body: {
|
||||
message: {
|
||||
message: string;
|
||||
full_error: string;
|
||||
};
|
||||
message: string;
|
||||
full_error: string;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue