[Rules migration][Integration test] Get migration rules API (#11232) (#210867)

## Summary

[Internal link](https://github.com/elastic/security-team/issues/10820)
to the feature details

Part of https://github.com/elastic/security-team/issues/11232

This PR covers SIEM Migrations GET API (route:
`/internal/siem_migrations/rules/{migration_id}`) integration test:
* Basic calls
* Filtering
* Sorting
* Pagination
This commit is contained in:
Ievgen Sorokopud 2025-02-13 13:44:08 +01:00 committed by GitHub
parent baadf59aa2
commit 526ff0516e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 749 additions and 43 deletions

View file

@ -8,9 +8,17 @@
import expect from 'expect';
import { v4 as uuidv4 } from 'uuid';
import {
RuleTranslationResult,
SiemMigrationStatus,
} from '@kbn/security-solution-plugin/common/siem_migrations/constants';
import {
RuleMigrationDocument,
createMigrationRules,
defaultElasticRule,
defaultOriginalRule,
deleteAllMigrationRules,
getMigrationRuleDocument,
getMigrationRuleDocuments,
migrationRulesRouteHelpersFactory,
} from '../../utils';
import { FtrProviderContext } from '../../../../ftr_provider_context';
@ -25,18 +33,652 @@ export default ({ getService }: FtrProviderContext) => {
await deleteAllMigrationRules(es);
});
it('should fetch existing rules within specified migration', async () => {
// create a document
const migrationId = uuidv4();
const migrationRuleDocument = getMigrationRuleDocument({ migration_id: migrationId });
await createMigrationRules(es, [migrationRuleDocument]);
describe('Basic', () => {
it('should fetch existing rules within specified migration', async () => {
// create a document
const migrationId = uuidv4();
const migrationRuleDocument = getMigrationRuleDocument({ migration_id: migrationId });
await createMigrationRules(es, [migrationRuleDocument]);
const { '@timestamp': timestamp, updated_at: updatedAt, ...rest } = migrationRuleDocument;
const { '@timestamp': timestamp, updated_at: updatedAt, ...rest } = migrationRuleDocument;
// fetch migration rule
const response = await migrationRulesRoutes.get(migrationId);
expect(response.body.total).toEqual(1);
expect(response.body.data).toEqual(expect.arrayContaining([expect.objectContaining(rest)]));
// fetch migration rule
const response = await migrationRulesRoutes.get({ migrationId });
expect(response.body.total).toEqual(1);
expect(response.body.data).toEqual(expect.arrayContaining([expect.objectContaining(rest)]));
});
});
describe('Filtering', () => {
it('should fetch rules filtered by `searchTerm`', async () => {
// create a document
const migrationId = uuidv4();
const overrideCallback = (index: number): Partial<RuleMigrationDocument> => {
const title = `${index < 5 ? 'Elastic' : 'Splunk'} rule - ${index}`;
const originalRule = { ...defaultOriginalRule, title };
const elasticRule = { ...defaultElasticRule, title };
return {
migration_id: migrationId,
original_rule: originalRule,
elastic_rule: elasticRule,
};
};
const migrationRuleDocuments = getMigrationRuleDocuments(10, overrideCallback);
await createMigrationRules(es, migrationRuleDocuments);
// Search by word `Elastic`
let expectedRuleDocuments = expect.arrayContaining(
migrationRuleDocuments
.slice(0, 5)
.map(({ '@timestamp': timestamp, updated_at: updatedAt, ...rest }) =>
expect.objectContaining(rest)
)
);
// fetch migration rules
let response = await migrationRulesRoutes.get({
migrationId,
filters: { searchTerm: 'Elastic' },
});
expect(response.body.total).toEqual(5);
expect(response.body.data).toEqual(expectedRuleDocuments);
// Search by word `Splunk`
expectedRuleDocuments = expect.arrayContaining(
migrationRuleDocuments
.slice(5)
.map(({ '@timestamp': timestamp, updated_at: updatedAt, ...rest }) =>
expect.objectContaining(rest)
)
);
// fetch migration rules
response = await migrationRulesRoutes.get({
migrationId,
filters: { searchTerm: 'Splunk' },
});
expect(response.body.total).toEqual(5);
expect(response.body.data).toEqual(expectedRuleDocuments);
});
it('should fetch rules filtered by `ids`', async () => {
// create a document
const migrationId = uuidv4();
const migrationRuleDocuments = getMigrationRuleDocuments(10, () => ({
migration_id: migrationId,
}));
const createdDocumentIds = await createMigrationRules(es, migrationRuleDocuments);
const expectedIds = createdDocumentIds.slice(0, 3).sort();
// fetch migration rules by existing ids
let response = await migrationRulesRoutes.get({
migrationId,
filters: { ids: expectedIds },
});
expect(response.body.total).toEqual(3);
expect(response.body.data.map(({ id }) => id).sort()).toEqual(expectedIds);
// fetch migration rules by non-existing id
response = await migrationRulesRoutes.get({
migrationId,
filters: { ids: [uuidv4()] },
});
expect(response.body.total).toEqual(0);
});
it('should fetch rules filtered by `prebuilt`', async () => {
// create a document
const migrationId = uuidv4();
const overrideCallback = (index: number): Partial<RuleMigrationDocument> => {
const prebuiltRuleId = index < 3 ? uuidv4() : undefined;
const elasticRule = { ...defaultElasticRule, prebuilt_rule_id: prebuiltRuleId };
return {
migration_id: migrationId,
elastic_rule: elasticRule,
};
};
const migrationRuleDocuments = getMigrationRuleDocuments(10, overrideCallback);
await createMigrationRules(es, migrationRuleDocuments);
// fetch migration rules matched Elastic prebuilt rules
let response = await migrationRulesRoutes.get({
migrationId,
filters: { prebuilt: true },
});
expect(response.body.total).toEqual(3);
// fetch custom translated migration rules
response = await migrationRulesRoutes.get({
migrationId,
filters: { prebuilt: false },
});
expect(response.body.total).toEqual(7);
});
it('should fetch rules filtered by `installed`', async () => {
// create a document
const migrationId = uuidv4();
const overrideCallback = (index: number): Partial<RuleMigrationDocument> => {
const installedRuleId = index < 2 ? uuidv4() : undefined;
const elasticRule = { ...defaultElasticRule, id: installedRuleId };
return {
migration_id: migrationId,
elastic_rule: elasticRule,
};
};
const migrationRuleDocuments = getMigrationRuleDocuments(10, overrideCallback);
await createMigrationRules(es, migrationRuleDocuments);
// fetch installed migration rules
let response = await migrationRulesRoutes.get({
migrationId,
filters: { installed: true },
});
expect(response.body.total).toEqual(2);
// fetch non-installed migration rules
response = await migrationRulesRoutes.get({
migrationId,
filters: { installed: false },
});
expect(response.body.total).toEqual(8);
});
it('should fetch rules filtered by `failed`', async () => {
// create a document
const migrationId = uuidv4();
const overrideCallback = (index: number): Partial<RuleMigrationDocument> => {
const status = index < 4 ? SiemMigrationStatus.FAILED : SiemMigrationStatus.COMPLETED;
return {
migration_id: migrationId,
status,
};
};
const migrationRuleDocuments = getMigrationRuleDocuments(10, overrideCallback);
await createMigrationRules(es, migrationRuleDocuments);
// fetch failed migration rules
let response = await migrationRulesRoutes.get({
migrationId,
filters: { failed: true },
});
expect(response.body.total).toEqual(4);
// fetch non-failed migration rules
response = await migrationRulesRoutes.get({
migrationId,
filters: { failed: false },
});
expect(response.body.total).toEqual(6);
});
it('should fetch rules filtered by `fullyTranslated`', async () => {
// create a document
const migrationId = uuidv4();
const overrideCallback = (index: number): Partial<RuleMigrationDocument> => {
const translationResult =
index < 6
? RuleTranslationResult.FULL
: index < 8
? RuleTranslationResult.PARTIAL
: RuleTranslationResult.UNTRANSLATABLE;
return {
migration_id: migrationId,
translation_result: translationResult,
};
};
const migrationRuleDocuments = getMigrationRuleDocuments(10, overrideCallback);
await createMigrationRules(es, migrationRuleDocuments);
// fetch failed migration rules
let response = await migrationRulesRoutes.get({
migrationId,
filters: { fullyTranslated: true },
});
expect(response.body.total).toEqual(6);
// fetch non-failed migration rules
response = await migrationRulesRoutes.get({
migrationId,
filters: { fullyTranslated: false },
});
expect(response.body.total).toEqual(4);
});
it('should fetch rules filtered by `partiallyTranslated`', async () => {
// create a document
const migrationId = uuidv4();
const overrideCallback = (index: number): Partial<RuleMigrationDocument> => {
const translationResult =
index < 4
? RuleTranslationResult.FULL
: index < 8
? RuleTranslationResult.PARTIAL
: RuleTranslationResult.UNTRANSLATABLE;
return {
migration_id: migrationId,
translation_result: translationResult,
};
};
const migrationRuleDocuments = getMigrationRuleDocuments(10, overrideCallback);
await createMigrationRules(es, migrationRuleDocuments);
// fetch failed migration rules
let response = await migrationRulesRoutes.get({
migrationId,
filters: { partiallyTranslated: true },
});
expect(response.body.total).toEqual(4);
// fetch non-failed migration rules
response = await migrationRulesRoutes.get({
migrationId,
filters: { partiallyTranslated: false },
});
expect(response.body.total).toEqual(6);
});
it('should fetch rules filtered by `untranslatable`', async () => {
// create a document
const migrationId = uuidv4();
const overrideCallback = (index: number): Partial<RuleMigrationDocument> => {
const translationResult =
index < 3
? RuleTranslationResult.FULL
: index < 5
? RuleTranslationResult.PARTIAL
: RuleTranslationResult.UNTRANSLATABLE;
return {
migration_id: migrationId,
translation_result: translationResult,
};
};
const migrationRuleDocuments = getMigrationRuleDocuments(10, overrideCallback);
await createMigrationRules(es, migrationRuleDocuments);
// fetch failed migration rules
let response = await migrationRulesRoutes.get({
migrationId,
filters: { untranslatable: true },
});
expect(response.body.total).toEqual(5);
// fetch non-failed migration rules
response = await migrationRulesRoutes.get({
migrationId,
filters: { untranslatable: false },
});
expect(response.body.total).toEqual(5);
});
});
describe('Sorting', () => {
it('should fetch rules sorted by `title`', async () => {
const titles = ['Elastic 1', 'Windows', 'Linux', 'Elastic 2'];
// create a document
const migrationId = uuidv4();
const overrideCallback = (index: number): Partial<RuleMigrationDocument> => {
const title = titles[index];
const originalRule = { ...defaultOriginalRule, title };
const elasticRule = { ...defaultElasticRule, title };
return {
migration_id: migrationId,
original_rule: originalRule,
elastic_rule: elasticRule,
};
};
const migrationRuleDocuments = getMigrationRuleDocuments(titles.length, overrideCallback);
await createMigrationRules(es, migrationRuleDocuments);
// fetch migration rules
let response = await migrationRulesRoutes.get({
migrationId,
sortField: 'elastic_rule.title',
sortDirection: 'asc',
});
expect(response.body.data.map((rule) => rule.elastic_rule?.title)).toEqual(titles.sort());
// fetch migration rules
response = await migrationRulesRoutes.get({
migrationId,
sortField: 'elastic_rule.title',
sortDirection: 'desc',
});
expect(response.body.data.map((rule) => rule.elastic_rule?.title)).toEqual(
titles.sort().reverse()
);
});
it('should fetch rules sorted by `severity`', async () => {
const severities = ['critical', 'low', 'medium', 'low', 'critical'];
// create a document
const migrationId = uuidv4();
const overrideCallback = (index: number): Partial<RuleMigrationDocument> => {
const severity = severities[index];
const elasticRule = { ...defaultElasticRule, severity };
return {
migration_id: migrationId,
elastic_rule: elasticRule,
};
};
const migrationRuleDocuments = getMigrationRuleDocuments(
severities.length,
overrideCallback
);
await createMigrationRules(es, migrationRuleDocuments);
// fetch migration rules
let response = await migrationRulesRoutes.get({
migrationId,
sortField: 'elastic_rule.severity',
sortDirection: 'asc',
});
expect(response.body.data.map((rule) => rule.elastic_rule?.severity)).toEqual([
'low',
'low',
'medium',
'critical',
'critical',
]);
// fetch migration rules
response = await migrationRulesRoutes.get({
migrationId,
sortField: 'elastic_rule.severity',
sortDirection: 'desc',
});
expect(response.body.data.map((rule) => rule.elastic_rule?.severity)).toEqual([
'critical',
'critical',
'medium',
'low',
'low',
]);
});
it('should fetch rules sorted by `risk_score`', async () => {
const riskScores = [55, 0, 100, 23];
// create a document
const migrationId = uuidv4();
const overrideCallback = (index: number): Partial<RuleMigrationDocument> => {
const riskScore = riskScores[index];
const elasticRule = { ...defaultElasticRule, risk_score: riskScore };
return {
migration_id: migrationId,
elastic_rule: elasticRule,
};
};
const migrationRuleDocuments = getMigrationRuleDocuments(
riskScores.length,
overrideCallback
);
await createMigrationRules(es, migrationRuleDocuments);
// fetch migration rules
let response = await migrationRulesRoutes.get({
migrationId,
sortField: 'elastic_rule.risk_score',
sortDirection: 'asc',
});
expect(response.body.data.map((rule) => rule.elastic_rule?.risk_score)).toEqual(
riskScores.sort((a, b) => {
return a - b;
})
);
// fetch migration rules
response = await migrationRulesRoutes.get({
migrationId,
sortField: 'elastic_rule.risk_score',
sortDirection: 'desc',
});
expect(response.body.data.map((rule) => rule.elastic_rule?.risk_score)).toEqual(
riskScores
.sort((a, b) => {
return a - b;
})
.reverse()
);
});
it('should fetch rules sorted by `prebuilt_rule_id`', async () => {
const prebuiltRuleIds = ['rule-1', undefined, undefined, 'rule-2', undefined];
// create a document
const migrationId = uuidv4();
const overrideCallback = (index: number): Partial<RuleMigrationDocument> => {
const prebuiltRuleId = prebuiltRuleIds[index];
const elasticRule = { ...defaultElasticRule, prebuilt_rule_id: prebuiltRuleId };
return {
migration_id: migrationId,
elastic_rule: elasticRule,
};
};
const migrationRuleDocuments = getMigrationRuleDocuments(
prebuiltRuleIds.length,
overrideCallback
);
await createMigrationRules(es, migrationRuleDocuments);
// fetch migration rules
let response = await migrationRulesRoutes.get({
migrationId,
sortField: 'elastic_rule.prebuilt_rule_id',
sortDirection: 'asc',
});
expect(response.body.data.map((rule) => rule.elastic_rule?.prebuilt_rule_id)).toEqual([
undefined,
undefined,
undefined,
'rule-1',
'rule-2',
]);
// fetch migration rules
response = await migrationRulesRoutes.get({
migrationId,
sortField: 'elastic_rule.prebuilt_rule_id',
sortDirection: 'desc',
});
expect(response.body.data.map((rule) => rule.elastic_rule?.prebuilt_rule_id)).toEqual([
'rule-2',
'rule-1',
undefined,
undefined,
undefined,
]);
});
it('should fetch rules sorted by `translation_result`', async () => {
const translationResults = [
RuleTranslationResult.UNTRANSLATABLE,
RuleTranslationResult.FULL,
RuleTranslationResult.PARTIAL,
];
// create a document
const migrationId = uuidv4();
const overrideCallback = (index: number): Partial<RuleMigrationDocument> => {
return {
migration_id: migrationId,
translation_result: translationResults[index],
};
};
const migrationRuleDocuments = getMigrationRuleDocuments(
translationResults.length,
overrideCallback
);
await createMigrationRules(es, migrationRuleDocuments);
// fetch migration rules
let response = await migrationRulesRoutes.get({
migrationId,
sortField: 'translation_result',
sortDirection: 'asc',
});
expect(response.body.data.map((rule) => rule.translation_result)).toEqual([
RuleTranslationResult.UNTRANSLATABLE,
RuleTranslationResult.PARTIAL,
RuleTranslationResult.FULL,
]);
// fetch migration rules
response = await migrationRulesRoutes.get({
migrationId,
sortField: 'translation_result',
sortDirection: 'desc',
});
expect(response.body.data.map((rule) => rule.translation_result)).toEqual([
RuleTranslationResult.FULL,
RuleTranslationResult.PARTIAL,
RuleTranslationResult.UNTRANSLATABLE,
]);
});
it('should fetch rules sorted by `updated_at`', async () => {
// create a document
const migrationId = uuidv4();
// Creating documents separately to have different `update_at` timestamps
await createMigrationRules(es, [getMigrationRuleDocument({ migration_id: migrationId })]);
await createMigrationRules(es, [getMigrationRuleDocument({ migration_id: migrationId })]);
await createMigrationRules(es, [getMigrationRuleDocument({ migration_id: migrationId })]);
await createMigrationRules(es, [getMigrationRuleDocument({ migration_id: migrationId })]);
await createMigrationRules(es, [getMigrationRuleDocument({ migration_id: migrationId })]);
// fetch migration rules
let response = await migrationRulesRoutes.get({
migrationId,
sortField: 'updated_at',
sortDirection: 'asc',
});
const ascSorted = response.body.data.map((rule) => rule.updated_at);
// fetch migration rules
response = await migrationRulesRoutes.get({
migrationId,
sortField: 'updated_at',
sortDirection: 'desc',
});
const descSorted = response.body.data.map((rule) => rule.updated_at);
expect(ascSorted).toEqual(descSorted.reverse());
});
});
describe('Pagination', () => {
it('should fetch rules within specific page', async () => {
const titles = Array.from({ length: 50 }, (_, index) => `Migration rule - ${index}`);
// create a document
const migrationId = uuidv4();
const overrideCallback = (index: number): Partial<RuleMigrationDocument> => {
const title = titles[index];
const originalRule = { ...defaultOriginalRule, title };
const elasticRule = { ...defaultElasticRule, title };
return {
migration_id: migrationId,
original_rule: originalRule,
elastic_rule: elasticRule,
};
};
const migrationRuleDocuments = getMigrationRuleDocuments(titles.length, overrideCallback);
await createMigrationRules(es, migrationRuleDocuments);
// fetch migration rules
const response = await migrationRulesRoutes.get({
migrationId,
page: 3,
perPage: 7,
});
const start = 3 * 7;
expect(response.body.data.map((rule) => rule.elastic_rule?.title)).toEqual(
titles.slice(start, start + 7)
);
});
it('should fetch rules within very first page if `perPage` is not specified', async () => {
const titles = Array.from({ length: 50 }, (_, index) => `Migration rule - ${index}`);
// create a document
const migrationId = uuidv4();
const overrideCallback = (index: number): Partial<RuleMigrationDocument> => {
const title = titles[index];
const originalRule = { ...defaultOriginalRule, title };
const elasticRule = { ...defaultElasticRule, title };
return {
migration_id: migrationId,
original_rule: originalRule,
elastic_rule: elasticRule,
};
};
const migrationRuleDocuments = getMigrationRuleDocuments(titles.length, overrideCallback);
await createMigrationRules(es, migrationRuleDocuments);
// fetch migration rules
const response = await migrationRulesRoutes.get({
migrationId,
page: 3,
});
const defaultSize = 10;
expect(response.body.data.map((rule) => rule.elastic_rule?.title)).toEqual(
titles.slice(0, defaultSize)
);
});
it('should fetch rules within very first page of a specified size if `perPage` is specified', async () => {
const titles = Array.from({ length: 50 }, (_, index) => `Migration rule - ${index}`);
// create a document
const migrationId = uuidv4();
const overrideCallback = (index: number): Partial<RuleMigrationDocument> => {
const title = titles[index];
const originalRule = { ...defaultOriginalRule, title };
const elasticRule = { ...defaultElasticRule, title };
return {
migration_id: migrationId,
original_rule: originalRule,
elastic_rule: elasticRule,
};
};
const migrationRuleDocuments = getMigrationRuleDocuments(titles.length, overrideCallback);
await createMigrationRules(es, migrationRuleDocuments);
// fetch migration rules
const response = await migrationRulesRoutes.get({
migrationId,
perPage: 18,
});
expect(response.body.data.map((rule) => rule.elastic_rule?.title)).toEqual(
titles.slice(0, 18)
);
});
});
});
};

