[main] [SecuritySolution] Fix risk engine component template renaming (#212853) (#213329)

# Backport

This will backport the following commits from `8.18` to `main`:
- [[SecuritySolution] Fix risk engine component template renaming
(#212853)](https://github.com/elastic/kibana/pull/212853)

<!--- Backport version: 9.6.6 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sorenlouv/backport)

<!--BACKPORT [{"author":{"name":"Pablo
Machado","email":"pablo.nevesmachado@elastic.co"},"sourceCommit":{"committedDate":"2025-03-05T09:50:31Z","message":"[SecuritySolution]
Fix risk engine component template renaming (#212853)\n\n##
Summary\n\nThe previous implementation tried to rename the index
template during\n`init` and did not consider multiple spaces. to fix it,
I have:\n* Delete the previous code from `init`\n* Created a new
migration that created the new component templates and\nupdated the
index templates\n* Deleted the old component template after all spaces
migration ran\n* Add support for multiple spaces\n* I also renamed a
function inside `init` to make the code more clear\n* Added error
handling code that concatenates error messages and logs\nall of them at
the end\n\n\n### How to test it:\n\n**Scenario 1**\n\n* The usual way to
desk test this PR would be\n* Create a cluster with 8.17\n* Enable the
risk Engine in 8.17\n* Create a new space in 8.17\n* Upgrade the cluster
to 8.18 (this branch)\n* Enable the risk engine in the second
space.\n\n**Scenario 2**\n* Create a cluster with 8.17\n* Enable the
risk engine\n* Create a space\n* Enable another risk engine\n* Create
another space\n* Upgrade the cluster to 8.18 (this branch)\n* Check if
the migration ran in the logs\n* Check if all risk engines are installed
and the index templates and\nindex components are there.\n* Install a
new risk engine in the space where it isn't installed.\n* Restart Kibana
and make sure the migrations didn't run a second time\n\n###
Checklist\n\nReviewers should verify this PR satisfies this list as
well.\n\n- [x] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common scenarios\n- [x] The PR
description includes the appropriate Release Notes section,\nand the
correct `release_note:*` label is applied per
the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\n\n###
Identify risks\n\n[ ] This PR needs to be tested for upgrades between
different versions\nand a diverse number of spaces and risk engines
installed\n\n---------\n\nCo-authored-by: abhishekbhatia1710
<abhishek.bhatia@elastic.co>","sha":"b7908a4c6f91c79459f7b509bfd444ad169d6770","branchLabelMapping":{"^v8.16.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["bug","release_note:skip","v9.0.0","Team:
SecuritySolution","Feature:Entity Analytics","Team:Entity
Analytics","backport:version","v8.18.0","v9.1.0","v8.19.0"],"title":"[SecuritySolution]
Fix risk engine component template
renaming","number":212853,"url":"https://github.com/elastic/kibana/pull/212853","mergeCommit":{"message":"[SecuritySolution]
Fix risk engine component template renaming (#212853)\n\n##
Summary\n\nThe previous implementation tried to rename the index
template during\n`init` and did not consider multiple spaces. to fix it,
I have:\n* Delete the previous code from `init`\n* Created a new
migration that created the new component templates and\nupdated the
index templates\n* Deleted the old component template after all spaces
migration ran\n* Add support for multiple spaces\n* I also renamed a
function inside `init` to make the code more clear\n* Added error
handling code that concatenates error messages and logs\nall of them at
the end\n\n\n### How to test it:\n\n**Scenario 1**\n\n* The usual way to
desk test this PR would be\n* Create a cluster with 8.17\n* Enable the
risk Engine in 8.17\n* Create a new space in 8.17\n* Upgrade the cluster
to 8.18 (this branch)\n* Enable the risk engine in the second
space.\n\n**Scenario 2**\n* Create a cluster with 8.17\n* Enable the
risk engine\n* Create a space\n* Enable another risk engine\n* Create
another space\n* Upgrade the cluster to 8.18 (this branch)\n* Check if
the migration ran in the logs\n* Check if all risk engines are installed
and the index templates and\nindex components are there.\n* Install a
new risk engine in the space where it isn't installed.\n* Restart Kibana
and make sure the migrations didn't run a second time\n\n###
Checklist\n\nReviewers should verify this PR satisfies this list as
well.\n\n- [x] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common scenarios\n- [x] The PR
description includes the appropriate Release Notes section,\nand the
correct `release_note:*` label is applied per
the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\n\n###
Identify risks\n\n[ ] This PR needs to be tested for upgrades between
different versions\nand a diverse number of spaces and risk engines
installed\n\n---------\n\nCo-authored-by: abhishekbhatia1710
<abhishek.bhatia@elastic.co>","sha":"b7908a4c6f91c79459f7b509bfd444ad169d6770"}},"sourceBranch":"8.18","suggestedTargetBranches":["9.0","main","8.x"],"targetPullRequestStates":[{"branch":"9.0","label":"v9.0.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"8.18","label":"v8.18.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/212853","number":212853,"mergeCommit":{"message":"[SecuritySolution]
Fix risk engine component template renaming (#212853)\n\n##
Summary\n\nThe previous implementation tried to rename the index
template during\n`init` and did not consider multiple spaces. to fix it,
I have:\n* Delete the previous code from `init`\n* Created a new
migration that created the new component templates and\nupdated the
index templates\n* Deleted the old component template after all spaces
migration ran\n* Add support for multiple spaces\n* I also renamed a
function inside `init` to make the code more clear\n* Added error
handling code that concatenates error messages and logs\nall of them at
the end\n\n\n### How to test it:\n\n**Scenario 1**\n\n* The usual way to
desk test this PR would be\n* Create a cluster with 8.17\n* Enable the
risk Engine in 8.17\n* Create a new space in 8.17\n* Upgrade the cluster
to 8.18 (this branch)\n* Enable the risk engine in the second
space.\n\n**Scenario 2**\n* Create a cluster with 8.17\n* Enable the
risk engine\n* Create a space\n* Enable another risk engine\n* Create
another space\n* Upgrade the cluster to 8.18 (this branch)\n* Check if
the migration ran in the logs\n* Check if all risk engines are installed
and the index templates and\nindex components are there.\n* Install a
new risk engine in the space where it isn't installed.\n* Restart Kibana
and make sure the migrations didn't run a second time\n\n###
Checklist\n\nReviewers should verify this PR satisfies this list as
well.\n\n- [x] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common scenarios\n- [x] The PR
description includes the appropriate Release Notes section,\nand the
correct `release_note:*` label is applied per
the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\n\n###
Identify risks\n\n[ ] This PR needs to be tested for upgrades between
different versions\nand a diverse number of spaces and risk engines
installed\n\n---------\n\nCo-authored-by: abhishekbhatia1710
<abhishek.bhatia@elastic.co>","sha":"b7908a4c6f91c79459f7b509bfd444ad169d6770"}},{"branch":"9.1","label":"v9.1.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"8.19","label":"v8.19.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->
This commit is contained in:
Pablo Machado 2025-03-06 12:49:51 +01:00 committed by GitHub
parent 48926e5173
commit 98c18a395e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 368 additions and 69 deletions

View file

@ -13,6 +13,7 @@ import { assetCrticalityCopyTimestampToEventIngested } from './asset_criticality
import { riskScoreCopyTimestampToEventIngested } from './risk_score_copy_timestamp_to_event_ingested';
import { updateAssetCriticalityMappings } from '../asset_criticality/migrations/update_asset_criticality_mappings';
import { updateRiskScoreMappings } from '../risk_engine/migrations/update_risk_score_mappings';
import { renameRiskScoreComponentTemplate } from '../risk_engine/migrations/rename_risk_score_component_templates';
export interface EntityAnalyticsMigrationsParams {
taskManager?: TaskManagerSetupContract;
@ -43,6 +44,7 @@ export const scheduleEntityAnalyticsMigration = async (params: EntityAnalyticsMi
await updateAssetCriticalityMappings({ ...params, logger: scopedLogger });
await scheduleAssetCriticalityEcsCompliancyMigration({ ...params, logger: scopedLogger });
await renameRiskScoreComponentTemplate({ ...params, logger: scopedLogger });
await updateRiskScoreMappings({ ...params, logger: scopedLogger });
};

View file

@ -0,0 +1,232 @@
/*
* 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 { renameRiskScoreComponentTemplate } from './rename_risk_score_component_templates';
import {
loggingSystemMock,
savedObjectsClientMock as mockSavedObjectsClient,
elasticsearchServiceMock,
} from '@kbn/core/server/mocks';
import { auditLoggerMock } from '@kbn/security-plugin/server/audit/mocks';
const mockCreateComponentTemplate = jest.fn();
const mockCreateIndexTemplate = jest.fn();
jest.mock('../../risk_score/risk_score_data_client', () => ({
RiskScoreDataClient: jest.fn().mockImplementation(() => ({
createOrUpdateRiskScoreComponentTemplate: () => mockCreateComponentTemplate(),
createOrUpdateRiskScoreIndexTemplate: () => mockCreateIndexTemplate(),
})),
}));
jest.mock('../../risk_score/tasks/helpers', () => ({
buildScopedInternalSavedObjectsClientUnsafe: () => mockSavedObjectsClient.create(),
}));
const buildSavedObjectResponse = (namespaces = ['default']) => ({
page: 1,
per_page: 20,
total: namespaces.length,
saved_objects: namespaces.map((namespace) => ({
namespaces: [namespace],
attributes: {},
id: 'id',
type: 'type',
references: [],
score: 1,
})),
});
describe('renameRiskScoreComponentTemplate', () => {
const mockGetStartServices = jest.fn();
const mockAuditLogger = auditLoggerMock.create();
const mockLogger = loggingSystemMock.createLogger();
const mockEsClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
const mockSoClient = mockSavedObjectsClient.create();
beforeEach(() => {
jest.clearAllMocks();
mockCreateComponentTemplate.mockReset();
mockCreateIndexTemplate.mockReset();
mockGetStartServices.mockResolvedValue([
{
savedObjects: {
createInternalRepository: jest.fn().mockReturnValue(mockSoClient),
},
elasticsearch: {
client: {
asInternalUser: mockEsClient,
},
},
},
]);
});
it('should not proceed if old component template does not exist', async () => {
mockEsClient.cluster.existsComponentTemplate.mockResolvedValue(false);
await renameRiskScoreComponentTemplate({
auditLogger: mockAuditLogger,
logger: mockLogger,
getStartServices: mockGetStartServices,
kibanaVersion: '8.0.0',
});
expect(mockEsClient.cluster.existsComponentTemplate).toHaveBeenCalledWith({
name: '.risk-score-mappings',
});
expect(mockEsClient.cluster.deleteComponentTemplate).not.toHaveBeenCalled();
});
it('should proceed with migration if old component template exists', async () => {
mockEsClient.cluster.existsComponentTemplate.mockResolvedValue(true);
mockSoClient.find.mockResolvedValue(buildSavedObjectResponse(['default']));
await renameRiskScoreComponentTemplate({
auditLogger: mockAuditLogger,
logger: mockLogger,
getStartServices: mockGetStartServices,
kibanaVersion: '8.0.0',
});
expect(mockEsClient.cluster.existsComponentTemplate).toHaveBeenCalledWith({
name: '.risk-score-mappings',
});
expect(mockEsClient.cluster.deleteComponentTemplate).toHaveBeenCalledWith(
{ name: '.risk-score-mappings' },
{ ignore: [404] }
);
});
it('should log an error if a saved object has no namespace', async () => {
const savedObj = buildSavedObjectResponse([]);
mockEsClient.cluster.existsComponentTemplate.mockResolvedValue(true);
mockSoClient.find.mockResolvedValue({
...savedObj,
saved_objects: [
{
...savedObj.saved_objects[0],
namespaces: [],
},
],
});
await renameRiskScoreComponentTemplate({
auditLogger: mockAuditLogger,
logger: mockLogger,
getStartServices: mockGetStartServices,
kibanaVersion: '8.0.0',
});
expect(mockLogger.error).toHaveBeenCalledWith(
'Unexpected saved object. Risk Score saved objects must have a namespace'
);
});
it('should throw an error if any promise is rejected', async () => {
mockEsClient.cluster.existsComponentTemplate.mockResolvedValue(true);
mockSoClient.find.mockResolvedValue(buildSavedObjectResponse(['default']));
mockCreateComponentTemplate.mockRejectedValue(new Error('Test error'));
await expect(
renameRiskScoreComponentTemplate({
auditLogger: mockAuditLogger,
logger: mockLogger,
getStartServices: mockGetStartServices,
kibanaVersion: '8.0.0',
})
).rejects.toThrow('Risk Score component template migration failed with errors: \nTest error');
expect(mockEsClient.cluster.deleteComponentTemplate).not.toHaveBeenCalled();
});
it('should throw an error with concatenated error messages when more than one error happens', async () => {
mockEsClient.cluster.existsComponentTemplate.mockResolvedValue(true);
mockSoClient.find.mockResolvedValue(buildSavedObjectResponse(['space-1', 'space-2']));
mockCreateComponentTemplate
.mockRejectedValueOnce(new Error('Test error 1'))
.mockRejectedValueOnce(new Error('Test error 2'));
await expect(
renameRiskScoreComponentTemplate({
auditLogger: mockAuditLogger,
logger: mockLogger,
getStartServices: mockGetStartServices,
kibanaVersion: '8.0.0',
})
).rejects.toThrow(
'Risk Score component template migration failed with errors: \nTest error 1\nTest error 2'
);
});
it('should handle errors when creating/updating index template', async () => {
mockEsClient.cluster.existsComponentTemplate.mockResolvedValue(true);
mockSoClient.find.mockResolvedValue(buildSavedObjectResponse(['default']));
mockCreateIndexTemplate.mockRejectedValue(new Error('Index template error'));
await expect(
renameRiskScoreComponentTemplate({
auditLogger: mockAuditLogger,
logger: mockLogger,
getStartServices: mockGetStartServices,
kibanaVersion: '8.0.0',
})
).rejects.toThrow(
'Risk Score component template migration failed with errors: \nIndex template error'
);
});
it('should log info when migration starts for a namespace', async () => {
mockEsClient.cluster.existsComponentTemplate.mockResolvedValue(true);
mockSoClient.find.mockResolvedValue(buildSavedObjectResponse(['default']));
await renameRiskScoreComponentTemplate({
auditLogger: mockAuditLogger,
logger: mockLogger,
getStartServices: mockGetStartServices,
kibanaVersion: '8.0.0',
});
expect(mockLogger.info).toHaveBeenCalledWith(
'Starting Risk Score component template migration on namespace default'
);
});
it('should log debug when migration completes for a namespace', async () => {
mockEsClient.cluster.existsComponentTemplate.mockResolvedValue(true);
mockSoClient.find.mockResolvedValue(buildSavedObjectResponse(['default']));
await renameRiskScoreComponentTemplate({
auditLogger: mockAuditLogger,
logger: mockLogger,
getStartServices: mockGetStartServices,
kibanaVersion: '8.0.0',
});
expect(mockLogger.debug).toHaveBeenCalledWith(
'Risk score component template migration ran on namespace default'
);
});
it('should delete the old component template if all migrations succeed', async () => {
mockEsClient.cluster.existsComponentTemplate.mockResolvedValue(true);
mockSoClient.find.mockResolvedValue(buildSavedObjectResponse(['default']));
await renameRiskScoreComponentTemplate({
auditLogger: mockAuditLogger,
logger: mockLogger,
getStartServices: mockGetStartServices,
kibanaVersion: '8.0.0',
});
expect(mockEsClient.cluster.deleteComponentTemplate).toHaveBeenCalledWith(
{ name: '.risk-score-mappings' },
{ ignore: [404] }
);
});
});

View file

@ -0,0 +1,96 @@
/*
* 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 { EntityAnalyticsMigrationsParams } from '../../migrations';
import { RiskScoreDataClient } from '../../risk_score/risk_score_data_client';
import type { RiskEngineConfiguration } from '../../types';
import { riskEngineConfigurationTypeName } from '../saved_object';
import { buildScopedInternalSavedObjectsClientUnsafe } from '../../risk_score/tasks/helpers';
import { mappingComponentName } from '../../risk_score/configurations';
export const MAX_PER_PAGE = 10_000;
/**
* This migration renames the Risk Score component templates to include the namespace in the name. Before 8.18 all spaces used the `.risk-score-mappings` component template, we now use `.risk-score-mappings-<spacename>`.
*
* The migration creates the new component template and updates the index template for each space, then finally deletes the old component template.
*/
export const renameRiskScoreComponentTemplate = async ({
auditLogger,
logger,
getStartServices,
kibanaVersion,
}: EntityAnalyticsMigrationsParams) => {
const [coreStart] = await getStartServices();
const soClientKibanaUser = coreStart.savedObjects.createInternalRepository();
const esClient = coreStart.elasticsearch.client.asInternalUser;
// Check if the legacy component templates (without the namespace in the name) exists
const oldComponentTemplateExists = await esClient.cluster.existsComponentTemplate({
name: mappingComponentName,
});
if (!oldComponentTemplateExists) {
return;
}
// Get all installed Risk Engine Configurations
const savedObjectsResponse = await soClientKibanaUser.find<RiskEngineConfiguration>({
type: riskEngineConfigurationTypeName,
perPage: MAX_PER_PAGE,
namespaces: ['*'],
});
const settledPromises = await Promise.allSettled(
savedObjectsResponse.saved_objects.map(async (savedObject) => {
const namespace = savedObject.namespaces?.[0]; // We need to create one component template per space
if (!namespace) {
logger.error('Unexpected saved object. Risk Score saved objects must have a namespace');
return;
}
logger.info(`Starting Risk Score component template migration on namespace ${namespace}`);
const soClient = buildScopedInternalSavedObjectsClientUnsafe({ coreStart, namespace });
const riskScoreDataClient = new RiskScoreDataClient({
logger,
kibanaVersion,
esClient,
namespace,
soClient,
auditLogger,
});
await riskScoreDataClient.createOrUpdateRiskScoreComponentTemplate();
await riskScoreDataClient.createOrUpdateRiskScoreIndexTemplate();
logger.debug(`Risk score component template migration ran on namespace ${namespace}`);
})
);
const rejectedPromises = settledPromises.filter(
(promise) => promise.status === 'rejected'
) as PromiseRejectedResult[];
// Migration successfully ran on all spaces
if (rejectedPromises.length === 0) {
// Delete the legacy component template without the namespace in the name
await esClient.cluster.deleteComponentTemplate(
{
name: mappingComponentName,
},
{ ignore: [404] }
);
} else {
const errorMessages = rejectedPromises.map((promise) => promise.reason?.message).join('\n');
throw new Error(
`Risk Score component template migration failed with errors: \n${errorMessages}`
);
}
};

View file

@ -68,7 +68,7 @@ export const updateRiskScoreMappings = async ({
});
await riskScoreDataClient.createOrUpdateRiskScoreLatestIndex();
await riskScoreDataClient.createOrUpdateRiskScoreIndexTemplate();
await riskScoreDataClient.createOrUpdateRiskScoreComponentTemplate();
await riskScoreDataClient.updateRiskScoreTimeSeriesIndexMappings();
await riskEngineDataClient.updateConfiguration({
_meta: {

View file

@ -111,7 +111,7 @@ export class RiskScoreDataClient {
});
};
public createOrUpdateRiskScoreIndexTemplate = async () =>
public createOrUpdateRiskScoreComponentTemplate = async () =>
createOrUpdateComponentTemplate({
logger: this.options.logger,
esClient: this.options.esClient,
@ -128,6 +128,40 @@ export class RiskScoreDataClient {
totalFieldsLimit,
});
public createOrUpdateRiskScoreIndexTemplate = async () => {
const indexPatterns = getIndexPatternDataStream(this.options.namespace);
const indexMetadata: Metadata = {
kibana: {
version: this.options.kibanaVersion,
},
managed: true,
namespace: this.options.namespace,
};
return createOrUpdateIndexTemplate({
logger: this.options.logger,
esClient: this.options.esClient,
template: {
name: indexPatterns.template,
data_stream: { hidden: true },
index_patterns: [indexPatterns.alias],
composed_of: [nameSpaceAwareMappingsComponentName(this.options.namespace)],
template: {
lifecycle: {},
settings: {
'index.mapping.total_fields.limit': totalFieldsLimit,
'index.default_pipeline': getIngestPipelineName(this.options.namespace),
},
mappings: {
dynamic: false,
_meta: indexMetadata,
},
},
_meta: indexMetadata,
},
});
};
public updateRiskScoreTimeSeriesIndexMappings = async () =>
updateUnderlyingMapping({
esClient: this.options.esClient,
@ -142,59 +176,11 @@ export class RiskScoreDataClient {
try {
await createEventIngestedFromTimestamp(esClient, namespace);
const indexPatterns = getIndexPatternDataStream(namespace);
await this.createOrUpdateRiskScoreComponentTemplate();
const indexMetadata: Metadata = {
kibana: {
version: this.options.kibanaVersion,
},
managed: true,
namespace,
};
// Check if there are any existing component templates with the namespace in the name
const oldComponentTemplateExists = await esClient.cluster.existsComponentTemplate({
name: mappingComponentName,
});
if (oldComponentTemplateExists) {
await this.updateComponentTemplateNameWithNamespace(namespace);
}
// Update the new component template with the required data
await this.createOrUpdateRiskScoreIndexTemplate();
// Reference the new component template in the index template
await createOrUpdateIndexTemplate({
logger: this.options.logger,
esClient,
template: {
name: indexPatterns.template,
data_stream: { hidden: true },
index_patterns: [indexPatterns.alias],
composed_of: [nameSpaceAwareMappingsComponentName(namespace)],
template: {
lifecycle: {},
settings: {
'index.mapping.total_fields.limit': totalFieldsLimit,
'index.default_pipeline': getIngestPipelineName(namespace),
},
mappings: {
dynamic: false,
_meta: indexMetadata,
},
},
_meta: indexMetadata,
},
});
// Delete the component template without the namespace in the name
await esClient.cluster.deleteComponentTemplate(
{
name: mappingComponentName,
},
{ ignore: [404] }
);
const indexPatterns = getIndexPatternDataStream(namespace);
await createDataStream({
logger: this.options.logger,
esClient,
@ -331,23 +317,6 @@ export class RiskScoreDataClient {
);
}
private async updateComponentTemplateNameWithNamespace(namespace: string): Promise<void> {
const esClient = this.options.esClient;
const oldComponentTemplateResponse = await esClient.cluster.getComponentTemplate(
{
name: mappingComponentName,
},
{ ignore: [404] }
);
const oldComponentTemplate = oldComponentTemplateResponse?.component_templates[0];
const newComponentTemplateName = nameSpaceAwareMappingsComponentName(namespace);
await esClient.cluster.putComponentTemplate({
name: newComponentTemplateName,
// @ts-expect-error elasticsearch@9.0.0 https://github.com/elastic/elasticsearch-js/issues/2584
body: oldComponentTemplate.component_template,
});
}
public copyTimestampToEventIngestedForRiskScore = (abortSignal?: AbortSignal) => {
return this.options.esClient.updateByQuery(
{