Skip to content

Commit

Permalink
[RAC] [RBAC] Adds bulk update route to rule registry and bulk update …
Browse files Browse the repository at this point in the history
…function to alerts client (#106297)

Adds a bulk update route (POST /internal/rac/alerts/bulk_update) to the rule registry and bulkUpdate function to the alerts as data client.
  • Loading branch information
dhurley14 committed Aug 9, 2021
1 parent bc17141 commit ab43afa
Show file tree
Hide file tree
Showing 33 changed files with 1,870 additions and 288 deletions.
2 changes: 2 additions & 0 deletions packages/kbn-rule-data-utils/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ NPM_MODULE_EXTRA_FILES = [
]

SRC_DEPS = [
"//packages/kbn-es-query",
"@npm//tslib",
"@npm//utility-types",
"@npm//@elastic/elasticsearch",
]

TYPES_DEPS = [
Expand Down
58 changes: 58 additions & 0 deletions packages/kbn-rule-data-utils/src/alerts_as_data_rbac.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
* Side Public License, v 1.
*/

import type { estypes } from '@elastic/elasticsearch';
import type { EsQueryConfig } from '@kbn/es-query';

/**
* registering a new instance of the rule data client
* in a new plugin will require updating the below data structure
Expand All @@ -24,6 +27,7 @@ export const AlertConsumers = {
SYNTHETICS: 'synthetics',
} as const;
export type AlertConsumers = typeof AlertConsumers[keyof typeof AlertConsumers];
export type STATUS_VALUES = 'open' | 'acknowledged' | 'closed';

export const mapConsumerToIndexName: Record<AlertConsumers, string | string[]> = {
apm: '.alerts-observability-apm',
Expand All @@ -38,3 +42,57 @@ export type ValidFeatureId = keyof typeof mapConsumerToIndexName;
export const validFeatureIds = Object.keys(mapConsumerToIndexName);
export const isValidFeatureId = (a: unknown): a is ValidFeatureId =>
typeof a === 'string' && validFeatureIds.includes(a);

/**
* Prevent javascript from returning Number.MAX_SAFE_INTEGER when Elasticsearch expects
* Java's Long.MAX_VALUE. This happens when sorting fields by date which are
* unmapped in the provided index
*
* Ref: https://github.com/elastic/elasticsearch/issues/28806#issuecomment-369303620
*
* return stringified Long.MAX_VALUE if we receive Number.MAX_SAFE_INTEGER
* @param sortIds estypes.SearchSortResults | undefined
* @returns SortResults
*/
export const getSafeSortIds = (sortIds: estypes.SearchSortResults | null | undefined) => {
if (sortIds == null) {
return sortIds;
}
return sortIds.map((sortId) => {
// haven't determined when we would receive a null value for a sort id
// but in case we do, default to sending the stringified Java max_int
if (sortId == null || sortId === '' || sortId >= Number.MAX_SAFE_INTEGER) {
return '9223372036854775807';
}
return sortId;
});
};

interface GetEsQueryConfigParamType {
allowLeadingWildcards?: EsQueryConfig['allowLeadingWildcards'];
queryStringOptions?: EsQueryConfig['queryStringOptions'];
ignoreFilterIfFieldNotInIndex?: EsQueryConfig['ignoreFilterIfFieldNotInIndex'];
dateFormatTZ?: EsQueryConfig['dateFormatTZ'];
}

type ConfigKeys = keyof GetEsQueryConfigParamType;

export const getEsQueryConfig = (params?: GetEsQueryConfigParamType): EsQueryConfig => {
const defaultConfigValues = {
allowLeadingWildcards: true,
queryStringOptions: { analyze_wildcard: true },
ignoreFilterIfFieldNotInIndex: false,
dateFormatTZ: 'Zulu',
};
if (params == null) {
return defaultConfigValues;
}
const paramKeysWithValues = Object.keys(params).reduce((acc: EsQueryConfig, key) => {
const configKey = key as ConfigKeys;
if (params[configKey] != null) {
return { [key]: params[configKey], ...acc };
}
return { [key]: defaultConfigValues[configKey], ...acc };
}, {} as EsQueryConfig);
return paramKeysWithValues;
};
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const createAlertingAuthorizationMock = () => {
const mocked: AlertingAuthorizationMock = {
ensureAuthorized: jest.fn(),
filterByRuleTypeAuthorization: jest.fn(),
getAuthorizationFilter: jest.fn(),
getFindAuthorizationFilter: jest.fn(),
getAugmentedRuleTypesWithAuthorization: jest.fn(),
getSpaceId: jest.fn(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -281,11 +281,23 @@ export class AlertingAuthorization {
filter?: KueryNode | JsonObject;
ensureRuleTypeIsAuthorized: (ruleTypeId: string, consumer: string, auth: string) => void;
logSuccessfulAuthorization: () => void;
}> {
return this.getAuthorizationFilter(authorizationEntity, filterOpts, ReadOperations.Find);
}

public async getAuthorizationFilter(
authorizationEntity: AlertingAuthorizationEntity,
filterOpts: AlertingAuthorizationFilterOpts,
operation: WriteOperations | ReadOperations
): Promise<{
filter?: KueryNode | JsonObject;
ensureRuleTypeIsAuthorized: (ruleTypeId: string, consumer: string, auth: string) => void;
logSuccessfulAuthorization: () => void;
}> {
if (this.authorization && this.shouldCheckAuthorization()) {
const { username, authorizedRuleTypes } = await this.augmentRuleTypesWithAuthorization(
this.ruleTypeRegistry.list(),
[ReadOperations.Find],
[operation],
authorizationEntity
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const alert: Alert = {
'rule.name': ['Latency threshold | frontend-rum'],
[ALERT_DURATION]: [62879000],
[ALERT_STATUS]: ['open'],
[SPACE_IDS]: ['myfakespaceid'],
tags: ['apm', 'service.name:frontend-rum'],
'transaction.type': ['page-load'],
[ALERT_PRODUCER]: ['apm'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ Alerts as data client API Interface

### Interfaces

- [BulkUpdateOptions](interfaces/bulkupdateoptions.md)
- [ConstructorOptions](interfaces/constructoroptions.md)
- [UpdateOptions](interfaces/updateoptions.md)
Loading

0 comments on commit ab43afa

Please sign in to comment.