[Entity Analytics] Implement Asset Criticality Create, Read & Delete APIs (#172073)

## Summary

Adds upsert, read and delete APIs for asset criticality records. I have
used the OpenAPI code generation to create the types and zod schemas.

The APIs added are as follows:

**POST /internal/risk_score/criticality**
Request Body:
```
{
    id_value: "host-1",
    id_field: "host.name",
    criticality_level: "very_important"
}
```

If the record already exists it will be overwritten, otherwise created

**GET
/internal/risk_score/criticality?id_field=host.name&id_value=host-1**
Response body:
```
{
    id_value: "host-1",
    id_field: "host.name",
    criticality_level: "very_important"
    @timestamp: "2023-11-29T11:43:43.175Z"
}
```

**DELETE
/internal/risk_score/criticality?id_field=host.name&id_value=host-1**

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Mark Hopkin 2023-12-01 10:50:48 +00:00 committed by GitHub
parent 823552fea5
commit 991b5f6f8c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 659 additions and 15 deletions

1
.github/CODEOWNERS vendored
View file

@ -1474,6 +1474,7 @@ x-pack/plugins/security_solution/server/lib/entity_analytics @elastic/security-e
x-pack/plugins/security_solution/server/lib/risk_score @elastic/security-entity-analytics
x-pack/test/security_solution_api_integration/test_suites/entity_analytics @elastic/security-entity-analytics
x-pack/plugins/security_solution/public/flyout/entity_details @elastic/security-entity-analytics
x-pack/plugins/security_solution/common/api/asset_criticality @elastic/security-entity-analytics
/x-pack/plugins/security_solution/public/entity_analytics @elastic/security-entity-analytics
/x-pack/test/security_solution_cypress/cypress/e2e/entity_analytics @elastic/security-entity-analytics

View file

@ -0,0 +1,50 @@
/*
* 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 { z } from 'zod';
/*
* NOTICE: Do not edit this file manually.
* This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator.
*/
export type IdField = z.infer<typeof IdField>;
export const IdField = z.enum(['host.name', 'user.name']);
export type IdFieldEnum = typeof IdField.enum;
export const IdFieldEnum = IdField.enum;
export type AssetCriticalityRecordIdParts = z.infer<typeof AssetCriticalityRecordIdParts>;
export const AssetCriticalityRecordIdParts = z.object({
/**
* The ID value of the asset.
*/
id_value: z.string(),
/**
* The field representing the ID.
*/
id_field: IdField,
});
export type CreateAssetCriticalityRecord = z.infer<typeof CreateAssetCriticalityRecord>;
export const CreateAssetCriticalityRecord = AssetCriticalityRecordIdParts.merge(
z.object({
/**
* The criticality level of the asset.
*/
criticality_level: z.enum(['very_important', 'important', 'normal', 'not_important']),
})
);
export type AssetCriticalityRecord = z.infer<typeof AssetCriticalityRecord>;
export const AssetCriticalityRecord = CreateAssetCriticalityRecord.merge(
z.object({
/**
* The time the record was created or updated.
*/
'@timestamp': z.string().datetime(),
})
);

View file

@ -0,0 +1,66 @@
openapi: 3.0.0
info:
title: Asset Criticality Common Schema
description: Common schema for asset criticality
version: 1.0.0
paths: { }
components:
parameters:
id_value:
name: id_value
in: query
required: true
schema:
type: string
description: The ID value of the asset.
id_field:
name: id_field
in: query
required: true
schema:
$ref: '#/components/schemas/IdField'
example: 'host.name'
description: The field representing the ID.
schemas:
IdField:
type: string
enum:
- 'host.name'
- 'user.name'
AssetCriticalityRecordIdParts:
type: object
properties:
id_value:
type: string
description: The ID value of the asset.
id_field:
$ref: '#/components/schemas/IdField'
example: 'host.name'
description: The field representing the ID.
required:
- id_value
- id_field
CreateAssetCriticalityRecord:
allOf:
- $ref: '#/components/schemas/AssetCriticalityRecordIdParts'
- type: object
properties:
criticality_level:
type: string
enum: [very_important, important, normal, not_important]
description: The criticality level of the asset.
required:
- criticality_level
AssetCriticalityRecord:
allOf:
- $ref: '#/components/schemas/CreateAssetCriticalityRecord'
- type: object
properties:
"@timestamp":
type: string
format: 'date-time'
example: '2017-07-21T17:32:28Z'
description: The time the record was created or updated.
required:
- "@timestamp"

View file

@ -0,0 +1,23 @@
openapi: 3.0.0
info:
version: 1.0.0
title: Asset Criticality Create Record Schema
paths:
/internal/asset_criticality:
post:
summary: Create Criticality Record
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateAssetCriticalityRecord'
responses:
'200':
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/SingleAssetCriticality'
'400':
description: Invalid request

View file

@ -0,0 +1,16 @@
openapi: 3.0.0
info:
version: 1.0.0
title: Asset Criticality Delete Record Schema
paths:
/internal/asset_criticality:
delete:
summary: Delete Criticality Record
parameters:
- $ref: '#/components/parameters/id_value'
- $ref: '#/components/parameters/id_field'
responses:
'200':
description: Successful response
'400':
description: Invalid request

View file

@ -0,0 +1,22 @@
openapi: 3.0.0
info:
version: 1.0.0
title: Asset Criticality Get Record Schema
paths:
/internal/asset_criticality:
get:
summary: Get Criticality Record
parameters:
- $ref: '#/components/parameters/id_value'
- $ref: '#/components/parameters/id_field'
responses:
'200':
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/SingleAssetCriticality'
'400':
description: Invalid request
'404':
description: Criticality record not found

View file

@ -0,0 +1,18 @@
/*
* 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 { z } from 'zod';
/*
* NOTICE: Do not edit this file manually.
* This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator.
*/
export type AssetCriticalityStatusResponse = z.infer<typeof AssetCriticalityStatusResponse>;
export const AssetCriticalityStatusResponse = z.object({
asset_criticality_resources_installed: z.boolean().optional(),
});

View file

@ -15,7 +15,6 @@ paths:
$ref: '#/components/schemas/AssetCriticalityStatusResponse'
'400':
description: Invalid request
responses:
components:
schemas:
@ -23,4 +22,4 @@ components:
type: object
properties:
asset_criticality_resources_installed:
type: boolean
type: boolean

View file

@ -0,0 +1,9 @@
/*
* 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.
*/
export * from './common.gen';
export * from './get_asset_criticality_status.gen';

View file

@ -6,6 +6,7 @@
*/
import type { Logger, ElasticsearchClient } from '@kbn/core/server';
import { mappingFromFieldMap } from '@kbn/alerting-plugin/common';
import type { AssetCriticalityRecord } from '../../../../common/api/asset_criticality';
import { createOrUpdateIndex } from '../utils/create_or_update_index';
import { getAssetCriticalityIndex } from '../../../../common/asset_criticality';
import { assetCriticalityFieldMap } from './configurations';
@ -16,6 +17,15 @@ interface AssetCriticalityClientOpts {
namespace: string;
}
interface AssetCriticalityUpsert {
idField: AssetCriticalityRecord['id_field'];
idValue: AssetCriticalityRecord['id_value'];
criticalityLevel: AssetCriticalityRecord['criticality_level'];
}
type AssetCriticalityIdParts = Pick<AssetCriticalityUpsert, 'idField' | 'idValue'>;
const createId = ({ idField, idValue }: AssetCriticalityIdParts) => `${idField}:${idValue}`;
export class AssetCriticalityDataClient {
constructor(private readonly options: AssetCriticalityClientOpts) {}
/**
@ -27,16 +37,20 @@ export class AssetCriticalityDataClient {
esClient: this.options.esClient,
logger: this.options.logger,
options: {
index: getAssetCriticalityIndex(this.options.namespace),
index: this.getIndex(),
mappings: mappingFromFieldMap(assetCriticalityFieldMap, 'strict'),
},
});
}
private getIndex() {
return getAssetCriticalityIndex(this.options.namespace);
}
public async doesIndexExist() {
try {
const result = await this.options.esClient.indices.exists({
index: getAssetCriticalityIndex(this.options.namespace),
index: this.getIndex(),
});
return result;
} catch (e) {
@ -51,4 +65,51 @@ export class AssetCriticalityDataClient {
isAssetCriticalityResourcesInstalled,
};
}
public async get(idParts: AssetCriticalityIdParts): Promise<AssetCriticalityRecord | undefined> {
const id = createId(idParts);
try {
const body = await this.options.esClient.get<AssetCriticalityRecord>({
id,
index: this.getIndex(),
});
return body._source;
} catch (err) {
if (err.statusCode === 404) {
return undefined;
} else {
throw err;
}
}
}
public async upsert(record: AssetCriticalityUpsert): Promise<AssetCriticalityRecord> {
const id = createId(record);
const doc = {
id_field: record.idField,
id_value: record.idValue,
criticality_level: record.criticalityLevel,
'@timestamp': new Date().toISOString(),
};
await this.options.esClient.update({
id,
index: this.getIndex(),
body: {
doc,
doc_as_upsert: true,
},
});
return doc;
}
public async delete(idParts: AssetCriticalityIdParts) {
await this.options.esClient.delete({
id: createId(idParts),
index: this.getIndex(),
});
}
}

View file

@ -0,0 +1,60 @@
/*
* 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 type { Logger } from '@kbn/core/server';
import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils';
import { transformError } from '@kbn/securitysolution-es-utils';
import { ASSET_CRITICALITY_URL, APP_ID } from '../../../../../common/constants';
import type { SecuritySolutionPluginRouter } from '../../../../types';
import { AssetCriticalityRecordIdParts } from '../../../../../common/api/asset_criticality';
import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation';
import { checkAndInitAssetCriticalityResources } from '../check_and_init_asset_criticality_resources';
export const assetCriticalityDeleteRoute = (
router: SecuritySolutionPluginRouter,
logger: Logger
) => {
router.versioned
.delete({
access: 'internal',
path: ASSET_CRITICALITY_URL,
options: {
tags: ['access:securitySolution', `access:${APP_ID}-entity-analytics`],
},
})
.addVersion(
{
version: '1',
validate: {
request: {
query: buildRouteValidationWithZod(AssetCriticalityRecordIdParts),
},
},
},
async (context, request, response) => {
const siemResponse = buildSiemResponse(response);
try {
await checkAndInitAssetCriticalityResources(context, logger);
const securitySolution = await context.securitySolution;
const assetCriticalityClient = securitySolution.getAssetCriticalityDataClient();
await assetCriticalityClient.delete({
idField: request.query.id_field,
idValue: request.query.id_value,
});
return response.ok();
} catch (e) {
const error = transformError(e);
return siemResponse.error({
statusCode: error.statusCode,
body: { message: error.message, full_error: JSON.stringify(e) },
bypassErrorFormat: true,
});
}
}
);
};

View file

@ -0,0 +1,61 @@
/*
* 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 type { Logger } from '@kbn/core/server';
import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils';
import { transformError } from '@kbn/securitysolution-es-utils';
import { ASSET_CRITICALITY_URL, APP_ID } from '../../../../../common/constants';
import type { SecuritySolutionPluginRouter } from '../../../../types';
import { checkAndInitAssetCriticalityResources } from '../check_and_init_asset_criticality_resources';
import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation';
import { AssetCriticalityRecordIdParts } from '../../../../../common/api/asset_criticality';
export const assetCriticalityGetRoute = (router: SecuritySolutionPluginRouter, logger: Logger) => {
router.versioned
.get({
access: 'internal',
path: ASSET_CRITICALITY_URL,
options: {
tags: ['access:securitySolution', `access:${APP_ID}-entity-analytics`],
},
})
.addVersion(
{
version: '1',
validate: {
request: {
query: buildRouteValidationWithZod(AssetCriticalityRecordIdParts),
},
},
},
async (context, request, response) => {
const siemResponse = buildSiemResponse(response);
try {
await checkAndInitAssetCriticalityResources(context, logger);
const securitySolution = await context.securitySolution;
const assetCriticalityClient = securitySolution.getAssetCriticalityDataClient();
const record = await assetCriticalityClient.get({
idField: request.query.id_field,
idValue: request.query.id_value,
});
if (!record) {
return response.notFound();
}
return response.ok({ body: record });
} catch (e) {
const error = transformError(e);
return siemResponse.error({
statusCode: error.statusCode,
body: { message: error.message, full_error: JSON.stringify(e) },
bypassErrorFormat: true,
});
}
}
);
};

View file

@ -6,3 +6,6 @@
*/
export { assetCriticalityStatusRoute } from './status';
export { assetCriticalityUpsertRoute } from './upsert';
export { assetCriticalityGetRoute } from './get';
export { assetCriticalityDeleteRoute } from './delete';

View file

@ -7,6 +7,7 @@
import type { Logger } from '@kbn/core/server';
import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils';
import { transformError } from '@kbn/securitysolution-es-utils';
import type { AssetCriticalityStatusResponse } from '../../../../../common/api/asset_criticality';
import { ASSET_CRITICALITY_STATUS_URL, APP_ID } from '../../../../../common/constants';
import type { SecuritySolutionPluginRouter } from '../../../../types';
import { checkAndInitAssetCriticalityResources } from '../check_and_init_asset_criticality_resources';
@ -32,10 +33,11 @@ export const assetCriticalityStatusRoute = (
const assetCriticalityClient = securitySolution.getAssetCriticalityDataClient();
const result = await assetCriticalityClient.getStatus();
const body: AssetCriticalityStatusResponse = {
asset_criticality_resources_installed: result.isAssetCriticalityResourcesInstalled,
};
return response.ok({
body: {
asset_criticality_resources_installed: result.isAssetCriticalityResourcesInstalled,
},
body,
});
} catch (e) {
const error = transformError(e);

View file

@ -0,0 +1,66 @@
/*
* 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 type { Logger } from '@kbn/core/server';
import { buildSiemResponse } from '@kbn/lists-plugin/server/routes/utils';
import { transformError } from '@kbn/securitysolution-es-utils';
import { ASSET_CRITICALITY_URL, APP_ID } from '../../../../../common/constants';
import type { SecuritySolutionPluginRouter } from '../../../../types';
import { checkAndInitAssetCriticalityResources } from '../check_and_init_asset_criticality_resources';
import { buildRouteValidationWithZod } from '../../../../utils/build_validation/route_validation';
import { CreateAssetCriticalityRecord } from '../../../../../common/api/asset_criticality';
export const assetCriticalityUpsertRoute = (
router: SecuritySolutionPluginRouter,
logger: Logger
) => {
router.versioned
.post({
access: 'internal',
path: ASSET_CRITICALITY_URL,
options: {
tags: ['access:securitySolution', `access:${APP_ID}-entity-analytics`],
},
})
.addVersion(
{
version: '1',
validate: {
request: {
body: buildRouteValidationWithZod(CreateAssetCriticalityRecord),
},
},
},
async (context, request, response) => {
const siemResponse = buildSiemResponse(response);
try {
await checkAndInitAssetCriticalityResources(context, logger);
const securitySolution = await context.securitySolution;
const assetCriticalityClient = securitySolution.getAssetCriticalityDataClient();
const assetCriticalityRecord = {
idField: request.body.id_field,
idValue: request.body.id_value,
criticalityLevel: request.body.criticality_level,
};
const result = await assetCriticalityClient.upsert(assetCriticalityRecord);
return response.ok({
body: result,
});
} catch (e) {
const error = transformError(e);
return siemResponse.error({
statusCode: error.statusCode,
body: { message: error.message, full_error: JSON.stringify(e) },
bypassErrorFormat: true,
});
}
}
);
};

View file

@ -66,8 +66,12 @@ import {
import { registerTimelineRoutes } from '../lib/timeline/routes';
import { riskScoreCalculationRoute } from '../lib/entity_analytics/risk_score/routes/calculation';
import { riskScorePreviewRoute } from '../lib/entity_analytics/risk_score/routes/preview';
import { assetCriticalityStatusRoute } from '../lib/entity_analytics/asset_criticality/routes';
import {
assetCriticalityStatusRoute,
assetCriticalityUpsertRoute,
assetCriticalityGetRoute,
assetCriticalityDeleteRoute,
} from '../lib/entity_analytics/asset_criticality/routes';
export const initRoutes = (
router: SecuritySolutionPluginRouter,
config: ConfigType,
@ -161,5 +165,8 @@ export const initRoutes = (
}
if (config.experimentalFeatures.entityAnalyticsAssetCriticalityEnabled) {
assetCriticalityStatusRoute(router, logger);
assetCriticalityUpsertRoute(router, logger);
assetCriticalityGetRoute(router, logger);
assetCriticalityDeleteRoute(router, logger);
}
};

View file

@ -10,6 +10,8 @@ import {
cleanRiskEngine,
cleanAssetCriticality,
assetCriticalityRouteHelpersFactory,
getAssetCriticalityDoc,
getAssetCriticalityIndex,
} from '../../utils';
import { FtrProviderContext } from '../../../../ftr_provider_context';
@ -33,13 +35,11 @@ export default ({ getService }: FtrProviderContext) => {
describe('initialisation of resources', () => {
it('should has index installed on status api call', async () => {
const assetCriticalityIndex = '.asset-criticality.asset-criticality-default';
let assetCriticalityIndexExist;
try {
assetCriticalityIndexExist = await es.indices.exists({
index: assetCriticalityIndex,
index: getAssetCriticalityIndex(),
});
} catch (e) {
assetCriticalityIndexExist = false;
@ -54,7 +54,7 @@ export default ({ getService }: FtrProviderContext) => {
});
const assetCriticalityIndexResult = await es.indices.get({
index: assetCriticalityIndex,
index: getAssetCriticalityIndex(),
});
expect(
@ -81,5 +81,125 @@ export default ({ getService }: FtrProviderContext) => {
});
});
});
describe('create', () => {
it('should correctly create asset criticality', async () => {
const assetCriticality = {
id_field: 'host.name',
id_value: 'host-01',
criticality_level: 'important',
};
const { body: result } = await assetCriticalityRoutes.upsert(assetCriticality);
expect(result.id_field).to.eql('host.name');
expect(result.id_value).to.eql('host-01');
expect(result.criticality_level).to.eql('important');
expect(result['@timestamp']).to.be.a('string');
const doc = await getAssetCriticalityDoc({ idField: 'host.name', idValue: 'host-01', es });
expect(doc).to.eql(result);
});
it('should return 400 if criticality is invalid', async () => {
const assetCriticality = {
id_field: 'host.name',
id_value: 'host-01',
criticality_level: 'invalid',
};
await assetCriticalityRoutes.upsert(assetCriticality, {
expectStatusCode: 400,
});
});
it('should return 400 if id_field is invalid', async () => {
const assetCriticality = {
id_field: 'invalid',
id_value: 'host-01',
criticality_level: 'important',
};
await assetCriticalityRoutes.upsert(assetCriticality, {
expectStatusCode: 400,
});
});
});
describe('read', () => {
it('should correctly get asset criticality', async () => {
const assetCriticality = {
id_field: 'host.name',
id_value: 'host-02',
criticality_level: 'important',
};
await assetCriticalityRoutes.upsert(assetCriticality);
const { body: result } = await assetCriticalityRoutes.get('host.name', 'host-02');
expect(result.id_field).to.eql('host.name');
expect(result.id_value).to.eql('host-02');
expect(result.criticality_level).to.eql('important');
expect(result['@timestamp']).to.be.a('string');
});
it('should return a 400 if id_field is invalid', async () => {
await assetCriticalityRoutes.get('invalid', 'host-02', {
expectStatusCode: 400,
});
});
});
describe('update', () => {
it('should correctly update asset criticality', async () => {
const assetCriticality = {
id_field: 'host.name',
id_value: 'host-01',
criticality_level: 'important',
};
const { body: createdDoc } = await assetCriticalityRoutes.upsert(assetCriticality);
const updatedAssetCriticality = {
id_field: 'host.name',
id_value: 'host-01',
criticality_level: 'very_important',
};
const { body: updatedDoc } = await assetCriticalityRoutes.upsert(updatedAssetCriticality);
expect(updatedDoc.id_field).to.eql('host.name');
expect(updatedDoc.id_value).to.eql('host-01');
expect(updatedDoc.criticality_level).to.eql('very_important');
expect(updatedDoc['@timestamp']).to.be.a('string');
expect(updatedDoc['@timestamp']).to.not.eql(createdDoc['@timestamp']);
const doc = await getAssetCriticalityDoc({ idField: 'host.name', idValue: 'host-01', es });
expect(doc).to.eql(updatedDoc);
});
});
describe('delete', () => {
it('should correctly delete asset criticality', async () => {
const assetCriticality = {
id_field: 'host.name',
id_value: 'delete-me',
criticality_level: 'important',
};
await assetCriticalityRoutes.upsert(assetCriticality);
await assetCriticalityRoutes.delete('host.name', 'delete-me');
const doc = await getAssetCriticalityDoc({
idField: 'host.name',
idValue: 'delete-me',
es,
});
expect(doc).to.eql(undefined);
});
});
});
};

View file

@ -10,11 +10,18 @@ import {
ELASTIC_HTTP_VERSION_HEADER,
X_ELASTIC_INTERNAL_ORIGIN_REQUEST,
} from '@kbn/core-http-common';
import { ASSET_CRITICALITY_STATUS_URL } from '@kbn/security-solution-plugin/common/constants';
import {
ASSET_CRITICALITY_STATUS_URL,
ASSET_CRITICALITY_URL,
} from '@kbn/security-solution-plugin/common/constants';
import type { Client } from '@elastic/elasticsearch';
import type { ToolingLog } from '@kbn/tooling-log';
import querystring from 'querystring';
import { routeWithNamespace } from '../../detections_response/utils';
export const getAssetCriticalityIndex = (namespace?: string) =>
`.asset-criticality.asset-criticality-${namespace ?? 'default'}`;
export const cleanAssetCriticality = async ({
log,
es,
@ -27,7 +34,7 @@ export const cleanAssetCriticality = async ({
try {
await Promise.allSettled([
es.indices.delete({
index: [`.asset-criticality.asset-criticality-${namespace}`],
index: [getAssetCriticalityIndex(namespace)],
}),
]);
} catch (e) {
@ -35,6 +42,24 @@ export const cleanAssetCriticality = async ({
}
};
export const getAssetCriticalityDoc = async (opts: {
es: Client;
idField: string;
idValue: string;
}) => {
const { es, idField, idValue } = opts;
try {
const doc = await es.get({
index: getAssetCriticalityIndex(),
id: `${idField}:${idValue}`,
});
return doc._source;
} catch (e) {
return undefined;
}
};
export const assetCriticalityRouteHelpersFactory = (
supertest: SuperTest.SuperTest<SuperTest.Test>,
namespace?: string
@ -47,4 +72,39 @@ export const assetCriticalityRouteHelpersFactory = (
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
.send()
.expect(200),
upsert: async (
body: Record<string, unknown>,
{ expectStatusCode }: { expectStatusCode: number } = { expectStatusCode: 200 }
) =>
await supertest
.post(routeWithNamespace(ASSET_CRITICALITY_URL, namespace))
.set('kbn-xsrf', 'true')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
.send(body)
.expect(expectStatusCode),
delete: async (idField: string, idValue: string) => {
const qs = querystring.stringify({ id_field: idField, id_value: idValue });
const route = `${routeWithNamespace(ASSET_CRITICALITY_URL, namespace)}?${qs}`;
return supertest
.delete(route)
.set('kbn-xsrf', 'true')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
.expect(200);
},
get: async (
idField: string,
idValue: string,
{ expectStatusCode }: { expectStatusCode: number } = { expectStatusCode: 200 }
) => {
const qs = querystring.stringify({ id_field: idField, id_value: idValue });
const route = `${routeWithNamespace(ASSET_CRITICALITY_URL, namespace)}?${qs}`;
return supertest
.get(route)
.set('kbn-xsrf', 'true')
.set(ELASTIC_HTTP_VERSION_HEADER, '1')
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')
.expect(expectStatusCode);
},
});