Skip to content

Commit

Permalink
[Maps] Use SO-references for geo-containment alerts (elastic#114559)
Browse files Browse the repository at this point in the history
  • Loading branch information
thomasneirynck authored and kibanamachine committed Oct 15, 2021
1 parent b25dd4e commit c41007e
Show file tree
Hide file tree
Showing 9 changed files with 428 additions and 27 deletions.
Original file line number Diff line number Diff line change
@@ -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 { extractEntityAndBoundaryReferences } from './migrations';

describe('geo_containment migration utilities', () => {
test('extractEntityAndBoundaryReferences', () => {
expect(
extractEntityAndBoundaryReferences({
index: 'foo*',
indexId: 'foobar',
geoField: 'geometry',
entity: 'vehicle_id',
dateField: '@timestamp',
boundaryType: 'entireIndex',
boundaryIndexTitle: 'boundary*',
boundaryIndexId: 'boundaryid',
boundaryGeoField: 'geometry',
})
).toEqual({
params: {
boundaryGeoField: 'geometry',
boundaryIndexRefName: 'boundary_index_boundaryid',
boundaryIndexTitle: 'boundary*',
boundaryType: 'entireIndex',
dateField: '@timestamp',
entity: 'vehicle_id',
geoField: 'geometry',
index: 'foo*',
indexRefName: 'tracked_index_foobar',
},
references: [
{
id: 'foobar',
name: 'param:tracked_index_foobar',
type: 'index-pattern',
},
{
id: 'boundaryid',
name: 'param:boundary_index_boundaryid',
type: 'index-pattern',
},
],
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* 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 {
SavedObjectAttributes,
SavedObjectReference,
SavedObjectUnsanitizedDoc,
} from 'kibana/server';
import { AlertTypeParams } from '../../index';
import { Query } from '../../../../../../src/plugins/data/common/query';
import { RawAlert } from '../../types';

// These definitions are dupes of the SO-types in stack_alerts/geo_containment
// There are not exported to avoid deep imports from stack_alerts plugins into here
const GEO_CONTAINMENT_ID = '.geo-containment';
interface GeoContainmentParams extends AlertTypeParams {
index: string;
indexId: string;
geoField: string;
entity: string;
dateField: string;
boundaryType: string;
boundaryIndexTitle: string;
boundaryIndexId: string;
boundaryGeoField: string;
boundaryNameField?: string;
indexQuery?: Query;
boundaryIndexQuery?: Query;
}
type GeoContainmentExtractedParams = Omit<GeoContainmentParams, 'indexId' | 'boundaryIndexId'> & {
indexRefName: string;
boundaryIndexRefName: string;
};

export function extractEntityAndBoundaryReferences(params: GeoContainmentParams): {
params: GeoContainmentExtractedParams;
references: SavedObjectReference[];
} {
const { indexId, boundaryIndexId, ...otherParams } = params;

const indexRefNamePrefix = 'tracked_index_';
const boundaryRefNamePrefix = 'boundary_index_';

// Since these are stack-alerts, we need to prefix with the `param:`-namespace
const references = [
{
name: `param:${indexRefNamePrefix}${indexId}`,
type: `index-pattern`,
id: indexId as string,
},
{
name: `param:${boundaryRefNamePrefix}${boundaryIndexId}`,
type: 'index-pattern',
id: boundaryIndexId as string,
},
];
return {
params: {
...otherParams,
indexRefName: `${indexRefNamePrefix}${indexId}`,
boundaryIndexRefName: `${boundaryRefNamePrefix}${boundaryIndexId}`,
},
references,
};
}

export function extractRefsFromGeoContainmentAlert(
doc: SavedObjectUnsanitizedDoc<RawAlert>
): SavedObjectUnsanitizedDoc<RawAlert> {
if (doc.attributes.alertTypeId !== GEO_CONTAINMENT_ID) {
return doc;
}

const {
attributes: { params },
} = doc;

const { params: newParams, references } = extractEntityAndBoundaryReferences(
params as GeoContainmentParams
);
return {
...doc,
attributes: {
...doc.attributes,
params: newParams as SavedObjectAttributes,
},
references: [...(doc.references || []), ...references],
};
}
90 changes: 90 additions & 0 deletions x-pack/plugins/alerting/server/saved_objects/migrations.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1913,6 +1913,96 @@ describe('successful migrations', () => {
],
});
});

test('geo-containment alert migration extracts boundary and index references', () => {
const migration7160 = getMigrations(encryptedSavedObjectsSetup, isPreconfigured)['7.16.0'];
const alert = {
...getMockData({
alertTypeId: '.geo-containment',
params: {
indexId: 'foo',
boundaryIndexId: 'bar',
},
}),
};

const migratedAlert = migration7160(alert, migrationContext);

expect(migratedAlert.references).toEqual([
{ id: 'foo', name: 'param:tracked_index_foo', type: 'index-pattern' },
{ id: 'bar', name: 'param:boundary_index_bar', type: 'index-pattern' },
]);

expect(migratedAlert.attributes.params).toEqual({
boundaryIndexRefName: 'boundary_index_bar',
indexRefName: 'tracked_index_foo',
});

expect(migratedAlert.attributes.params.indexId).toEqual(undefined);
expect(migratedAlert.attributes.params.boundaryIndexId).toEqual(undefined);
});

test('geo-containment alert migration should preserve foreign references', () => {
const migration7160 = getMigrations(encryptedSavedObjectsSetup, isPreconfigured)['7.16.0'];
const alert = {
...getMockData({
alertTypeId: '.geo-containment',
params: {
indexId: 'foo',
boundaryIndexId: 'bar',
},
}),
references: [
{
name: 'foreign-name',
id: '999',
type: 'foreign-name',
},
],
};

const migratedAlert = migration7160(alert, migrationContext);

expect(migratedAlert.references).toEqual([
{
name: 'foreign-name',
id: '999',
type: 'foreign-name',
},
{ id: 'foo', name: 'param:tracked_index_foo', type: 'index-pattern' },
{ id: 'bar', name: 'param:boundary_index_bar', type: 'index-pattern' },
]);

expect(migratedAlert.attributes.params).toEqual({
boundaryIndexRefName: 'boundary_index_bar',
indexRefName: 'tracked_index_foo',
});

expect(migratedAlert.attributes.params.indexId).toEqual(undefined);
expect(migratedAlert.attributes.params.boundaryIndexId).toEqual(undefined);
});

test('geo-containment alert migration ignores other alert-types', () => {
const migration7160 = getMigrations(encryptedSavedObjectsSetup, isPreconfigured)['7.16.0'];
const alert = {
...getMockData({
alertTypeId: '.foo',
references: [
{
name: 'foreign-name',
id: '999',
type: 'foreign-name',
},
],
}),
};

const migratedAlert = migration7160(alert, migrationContext);

expect(typeof migratedAlert.attributes.legacyId).toEqual('string'); // introduced by setLegacyId migration
delete migratedAlert.attributes.legacyId;
expect(migratedAlert).toEqual(alert);
});
});
});

Expand Down
4 changes: 3 additions & 1 deletion x-pack/plugins/alerting/server/saved_objects/migrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
import { RawAlert, RawAlertAction } from '../types';
import { EncryptedSavedObjectsPluginSetup } from '../../../encrypted_saved_objects/server';
import type { IsMigrationNeededPredicate } from '../../../encrypted_saved_objects/server';
import { extractRefsFromGeoContainmentAlert } from './geo_containment/migrations';

const SIEM_APP_ID = 'securitySolution';
const SIEM_SERVER_APP_ID = 'siem';
Expand Down Expand Up @@ -117,7 +118,8 @@ export function getMigrations(
pipeMigrations(
setLegacyId,
getRemovePreconfiguredConnectorsFromReferencesFn(isPreconfigured),
addRuleIdsToLegacyNotificationReferences
addRuleIdsToLegacyNotificationReferences,
extractRefsFromGeoContainmentAlert
)
);

Expand Down
Loading

0 comments on commit c41007e

Please sign in to comment.