Skip to content

Commit

Permalink
RFC for Prebuilt Rules Customization - Phase 3 - Part 1
Browse files Browse the repository at this point in the history
  • Loading branch information
jpdjere committed Feb 8, 2024
1 parent 52f35fc commit c0f2e05
Show file tree
Hide file tree
Showing 36 changed files with 2,873 additions and 107 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ import {
transformRuleDomainToRule,
} from '../../transforms';
import { validateScheduleLimit, ValidateScheduleLimitResult } from '../get_schedule_frequency';
import { migratePrebuiltSchemaOnRuleBulkEdit } from './schemas/migrate_prebuilt_schema_on_bulk_edit';

const isValidInterval = (interval: string | undefined): interval is string => {
return interval !== undefined;
Expand Down Expand Up @@ -512,9 +513,13 @@ async function updateRuleAttributesAndParamsInMemory<Params extends RuleParams>(
updatedRule.revision += 1;
}

const isRuleUpdated = !(isAttributesUpdateSkipped && isParamsUpdateSkipped);

migratePrebuiltSchemaOnRuleBulkEdit(ruleParams, isRuleUpdated);

// If neither attributes nor parameters were updated, mark
// the rule as skipped and continue to the next rule.
if (isAttributesUpdateSkipped && isParamsUpdateSkipped) {
if (!isRuleUpdated) {
skipped.push({
id: rule.id,
name: rule.attributes.name,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* 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 { RuleParams } from '../../../types';

const getPrebuiltValueForRuleBulkEdit = (
ruleParams: RuleParams,
isRuleUpdatedDuringBulkUpdate: boolean
) => {
if (ruleParams?.prebuilt) {
return {
...ruleParams.prebuilt,
isCustomized: ruleParams.prebuilt.isCustomized || isRuleUpdatedDuringBulkUpdate,
};
}

if (ruleParams.immutable) {
return {
isCustomized: isRuleUpdatedDuringBulkUpdate,
};
}

return undefined;
};

export const migratePrebuiltSchemaOnRuleBulkEdit = (
ruleParams: RuleParams,
isRuleUpdatedDuringBulkUpdate: boolean
) => {
const immutable = Boolean(ruleParams.prebuilt) || ruleParams.immutable;
const prebuilt = getPrebuiltValueForRuleBulkEdit(ruleParams, isRuleUpdatedDuringBulkUpdate);

ruleParams.prebuilt = prebuilt;
ruleParams.immutable = immutable;
};
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,33 @@ export const KqlQueryLanguage = z.enum(['kuery', 'lucene']);
export type KqlQueryLanguageEnum = typeof KqlQueryLanguage.enum;
export const KqlQueryLanguageEnum = KqlQueryLanguage.enum;

/**
* [DEPRECATION WARNING - This field is deprecated and will be removed in a future release. Use the prebuilt field to determine if a rule is an Elastic prebuilt rule or a custom rule.] - Determines whether the rule is immutable (i.e. cannot be modified by the user).
*/
export type IsRuleImmutable = z.infer<typeof IsRuleImmutable>;
export const IsRuleImmutable = z.boolean();

/**
* Determines whether the prebuilt rule has been customized by the user (i.e. any of its fields have been modified and diverge from the base value).
*/
export type IsPrebuiltRuleCustomized = z.infer<typeof IsPrebuiltRuleCustomized>;
export const IsPrebuiltRuleCustomized = z.boolean();

/**
* The date and time that the prebuilt rule was last updated by Elastic.
*/
export type ElasticUpdateDate = z.infer<typeof ElasticUpdateDate>;
export const ElasticUpdateDate = z.string().datetime();

/**
* Property whose existence determines whether the rule is an Elastic Prebuilt Rule that can receive upstream updates via Fleet. Contains information relating to prebuilt rules.
*/
export type Prebuilt = z.infer<typeof Prebuilt>;
export const Prebuilt = z.object({
isCustomized: IsPrebuiltRuleCustomized,
elasticUpdateDate: ElasticUpdateDate.optional(),
});

/**
* Determines whether the rule is enabled.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,27 @@ components:

IsRuleImmutable:
type: boolean
description: '[DEPRECATION WARNING - This field is deprecated and will be removed in a future release. Use the prebuilt field to determine if a rule is an Elastic prebuilt rule or a custom rule.] - Determines whether the rule is immutable (i.e. cannot be modified by the user).'

IsPrebuiltRuleCustomized:
type: boolean
description: Determines whether the prebuilt rule has been customized by the user (i.e. any of its fields have been modified and diverge from the base value).

ElasticUpdateDate:
type: string
format: date-time
description: The date and time that the prebuilt rule was last updated by Elastic.

Prebuilt:
type: object
description: Property whose existence determines whether the rule is an Elastic Prebuilt Rule that can receive upstream updates via Fleet. Contains information relating to prebuilt rules.
properties:
isCustomized:
$ref: '#/components/schemas/IsPrebuiltRuleCustomized'
elasticUpdateDate:
$ref: '#/components/schemas/ElasticUpdateDate'
required:
- isCustomized

IsRuleEnabled:
type: boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import {
RuleObjectId,
RuleSignatureId,
IsRuleImmutable,
Prebuilt,
RelatedIntegrationArray,
RequiredFieldArray,
SetupGuide,
Expand Down Expand Up @@ -155,6 +156,7 @@ export const ResponseFields = z.object({
id: RuleObjectId,
rule_id: RuleSignatureId,
immutable: IsRuleImmutable,
prebuilt: Prebuilt.optional(),
updated_at: z.string().datetime(),
updated_by: z.string(),
created_at: z.string().datetime(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@ components:
$ref: './common_attributes.schema.yaml#/components/schemas/RuleSignatureId'
immutable:
$ref: './common_attributes.schema.yaml#/components/schemas/IsRuleImmutable'
prebuilt:
$ref: './common_attributes.schema.yaml#/components/schemas/Prebuilt'
updated_at:
type: string
format: date-time
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@
* 2.0.
*/

import * as z from 'zod';
import type * as z from 'zod';
import {
BaseCreateProps,
ResponseFields,
RuleSignatureId,
TypeSpecificCreateProps,
IsRuleImmutable,
Prebuilt,
} from '../../model/rule_schema';

/**
Expand All @@ -28,6 +30,7 @@ export type RuleToImportInput = z.input<typeof RuleToImport>;
export const RuleToImport = BaseCreateProps.and(TypeSpecificCreateProps).and(
ResponseFields.partial().extend({
rule_id: RuleSignatureId,
immutable: z.literal(false).default(false),
immutable: IsRuleImmutable.optional(),
prebuilt: Prebuilt.optional(),
})
);
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@ export const ENABLED_FIELD = 'alert.attributes.enabled';
export const TAGS_FIELD = 'alert.attributes.tags';
export const PARAMS_TYPE_FIELD = 'alert.attributes.params.type';
export const PARAMS_IMMUTABLE_FIELD = 'alert.attributes.params.immutable';
export const PARAMS_PREBUILT_FIELD = 'alert.attributes.params.prebuilt';
export const PARAMS_PREBUILT_IS_CUSTOMIZED_FIELD = 'alert.attributes.params.prebuilt.isCustomized';
export const LAST_RUN_OUTCOME_FIELD = 'alert.attributes.lastRun.outcome';
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,17 @@ import {
ENABLED_FIELD,
LAST_RUN_OUTCOME_FIELD,
PARAMS_IMMUTABLE_FIELD,
PARAMS_PREBUILT_IS_CUSTOMIZED_FIELD,
PARAMS_TYPE_FIELD,
RULE_NAME_FIELD,
RULE_PARAMS_FIELDS,
TAGS_FIELD,
} from './rule_fields';

// KQL does not allow to search for existence of the prebuilt object field, since params is unmapped
// so we can search for the existence of the isCustomized subfield instead, which is required
export const KQL_FILTER_PREBUILT_RULES = `${PARAMS_PREBUILT_IS_CUSTOMIZED_FIELD}: *`;
export const KQL_FILTER_CUSTOM_RULES = `NOT ${PARAMS_PREBUILT_IS_CUSTOMIZED_FIELD}: *`;
export const KQL_FILTER_IMMUTABLE_RULES = `${PARAMS_IMMUTABLE_FIELD}: true`;
export const KQL_FILTER_MUTABLE_RULES = `${PARAMS_IMMUTABLE_FIELD}: false`;
export const KQL_FILTER_ENABLED_RULES = `${ENABLED_FIELD}: true`;
Expand Down Expand Up @@ -59,9 +64,11 @@ export function convertRulesFilterToKQL({
if (showCustomRules && showElasticRules) {
// if both showCustomRules && showElasticRules selected we omit filter, as it includes all existing rules
} else if (showElasticRules) {
kql.push(KQL_FILTER_IMMUTABLE_RULES);
kql.push(`${KQL_FILTER_PREBUILT_RULES}`);
// kql.push(`(${KQL_FILTER_PREBUILT_RULES} OR ${KQL_FILTER_IMMUTABLE_RULES})`);
} else if (showCustomRules) {
kql.push(KQL_FILTER_MUTABLE_RULES);
kql.push(`${KQL_FILTER_CUSTOM_RULES}`);
// kql.push(`(${KQL_FILTER_CUSTOM_RULES} OR ${KQL_FILTER_MUTABLE_RULES})`);
}

if (enabled !== undefined) {
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit c0f2e05

Please sign in to comment.