Skip to content

Commit

Permalink
Review feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
e40pud committed Dec 9, 2024
1 parent 12d57a8 commit 786a025
Show file tree
Hide file tree
Showing 3 changed files with 177 additions and 133 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
* 2.0.
*/

import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
import type {
AggregationsAggregationContainer,
AggregationsFilterAggregate,
Expand All @@ -16,17 +15,16 @@ import type {
QueryDslQueryContainer,
} from '@elastic/elasticsearch/lib/api/types';
import type { StoredRuleMigration } from '../types';
import {
SiemMigrationRuleTranslationResult,
SiemMigrationStatus,
} from '../../../../../common/siem_migrations/constants';
import { SiemMigrationStatus } from '../../../../../common/siem_migrations/constants';
import type {
ElasticRule,
RuleMigration,
RuleMigrationTaskStats,
RuleMigrationTranslationStats,
} from '../../../../../common/siem_migrations/model/rule_migration.gen';
import { RuleMigrationsDataBaseClient } from './rule_migrations_data_base_client';
import { getSortingOptions, type RuleMigrationSort } from './sort';
import { conditions as searchConditions } from './search';

export type CreateRuleMigrationInput = Omit<
RuleMigration,
Expand All @@ -46,10 +44,6 @@ export interface RuleMigrationFilters {
prebuilt?: boolean;
searchTerm?: string;
}
export interface RuleMigrationSort {
sortField?: string;
sortDirection?: estypes.SortOrder;
}
export interface RuleMigrationGetOptions {
filters?: RuleMigrationFilters;
sort?: RuleMigrationSort;
Expand Down Expand Up @@ -250,8 +244,8 @@ export class RuleMigrationsDataRulesClient extends RuleMigrationsDataBaseClient
const query = this.getFilterQuery(migrationId);

const aggregations = {
prebuilt: { filter: conditions.isPrebuilt() },
installable: { filter: { bool: { must: conditions.isInstallable() } } },
prebuilt: { filter: searchConditions.isPrebuilt() },
installable: { filter: { bool: { must: searchConditions.isInstallable() } } },
};
const result = await this.esClient
.search({ index, query, aggregations, _source: false })
Expand Down Expand Up @@ -363,133 +357,14 @@ export class RuleMigrationsDataRulesClient extends RuleMigrationsDataBaseClient
filter.push({ terms: { _id: ids } });
}
if (installable) {
filter.push(...conditions.isInstallable());
filter.push(...searchConditions.isInstallable());
}
if (prebuilt) {
filter.push(conditions.isPrebuilt());
filter.push(searchConditions.isPrebuilt());
}
if (searchTerm?.length) {
filter.push(conditions.matchTitle(searchTerm));
filter.push(searchConditions.matchTitle(searchTerm));
}
return { bool: { filter } };
}
}

const conditions = {
isFullyTranslated(): QueryDslQueryContainer {
return { term: { translation_result: SiemMigrationRuleTranslationResult.FULL } };
},
isNotInstalled(): QueryDslQueryContainer {
return {
nested: {
path: 'elastic_rule',
query: { bool: { must_not: { exists: { field: 'elastic_rule.id' } } } },
},
};
},
isPrebuilt(): QueryDslQueryContainer {
return {
nested: {
path: 'elastic_rule',
query: { exists: { field: 'elastic_rule.prebuilt_rule_id' } },
},
};
},
matchTitle(title: string): QueryDslQueryContainer {
return {
nested: {
path: 'elastic_rule',
query: { match: { 'elastic_rule.title': title } },
},
};
},
isInstallable(): QueryDslQueryContainer[] {
return [this.isFullyTranslated(), this.isNotInstalled()];
},
};

const missing = (direction: estypes.SortOrder = 'asc') =>
direction === 'desc' ? '_last' : '_first';

const sortingOptions = {
author(direction: estypes.SortOrder = 'asc'): estypes.SortCombinations {
return {
'elastic_rule.prebuilt_rule_id': {
order: direction,
nested: { path: 'elastic_rule' },
missing: missing(direction),
},
};
},
severity(direction: estypes.SortOrder = 'asc'): estypes.SortCombinations {
const field = 'elastic_rule.severity';
return {
_script: {
order: direction,
type: 'number',
script: {
source: `
if (doc.containsKey('${field}') && !doc['${field}'].empty) {
def value = doc['${field}'].value.toLowerCase();
if (value == 'critical') { return 3 }
if (value == 'high') { return 2 }
if (value == 'medium') { return 1 }
if (value == 'low') { return 0 }
}
return -1;
`,
lang: 'painless',
},
nested: { path: 'elastic_rule' },
},
};
},
status(direction: estypes.SortOrder = 'asc'): estypes.SortCombinations {
const field = 'translation_result';
return {
_script: {
order: direction,
type: 'number',
script: {
source: `
if (doc.containsKey('${field}') && !doc['${field}'].empty) {
def value = doc['${field}'].value.toLowerCase();
if (value == 'full') { return 2 }
if (value == 'partial') { return 1 }
if (value == 'untranslatable') { return 0 }
}
return -1;
`,
lang: 'painless',
},
},
};
},
updated(direction: estypes.SortOrder = 'asc'): estypes.SortCombinations {
return { updated_at: direction };
},
name(direction: estypes.SortOrder = 'asc'): estypes.SortCombinations {
return { 'elastic_rule.title.keyword': { order: direction, nested: { path: 'elastic_rule' } } };
},
};

