Skip to content

Commit

Permalink
[Entity Analytics] Move risk scoring painless to static files... agai…
Browse files Browse the repository at this point in the history
…n (with sorting fix after test failure) (#183844)

## Summary

This code was originally approved and merged in
#182038

It was then reverted in #183759
after a [test failure](#183758).

The previous code had introduced flakiness, occasionally the inputs
would be supplied to risk scoring in the wrong order causing the score
to decrease. Re-adding the sorting in the reduce script has fixed this.

Here is the only new code:
a8cbb1c

[Flaky test
run](https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/6045)
🟢

---------

Co-authored-by: oatkiller <robert.austin@elastic.co>
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
3 people committed May 20, 2024
1 parent 2725099 commit 1830300
Show file tree
Hide file tree
Showing 15 changed files with 143 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'
);
});
});
});
});
});
Loading

0 comments on commit 1830300

Please sign in to comment.