Skip to content

Commit

Permalink
[Entity Analytics] Move scripted metric painless scripts to static fi…
Browse files Browse the repository at this point in the history
…le & remove category based weighting (#182038)

## Summary

The scripted metric aggregation is being deprecated but an exception is
being made for our team, moving the painless to static files allows for
this exception to be made. We have had to remove category weighting to
make the script less dynamic, weights weren't used anyway so not a
breaking change.

The scripts are loaded once when they are first used and then cached. A
unit test verifies the content of the script hasnt changed.

Here is a diff of the scripted metric before and after
https://www.diffchecker.com/gefuBoYK/

---------

Co-authored-by: Mark Hopkin <mark.hopkin@elastic.co>
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
3 people committed May 17, 2024
1 parent f240808 commit 01cb168
Show file tree
Hide file tree
Showing 15 changed files with 140 additions and 542 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,8 @@ export const RiskScoreWeightGlobalShared = z.object({
type: z.literal('global_identifier'),
});

export type RiskScoreWeightGlobal = z.infer<typeof RiskScoreWeightGlobal>;
export const RiskScoreWeightGlobal = z.union([
export type RiskScoreWeight = z.infer<typeof RiskScoreWeight>;
export const RiskScoreWeight = z.union([
RiskScoreWeightGlobalShared.merge(
z.object({
host: RiskScoreEntityIdentifierWeights,
Expand All @@ -171,34 +171,6 @@ export const RiskScoreWeightGlobal = z.union([
),
]);

export type RiskScoreWeightCategoryShared = z.infer<typeof RiskScoreWeightCategoryShared>;
export const RiskScoreWeightCategoryShared = z.object({
type: z.literal('risk_category'),
value: RiskScoreCategories,
});

export type RiskScoreWeightCategory = z.infer<typeof RiskScoreWeightCategory>;
export const RiskScoreWeightCategory = z.union([
RiskScoreWeightCategoryShared.merge(
z.object({
host: RiskScoreEntityIdentifierWeights,
user: RiskScoreEntityIdentifierWeights.optional(),
})
),
RiskScoreWeightCategoryShared.merge(
z.object({
host: RiskScoreEntityIdentifierWeights.optional(),
user: RiskScoreEntityIdentifierWeights,
})
),
]);

/**
* Configuration used to tune risk scoring. Weights can be used to change the score contribution of risk inputs for hosts and users at both a global level and also for Risk Input categories (e.g. 'category_1').
*/
export type RiskScoreWeight = z.infer<typeof RiskScoreWeight>;
export const RiskScoreWeight = z.union([RiskScoreWeightGlobal, RiskScoreWeightCategory]);

/**
* A list of weights to be applied to the scoring calculation.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ components:
enum:
- global_identifier

RiskScoreWeightGlobal:
RiskScoreWeight:
oneOf:
- allOf:
- $ref: '#/components/schemas/RiskScoreWeightGlobalShared'
Expand All @@ -225,65 +225,12 @@ components:
user:
$ref: '#/components/schemas/RiskScoreEntityIdentifierWeights'

RiskScoreWeightCategoryShared:
x-inline: true
type: object
required:
- type
- value
properties:
type:
type: string
enum:
- risk_category
value:
$ref: '#/components/schemas/RiskScoreCategories'

RiskScoreWeightCategory:
oneOf:
- allOf:
- $ref: '#/components/schemas/RiskScoreWeightCategoryShared'
- type: object
required:
- host
properties:
host:
$ref: '#/components/schemas/RiskScoreEntityIdentifierWeights'
user:
$ref: '#/components/schemas/RiskScoreEntityIdentifierWeights'

- allOf:
- $ref: '#/components/schemas/RiskScoreWeightCategoryShared'
- type: object
required:
- user
properties:
host:
$ref: '#/components/schemas/RiskScoreEntityIdentifierWeights'
user:
$ref: '#/components/schemas/RiskScoreEntityIdentifierWeights'

RiskScoreWeight:
description: "Configuration used to tune risk scoring. Weights can be used to change the score contribution of risk inputs for hosts and users at both a global level and also for Risk Input categories (e.g. 'category_1')."
oneOf:
- $ref: '#/components/schemas/RiskScoreWeightGlobal'
- $ref: '#/components/schemas/RiskScoreWeightCategory'
example:
type: 'risk_category'
value: 'category_1'
host: 0.8
user: 0.4

RiskScoreWeights:
description: 'A list of weights to be applied to the scoring calculation.'
type: array
items:
$ref: '#/components/schemas/RiskScoreWeight'
example:
- type: 'risk_category'
value: 'category_1'
host: 0.8
user: 0.4
- type: 'global_identifier'
host: 0.5
user: 0.1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,7 @@ describe('risk weight schema', () => {
const decoded = RiskScoreWeight.safeParse(payload) as SafeParseError<object>;

expect(decoded.success).toBeFalsy();
expect(stringifyZodError(decoded.error)).toEqual(
'host: Required, user: Required, type: Invalid literal value, expected "risk_category", value: Invalid literal value, expected "category_1", host: Required, and 3 more'
);
expect(stringifyZodError(decoded.error)).toContain('host: Required, user: Required');
});

it('allows a single host weight', () => {
Expand Down Expand Up @@ -123,44 +121,10 @@ describe('risk weight schema', () => {

expect(decoded.success).toBeFalsy();
expect(stringifyZodError(decoded.error)).toEqual(
'type: Invalid literal value, expected "global_identifier", host: Required, type: Invalid literal value, expected "global_identifier", value: Invalid literal value, expected "category_1", host: Required, and 1 more'
'type: Invalid literal value, expected "global_identifier", host: Required, type: Invalid literal value, expected "global_identifier"'
);
});

it('rejects if neither host nor user weight are specified', () => {
const payload = { type, value: RiskCategories.category_1 };
const decoded = RiskScoreWeight.safeParse(payload) as SafeParseError<object>;

expect(decoded.success).toBeFalsy();
expect(stringifyZodError(decoded.error)).toEqual(
'type: Invalid literal value, expected "global_identifier", host: Required, type: Invalid literal value, expected "global_identifier", user: Required, host: Required, and 1 more'
);
});

it('allows a single host weight', () => {
const payload = { type, value: RiskCategories.category_1, host: 0.1 };
const decoded = RiskScoreWeight.safeParse(payload) as SafeParseSuccess<object>;

expect(decoded.success).toBeTruthy();
expect(decoded.data).toEqual(payload);
});

it('allows a single user weight', () => {
const payload = { type, value: RiskCategories.category_1, user: 0.1 };
const decoded = RiskScoreWeight.safeParse(payload) as SafeParseSuccess<object>;

expect(decoded.success).toBeTruthy();
expect(decoded.data).toEqual(payload);
});

it('allows both a host and user weight', () => {
const payload = { type, value: RiskCategories.category_1, user: 0.1, host: 0.5 };
const decoded = RiskScoreWeight.safeParse(payload) as SafeParseSuccess<object>;

expect(decoded.success).toBeTruthy();
expect(decoded.data).toEqual(payload);
});

it('rejects a weight outside of 0-1', () => {
const payload = { type, value: RiskCategories.category_1, host: -5 };
const decoded = RiskScoreWeight.safeParse(payload) as SafeParseError<object>;
Expand All @@ -170,47 +134,6 @@ describe('risk weight schema', () => {
`host: Number must be greater than or equal to 0`
);
});

it('removes extra keys if specified', () => {
const payload = {
type,
value: RiskCategories.category_1,
host: 0.1,
extra: 'even more',
};
const decoded = RiskScoreWeight.safeParse(payload) as SafeParseSuccess<object>;

expect(decoded.success).toBeTruthy();
expect(decoded.data).toEqual({ type, value: RiskCategories.category_1, host: 0.1 });
});

describe('allowed category values', () => {
it('allows the alerts type for a category', () => {
const payload = {
type,
value: RiskCategories.category_1,
host: 0.1,
};
const decoded = RiskScoreWeight.safeParse(payload) as SafeParseSuccess<object>;

expect(decoded.success).toBeTruthy();
expect(decoded.data).toEqual(payload);
});

it('rejects an unknown category value', () => {
const payload = {
type,
value: 'unknown',
host: 0.1,
};
const decoded = RiskScoreWeight.safeParse(payload) as SafeParseError<object>;

expect(decoded.success).toBeFalsy();
expect(stringifyZodError(decoded.error)).toContain(
'type: Invalid literal value, expected "global_identifier", type: Invalid literal value, expected "global_identifier", user: Required, value: Invalid literal value, expected "category_1", value: Invalid literal value, expected "category_1", and 1 more'
);
});
});
});
});
});

0 comments on commit 01cb168

Please sign in to comment.