const DEFAULT_SORTING: estypes.Sort = [
sortingOptions.status('desc'),
sortingOptions.author('desc'),
sortingOptions.severity(),
sortingOptions.updated(),
];

const getSortingOptions = (sort?: RuleMigrationSort): estypes.Sort => {
if (!sort?.sortField) {
return DEFAULT_SORTING;
}
const sortingOptionsMap: { [key: string]: estypes.Sort } = {
'elastic_rule.title': sortingOptions.name(sort.sortDirection),
'elastic_rule.severity': sortingOptions.severity(sort.sortDirection),
'elastic_rule.prebuilt_rule_id': sortingOptions.author(sort.sortDirection),
translation_result: sortingOptions.status(sort.sortDirection),
updated_at: sortingOptions.updated(sort.sortDirection),
};
return sortingOptionsMap[sort.sortField] ?? DEFAULT_SORTING;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* 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 { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types';
import { SiemMigrationRuleTranslationResult } from '../../../../../common/siem_migrations/constants';

export const conditions = {
isFullyTranslated(): QueryDslQueryContainer {
return { term: { translation_result: SiemMigrationRuleTranslationResult.FULL } };
},
isNotInstalled(): QueryDslQueryContainer {
return {
nested: {
path: 'elastic_rule',
query: { bool: { must_not: { exists: { field: 'elastic_rule.id' } } } },
},
};
},
isPrebuilt(): QueryDslQueryContainer {
return {
nested: {
path: 'elastic_rule',
query: { exists: { field: 'elastic_rule.prebuilt_rule_id' } },
},
};
},
matchTitle(title: string): QueryDslQueryContainer {
return {
nested: {
path: 'elastic_rule',
query: { match: { 'elastic_rule.title': title } },
},
};
},
isInstallable(): QueryDslQueryContainer[] {
return [this.isFullyTranslated(), this.isNotInstalled()];
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/*
* 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 * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';

export interface RuleMigrationSort {
sortField?: string;
sortDirection?: estypes.SortOrder;
}

const sortMissingValue = (direction: estypes.SortOrder = 'asc') =>
direction === 'desc' ? '_last' : '_first';

const sortingOptions = {
matchedPrebuiltRule(direction: estypes.SortOrder = 'asc'): estypes.SortCombinations[] {
return [
{
'elastic_rule.prebuilt_rule_id': {
order: direction,
nested: { path: 'elastic_rule' },
missing: sortMissingValue(direction),
},
},
];
},
severity(direction: estypes.SortOrder = 'asc'): estypes.SortCombinations[] {
const field = 'elastic_rule.severity';
return [
{
_script: {
order: direction,
type: 'number',
script: {
source: `
if (doc.containsKey('${field}') && !doc['${field}'].empty) {
def value = doc['${field}'].value.toLowerCase();
if (value == 'critical') { return 3 }
if (value == 'high') { return 2 }
if (value == 'medium') { return 1 }
if (value == 'low') { return 0 }
}
return -1;
`,
lang: 'painless',
},
nested: { path: 'elastic_rule' },
},
},
];
},
status(direction: estypes.SortOrder = 'asc'): estypes.SortCombinations[] {
const field = 'translation_result';
const installedRuleField = 'elastic_rule.id';
return [
{
_script: {
order: direction,
type: 'number',
script: {
source: `
if (doc.containsKey('${field}') && !doc['${field}'].empty) {
def value = doc['${field}'].value.toLowerCase();
if (value == 'full') { return 2 }
if (value == 'partial') { return 1 }
if (value == 'untranslatable') { return 0 }
}
return -1;
`,
lang: 'painless',
},
},
},
{
_script: {
order: direction,
type: 'number',
script: {
source: `
if (doc.containsKey('${installedRuleField}') && !doc['${installedRuleField}'].empty) {
return 0;
}
return -1;
`,
lang: 'painless',
},
nested: { path: 'elastic_rule' },
},
},
];
},
updated(direction: estypes.SortOrder = 'asc'): estypes.SortCombinations[] {
return [{ updated_at: direction }];
},
name(direction: estypes.SortOrder = 'asc'): estypes.SortCombinations[] {
return [
{ 'elastic_rule.title.keyword': { order: direction, nested: { path: 'elastic_rule' } } },
];
},
};

const DEFAULT_SORTING: estypes.Sort = [
...sortingOptions.status('desc'),
...sortingOptions.matchedPrebuiltRule('desc'),
...sortingOptions.severity(),
...sortingOptions.updated(),
];

const sortingOptionsMap: {
[key: string]: (direction?: estypes.SortOrder) => estypes.SortCombinations[];
} = {
'elastic_rule.title': sortingOptions.name,
'elastic_rule.severity': sortingOptions.severity,
'elastic_rule.prebuilt_rule_id': sortingOptions.matchedPrebuiltRule,
translation_result: sortingOptions.status,
updated_at: sortingOptions.updated,
};

export const getSortingOptions = (sort?: RuleMigrationSort): estypes.Sort => {
if (!sort?.sortField) {
return DEFAULT_SORTING;
}
return sortingOptionsMap[sort.sortField]?.(sort.sortDirection) ?? DEFAULT_SORTING;
};

0 comments on commit 786a025

Please sign in to comment.