View file

@ -10,32 +10,51 @@ import type { Client } from '@elastic/elasticsearch';
import { X_ELASTIC_INTERNAL_ORIGIN_REQUEST } from '@kbn/core-http-common';
import { replaceParams } from '@kbn/openapi-common/shared';
import { RuleMigration } from '@kbn/security-solution-plugin/common/siem_migrations/model/rule_migration.gen';
import {
ElasticRule,
OriginalRule,
RuleMigration,
} from '@kbn/security-solution-plugin/common/siem_migrations/model/rule_migration.gen';
import { INDEX_PATTERN as SIEM_MIGRATIONS_INDEX_PATTERN } from '@kbn/security-solution-plugin/server/lib/siem_migrations/rules/data/rule_migrations_data_service';
import { SIEM_RULE_MIGRATION_PATH } from '@kbn/security-solution-plugin/common/siem_migrations/constants';
import { GetRuleMigrationResponse } from '@kbn/security-solution-plugin/common/siem_migrations/model/api/rules/rule_migration.gen';
import { generateAssistantComment } from '@kbn/security-solution-plugin/server/lib/siem_migrations/rules/task/util/comments';
import { RuleMigrationFilters } from '@kbn/security-solution-plugin/common/siem_migrations/types';
const SIEM_MIGRATIONS_RULES_INDEX_PATTERN = `${SIEM_MIGRATIONS_INDEX_PATTERN}-rules-default`;
export type RuleMigrationDocument = Omit<RuleMigration, 'id'>;
const migrationRuleDocument: RuleMigrationDocument = {
export const defaultOriginalRule: OriginalRule = {
id: 'https://127.0.0.1:8089/servicesNS/nobody/SA-AccessProtection/saved/searches/Access%20-%20Default%20Account%20Usage%20-%20Rule',
vendor: 'splunk',
title: 'Access - Default Account Usage - Rule',
description:
'Discovers use of default accounts (such as admin, administrator, etc.). Default accounts have default passwords and are therefore commonly targeted by attackers using brute force attack tools.',
query:
'| from datamodel:"Authentication"."Successful_Default_Authentication" | stats max("_time") as "lastTime",values("tag") as "tag",count by "dest","user","app"',
query_language: 'spl',
annotations: {
mitre_attack: ['T1078'],
},
};
export const defaultElasticRule: ElasticRule = {
severity: 'low',
risk_score: 21,
integration_ids: [''],
query:
'FROM [indexPattern]\n| STATS lastTime = max(_time), tag = values(tag), count BY dest, user, app',
description:
'Discovers use of default accounts (such as admin, administrator, etc.). Default accounts have default passwords and are therefore commonly targeted by attackers using brute force attack tools.',
query_language: 'esql',
title: 'Access - Default Account Usage - Rule',
};
const defaultMigrationRuleDocument: RuleMigrationDocument = {
'@timestamp': '2025-01-13T15:17:43.571Z',
migration_id: '25a24356-3aab-401b-a73c-905cb8bf7a6d',
original_rule: {
id: 'https://127.0.0.1:8089/servicesNS/nobody/SA-AccessProtection/saved/searches/Access%20-%20Default%20Account%20Usage%20-%20Rule',
vendor: 'splunk',
title: 'Access - Default Account Usage - Rule',
description:
'Discovers use of default accounts (such as admin, administrator, etc.). Default accounts have default passwords and are therefore commonly targeted by attackers using brute force attack tools.',
query:
'| from datamodel:"Authentication"."Successful_Default_Authentication" | stats max("_time") as "lastTime",values("tag") as "tag",count by "dest","user","app"',
query_language: 'spl',
annotations: {
mitre_attack: ['T1078'],
},
},
original_rule: defaultOriginalRule,
status: 'completed',
created_by: 'u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0',
updated_by: 'u_mGBROF_q5bmFCATbLXAcCwKa0k8JvONAwSruelyKA5E_0',
@ -50,32 +69,34 @@ const migrationRuleDocument: RuleMigrationDocument = {
),
],
translation_result: 'partial',
elastic_rule: {
severity: 'low',
risk_score: 21,
integration_ids: [''],
query:
'FROM [indexPattern]\n| STATS lastTime = max(_time), tag = values(tag), count BY dest, user, app',
description:
'Discovers use of default accounts (such as admin, administrator, etc.). Default accounts have default passwords and are therefore commonly targeted by attackers using brute force attack tools.',
query_language: 'esql',
title: 'Access - Default Account Usage - Rule',
},
elastic_rule: defaultElasticRule,
};
export const getMigrationRuleDocument = (
overrideParams: Partial<RuleMigrationDocument>
): RuleMigrationDocument => ({
...migrationRuleDocument,
...defaultMigrationRuleDocument,
...overrideParams,
});
export const getMigrationRuleDocuments = (
count: number,
overrideCallback: (index: number) => Partial<RuleMigrationDocument>
): RuleMigrationDocument[] => {
const docs: RuleMigrationDocument[] = [];
for (let i = 0; i < count; i++) {
const overrideParams = overrideCallback(i);
docs.push(getMigrationRuleDocument(overrideParams));
}
return docs;
};
export const createMigrationRules = async (
es: Client,
rules: RuleMigrationDocument[]
): Promise<void> => {
): Promise<string[]> => {
const createdAt = new Date().toISOString();
await es.bulk({
const res = await es.bulk({
refresh: 'wait_for',
operations: rules.flatMap((ruleMigration) => [
{ create: { _index: SIEM_MIGRATIONS_RULES_INDEX_PATTERN } },
@ -86,6 +107,13 @@ export const createMigrationRules = async (
},
]),
});
const ids = res.items.reduce((acc, item) => {
if (item.create?._id) {
acc.push(item.create._id);
}
return acc;
}, [] as string[]);
return ids;
};
export const deleteAllMigrationRules = async (es: Client): Promise<void> => {
@ -109,14 +137,50 @@ const assertStatusCode = (statusCode: number, response: SuperTest.Response) => {
}
};
export interface GetRuleMigrationParams {
/** `id` of the migration to get rules documents for */
migrationId: string;
/** Optional page number to retrieve */
page?: number;
/** Optional number of documents per page to retrieve */
perPage?: number;
/** Optional field of the rule migration object to sort results by */
sortField?: string;
/** Optional direction to sort results by */
sortDirection?: 'asc' | 'desc';
/** Optional parameter to filter documents */
filters?: RuleMigrationFilters;
/** Optional expected status code parameter */
expectStatusCode?: number;
}
export const migrationRulesRouteHelpersFactory = (supertest: SuperTest.Agent) => {
return {
get: async (
migrationId: string,
expectStatusCode: number = 200
): Promise<{ body: GetRuleMigrationResponse }> => {
get: async ({
migrationId,
page,
perPage,
sortField,
sortDirection,
filters,
expectStatusCode = 200,
}: GetRuleMigrationParams): Promise<{ body: GetRuleMigrationResponse }> => {
const response = await supertest
.get(replaceParams(SIEM_RULE_MIGRATION_PATH, { migration_id: migrationId }))
.query({
page,
per_page: perPage,
sort_field: sortField,
sort_direction: sortDirection,
search_term: filters?.searchTerm,
ids: filters?.ids,
is_prebuilt: filters?.prebuilt,
is_installed: filters?.installed,
is_fully_translated: filters?.fullyTranslated,
is_partially_translated: filters?.partiallyTranslated,
is_untranslatable: filters?.untranslatable,
is_failed: filters?.failed,
})
.set('kbn-xsrf', 'true')
.set('elastic-api-version', '1')
.set(X_ELASTIC_INTERNAL_ORIGIN_REQUEST, 'kibana')