Skip to content

Commit

Permalink
Endpoint: Redux types (#63413)
Browse files Browse the repository at this point in the history
## Summary

Changes some types around so modifying redux state or actions will cause type errors

* the state and action types aren't using `Immutable` directly. This means that you can instantiate them and mutate them
* the `state` and `action` params received by all reducers will be automatically cast to `Immutable`
* reducers can return either `Immutable` or regular versions of `state`
* some code may be mutating redux state directly, this is being ignored (at least for now)
  • Loading branch information
Robert Austin committed Apr 15, 2020
1 parent bb0d03f commit 08aa214
Show file tree
Hide file tree
Showing 36 changed files with 444 additions and 305 deletions.
9 changes: 3 additions & 6 deletions x-pack/plugins/endpoint/common/generate_data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,8 @@

import uuid from 'uuid';
import seedrandom from 'seedrandom';
import { AlertEvent, EndpointEvent, HostMetadata, OSFields, HostFields } from './types';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { PolicyData } from '../public/applications/endpoint/types';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { generatePolicy } from '../public/applications/endpoint/models/policy';
import { AlertEvent, EndpointEvent, HostMetadata, OSFields, HostFields, PolicyData } from './types';
import { factory as policyFactory } from './models/policy_config';

export type Event = AlertEvent | EndpointEvent;

Expand Down Expand Up @@ -474,7 +471,7 @@ export class EndpointDocGenerator {
streams: [],
config: {
policy: {
value: generatePolicy(),
value: policyFactory(),
},
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,9 @@
import { PolicyConfig, ProtectionModes } from '../types';

/**
* Generate a new Policy model.
* NOTE: in the near future, this will likely be removed and an API call to EPM will be used to retrieve
* the latest from the Endpoint package
* Return a new default `PolicyConfig`.
*/
export const generatePolicy = (): PolicyConfig => {
export const factory = (): PolicyConfig => {
return {
windows: {
events: {
Expand Down
125 changes: 125 additions & 0 deletions x-pack/plugins/endpoint/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@
import { SearchResponse } from 'elasticsearch';
import { TypeOf } from '@kbn/config-schema';
import { alertingIndexGetQuerySchema } from './schema/alert_index';
import { Datasource, NewDatasource } from '../../ingest_manager/common';

/**
* A deep readonly type that will make all children of a given object readonly recursively
*/
export type Immutable<T> = T extends undefined | null | boolean | string | number
? T
: unknown extends T
? unknown
: T extends Array<infer U>
? ImmutableArray<U>
: T extends Map<infer K, infer V>
Expand Down Expand Up @@ -442,3 +445,125 @@ export type AlertingIndexGetQueryInput = KbnConfigSchemaInputTypeOf<
* Result of the validated query params when handling alert index requests.
*/
export type AlertingIndexGetQueryResult = TypeOf<typeof alertingIndexGetQuerySchema>;

/**
* Endpoint Policy configuration
*/
export interface PolicyConfig {
windows: {
events: {
dll_and_driver_load: boolean;
dns: boolean;
file: boolean;
network: boolean;
process: boolean;
registry: boolean;
security: boolean;
};
malware: MalwareFields;
logging: {
stdout: string;
file: string;
};
advanced: PolicyConfigAdvancedOptions;
};
mac: {
events: {
file: boolean;
process: boolean;
network: boolean;
};
malware: MalwareFields;
logging: {
stdout: string;
file: string;
};
advanced: PolicyConfigAdvancedOptions;
};
linux: {
events: {
file: boolean;
process: boolean;
network: boolean;
};
logging: {
stdout: string;
file: string;
};
advanced: PolicyConfigAdvancedOptions;
};
}

/**
* Windows-specific policy configuration that is supported via the UI
*/
type WindowsPolicyConfig = Pick<PolicyConfig['windows'], 'events' | 'malware'>;

/**
* Mac-specific policy configuration that is supported via the UI
*/
type MacPolicyConfig = Pick<PolicyConfig['mac'], 'malware' | 'events'>;

/**
* Linux-specific policy configuration that is supported via the UI
*/
type LinuxPolicyConfig = Pick<PolicyConfig['linux'], 'events'>;

/**
* The set of Policy configuration settings that are show/edited via the UI
*/
export interface UIPolicyConfig {
windows: WindowsPolicyConfig;
mac: MacPolicyConfig;
linux: LinuxPolicyConfig;
}

interface PolicyConfigAdvancedOptions {
elasticsearch: {
indices: {
control: string;
event: string;
logging: string;
};
kernel: {
connect: boolean;
process: boolean;
};
};
}

/** Policy: Malware protection fields */
export interface MalwareFields {
mode: ProtectionModes;
}

/** Policy protection mode options */
export enum ProtectionModes {
detect = 'detect',
prevent = 'prevent',
preventNotify = 'preventNotify',
off = 'off',
}

/**
* Endpoint Policy data, which extends Ingest's `Datasource` type
*/
export type PolicyData = Datasource & NewPolicyData;

/**
* New policy data. Used when updating the policy record via ingest APIs
*/
export type NewPolicyData = NewDatasource & {
inputs: [
{
type: 'endpoint';
enabled: boolean;
streams: [];
config: {
policy: {
value: PolicyConfig;
};
};
}
];
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { all } from 'deepmerge';
import { Immutable } from '../../../../common/types';
import { IIndexPattern } from '../../../../../../../src/plugins/data/common';

/**
* Model for the `IIndexPattern` interface exported by the `data` plugin.
*/
export function clone(value: IIndexPattern | Immutable<IIndexPattern>): IIndexPattern {
return all([value]) as IIndexPattern;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { UIPolicyConfig } from '../types';
import { UIPolicyConfig } from '../../../../common/types';

/**
* A typed Object.entries() function where the keys and values are typed based on the given object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,17 @@ import { coreMock } from 'src/core/public/mocks';
import { DepsStartMock, depsStartMock } from '../../mocks';
import { createBrowserHistory } from 'history';
import { mockAlertResultList } from './mock_alert_result_list';
import { Immutable } from '../../../../../common/types';

describe('alert details tests', () => {
let store: Store<AlertListState, AppAction>;
let store: Store<Immutable<AlertListState>, Immutable<AppAction>>;
let coreStart: ReturnType<typeof coreMock.createStart>;
let depsStart: DepsStartMock;
let history: History<never>;
/**
* A function that waits until a selector returns true.
*/
let selectorIsTrue: (selector: (state: AlertListState) => boolean) => Promise<void>;
let selectorIsTrue: (selector: (state: Immutable<AlertListState>) => boolean) => Promise<void>;
beforeEach(() => {
coreStart = coreMock.createStart();
depsStart = depsStartMock();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,20 @@ import { alertMiddlewareFactory } from './middleware';
import { AppAction } from '../action';
import { coreMock } from 'src/core/public/mocks';
import { DepsStartMock, depsStartMock } from '../../mocks';
import { AlertResultList } from '../../../../../common/types';
import { AlertResultList, Immutable } from '../../../../../common/types';
import { isOnAlertPage } from './selectors';
import { createBrowserHistory } from 'history';
import { mockAlertResultList } from './mock_alert_result_list';

describe('alert list tests', () => {
let store: Store<AlertListState, AppAction>;
let store: Store<Immutable<AlertListState>, Immutable<AppAction>>;
let coreStart: ReturnType<typeof coreMock.createStart>;
let depsStart: DepsStartMock;
let history: History<never>;
/**
* A function that waits until a selector returns true.
*/
let selectorIsTrue: (selector: (state: AlertListState) => boolean) => Promise<void>;
let selectorIsTrue: (selector: (state: Immutable<AlertListState>) => boolean) => Promise<void>;
beforeEach(() => {
coreStart = coreMock.createStart();
depsStart = depsStartMock();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ import { DepsStartMock, depsStartMock } from '../../mocks';
import { createBrowserHistory } from 'history';
import { uiQueryParams } from './selectors';
import { urlFromQueryParams } from '../../view/alerts/url_from_query_params';
import { Immutable } from '../../../../../common/types';

describe('alert list pagination', () => {
let store: Store<AlertListState, AppAction>;
let store: Store<Immutable<AlertListState>, Immutable<AppAction>>;
let coreStart: ReturnType<typeof coreMock.createStart>;
let depsStart: DepsStartMock;
let history: History<never>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { Reducer } from 'redux';
import { AlertListState } from '../../types';
import { AlertListState, ImmutableReducer } from '../../types';
import { AppAction } from '../action';
import { Immutable } from '../../../../../common/types';

const initialState = (): AlertListState => {
const initialState = (): Immutable<AlertListState> => {
return {
alerts: [],
alertDetails: undefined,
Expand All @@ -22,7 +22,7 @@ const initialState = (): AlertListState => {
};
};

export const alertListReducer: Reducer<AlertListState, AppAction> = (
export const alertListReducer: ImmutableReducer<AlertListState, AppAction> = (
state = initialState(),
action
) => {
Expand Down
Loading

0 comments on commit 08aa214

Please sign in to comment.