Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
machadoum committed May 8, 2024
1 parent 9f3afe2 commit f2e6834
Show file tree
Hide file tree
Showing 35 changed files with 276 additions and 837 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,23 @@ export const AssetCriticalityRecordIdParts = z.object({
id_field: IdField,
});

/**
* The criticality level of the asset.
*/
export type AssetCriticalityLevel = z.infer<typeof AssetCriticalityLevel>;
export const AssetCriticalityLevel = z.enum([
'low_impact',
'medium_impact',
'high_impact',
'extreme_impact',
]);
export type AssetCriticalityLevelEnum = typeof AssetCriticalityLevel.enum;
export const AssetCriticalityLevelEnum = AssetCriticalityLevel.enum;

export type CreateAssetCriticalityRecord = z.infer<typeof CreateAssetCriticalityRecord>;
export const CreateAssetCriticalityRecord = AssetCriticalityRecordIdParts.merge(
z.object({
/**
* The criticality level of the asset.
*/
criticality_level: z.enum(['low_impact', 'medium_impact', 'high_impact', 'extreme_impact']),
criticality_level: AssetCriticalityLevel,
})
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,22 @@ components:
required:
- id_value
- id_field
AssetCriticalityLevel:
type: string
enum:
- low_impact
- medium_impact
- high_impact
- extreme_impact
description: The criticality level of the asset.

CreateAssetCriticalityRecord:
allOf:
- $ref: '#/components/schemas/AssetCriticalityRecordIdParts'
- type: object
properties:
criticality_level:
type: string
enum: [low_impact, medium_impact, high_impact, extreme_impact]
description: The criticality level of the asset.
$ref : '#/components/schemas/AssetCriticalityLevel'
required:
- criticality_level
AssetCriticalityRecord:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* 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 { AfterKeys } from '.';
import type { SafeParseSuccess } from 'zod';

describe('after_keys schema', () => {
it('allows an empty object', () => {
const payload = {};
const decoded = AfterKeys.safeParse(payload) as SafeParseSuccess<object>;

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

it('allows a valid host key', () => {
const payload = { host: { 'host.name': 'hello' } };
const decoded = AfterKeys.safeParse(payload) as SafeParseSuccess<object>;

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

it('allows a valid user key', () => {
const payload = { user: { 'user.name': 'hello' } };
const decoded = AfterKeys.safeParse(payload) as SafeParseSuccess<object>;

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

it('allows both valid host and user keys', () => {
const payload = { user: { 'user.name': 'hello' }, host: { 'host.name': 'hello' } };
const decoded = AfterKeys.safeParse(payload) as SafeParseSuccess<object>;

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

it('removes an unknown identifier key if used', () => {
const payload = { bad: 'key' };

const decoded = AfterKeys.safeParse(payload) as SafeParseSuccess<object>;

expect(decoded.success).toBeTruthy();
expect(decoded.data).toEqual({});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,15 @@ import { z } from 'zod';
* version: 1.0.0
*/

import { AssetCriticalityLevel } from '../asset_criticality/common.gen';

export type EntityAfterKey = z.infer<typeof EntityAfterKey>;
export const EntityAfterKey = z.object({}).catchall(z.string());

export type AfterKeys = z.infer<typeof AfterKeys>;
export const AfterKeys = z.object({
host: z.object({}).catchall(z.string()).optional(),
user: z.object({}).catchall(z.string()).optional(),
host: EntityAfterKey.optional(),
user: EntityAfterKey.optional(),
});

/**
Expand Down Expand Up @@ -86,18 +91,14 @@ export const RiskScoreInput = z.object({
* The @timestamp of the risk input document.
*/
timestamp: z.string().optional(),
contribution_score: z.number().optional(),
});

export type RiskWeightTypes = z.infer<typeof RiskWeightTypes>;
export const RiskWeightTypes = z.enum(['global_identifier', 'risk_category']);
export type RiskWeightTypesEnum = typeof RiskWeightTypes.enum;
export const RiskWeightTypesEnum = RiskWeightTypes.enum;

export type RiskScoreCategories = z.infer<typeof RiskScoreCategories>;
export const RiskScoreCategories = z.literal('category_1');

export type RiskScore = z.infer<typeof RiskScore>;
export const RiskScore = z.object({
export type EntityRiskScore = z.infer<typeof EntityRiskScore>;
export const EntityRiskScore = z.object({
/**
* The time at which the risk score was calculated.
*/
Expand Down Expand Up @@ -134,6 +135,11 @@ export const RiskScore = z.object({
* A list of the highest-risk documents contributing to this risk score. Useful for investigative purposes.
*/
inputs: z.array(RiskScoreInput),
category_2_score: z.number().optional(),
category_2_count: z.number().optional(),
notes: z.array(z.string()),
criticality_modifier: z.number().optional(),
criticality_level: AssetCriticalityLevel.optional(),
});

export type RiskScoreEntityIdentifierWeights = z.infer<typeof RiskScoreEntityIdentifierWeights>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,18 @@ info:
paths: {}
components:
schemas:
EntityAfterKey:
type: object
additionalProperties:
type: string

AfterKeys:
type: object
properties:
host:
type: object
additionalProperties:
type: string
$ref: '#/components/schemas/EntityAfterKey'
user:
type: object
additionalProperties:
type: string
$ref: '#/components/schemas/EntityAfterKey'
example:
host:
'host.name': 'example.host'
Expand Down Expand Up @@ -89,20 +90,16 @@ components:
type: string
example: '2017-07-21T17:32:28Z'
description: The @timestamp of the risk input document.

RiskWeightTypes:
type: string
enum:
- global_identifier
- risk_category
contribution_score:
type: number
format: double

RiskScoreCategories:
type: string
enum:
- category_1


RiskScore:
EntityRiskScore:
type: object
required:
- '@timestamp'
Expand All @@ -114,6 +111,7 @@ components:
- category_1_score
- category_1_count
- inputs
- notes
properties:
'@timestamp':
type: string
Expand Down Expand Up @@ -155,7 +153,22 @@ components:
description: A list of the highest-risk documents contributing to this risk score. Useful for investigative purposes.
items:
$ref: '#/components/schemas/RiskScoreInput'

category_2_score:
type: number
format: double
category_2_count:
type: number
format: integer
notes:
type: array
items:
type: string
criticality_modifier:
type: number
format: double
criticality_level:
$ref: '../asset_criticality/common.schema.yaml#/components/schemas/AssetCriticalityLevel'

RiskScoreEntityIdentifierWeights:
type: number
format: double
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
* 2.0.
*/

import { RiskCategories, RiskWeightTypes } from './types';
import { RiskScoreWeight } from '../../../api/entity_analytics/common';
import { RiskScoreWeight } from '.';
import type { SafeParseError, SafeParseSuccess } from 'zod';
import { stringifyZodError } from '@kbn/zod-helpers';
import { RiskCategories, RiskWeightTypes } from '../../../entity_analytics/risk_engine';

describe('risk weight schema', () => {
let type: string;
Expand Down Expand Up @@ -117,29 +117,6 @@ describe('risk weight schema', () => {
type = RiskWeightTypes.riskCategory;
});

// const globalRiskWeightSchema = t.intersection([
// t.exact(
// t.type({
// type: t.literal(RiskWeightTypes.global),
// })
// ),
// identifierWeights,
// ]);
// export type GlobalRiskWeight = t.TypeOf<typeof globalRiskWeightSchema>;

// const riskCategoryRiskWeightSchema = t.intersection([
// t.exact(
// t.type({
// type: t.literal(RiskWeightTypes.riskCategory),
// value: riskCategories,
// })
// ),
// identifierWeights,
// ]);
// export type RiskCategoryRiskWeight = t.TypeOf<typeof riskCategoryRiskWeightSchema>;

// export const riskWeightSchema = t.union([globalRiskWeightSchema

it('requires a value', () => {
const payload = { type, user: 0.1 };
const decoded = RiskScoreWeight.safeParse(payload) as SafeParseError<object>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,9 @@ components:
type: number
format: integer
description: The number of risk scores persisted to elasticsearch.
# scores:
# type: array
# description: A list of risk scores calculated during the request.
# items:
# $ref: '../common/common.schema.yaml#/components/schemas/RiskScore'
# todo add scores here? I think we do.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { z } from 'zod';
* version: 1.0.0
*/

import { IdentifierType, RiskScore } from '../common/common.gen';
import { IdentifierType, EntityRiskScore } from '../common/common.gen';

export type RiskScoresEntityCalculationRequest = z.infer<typeof RiskScoresEntityCalculationRequest>;
export const RiskScoresEntityCalculationRequest = z.object({
Expand All @@ -39,5 +39,5 @@ export type RiskScoresEntityCalculationResponse = z.infer<
>;
export const RiskScoresEntityCalculationResponse = z.object({
success: z.boolean(),
score: RiskScore.optional(),
score: EntityRiskScore.optional(),
});
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,4 @@ components:
success:
type: boolean
score:
$ref: '../common/common.schema.yaml#/components/schemas/RiskScore'
$ref: '../common/common.schema.yaml#/components/schemas/EntityRiskScore'
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,26 @@ import { z } from 'zod';
*/

import {
AfterKeys,
DataViewId,
AfterKeys,
Filter,
PageSize,
IdentifierType,
DateRange,
RiskScoreWeights,
RiskScore,
EntityRiskScore,
} from '../common/common.gen';

export type RiskScoresPreviewRequest = z.infer<typeof RiskScoresPreviewRequest>;
export const RiskScoresPreviewRequest = z.object({
/**
* Used to retrieve a specific "page" of risk scores. If unspecified, the first "page" of scores is returned. See also the `after_keys` key in a risk scores response.
*/
after_keys: AfterKeys,
/**
* The identifier of the Kibana data view to be used when generating risk scores. If a data view is not found, the provided ID will be used as the query's index pattern instead.
*/
data_view_id: DataViewId,
/**
* Used to retrieve a specific "page" of risk scores. If unspecified, the first "page" of scores is returned. See also the `after_keys` key in a risk scores response.
*/
after_keys: AfterKeys.optional(),
/**
* If set to `true`, a `debug` key is added to the response, containing both the internal request and response with elasticsearch.
*/
Expand All @@ -49,7 +49,7 @@ export const RiskScoresPreviewRequest = z.object({
/**
* Used to restrict the type of risk scores involved. If unspecified, both `host` and `user` scores will be returned.
*/
identifier_type: IdentifierType,
identifier_type: IdentifierType.optional(),
/**
* Defines the time period over which scores will be evaluated. If unspecified, a range of `[now, now-30d]` will be used.
*/
Expand All @@ -72,8 +72,14 @@ export const RiskScoresPreviewResponse = z.object({
response: z.string().optional(),
})
.optional(),
/**
* A list of risk scores
*/
scores: z.array(RiskScore),
scores: z.object({
/**
* A list of host risk scores
*/
host: z.array(EntityRiskScore).optional(),
/**
* A list of user risk scores
*/
user: z.array(EntityRiskScore).optional(),
}),
});
Loading

0 comments on commit f2e6834

Please sign in to comment.