mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[SIEM][Detection Engine][Lists] Adds conflict versioning and io-ts improvements to lists (#72337)
## Summary * Adds conflict versioning by exposing the "_version" from the saved object system. It renames "version" to "_version" so that we can use regular "version" later for versioning things for pre-packaged lists abilities. * Utilizes `t.OutputOf` in the requests and the data types to give us more correctly types * Removes the `Identity` utility as that is adding confusion and can confuse vs code rather than improves things * Removes extra types that were causing confusion which was an idiom from io-ts * Changes the wording of `Partial` by removing that and instead focuses the request types on either client side or server side at this point. NOTE: The UI can migrate to holding onto the `_version` and then push it back down when it wants to migrate to using the conflict resolution. If the UI does not push it down, then a value of undefined will be used which is indicating that no conflict errors are wanted. Output example of posting an exception list: ❯ ./post_exception_list.sh ```ts { "_tags": [ "endpoint", "process", "malware", "os:linux" ], "_version": "Wzk4NiwxXQ==", "created_at": "2020-07-17T18:59:22.872Z", "created_by": "yo", "description": "This is a sample endpoint type exception", "id": "a08795b0-c85f-11ea-b1a6-c155df988a92", "list_id": "simple_list", "name": "Sample Endpoint Exception List", "namespace_type": "single", "tags": [ "user added string for a tag", "malware" ], "tie_breaker_id": "b789ec05-3e0f-4344-a156-0c0f5b6e2f9c", "type": "detection", "updated_at": "2020-07-17T18:59:22.891Z", "updated_by": "yo" } ``` Output example of posting an exception list item ❯ ./post_exception_list_item.sh ```ts { "_tags": [ "endpoint", "process", "malware", "os:linux" ], "_version": "Wzk4NywxXQ==", "comments": [], "created_at": "2020-07-17T18:59:30.286Z", "created_by": "yo", "description": "This is a sample endpoint type exception", "entries": [ { "field": "actingProcess.file.signer", "operator": "excluded", "type": "exists" }, { "field": "host.name", "operator": "included", "type": "match_any", "value": [ "some host", "another host" ] } ], "id": "a4f2b800-c85f-11ea-b1a6-c155df988a92", "item_id": "simple_list_item", "list_id": "simple_list", "name": "Sample Endpoint Exception List", "namespace_type": "single", "tags": [ "user added string for a tag", "malware" ], "tie_breaker_id": "1dc456bc-7aa9-44b4-bca3-131689cf729f", "type": "simple", "updated_at": "2020-07-17T18:59:30.304Z", "updated_by": "yo" } ``` Output example of when you get an exception list: ❯ ./get_exception_list.sh simple_list ```ts { "_tags": [ "endpoint", "process", "malware", "os:linux" ], "_version": "WzEwNzcsMV0=", "created_at": "2020-07-17T18:59:22.872Z", "created_by": "yo", "description": "Different description", "id": "a08795b0-c85f-11ea-b1a6-c155df988a92", "list_id": "simple_list", "name": "Sample Endpoint Exception List", "namespace_type": "single", "tags": [ "user added string for a tag", "malware" ], "tie_breaker_id": "b789ec05-3e0f-4344-a156-0c0f5b6e2f9c", "type": "endpoint", "updated_at": "2020-07-17T20:01:24.958Z", "updated_by": "yo" } ``` Example of the error you get if you do an update of an exception list and someone else has changed it: ```ts { "message": "[exception-list:a08795b0-c85f-11ea-b1a6-c155df988a92]: version conflict, required seqNo [1074], primary term [1]. current document has seqNo [1077] and primary term [1]: [version_conflict_engine_exception] [exception-list:a08795b0-c85f-11ea-b1a6-c155df988a92]: version conflict, required seqNo [1074], primary term [1]. current document has seqNo [1077] and primary term [1], with { index_uuid=\"a2mgXBO6Tl2ULDq-MTs1Tw\" & shard=\"0\" & index=\".kibana-hassanabad_1\" }", "status_code": 409 } ``` Lists are the same way and flavor, they encode the _version the same way that saved objects do. To see those work you run these scripts: ```ts ./post_list.sh ./post_list_item.sh ./find_list.sh ./find_list_item.sh ``` ### Checklist - [x] [Unit or functional tests](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility) were updated or added to match the most common scenarios
This commit is contained in:
parent
75e4c7a2b7
commit
afae94a85e
128 changed files with 517 additions and 435 deletions
|
@ -60,3 +60,4 @@ export const TAGS = [];
|
|||
export const COMMENTS = [];
|
||||
export const FILTER = 'name:Nicolas Bourbaki';
|
||||
export const CURSOR = 'c29tZXN0cmluZ2ZvcnlvdQ==';
|
||||
export const _VERSION = 'WzI5NywxXQ==';
|
||||
|
|
|
@ -307,3 +307,7 @@ export type Deserializer = t.TypeOf<typeof deserializer>;
|
|||
|
||||
export const deserializerOrUndefined = t.union([deserializer, t.undefined]);
|
||||
export type DeserializerOrUndefined = t.TypeOf<typeof deserializerOrUndefined>;
|
||||
|
||||
export const _version = t.string;
|
||||
export const _versionOrUndefined = t.union([_version, t.undefined]);
|
||||
export type _VersionOrUndefined = t.TypeOf<typeof _versionOrUndefined>;
|
||||
|
|
|
@ -14,4 +14,4 @@ export const createEsBulkTypeSchema = t.exact(
|
|||
})
|
||||
);
|
||||
|
||||
export type CreateEsBulkTypeSchema = t.TypeOf<typeof createEsBulkTypeSchema>;
|
||||
export type CreateEsBulkTypeSchema = t.OutputOf<typeof createEsBulkTypeSchema>;
|
||||
|
|
|
@ -38,4 +38,4 @@ export const indexEsListItemSchema = t.intersection([
|
|||
esDataTypeUnion,
|
||||
]);
|
||||
|
||||
export type IndexEsListItemSchema = t.TypeOf<typeof indexEsListItemSchema>;
|
||||
export type IndexEsListItemSchema = t.OutputOf<typeof indexEsListItemSchema>;
|
||||
|
|
|
@ -38,4 +38,4 @@ export const indexEsListSchema = t.exact(
|
|||
})
|
||||
);
|
||||
|
||||
export type IndexEsListSchema = t.TypeOf<typeof indexEsListSchema>;
|
||||
export type IndexEsListSchema = t.OutputOf<typeof indexEsListSchema>;
|
||||
|
|
|
@ -21,4 +21,4 @@ export const updateEsListItemSchema = t.intersection([
|
|||
esDataTypeUnion,
|
||||
]);
|
||||
|
||||
export type UpdateEsListItemSchema = t.TypeOf<typeof updateEsListItemSchema>;
|
||||
export type UpdateEsListItemSchema = t.OutputOf<typeof updateEsListItemSchema>;
|
||||
|
|
|
@ -26,4 +26,4 @@ export const updateEsListSchema = t.exact(
|
|||
})
|
||||
);
|
||||
|
||||
export type UpdateEsListSchema = t.TypeOf<typeof updateEsListSchema>;
|
||||
export type UpdateEsListSchema = t.OutputOf<typeof updateEsListSchema>;
|
||||
|
|
|
@ -19,7 +19,7 @@ import {
|
|||
name,
|
||||
tags,
|
||||
} from '../common/schemas';
|
||||
import { Identity, RequiredKeepUndefined } from '../../types';
|
||||
import { RequiredKeepUndefined } from '../../types';
|
||||
import { CreateCommentsArray, DefaultCreateCommentsArray, DefaultEntryArray } from '../types';
|
||||
import { EntriesArray } from '../types/entries';
|
||||
import { DefaultUuid } from '../../siem_common_deps';
|
||||
|
@ -44,20 +44,16 @@ export const createEndpointListItemSchema = t.intersection([
|
|||
),
|
||||
]);
|
||||
|
||||
export type CreateEndpointListItemSchemaPartial = Identity<
|
||||
t.TypeOf<typeof createEndpointListItemSchema>
|
||||
>;
|
||||
export type CreateEndpointListItemSchema = RequiredKeepUndefined<
|
||||
t.TypeOf<typeof createEndpointListItemSchema>
|
||||
>;
|
||||
export type CreateEndpointListItemSchema = t.OutputOf<typeof createEndpointListItemSchema>;
|
||||
|
||||
// This type is used after a decode since some things are defaults after a decode.
|
||||
export type CreateEndpointListItemSchemaDecoded = Identity<
|
||||
Omit<CreateEndpointListItemSchema, '_tags' | 'tags' | 'item_id' | 'entries' | 'comments'> & {
|
||||
_tags: _Tags;
|
||||
comments: CreateCommentsArray;
|
||||
tags: Tags;
|
||||
item_id: ItemId;
|
||||
entries: EntriesArray;
|
||||
}
|
||||
>;
|
||||
export type CreateEndpointListItemSchemaDecoded = Omit<
|
||||
RequiredKeepUndefined<t.TypeOf<typeof createEndpointListItemSchema>>,
|
||||
'_tags' | 'tags' | 'item_id' | 'entries' | 'comments'
|
||||
> & {
|
||||
_tags: _Tags;
|
||||
comments: CreateCommentsArray;
|
||||
tags: Tags;
|
||||
item_id: ItemId;
|
||||
entries: EntriesArray;
|
||||
};
|
||||
|
|
|
@ -21,7 +21,7 @@ import {
|
|||
namespace_type,
|
||||
tags,
|
||||
} from '../common/schemas';
|
||||
import { Identity, RequiredKeepUndefined } from '../../types';
|
||||
import { RequiredKeepUndefined } from '../../types';
|
||||
import {
|
||||
CreateCommentsArray,
|
||||
DefaultCreateCommentsArray,
|
||||
|
@ -53,24 +53,17 @@ export const createExceptionListItemSchema = t.intersection([
|
|||
),
|
||||
]);
|
||||
|
||||
export type CreateExceptionListItemSchemaPartial = Identity<
|
||||
t.TypeOf<typeof createExceptionListItemSchema>
|
||||
>;
|
||||
export type CreateExceptionListItemSchema = RequiredKeepUndefined<
|
||||
t.TypeOf<typeof createExceptionListItemSchema>
|
||||
>;
|
||||
export type CreateExceptionListItemSchema = t.OutputOf<typeof createExceptionListItemSchema>;
|
||||
|
||||
// This type is used after a decode since some things are defaults after a decode.
|
||||
export type CreateExceptionListItemSchemaDecoded = Identity<
|
||||
Omit<
|
||||
CreateExceptionListItemSchema,
|
||||
'_tags' | 'tags' | 'item_id' | 'entries' | 'namespace_type' | 'comments'
|
||||
> & {
|
||||
_tags: _Tags;
|
||||
comments: CreateCommentsArray;
|
||||
tags: Tags;
|
||||
item_id: ItemId;
|
||||
entries: EntriesArray;
|
||||
namespace_type: NamespaceType;
|
||||
}
|
||||
>;
|
||||
export type CreateExceptionListItemSchemaDecoded = Omit<
|
||||
RequiredKeepUndefined<t.TypeOf<typeof createExceptionListItemSchema>>,
|
||||
'_tags' | 'tags' | 'item_id' | 'entries' | 'namespace_type' | 'comments'
|
||||
> & {
|
||||
_tags: _Tags;
|
||||
comments: CreateCommentsArray;
|
||||
tags: Tags;
|
||||
item_id: ItemId;
|
||||
entries: EntriesArray;
|
||||
namespace_type: NamespaceType;
|
||||
};
|
||||
|
|
|
@ -20,7 +20,7 @@ import {
|
|||
namespace_type,
|
||||
tags,
|
||||
} from '../common/schemas';
|
||||
import { Identity, RequiredKeepUndefined } from '../../types';
|
||||
import { RequiredKeepUndefined } from '../../types';
|
||||
import { DefaultUuid } from '../../siem_common_deps';
|
||||
import { NamespaceType } from '../types';
|
||||
|
||||
|
@ -43,17 +43,15 @@ export const createExceptionListSchema = t.intersection([
|
|||
),
|
||||
]);
|
||||
|
||||
export type CreateExceptionListSchemaPartial = Identity<t.TypeOf<typeof createExceptionListSchema>>;
|
||||
export type CreateExceptionListSchema = RequiredKeepUndefined<
|
||||
t.TypeOf<typeof createExceptionListSchema>
|
||||
>;
|
||||
export type CreateExceptionListSchema = t.OutputOf<typeof createExceptionListSchema>;
|
||||
|
||||
// This type is used after a decode since some things are defaults after a decode.
|
||||
export type CreateExceptionListSchemaDecoded = Identity<
|
||||
Omit<CreateExceptionListSchema, '_tags' | 'tags' | 'list_id' | 'namespace_type'> & {
|
||||
_tags: _Tags;
|
||||
tags: Tags;
|
||||
list_id: ListId;
|
||||
namespace_type: NamespaceType;
|
||||
}
|
||||
>;
|
||||
export type CreateExceptionListSchemaDecoded = Omit<
|
||||
RequiredKeepUndefined<t.TypeOf<typeof createExceptionListSchema>>,
|
||||
'_tags' | 'tags' | 'list_id' | 'namespace_type'
|
||||
> & {
|
||||
_tags: _Tags;
|
||||
tags: Tags;
|
||||
list_id: ListId;
|
||||
namespace_type: NamespaceType;
|
||||
};
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import * as t from 'io-ts';
|
||||
|
||||
import { id, list_id, meta, value } from '../common/schemas';
|
||||
import { Identity, RequiredKeepUndefined } from '../../types';
|
||||
import { RequiredKeepUndefined } from '../../types';
|
||||
|
||||
export const createListItemSchema = t.intersection([
|
||||
t.exact(
|
||||
|
@ -21,5 +21,7 @@ export const createListItemSchema = t.intersection([
|
|||
t.exact(t.partial({ id, meta })),
|
||||
]);
|
||||
|
||||
export type CreateListItemSchemaPartial = Identity<t.TypeOf<typeof createListItemSchema>>;
|
||||
export type CreateListItemSchema = RequiredKeepUndefined<t.TypeOf<typeof createListItemSchema>>;
|
||||
export type CreateListItemSchema = t.OutputOf<typeof createListItemSchema>;
|
||||
export type CreateListItemSchemaDecoded = RequiredKeepUndefined<
|
||||
t.TypeOf<typeof createListItemSchema>
|
||||
>;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
import * as t from 'io-ts';
|
||||
|
||||
import { description, deserializer, id, meta, name, serializer, type } from '../common/schemas';
|
||||
import { Identity, RequiredKeepUndefined } from '../../types';
|
||||
import { RequiredKeepUndefined } from '../../types';
|
||||
|
||||
export const createListSchema = t.intersection([
|
||||
t.exact(
|
||||
|
@ -20,5 +20,5 @@ export const createListSchema = t.intersection([
|
|||
t.exact(t.partial({ deserializer, id, meta, serializer })),
|
||||
]);
|
||||
|
||||
export type CreateListSchemaPartial = Identity<t.TypeOf<typeof createListSchema>>;
|
||||
export type CreateListSchema = RequiredKeepUndefined<t.TypeOf<typeof createListSchema>>;
|
||||
export type CreateListSchema = t.OutputOf<typeof createListSchema>;
|
||||
export type CreateListSchemaDecoded = RequiredKeepUndefined<t.TypeOf<typeof createListSchema>>;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
import * as t from 'io-ts';
|
||||
|
||||
import { id, item_id } from '../common/schemas';
|
||||
import { RequiredKeepUndefined } from '../../types';
|
||||
|
||||
export const deleteEndpointListItemSchema = t.exact(
|
||||
t.partial({
|
||||
|
@ -17,7 +18,9 @@ export const deleteEndpointListItemSchema = t.exact(
|
|||
})
|
||||
);
|
||||
|
||||
export type DeleteEndpointListItemSchema = t.TypeOf<typeof deleteEndpointListItemSchema>;
|
||||
export type DeleteEndpointListItemSchema = t.OutputOf<typeof deleteEndpointListItemSchema>;
|
||||
|
||||
// This type is used after a decode since some things are defaults after a decode.
|
||||
export type DeleteEndpointListItemSchemaDecoded = DeleteEndpointListItemSchema;
|
||||
export type DeleteEndpointListItemSchemaDecoded = RequiredKeepUndefined<
|
||||
t.TypeOf<typeof deleteEndpointListItemSchema>
|
||||
>;
|
||||
|
|
|
@ -10,6 +10,7 @@ import * as t from 'io-ts';
|
|||
|
||||
import { id, item_id, namespace_type } from '../common/schemas';
|
||||
import { NamespaceType } from '../types';
|
||||
import { RequiredKeepUndefined } from '../../types';
|
||||
|
||||
export const deleteExceptionListItemSchema = t.exact(
|
||||
t.partial({
|
||||
|
@ -19,11 +20,11 @@ export const deleteExceptionListItemSchema = t.exact(
|
|||
})
|
||||
);
|
||||
|
||||
export type DeleteExceptionListItemSchema = t.TypeOf<typeof deleteExceptionListItemSchema>;
|
||||
export type DeleteExceptionListItemSchema = t.OutputOf<typeof deleteExceptionListItemSchema>;
|
||||
|
||||
// This type is used after a decode since some things are defaults after a decode.
|
||||
export type DeleteExceptionListItemSchemaDecoded = Omit<
|
||||
DeleteExceptionListItemSchema,
|
||||
RequiredKeepUndefined<t.TypeOf<typeof deleteExceptionListItemSchema>>,
|
||||
'namespace_type'
|
||||
> & {
|
||||
namespace_type: NamespaceType;
|
||||
|
|
|
@ -10,6 +10,7 @@ import * as t from 'io-ts';
|
|||
|
||||
import { id, list_id, namespace_type } from '../common/schemas';
|
||||
import { NamespaceType } from '../types';
|
||||
import { RequiredKeepUndefined } from '../../types';
|
||||
|
||||
export const deleteExceptionListSchema = t.exact(
|
||||
t.partial({
|
||||
|
@ -19,9 +20,12 @@ export const deleteExceptionListSchema = t.exact(
|
|||
})
|
||||
);
|
||||
|
||||
export type DeleteExceptionListSchema = t.TypeOf<typeof deleteExceptionListSchema>;
|
||||
export type DeleteExceptionListSchema = t.OutputOf<typeof deleteExceptionListSchema>;
|
||||
|
||||
// This type is used after a decode since some things are defaults after a decode.
|
||||
export type DeleteExceptionListSchemaDecoded = Omit<DeleteExceptionListSchema, 'namespace_type'> & {
|
||||
export type DeleteExceptionListSchemaDecoded = Omit<
|
||||
RequiredKeepUndefined<t.TypeOf<typeof deleteExceptionListSchema>>,
|
||||
'namespace_type'
|
||||
> & {
|
||||
namespace_type: NamespaceType;
|
||||
};
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import * as t from 'io-ts';
|
||||
|
||||
import { id, list_id, valueOrUndefined } from '../common/schemas';
|
||||
import { Identity, RequiredKeepUndefined } from '../../types';
|
||||
import { RequiredKeepUndefined } from '../../types';
|
||||
|
||||
export const deleteListItemSchema = t.intersection([
|
||||
t.exact(
|
||||
|
@ -20,5 +20,7 @@ export const deleteListItemSchema = t.intersection([
|
|||
t.exact(t.partial({ id, list_id })),
|
||||
]);
|
||||
|
||||
export type DeleteListItemSchemaPartial = Identity<t.TypeOf<typeof deleteListItemSchema>>;
|
||||
export type DeleteListItemSchema = RequiredKeepUndefined<t.TypeOf<typeof deleteListItemSchema>>;
|
||||
export type DeleteListItemSchema = t.OutputOf<typeof deleteListItemSchema>;
|
||||
export type DeleteListItemSchemaDecoded = RequiredKeepUndefined<
|
||||
t.TypeOf<typeof deleteListItemSchema>
|
||||
>;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
import * as t from 'io-ts';
|
||||
|
||||
import { id } from '../common/schemas';
|
||||
import { RequiredKeepUndefined } from '../../types';
|
||||
|
||||
export const deleteListSchema = t.exact(
|
||||
t.type({
|
||||
|
@ -16,5 +17,5 @@ export const deleteListSchema = t.exact(
|
|||
})
|
||||
);
|
||||
|
||||
export type DeleteListSchema = t.TypeOf<typeof deleteListSchema>;
|
||||
export type DeleteListSchema = RequiredKeepUndefined<t.TypeOf<typeof deleteListSchema>>;
|
||||
export type DeleteListSchemaEncoded = t.OutputOf<typeof deleteListSchema>;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
import * as t from 'io-ts';
|
||||
|
||||
import { list_id } from '../common/schemas';
|
||||
import { RequiredKeepUndefined } from '../../types';
|
||||
|
||||
export const exportListItemQuerySchema = t.exact(
|
||||
t.type({
|
||||
|
@ -17,5 +18,7 @@ export const exportListItemQuerySchema = t.exact(
|
|||
})
|
||||
);
|
||||
|
||||
export type ExportListItemQuerySchema = t.TypeOf<typeof exportListItemQuerySchema>;
|
||||
export type ExportListItemQuerySchema = RequiredKeepUndefined<
|
||||
t.TypeOf<typeof exportListItemQuerySchema>
|
||||
>;
|
||||
export type ExportListItemQuerySchemaEncoded = t.OutputOf<typeof exportListItemQuerySchema>;
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
import { FILTER } from '../../constants.mock';
|
||||
|
||||
import {
|
||||
FindEndpointListItemSchemaPartial,
|
||||
FindEndpointListItemSchemaPartialDecoded,
|
||||
FindEndpointListItemSchema,
|
||||
FindEndpointListItemSchemaDecoded,
|
||||
} from './find_endpoint_list_item_schema';
|
||||
|
||||
export const getFindEndpointListItemSchemaMock = (): FindEndpointListItemSchemaPartial => ({
|
||||
export const getFindEndpointListItemSchemaMock = (): FindEndpointListItemSchema => ({
|
||||
filter: FILTER,
|
||||
page: '1',
|
||||
per_page: '25',
|
||||
|
@ -19,7 +19,7 @@ export const getFindEndpointListItemSchemaMock = (): FindEndpointListItemSchemaP
|
|||
sort_order: undefined,
|
||||
});
|
||||
|
||||
export const getFindEndpointListItemSchemaDecodedMock = (): FindEndpointListItemSchemaPartialDecoded => ({
|
||||
export const getFindEndpointListItemSchemaDecodedMock = (): FindEndpointListItemSchemaDecoded => ({
|
||||
filter: FILTER,
|
||||
page: 1,
|
||||
per_page: 25,
|
||||
|
|
|
@ -14,7 +14,7 @@ import {
|
|||
getFindEndpointListItemSchemaMock,
|
||||
} from './find_endpoint_list_item_schema.mock';
|
||||
import {
|
||||
FindEndpointListItemSchemaPartial,
|
||||
FindEndpointListItemSchema,
|
||||
findEndpointListItemSchema,
|
||||
} from './find_endpoint_list_item_schema';
|
||||
|
||||
|
@ -29,7 +29,7 @@ describe('find_endpoint_list_item_schema', () => {
|
|||
});
|
||||
|
||||
test('it should validate and empty object since everything is optional and has defaults', () => {
|
||||
const payload: FindEndpointListItemSchemaPartial = {};
|
||||
const payload: FindEndpointListItemSchema = {};
|
||||
const decoded = findEndpointListItemSchema.decode(payload);
|
||||
const checked = exactCheck(payload, decoded);
|
||||
const message = pipe(checked, foldLeftRight);
|
||||
|
@ -98,7 +98,7 @@ describe('find_endpoint_list_item_schema', () => {
|
|||
});
|
||||
|
||||
test('it should not allow an extra key to be sent in', () => {
|
||||
const payload: FindEndpointListItemSchemaPartial & {
|
||||
const payload: FindEndpointListItemSchema & {
|
||||
extraKey: string;
|
||||
} = { ...getFindEndpointListItemSchemaMock(), extraKey: 'some new value' };
|
||||
const decoded = findEndpointListItemSchema.decode(payload);
|
||||
|
|
|
@ -22,16 +22,9 @@ export const findEndpointListItemSchema = t.exact(
|
|||
})
|
||||
);
|
||||
|
||||
export type FindEndpointListItemSchemaPartial = t.OutputOf<typeof findEndpointListItemSchema>;
|
||||
|
||||
// This type is used after a decode since some things are defaults after a decode.
|
||||
export type FindEndpointListItemSchemaPartialDecoded = t.TypeOf<typeof findEndpointListItemSchema>;
|
||||
export type FindEndpointListItemSchema = t.OutputOf<typeof findEndpointListItemSchema>;
|
||||
|
||||
// This type is used after a decode since some things are defaults after a decode.
|
||||
export type FindEndpointListItemSchemaDecoded = RequiredKeepUndefined<
|
||||
FindEndpointListItemSchemaPartialDecoded
|
||||
>;
|
||||
|
||||
export type FindEndpointListItemSchema = RequiredKeepUndefined<
|
||||
t.TypeOf<typeof findEndpointListItemSchema>
|
||||
>;
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
import { FILTER, LIST_ID, NAMESPACE_TYPE } from '../../constants.mock';
|
||||
|
||||
import {
|
||||
FindExceptionListItemSchemaPartial,
|
||||
FindExceptionListItemSchemaPartialDecoded,
|
||||
FindExceptionListItemSchema,
|
||||
FindExceptionListItemSchemaDecoded,
|
||||
} from './find_exception_list_item_schema';
|
||||
|
||||
export const getFindExceptionListItemSchemaMock = (): FindExceptionListItemSchemaPartial => ({
|
||||
export const getFindExceptionListItemSchemaMock = (): FindExceptionListItemSchema => ({
|
||||
filter: FILTER,
|
||||
list_id: LIST_ID,
|
||||
namespace_type: NAMESPACE_TYPE,
|
||||
|
@ -21,7 +21,7 @@ export const getFindExceptionListItemSchemaMock = (): FindExceptionListItemSchem
|
|||
sort_order: undefined,
|
||||
});
|
||||
|
||||
export const getFindExceptionListItemSchemaMultipleMock = (): FindExceptionListItemSchemaPartial => ({
|
||||
export const getFindExceptionListItemSchemaMultipleMock = (): FindExceptionListItemSchema => ({
|
||||
filter: 'name:Sofia Kovalevskaya,name:Hypatia,name:Sophie Germain',
|
||||
list_id: 'list-1,list-2,list-3',
|
||||
namespace_type: 'single,single,agnostic',
|
||||
|
@ -31,7 +31,7 @@ export const getFindExceptionListItemSchemaMultipleMock = (): FindExceptionListI
|
|||
sort_order: undefined,
|
||||
});
|
||||
|
||||
export const getFindExceptionListItemSchemaDecodedMock = (): FindExceptionListItemSchemaPartialDecoded => ({
|
||||
export const getFindExceptionListItemSchemaDecodedMock = (): FindExceptionListItemSchemaDecoded => ({
|
||||
filter: [FILTER],
|
||||
list_id: [LIST_ID],
|
||||
namespace_type: [NAMESPACE_TYPE],
|
||||
|
@ -41,7 +41,7 @@ export const getFindExceptionListItemSchemaDecodedMock = (): FindExceptionListIt
|
|||
sort_order: undefined,
|
||||
});
|
||||
|
||||
export const getFindExceptionListItemSchemaDecodedMultipleMock = (): FindExceptionListItemSchemaPartialDecoded => ({
|
||||
export const getFindExceptionListItemSchemaDecodedMultipleMock = (): FindExceptionListItemSchemaDecoded => ({
|
||||
filter: ['name:Sofia Kovalevskaya', 'name:Hypatia', 'name:Sophie Germain'],
|
||||
list_id: ['list-1', 'list-2', 'list-3'],
|
||||
namespace_type: ['single', 'single', 'agnostic'],
|
||||
|
|
|
@ -17,8 +17,8 @@ import {
|
|||
getFindExceptionListItemSchemaMultipleMock,
|
||||
} from './find_exception_list_item_schema.mock';
|
||||
import {
|
||||
FindExceptionListItemSchemaPartial,
|
||||
FindExceptionListItemSchemaPartialDecoded,
|
||||
FindExceptionListItemSchema,
|
||||
FindExceptionListItemSchemaDecoded,
|
||||
findExceptionListItemSchema,
|
||||
} from './find_exception_list_item_schema';
|
||||
|
||||
|
@ -42,15 +42,19 @@ describe('find_list_item_schema', () => {
|
|||
});
|
||||
|
||||
test('it should validate just a list_id where it decodes into an array for list_id and adds a namespace_type of "single" as an array', () => {
|
||||
const payload: FindExceptionListItemSchemaPartial = { list_id: LIST_ID };
|
||||
const payload: FindExceptionListItemSchema = { list_id: LIST_ID };
|
||||
const decoded = findExceptionListItemSchema.decode(payload);
|
||||
const checked = exactCheck(payload, decoded);
|
||||
const message = pipe(checked, foldLeftRight);
|
||||
expect(getPaths(left(message.errors))).toEqual([]);
|
||||
const expected: FindExceptionListItemSchemaPartialDecoded = {
|
||||
const expected: FindExceptionListItemSchemaDecoded = {
|
||||
filter: [],
|
||||
list_id: [LIST_ID],
|
||||
namespace_type: ['single'],
|
||||
page: undefined,
|
||||
per_page: undefined,
|
||||
sort_field: undefined,
|
||||
sort_order: undefined,
|
||||
};
|
||||
expect(message.schema).toEqual(expected);
|
||||
});
|
||||
|
@ -86,7 +90,7 @@ describe('find_list_item_schema', () => {
|
|||
const checked = exactCheck(payload, decoded);
|
||||
const message = pipe(checked, foldLeftRight);
|
||||
expect(getPaths(left(message.errors))).toEqual([]);
|
||||
const expected: FindExceptionListItemSchemaPartialDecoded = {
|
||||
const expected: FindExceptionListItemSchemaDecoded = {
|
||||
...getFindExceptionListItemSchemaDecodedMock(),
|
||||
filter: [],
|
||||
};
|
||||
|
@ -118,7 +122,7 @@ describe('find_list_item_schema', () => {
|
|||
});
|
||||
|
||||
test('it should not allow an extra key to be sent in', () => {
|
||||
const payload: FindExceptionListItemSchemaPartial & {
|
||||
const payload: FindExceptionListItemSchema & {
|
||||
extraKey: string;
|
||||
} = { ...getFindExceptionListItemSchemaMock(), extraKey: 'some new value' };
|
||||
const decoded = findExceptionListItemSchema.decode(payload);
|
||||
|
|
|
@ -36,22 +36,13 @@ export const findExceptionListItemSchema = t.intersection([
|
|||
),
|
||||
]);
|
||||
|
||||
export type FindExceptionListItemSchemaPartial = t.OutputOf<typeof findExceptionListItemSchema>;
|
||||
export type FindExceptionListItemSchema = t.OutputOf<typeof findExceptionListItemSchema>;
|
||||
|
||||
// This type is used after a decode since some things are defaults after a decode.
|
||||
export type FindExceptionListItemSchemaPartialDecoded = Omit<
|
||||
t.TypeOf<typeof findExceptionListItemSchema>,
|
||||
export type FindExceptionListItemSchemaDecoded = Omit<
|
||||
RequiredKeepUndefined<t.TypeOf<typeof findExceptionListItemSchema>>,
|
||||
'namespace_type' | 'filter'
|
||||
> & {
|
||||
filter: EmptyStringArrayDecoded;
|
||||
namespace_type: DefaultNamespaceArrayTypeDecoded;
|
||||
};
|
||||
|
||||
// This type is used after a decode since some things are defaults after a decode.
|
||||
export type FindExceptionListItemSchemaDecoded = RequiredKeepUndefined<
|
||||
FindExceptionListItemSchemaPartialDecoded
|
||||
>;
|
||||
|
||||
export type FindExceptionListItemSchema = RequiredKeepUndefined<
|
||||
t.TypeOf<typeof findExceptionListItemSchema>
|
||||
>;
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
import { FILTER, NAMESPACE_TYPE } from '../../constants.mock';
|
||||
|
||||
import {
|
||||
FindExceptionListSchemaPartial,
|
||||
FindExceptionListSchemaPartialDecoded,
|
||||
FindExceptionListSchema,
|
||||
FindExceptionListSchemaDecoded,
|
||||
} from './find_exception_list_schema';
|
||||
|
||||
export const getFindExceptionListSchemaMock = (): FindExceptionListSchemaPartial => ({
|
||||
export const getFindExceptionListSchemaMock = (): FindExceptionListSchema => ({
|
||||
filter: FILTER,
|
||||
namespace_type: NAMESPACE_TYPE,
|
||||
page: '1',
|
||||
|
@ -20,7 +20,7 @@ export const getFindExceptionListSchemaMock = (): FindExceptionListSchemaPartial
|
|||
sort_order: undefined,
|
||||
});
|
||||
|
||||
export const getFindExceptionListSchemaDecodedMock = (): FindExceptionListSchemaPartialDecoded => ({
|
||||
export const getFindExceptionListSchemaDecodedMock = (): FindExceptionListSchemaDecoded => ({
|
||||
filter: FILTER,
|
||||
namespace_type: NAMESPACE_TYPE,
|
||||
page: 1,
|
||||
|
|
|
@ -14,8 +14,8 @@ import {
|
|||
getFindExceptionListSchemaMock,
|
||||
} from './find_exception_list_schema.mock';
|
||||
import {
|
||||
FindExceptionListSchemaPartial,
|
||||
FindExceptionListSchemaPartialDecoded,
|
||||
FindExceptionListSchema,
|
||||
FindExceptionListSchemaDecoded,
|
||||
findExceptionListSchema,
|
||||
} from './find_exception_list_schema';
|
||||
|
||||
|
@ -30,13 +30,18 @@ describe('find_exception_list_schema', () => {
|
|||
});
|
||||
|
||||
test('it should validate and empty object since everything is optional and will respond only with namespace_type filled out to be "single"', () => {
|
||||
const payload: FindExceptionListSchemaPartial = {};
|
||||
const payload: FindExceptionListSchema = {};
|
||||
const decoded = findExceptionListSchema.decode(payload);
|
||||
const checked = exactCheck(payload, decoded);
|
||||
const message = pipe(checked, foldLeftRight);
|
||||
expect(getPaths(left(message.errors))).toEqual([]);
|
||||
const expected: FindExceptionListSchemaPartialDecoded = {
|
||||
const expected: FindExceptionListSchemaDecoded = {
|
||||
filter: undefined,
|
||||
namespace_type: 'single',
|
||||
page: undefined,
|
||||
per_page: undefined,
|
||||
sort_field: undefined,
|
||||
sort_order: undefined,
|
||||
};
|
||||
expect(message.schema).toEqual(expected);
|
||||
});
|
||||
|
@ -102,7 +107,7 @@ describe('find_exception_list_schema', () => {
|
|||
});
|
||||
|
||||
test('it should not allow an extra key to be sent in', () => {
|
||||
const payload: FindExceptionListSchemaPartial & {
|
||||
const payload: FindExceptionListSchema & {
|
||||
extraKey: string;
|
||||
} = { ...getFindExceptionListSchemaMock(), extraKey: 'some new value' };
|
||||
const decoded = findExceptionListSchema.decode(payload);
|
||||
|
|
|
@ -24,21 +24,12 @@ export const findExceptionListSchema = t.exact(
|
|||
})
|
||||
);
|
||||
|
||||
export type FindExceptionListSchemaPartial = t.OutputOf<typeof findExceptionListSchema>;
|
||||
export type FindExceptionListSchema = t.OutputOf<typeof findExceptionListSchema>;
|
||||
|
||||
// This type is used after a decode since some things are defaults after a decode.
|
||||
export type FindExceptionListSchemaPartialDecoded = Omit<
|
||||
t.TypeOf<typeof findExceptionListSchema>,
|
||||
export type FindExceptionListSchemaDecoded = Omit<
|
||||
RequiredKeepUndefined<t.TypeOf<typeof findExceptionListSchema>>,
|
||||
'namespace_type'
|
||||
> & {
|
||||
namespace_type: NamespaceType;
|
||||
};
|
||||
|
||||
// This type is used after a decode since some things are defaults after a decode.
|
||||
export type FindExceptionListSchemaDecoded = RequiredKeepUndefined<
|
||||
FindExceptionListSchemaPartialDecoded
|
||||
>;
|
||||
|
||||
export type FindExceptionListSchema = RequiredKeepUndefined<
|
||||
t.TypeOf<typeof findExceptionListSchema>
|
||||
>;
|
||||
|
|
|
@ -6,12 +6,9 @@
|
|||
|
||||
import { CURSOR, FILTER, LIST_ID } from '../../constants.mock';
|
||||
|
||||
import {
|
||||
FindListItemSchemaPartial,
|
||||
FindListItemSchemaPartialDecoded,
|
||||
} from './find_list_item_schema';
|
||||
import { FindListItemSchema, FindListItemSchemaDecoded } from './find_list_item_schema';
|
||||
|
||||
export const getFindListItemSchemaMock = (): FindListItemSchemaPartial => ({
|
||||
export const getFindListItemSchemaMock = (): FindListItemSchema => ({
|
||||
cursor: CURSOR,
|
||||
filter: FILTER,
|
||||
list_id: LIST_ID,
|
||||
|
@ -21,7 +18,7 @@ export const getFindListItemSchemaMock = (): FindListItemSchemaPartial => ({
|
|||
sort_order: undefined,
|
||||
});
|
||||
|
||||
export const getFindListItemSchemaDecodedMock = (): FindListItemSchemaPartialDecoded => ({
|
||||
export const getFindListItemSchemaDecodedMock = (): FindListItemSchemaDecoded => ({
|
||||
cursor: CURSOR,
|
||||
filter: FILTER,
|
||||
list_id: LIST_ID,
|
||||
|
|
|
@ -15,8 +15,8 @@ import {
|
|||
getFindListItemSchemaMock,
|
||||
} from './find_list_item_schema.mock';
|
||||
import {
|
||||
FindListItemSchemaPartial,
|
||||
FindListItemSchemaPartialDecoded,
|
||||
FindListItemSchema,
|
||||
FindListItemSchemaDecoded,
|
||||
findListItemSchema,
|
||||
} from './find_list_item_schema';
|
||||
|
||||
|
@ -31,12 +31,12 @@ describe('find_list_item_schema', () => {
|
|||
});
|
||||
|
||||
test('it should validate just a list_id where it decodes into an array for list_id and adds a namespace_type of "single"', () => {
|
||||
const payload: FindListItemSchemaPartial = { list_id: LIST_ID };
|
||||
const payload: FindListItemSchema = { list_id: LIST_ID };
|
||||
const decoded = findListItemSchema.decode(payload);
|
||||
const checked = exactCheck(payload, decoded);
|
||||
const message = pipe(checked, foldLeftRight);
|
||||
expect(getPaths(left(message.errors))).toEqual([]);
|
||||
const expected: FindListItemSchemaPartialDecoded = {
|
||||
const expected: FindListItemSchemaDecoded = {
|
||||
cursor: undefined,
|
||||
filter: undefined,
|
||||
list_id: LIST_ID,
|
||||
|
@ -97,7 +97,7 @@ describe('find_list_item_schema', () => {
|
|||
});
|
||||
|
||||
test('it should not allow an extra key to be sent in', () => {
|
||||
const payload: FindListItemSchemaPartial & {
|
||||
const payload: FindListItemSchema & {
|
||||
extraKey: string;
|
||||
} = { ...getFindListItemSchemaMock(), extraKey: 'some new value' };
|
||||
const decoded = findListItemSchema.decode(payload);
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import * as t from 'io-ts';
|
||||
|
||||
import { cursor, filter, list_id, sort_field, sort_order } from '../common/schemas';
|
||||
import { Identity, RequiredKeepUndefined } from '../../types';
|
||||
import { RequiredKeepUndefined } from '../../types';
|
||||
import { StringToPositiveNumber } from '../types/string_to_positive_number';
|
||||
|
||||
export const findListItemSchema = t.intersection([
|
||||
|
@ -26,9 +26,7 @@ export const findListItemSchema = t.intersection([
|
|||
),
|
||||
]);
|
||||
|
||||
export type FindListItemSchemaPartial = Identity<t.OutputOf<typeof findListItemSchema>>;
|
||||
export type FindListItemSchema = t.OutputOf<typeof findListItemSchema>;
|
||||
|
||||
// This type is used after a decode since some things are defaults after a decode.
|
||||
export type FindListItemSchemaPartialDecoded = RequiredKeepUndefined<
|
||||
t.TypeOf<typeof findListItemSchema>
|
||||
>;
|
||||
export type FindListItemSchemaDecoded = RequiredKeepUndefined<t.TypeOf<typeof findListItemSchema>>;
|
||||
|
|
|
@ -17,6 +17,7 @@ export const getFindListSchemaMock = (): FindListSchemaEncoded => ({
|
|||
});
|
||||
|
||||
export const getFindListSchemaDecodedMock = (): FindListSchema => ({
|
||||
cursor: undefined,
|
||||
filter: FILTER,
|
||||
page: 1,
|
||||
per_page: 25,
|
||||
|
|
|
@ -10,7 +10,7 @@ import { pipe } from 'fp-ts/lib/pipeable';
|
|||
import { exactCheck, foldLeftRight, getPaths } from '../../siem_common_deps';
|
||||
|
||||
import { getFindListSchemaDecodedMock, getFindListSchemaMock } from './find_list_schema.mock';
|
||||
import { FindListSchema, FindListSchemaEncoded, findListSchema } from './find_list_schema';
|
||||
import { FindListSchemaEncoded, findListSchema } from './find_list_schema';
|
||||
|
||||
describe('find_list_schema', () => {
|
||||
test('it should validate a typical find item request', () => {
|
||||
|
@ -28,8 +28,7 @@ describe('find_list_schema', () => {
|
|||
const checked = exactCheck(payload, decoded);
|
||||
const message = pipe(checked, foldLeftRight);
|
||||
expect(getPaths(left(message.errors))).toEqual([]);
|
||||
const expected: FindListSchema = {};
|
||||
expect(message.schema).toEqual(expected);
|
||||
expect(message.schema).toEqual(payload);
|
||||
});
|
||||
|
||||
test('it should validate with page missing', () => {
|
||||
|
|
|
@ -10,6 +10,7 @@ import * as t from 'io-ts';
|
|||
|
||||
import { cursor, filter, sort_field, sort_order } from '../common/schemas';
|
||||
import { StringToPositiveNumber } from '../types/string_to_positive_number';
|
||||
import { RequiredKeepUndefined } from '../../types';
|
||||
|
||||
export const findListSchema = t.exact(
|
||||
t.partial({
|
||||
|
@ -22,5 +23,5 @@ export const findListSchema = t.exact(
|
|||
})
|
||||
);
|
||||
|
||||
export type FindListSchema = t.TypeOf<typeof findListSchema>;
|
||||
export type FindListSchema = RequiredKeepUndefined<t.TypeOf<typeof findListSchema>>;
|
||||
export type FindListSchemaEncoded = t.OutputOf<typeof findListSchema>;
|
||||
|
|
|
@ -8,14 +8,14 @@
|
|||
|
||||
import * as t from 'io-ts';
|
||||
|
||||
import { RequiredKeepUndefined } from '../../types';
|
||||
import { deserializer, list_id, serializer, type } from '../common/schemas';
|
||||
import { Identity } from '../../types';
|
||||
|
||||
export const importListItemQuerySchema = t.exact(
|
||||
t.partial({ deserializer, list_id, serializer, type })
|
||||
);
|
||||
|
||||
export type ImportListItemQuerySchemaPartial = Identity<t.TypeOf<typeof importListItemQuerySchema>>;
|
||||
|
||||
export type ImportListItemQuerySchema = t.TypeOf<typeof importListItemQuerySchema>;
|
||||
export type ImportListItemQuerySchema = RequiredKeepUndefined<
|
||||
t.TypeOf<typeof importListItemQuerySchema>
|
||||
>;
|
||||
export type ImportListItemQuerySchemaEncoded = t.OutputOf<typeof importListItemQuerySchema>;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
import * as t from 'io-ts';
|
||||
|
||||
import { file } from '../common/schemas';
|
||||
import { RequiredKeepUndefined } from '../../types';
|
||||
|
||||
export const importListItemSchema = t.exact(
|
||||
t.type({
|
||||
|
@ -16,5 +17,5 @@ export const importListItemSchema = t.exact(
|
|||
})
|
||||
);
|
||||
|
||||
export type ImportListItemSchema = t.TypeOf<typeof importListItemSchema>;
|
||||
export type ImportListItemSchema = RequiredKeepUndefined<t.TypeOf<typeof importListItemSchema>>;
|
||||
export type ImportListItemSchemaEncoded = t.OutputOf<typeof importListItemSchema>;
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
import * as t from 'io-ts';
|
||||
|
||||
import { id, meta, value } from '../common/schemas';
|
||||
import { Identity, RequiredKeepUndefined } from '../../types';
|
||||
import { _version, id, meta, value } from '../common/schemas';
|
||||
import { RequiredKeepUndefined } from '../../types';
|
||||
|
||||
export const patchListItemSchema = t.intersection([
|
||||
t.exact(
|
||||
|
@ -17,8 +17,10 @@ export const patchListItemSchema = t.intersection([
|
|||
id,
|
||||
})
|
||||
),
|
||||
t.exact(t.partial({ meta, value })),
|
||||
t.exact(t.partial({ _version, meta, value })),
|
||||
]);
|
||||
|
||||
export type PatchListItemSchemaPartial = Identity<t.TypeOf<typeof patchListItemSchema>>;
|
||||
export type PatchListItemSchema = RequiredKeepUndefined<t.TypeOf<typeof patchListItemSchema>>;
|
||||
export type PatchListItemSchema = t.OutputOf<typeof patchListItemSchema>;
|
||||
export type PatchListItemSchemaDecoded = RequiredKeepUndefined<
|
||||
t.TypeOf<typeof patchListItemSchema>
|
||||
>;
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
import * as t from 'io-ts';
|
||||
|
||||
import { description, id, meta, name } from '../common/schemas';
|
||||
import { Identity, RequiredKeepUndefined } from '../../types';
|
||||
import { _version, description, id, meta, name } from '../common/schemas';
|
||||
import { RequiredKeepUndefined } from '../../types';
|
||||
|
||||
export const patchListSchema = t.intersection([
|
||||
t.exact(
|
||||
|
@ -17,8 +17,8 @@ export const patchListSchema = t.intersection([
|
|||
id,
|
||||
})
|
||||
),
|
||||
t.exact(t.partial({ description, meta, name })),
|
||||
t.exact(t.partial({ _version, description, meta, name })),
|
||||
]);
|
||||
|
||||
export type PatchListSchemaPartial = Identity<t.TypeOf<typeof patchListSchema>>;
|
||||
export type PatchListSchema = RequiredKeepUndefined<Identity<t.TypeOf<typeof patchListSchema>>>;
|
||||
export type PatchListSchema = t.OutputOf<typeof patchListSchema>;
|
||||
export type PatchListSchemaDecoded = RequiredKeepUndefined<t.TypeOf<typeof patchListSchema>>;
|
||||
|
|
|
@ -18,14 +18,9 @@ export const readEndpointListItemSchema = t.exact(
|
|||
})
|
||||
);
|
||||
|
||||
export type ReadEndpointListItemSchemaPartial = t.TypeOf<typeof readEndpointListItemSchema>;
|
||||
|
||||
// This type is used after a decode since some things are defaults after a decode.
|
||||
export type ReadEndpointListItemSchemaPartialDecoded = ReadEndpointListItemSchemaPartial;
|
||||
export type ReadEndpointListItemSchema = t.OutputOf<typeof readEndpointListItemSchema>;
|
||||
|
||||
// This type is used after a decode since some things are defaults after a decode.
|
||||
export type ReadEndpointListItemSchemaDecoded = RequiredKeepUndefined<
|
||||
ReadEndpointListItemSchemaPartialDecoded
|
||||
t.TypeOf<typeof readEndpointListItemSchema>
|
||||
>;
|
||||
|
||||
export type ReadEndpointListItemSchema = RequiredKeepUndefined<ReadEndpointListItemSchemaPartial>;
|
||||
|
|
|
@ -20,19 +20,12 @@ export const readExceptionListItemSchema = t.exact(
|
|||
})
|
||||
);
|
||||
|
||||
export type ReadExceptionListItemSchemaPartial = t.TypeOf<typeof readExceptionListItemSchema>;
|
||||
export type ReadExceptionListItemSchema = t.OutputOf<typeof readExceptionListItemSchema>;
|
||||
|
||||
// This type is used after a decode since some things are defaults after a decode.
|
||||
export type ReadExceptionListItemSchemaPartialDecoded = Omit<
|
||||
ReadExceptionListItemSchemaPartial,
|
||||
export type ReadExceptionListItemSchemaDecoded = Omit<
|
||||
RequiredKeepUndefined<t.TypeOf<typeof readExceptionListItemSchema>>,
|
||||
'namespace_type'
|
||||
> & {
|
||||
namespace_type: NamespaceType;
|
||||
};
|
||||
|
||||
// This type is used after a decode since some things are defaults after a decode.
|
||||
export type ReadExceptionListItemSchemaDecoded = RequiredKeepUndefined<
|
||||
ReadExceptionListItemSchemaPartialDecoded
|
||||
>;
|
||||
|
||||
export type ReadExceptionListItemSchema = RequiredKeepUndefined<ReadExceptionListItemSchemaPartial>;
|
||||
|
|
|
@ -20,19 +20,12 @@ export const readExceptionListSchema = t.exact(
|
|||
})
|
||||
);
|
||||
|
||||
export type ReadExceptionListSchemaPartial = t.TypeOf<typeof readExceptionListSchema>;
|
||||
export type ReadExceptionListSchema = t.OutputOf<typeof readExceptionListSchema>;
|
||||
|
||||
// This type is used after a decode since some things are defaults after a decode.
|
||||
export type ReadExceptionListSchemaPartialDecoded = Omit<
|
||||
ReadExceptionListSchemaPartial,
|
||||
export type ReadExceptionListSchemaDecoded = Omit<
|
||||
RequiredKeepUndefined<t.TypeOf<typeof readExceptionListSchema>>,
|
||||
'namespace_type'
|
||||
> & {
|
||||
namespace_type: NamespaceType;
|
||||
};
|
||||
|
||||
// This type is used after a decode since some things are defaults after a decode.
|
||||
export type ReadExceptionListSchemaDecoded = RequiredKeepUndefined<
|
||||
ReadExceptionListSchemaPartialDecoded
|
||||
>;
|
||||
|
||||
export type ReadExceptionListSchema = RequiredKeepUndefined<ReadExceptionListSchemaPartial>;
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
import * as t from 'io-ts';
|
||||
|
||||
import { id, list_id, value } from '../common/schemas';
|
||||
import { Identity, RequiredKeepUndefined } from '../../types';
|
||||
import { RequiredKeepUndefined } from '../../types';
|
||||
|
||||
export const readListItemSchema = t.exact(t.partial({ id, list_id, value }));
|
||||
|
||||
export type ReadListItemSchemaPartial = Identity<t.TypeOf<typeof readListItemSchema>>;
|
||||
export type ReadListItemSchema = RequiredKeepUndefined<t.TypeOf<typeof readListItemSchema>>;
|
||||
export type ReadListItemSchema = t.OutputOf<typeof readListItemSchema>;
|
||||
export type ReadListItemSchemaDecoded = RequiredKeepUndefined<t.TypeOf<typeof readListItemSchema>>;
|
||||
|
|
|
@ -16,4 +16,4 @@ export const readListSchema = t.exact(
|
|||
})
|
||||
);
|
||||
|
||||
export type ReadListSchema = t.TypeOf<typeof readListSchema>;
|
||||
export type ReadListSchema = t.OutputOf<typeof readListSchema>;
|
||||
|
|
|
@ -21,6 +21,7 @@ import { UpdateEndpointListItemSchema } from './update_endpoint_list_item_schema
|
|||
|
||||
export const getUpdateEndpointListItemSchemaMock = (): UpdateEndpointListItemSchema => ({
|
||||
_tags: _TAGS,
|
||||
_version: undefined,
|
||||
comments: COMMENTS,
|
||||
description: DESCRIPTION,
|
||||
entries: ENTRIES,
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
Tags,
|
||||
_Tags,
|
||||
_tags,
|
||||
_version,
|
||||
description,
|
||||
exceptionListItemType,
|
||||
id,
|
||||
|
@ -19,7 +20,7 @@ import {
|
|||
name,
|
||||
tags,
|
||||
} from '../common/schemas';
|
||||
import { Identity, RequiredKeepUndefined } from '../../types';
|
||||
import { RequiredKeepUndefined } from '../../types';
|
||||
import {
|
||||
DefaultEntryArray,
|
||||
DefaultUpdateCommentsArray,
|
||||
|
@ -38,6 +39,7 @@ export const updateEndpointListItemSchema = t.intersection([
|
|||
t.exact(
|
||||
t.partial({
|
||||
_tags, // defaults to empty array if not set during decode
|
||||
_version, // defaults to undefined if not set during decode
|
||||
comments: DefaultUpdateCommentsArray, // defaults to empty array if not set during decode
|
||||
entries: DefaultEntryArray, // defaults to empty array if not set during decode
|
||||
id, // defaults to undefined if not set during decode
|
||||
|
@ -48,19 +50,15 @@ export const updateEndpointListItemSchema = t.intersection([
|
|||
),
|
||||
]);
|
||||
|
||||
export type UpdateEndpointListItemSchemaPartial = Identity<
|
||||
t.TypeOf<typeof updateEndpointListItemSchema>
|
||||
>;
|
||||
export type UpdateEndpointListItemSchema = RequiredKeepUndefined<
|
||||
t.TypeOf<typeof updateEndpointListItemSchema>
|
||||
>;
|
||||
export type UpdateEndpointListItemSchema = t.OutputOf<typeof updateEndpointListItemSchema>;
|
||||
|
||||
// This type is used after a decode since some things are defaults after a decode.
|
||||
export type UpdateEndpointListItemSchemaDecoded = Identity<
|
||||
Omit<UpdateEndpointListItemSchema, '_tags' | 'tags' | 'entries' | 'comments'> & {
|
||||
_tags: _Tags;
|
||||
comments: UpdateCommentsArray;
|
||||
tags: Tags;
|
||||
entries: EntriesArray;
|
||||
}
|
||||
>;
|
||||
export type UpdateEndpointListItemSchemaDecoded = Omit<
|
||||
RequiredKeepUndefined<t.TypeOf<typeof updateEndpointListItemSchema>>,
|
||||
'_tags' | 'tags' | 'entries' | 'comments'
|
||||
> & {
|
||||
_tags: _Tags;
|
||||
comments: UpdateCommentsArray;
|
||||
tags: Tags;
|
||||
entries: EntriesArray;
|
||||
};
|
||||
|
|
|
@ -22,6 +22,7 @@ import { UpdateExceptionListItemSchema } from './update_exception_list_item_sche
|
|||
|
||||
export const getUpdateExceptionListItemSchemaMock = (): UpdateExceptionListItemSchema => ({
|
||||
_tags: _TAGS,
|
||||
_version: undefined,
|
||||
comments: COMMENTS,
|
||||
description: DESCRIPTION,
|
||||
entries: ENTRIES,
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
Tags,
|
||||
_Tags,
|
||||
_tags,
|
||||
_version,
|
||||
description,
|
||||
exceptionListItemType,
|
||||
id,
|
||||
|
@ -20,7 +21,7 @@ import {
|
|||
namespace_type,
|
||||
tags,
|
||||
} from '../common/schemas';
|
||||
import { Identity, RequiredKeepUndefined } from '../../types';
|
||||
import { RequiredKeepUndefined } from '../../types';
|
||||
import {
|
||||
DefaultEntryArray,
|
||||
DefaultUpdateCommentsArray,
|
||||
|
@ -40,6 +41,7 @@ export const updateExceptionListItemSchema = t.intersection([
|
|||
t.exact(
|
||||
t.partial({
|
||||
_tags, // defaults to empty array if not set during decode
|
||||
_version, // defaults to undefined if not set during decode
|
||||
comments: DefaultUpdateCommentsArray, // defaults to empty array if not set during decode
|
||||
entries: DefaultEntryArray, // defaults to empty array if not set during decode
|
||||
id, // defaults to undefined if not set during decode
|
||||
|
@ -51,23 +53,16 @@ export const updateExceptionListItemSchema = t.intersection([
|
|||
),
|
||||
]);
|
||||
|
||||
export type UpdateExceptionListItemSchemaPartial = Identity<
|
||||
t.TypeOf<typeof updateExceptionListItemSchema>
|
||||
>;
|
||||
export type UpdateExceptionListItemSchema = RequiredKeepUndefined<
|
||||
t.TypeOf<typeof updateExceptionListItemSchema>
|
||||
>;
|
||||
export type UpdateExceptionListItemSchema = t.OutputOf<typeof updateExceptionListItemSchema>;
|
||||
|
||||
// This type is used after a decode since some things are defaults after a decode.
|
||||
export type UpdateExceptionListItemSchemaDecoded = Identity<
|
||||
Omit<
|
||||
UpdateExceptionListItemSchema,
|
||||
'_tags' | 'tags' | 'entries' | 'namespace_type' | 'comments'
|
||||
> & {
|
||||
_tags: _Tags;
|
||||
comments: UpdateCommentsArray;
|
||||
tags: Tags;
|
||||
entries: EntriesArray;
|
||||
namespace_type: NamespaceType;
|
||||
}
|
||||
>;
|
||||
export type UpdateExceptionListItemSchemaDecoded = Omit<
|
||||
RequiredKeepUndefined<t.TypeOf<typeof updateExceptionListItemSchema>>,
|
||||
'_tags' | 'tags' | 'entries' | 'namespace_type' | 'comments'
|
||||
> & {
|
||||
_tags: _Tags;
|
||||
comments: UpdateCommentsArray;
|
||||
tags: Tags;
|
||||
entries: EntriesArray;
|
||||
namespace_type: NamespaceType;
|
||||
};
|
||||
|
|
|
@ -10,6 +10,7 @@ import { UpdateExceptionListSchema } from './update_exception_list_schema';
|
|||
|
||||
export const getUpdateExceptionListSchemaMock = (): UpdateExceptionListSchema => ({
|
||||
_tags: _TAGS,
|
||||
_version: undefined,
|
||||
description: DESCRIPTION,
|
||||
id: ID,
|
||||
list_id: LIST_ID,
|
||||
|
|
|
@ -12,14 +12,17 @@ import {
|
|||
Tags,
|
||||
_Tags,
|
||||
_tags,
|
||||
_version,
|
||||
description,
|
||||
exceptionListType,
|
||||
id,
|
||||
list_id,
|
||||
meta,
|
||||
name,
|
||||
namespace_type,
|
||||
tags,
|
||||
} from '../common/schemas';
|
||||
import { Identity, RequiredKeepUndefined } from '../../types';
|
||||
import { RequiredKeepUndefined } from '../../types';
|
||||
import { NamespaceType } from '../types';
|
||||
|
||||
export const updateExceptionListSchema = t.intersection([
|
||||
|
@ -33,8 +36,9 @@ export const updateExceptionListSchema = t.intersection([
|
|||
t.exact(
|
||||
t.partial({
|
||||
_tags, // defaults to empty array if not set during decode
|
||||
id: t.union([t.string, t.undefined]), // defaults to undefined if not set during decode
|
||||
list_id: t.union([t.string, t.undefined]), // defaults to undefined if not set during decode
|
||||
_version, // defaults to undefined if not set during decode
|
||||
id, // defaults to undefined if not set during decode
|
||||
list_id, // defaults to undefined if not set during decode
|
||||
meta, // defaults to undefined if not set during decode
|
||||
namespace_type, // defaults to 'single' if not set during decode
|
||||
tags, // defaults to empty array if not set during decode
|
||||
|
@ -42,16 +46,14 @@ export const updateExceptionListSchema = t.intersection([
|
|||
),
|
||||
]);
|
||||
|
||||
export type UpdateExceptionListSchemaPartial = Identity<t.TypeOf<typeof updateExceptionListSchema>>;
|
||||
export type UpdateExceptionListSchema = RequiredKeepUndefined<
|
||||
t.TypeOf<typeof updateExceptionListSchema>
|
||||
>;
|
||||
export type UpdateExceptionListSchema = t.OutputOf<typeof updateExceptionListSchema>;
|
||||
|
||||
// This type is used after a decode since the arrays turn into defaults of empty arrays.
|
||||
export type UpdateExceptionListSchemaDecoded = Identity<
|
||||
Omit<UpdateExceptionListSchema, '_tags | tags | namespace_type'> & {
|
||||
_tags: _Tags;
|
||||
tags: Tags;
|
||||
namespace_type: NamespaceType;
|
||||
}
|
||||
>;
|
||||
export type UpdateExceptionListSchemaDecoded = Omit<
|
||||
RequiredKeepUndefined<t.TypeOf<typeof updateExceptionListSchema>>,
|
||||
'_tags | tags | namespace_type'
|
||||
> & {
|
||||
_tags: _Tags;
|
||||
tags: Tags;
|
||||
namespace_type: NamespaceType;
|
||||
};
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
import * as t from 'io-ts';
|
||||
|
||||
import { id, meta, value } from '../common/schemas';
|
||||
import { Identity, RequiredKeepUndefined } from '../../types';
|
||||
import { _version, id, meta, value } from '../common/schemas';
|
||||
import { RequiredKeepUndefined } from '../../types';
|
||||
|
||||
export const updateListItemSchema = t.intersection([
|
||||
t.exact(
|
||||
|
@ -20,10 +20,13 @@ export const updateListItemSchema = t.intersection([
|
|||
),
|
||||
t.exact(
|
||||
t.partial({
|
||||
_version, // defaults to undefined if not set during decode
|
||||
meta, // defaults to undefined if not set during decode
|
||||
})
|
||||
),
|
||||
]);
|
||||
|
||||
export type UpdateListItemSchemaPartial = Identity<t.TypeOf<typeof updateListItemSchema>>;
|
||||
export type UpdateListItemSchema = RequiredKeepUndefined<t.TypeOf<typeof updateListItemSchema>>;
|
||||
export type UpdateListItemSchema = t.OutputOf<typeof updateListItemSchema>;
|
||||
export type UpdateListItemSchemaDecoded = RequiredKeepUndefined<
|
||||
t.TypeOf<typeof updateListItemSchema>
|
||||
>;
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
import * as t from 'io-ts';
|
||||
|
||||
import { description, id, meta, name } from '../common/schemas';
|
||||
import { Identity, RequiredKeepUndefined } from '../../types';
|
||||
import { _version, description, id, meta, name } from '../common/schemas';
|
||||
import { RequiredKeepUndefined } from '../../types';
|
||||
|
||||
export const updateListSchema = t.intersection([
|
||||
t.exact(
|
||||
|
@ -21,10 +21,11 @@ export const updateListSchema = t.intersection([
|
|||
),
|
||||
t.exact(
|
||||
t.partial({
|
||||
_version, // defaults to undefined if not set during decode
|
||||
meta, // defaults to undefined if not set during decode
|
||||
})
|
||||
),
|
||||
]);
|
||||
|
||||
export type UpdateListSchemaPartial = Identity<t.TypeOf<typeof updateListSchema>>;
|
||||
export type UpdateListSchema = RequiredKeepUndefined<t.TypeOf<typeof updateListSchema>>;
|
||||
export type UpdateListSchema = t.OutputOf<typeof updateListSchema>;
|
||||
export type UpdateListSchemaDecoded = RequiredKeepUndefined<t.TypeOf<typeof updateListSchema>>;
|
||||
|
|
|
@ -41,7 +41,7 @@ describe('create_endpoint_list_schema', () => {
|
|||
const message = pipe(checked, foldLeftRight);
|
||||
|
||||
expect(getPaths(left(message.errors))).toEqual([
|
||||
'invalid keys "_tags,["endpoint","process","malware","os:linux"],created_at,created_by,description,id,meta,{},name,namespace_type,tags,["user added string for a tag","malware"],tie_breaker_id,type,updated_at,updated_by"',
|
||||
'invalid keys "_tags,["endpoint","process","malware","os:linux"],_version,created_at,created_by,description,id,meta,{},name,namespace_type,tags,["user added string for a tag","malware"],tie_breaker_id,type,updated_at,updated_by"',
|
||||
]);
|
||||
expect(message.schema).toEqual({});
|
||||
});
|
||||
|
|
|
@ -3,26 +3,38 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
import { ENTRIES } from '../../constants.mock';
|
||||
import {
|
||||
COMMENTS,
|
||||
DATE_NOW,
|
||||
DESCRIPTION,
|
||||
ENTRIES,
|
||||
ITEM_TYPE,
|
||||
META,
|
||||
NAME,
|
||||
NAMESPACE_TYPE,
|
||||
TIE_BREAKER,
|
||||
USER,
|
||||
} from '../../constants.mock';
|
||||
|
||||
import { ExceptionListItemSchema } from './exception_list_item_schema';
|
||||
|
||||
export const getExceptionListItemSchemaMock = (): ExceptionListItemSchema => ({
|
||||
_tags: ['endpoint', 'process', 'malware', 'os:linux'],
|
||||
comments: [],
|
||||
created_at: '2020-04-23T00:19:13.289Z',
|
||||
created_by: 'user_name',
|
||||
description: 'This is a sample endpoint type exception',
|
||||
_version: undefined,
|
||||
comments: COMMENTS,
|
||||
created_at: DATE_NOW,
|
||||
created_by: USER,
|
||||
description: DESCRIPTION,
|
||||
entries: ENTRIES,
|
||||
id: '1',
|
||||
item_id: 'endpoint_list_item',
|
||||
list_id: 'endpoint_list_id',
|
||||
meta: {},
|
||||
name: 'Sample Endpoint Exception List',
|
||||
namespace_type: 'single',
|
||||
meta: META,
|
||||
name: NAME,
|
||||
namespace_type: NAMESPACE_TYPE,
|
||||
tags: ['user added string for a tag', 'malware'],
|
||||
tie_breaker_id: '77fd1909-6786-428a-a671-30229a719c1f',
|
||||
type: 'simple',
|
||||
updated_at: '2020-04-23T00:19:13.289Z',
|
||||
updated_by: 'user_name',
|
||||
tie_breaker_id: TIE_BREAKER,
|
||||
type: ITEM_TYPE,
|
||||
updated_at: DATE_NOW,
|
||||
updated_by: USER,
|
||||
});
|
||||
|
|
|
@ -10,6 +10,7 @@ import * as t from 'io-ts';
|
|||
|
||||
import {
|
||||
_tags,
|
||||
_versionOrUndefined,
|
||||
created_at,
|
||||
created_by,
|
||||
description,
|
||||
|
@ -30,6 +31,7 @@ import { commentsArray, entriesArray } from '../types';
|
|||
export const exceptionListItemSchema = t.exact(
|
||||
t.type({
|
||||
_tags,
|
||||
_version: _versionOrUndefined,
|
||||
comments: commentsArray,
|
||||
created_at,
|
||||
created_by,
|
||||
|
|
|
@ -4,23 +4,32 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import {
|
||||
DATE_NOW,
|
||||
DESCRIPTION,
|
||||
ENDPOINT_TYPE,
|
||||
META,
|
||||
TIE_BREAKER,
|
||||
USER,
|
||||
_VERSION,
|
||||
} from '../../constants.mock';
|
||||
import { ENDPOINT_LIST_ID } from '../..';
|
||||
|
||||
import { ExceptionListSchema } from './exception_list_schema';
|
||||
|
||||
export const getExceptionListSchemaMock = (): ExceptionListSchema => ({
|
||||
_tags: ['endpoint', 'process', 'malware', 'os:linux'],
|
||||
created_at: '2020-04-23T00:19:13.289Z',
|
||||
created_by: 'user_name',
|
||||
description: 'This is a sample endpoint type exception',
|
||||
_version: _VERSION,
|
||||
created_at: DATE_NOW,
|
||||
created_by: USER,
|
||||
description: DESCRIPTION,
|
||||
id: '1',
|
||||
list_id: ENDPOINT_LIST_ID,
|
||||
meta: {},
|
||||
meta: META,
|
||||
name: 'Sample Endpoint Exception List',
|
||||
namespace_type: 'agnostic',
|
||||
tags: ['user added string for a tag', 'malware'],
|
||||
tie_breaker_id: '77fd1909-6786-428a-a671-30229a719c1f',
|
||||
type: 'endpoint',
|
||||
updated_at: '2020-04-23T00:19:13.289Z',
|
||||
tie_breaker_id: TIE_BREAKER,
|
||||
type: ENDPOINT_TYPE,
|
||||
updated_at: DATE_NOW,
|
||||
updated_by: 'user_name',
|
||||
});
|
||||
|
|
|
@ -10,6 +10,7 @@ import * as t from 'io-ts';
|
|||
|
||||
import {
|
||||
_tags,
|
||||
_versionOrUndefined,
|
||||
created_at,
|
||||
created_by,
|
||||
description,
|
||||
|
@ -28,6 +29,7 @@ import {
|
|||
export const exceptionListSchema = t.exact(
|
||||
t.type({
|
||||
_tags,
|
||||
_version: _versionOrUndefined,
|
||||
created_at,
|
||||
created_by,
|
||||
description,
|
||||
|
|
|
@ -17,6 +17,7 @@ import {
|
|||
} from '../../../common/constants.mock';
|
||||
|
||||
export const getListItemResponseMock = (): ListItemSchema => ({
|
||||
_version: undefined,
|
||||
created_at: DATE_NOW,
|
||||
created_by: USER,
|
||||
deserializer: undefined,
|
||||
|
|
|
@ -9,6 +9,7 @@ import * as t from 'io-ts';
|
|||
/* eslint-disable @typescript-eslint/camelcase */
|
||||
|
||||
import {
|
||||
_versionOrUndefined,
|
||||
created_at,
|
||||
created_by,
|
||||
deserializerOrUndefined,
|
||||
|
@ -25,6 +26,7 @@ import {
|
|||
|
||||
export const listItemSchema = t.exact(
|
||||
t.type({
|
||||
_version: _versionOrUndefined,
|
||||
created_at,
|
||||
created_by,
|
||||
deserializer: deserializerOrUndefined,
|
||||
|
|
|
@ -17,6 +17,7 @@ import {
|
|||
} from '../../../common/constants.mock';
|
||||
|
||||
export const getListResponseMock = (): ListSchema => ({
|
||||
_version: undefined,
|
||||
created_at: DATE_NOW,
|
||||
created_by: USER,
|
||||
description: DESCRIPTION,
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
import * as t from 'io-ts';
|
||||
|
||||
import {
|
||||
_versionOrUndefined,
|
||||
created_at,
|
||||
created_by,
|
||||
description,
|
||||
|
@ -25,6 +26,7 @@ import {
|
|||
|
||||
export const listSchema = t.exact(
|
||||
t.type({
|
||||
_version: _versionOrUndefined,
|
||||
created_at,
|
||||
created_by,
|
||||
description,
|
||||
|
|
|
@ -9,17 +9,11 @@ import { Either } from 'fp-ts/lib/Either';
|
|||
|
||||
import { CommentsArray, comments } from './comments';
|
||||
|
||||
export type DefaultCommentsArrayC = t.Type<CommentsArray, CommentsArray, unknown>;
|
||||
|
||||
/**
|
||||
* Types the DefaultCommentsArray as:
|
||||
* - If null or undefined, then a default array of type entry will be set
|
||||
*/
|
||||
export const DefaultCommentsArray: DefaultCommentsArrayC = new t.Type<
|
||||
CommentsArray,
|
||||
CommentsArray,
|
||||
unknown
|
||||
>(
|
||||
export const DefaultCommentsArray = new t.Type<CommentsArray, CommentsArray, unknown>(
|
||||
'DefaultCommentsArray',
|
||||
t.array(comments).is,
|
||||
(input): Either<t.Errors, CommentsArray> =>
|
||||
|
|
|
@ -9,13 +9,11 @@ import { Either } from 'fp-ts/lib/Either';
|
|||
|
||||
import { CreateCommentsArray, createComments } from './create_comments';
|
||||
|
||||
export type DefaultCreateCommentsArrayC = t.Type<CreateCommentsArray, CreateCommentsArray, unknown>;
|
||||
|
||||
/**
|
||||
* Types the DefaultCreateComments as:
|
||||
* - If null or undefined, then a default array of type entry will be set
|
||||
*/
|
||||
export const DefaultCreateCommentsArray: DefaultCreateCommentsArrayC = new t.Type<
|
||||
export const DefaultCreateCommentsArray = new t.Type<
|
||||
CreateCommentsArray,
|
||||
CreateCommentsArray,
|
||||
unknown
|
||||
|
|
|
@ -9,17 +9,11 @@ import { Either } from 'fp-ts/lib/Either';
|
|||
|
||||
import { EntriesArray, entriesArray } from './entries';
|
||||
|
||||
export type DefaultEntriesArrayC = t.Type<EntriesArray, EntriesArray, unknown>;
|
||||
|
||||
/**
|
||||
* Types the DefaultEntriesArray as:
|
||||
* - If null or undefined, then a default array of type entry will be set
|
||||
*/
|
||||
export const DefaultEntryArray: DefaultEntriesArrayC = new t.Type<
|
||||
EntriesArray,
|
||||
EntriesArray,
|
||||
unknown
|
||||
>(
|
||||
export const DefaultEntryArray = new t.Type<EntriesArray, EntriesArray, unknown>(
|
||||
'DefaultEntryArray',
|
||||
entriesArray.is,
|
||||
(input): Either<t.Errors, EntriesArray> =>
|
||||
|
|
|
@ -14,12 +14,10 @@ export type NamespaceType = t.TypeOf<typeof namespaceType>;
|
|||
* Types the DefaultNamespace as:
|
||||
* - If null or undefined, then a default string/enumeration of "single" will be used.
|
||||
*/
|
||||
export const DefaultNamespace = new t.Type<NamespaceType, NamespaceType, unknown>(
|
||||
export const DefaultNamespace = new t.Type<NamespaceType, NamespaceType | undefined, unknown>(
|
||||
'DefaultNamespace',
|
||||
namespaceType.is,
|
||||
(input, context): Either<t.Errors, NamespaceType> =>
|
||||
input == null ? t.success('single') : namespaceType.validate(input, context),
|
||||
t.identity
|
||||
);
|
||||
|
||||
export type DefaultNamespaceC = typeof DefaultNamespace;
|
||||
|
|
|
@ -9,11 +9,11 @@ import { left } from 'fp-ts/lib/Either';
|
|||
|
||||
import { foldLeftRight, getPaths } from '../../siem_common_deps';
|
||||
|
||||
import { DefaultNamespaceArray, DefaultNamespaceArrayTypeEncoded } from './default_namespace_array';
|
||||
import { DefaultNamespaceArray, DefaultNamespaceArrayType } from './default_namespace_array';
|
||||
|
||||
describe('default_namespace_array', () => {
|
||||
test('it should validate "null" single item as an array with a "single" value', () => {
|
||||
const payload: DefaultNamespaceArrayTypeEncoded = null;
|
||||
const payload: DefaultNamespaceArrayType = null;
|
||||
const decoded = DefaultNamespaceArray.decode(payload);
|
||||
const message = pipe(decoded, foldLeftRight);
|
||||
|
||||
|
@ -33,7 +33,7 @@ describe('default_namespace_array', () => {
|
|||
});
|
||||
|
||||
test('it should validate "undefined" item as an array with a "single" value', () => {
|
||||
const payload: DefaultNamespaceArrayTypeEncoded = undefined;
|
||||
const payload: DefaultNamespaceArrayType = undefined;
|
||||
const decoded = DefaultNamespaceArray.decode(payload);
|
||||
const message = pipe(decoded, foldLeftRight);
|
||||
|
||||
|
@ -42,7 +42,7 @@ describe('default_namespace_array', () => {
|
|||
});
|
||||
|
||||
test('it should validate "single" as an array of a "single" value', () => {
|
||||
const payload: DefaultNamespaceArrayTypeEncoded = 'single';
|
||||
const payload: DefaultNamespaceArrayType = 'single';
|
||||
const decoded = DefaultNamespaceArray.decode(payload);
|
||||
const message = pipe(decoded, foldLeftRight);
|
||||
|
||||
|
@ -51,7 +51,7 @@ describe('default_namespace_array', () => {
|
|||
});
|
||||
|
||||
test('it should validate "agnostic" as an array of a "agnostic" value', () => {
|
||||
const payload: DefaultNamespaceArrayTypeEncoded = 'agnostic';
|
||||
const payload: DefaultNamespaceArrayType = 'agnostic';
|
||||
const decoded = DefaultNamespaceArray.decode(payload);
|
||||
const message = pipe(decoded, foldLeftRight);
|
||||
|
||||
|
@ -60,7 +60,7 @@ describe('default_namespace_array', () => {
|
|||
});
|
||||
|
||||
test('it should validate "single,agnostic" as an array of 2 values of ["single", "agnostic"] values', () => {
|
||||
const payload: DefaultNamespaceArrayTypeEncoded = 'agnostic,single';
|
||||
const payload: DefaultNamespaceArrayType = 'agnostic,single';
|
||||
const decoded = DefaultNamespaceArray.decode(payload);
|
||||
const message = pipe(decoded, foldLeftRight);
|
||||
|
||||
|
@ -69,7 +69,7 @@ describe('default_namespace_array', () => {
|
|||
});
|
||||
|
||||
test('it should validate 3 elements of "single,agnostic,single" as an array of 3 values of ["single", "agnostic", "single"] values', () => {
|
||||
const payload: DefaultNamespaceArrayTypeEncoded = 'single,agnostic,single';
|
||||
const payload: DefaultNamespaceArrayType = 'single,agnostic,single';
|
||||
const decoded = DefaultNamespaceArray.decode(payload);
|
||||
const message = pipe(decoded, foldLeftRight);
|
||||
|
||||
|
@ -78,7 +78,7 @@ describe('default_namespace_array', () => {
|
|||
});
|
||||
|
||||
test('it should validate 3 elements of "single,agnostic, single" as an array of 3 values of ["single", "agnostic", "single"] values when there are spaces', () => {
|
||||
const payload: DefaultNamespaceArrayTypeEncoded = ' single, agnostic, single ';
|
||||
const payload: DefaultNamespaceArrayType = ' single, agnostic, single ';
|
||||
const decoded = DefaultNamespaceArray.decode(payload);
|
||||
const message = pipe(decoded, foldLeftRight);
|
||||
|
||||
|
@ -87,7 +87,7 @@ describe('default_namespace_array', () => {
|
|||
});
|
||||
|
||||
test('it should not validate 3 elements of "single,agnostic,junk" since the 3rd value is junk', () => {
|
||||
const payload: DefaultNamespaceArrayTypeEncoded = 'single,agnostic,junk';
|
||||
const payload: DefaultNamespaceArrayType = 'single,agnostic,junk';
|
||||
const decoded = DefaultNamespaceArray.decode(payload);
|
||||
const message = pipe(decoded, foldLeftRight);
|
||||
|
||||
|
|
|
@ -39,7 +39,5 @@ export const DefaultNamespaceArray = new t.Type<
|
|||
String
|
||||
);
|
||||
|
||||
export type DefaultNamespaceC = typeof DefaultNamespaceArray;
|
||||
|
||||
export type DefaultNamespaceArrayTypeEncoded = t.OutputOf<typeof DefaultNamespaceArray>;
|
||||
export type DefaultNamespaceArrayType = t.OutputOf<typeof DefaultNamespaceArray>;
|
||||
export type DefaultNamespaceArrayTypeDecoded = t.TypeOf<typeof DefaultNamespaceArray>;
|
||||
|
|
|
@ -9,13 +9,11 @@ import { Either } from 'fp-ts/lib/Either';
|
|||
|
||||
import { UpdateCommentsArray, updateCommentsArray } from './update_comments';
|
||||
|
||||
export type DefaultUpdateCommentsArrayC = t.Type<UpdateCommentsArray, UpdateCommentsArray, unknown>;
|
||||
|
||||
/**
|
||||
* Types the DefaultCommentsUpdate as:
|
||||
* - If null or undefined, then a default array of type entry will be set
|
||||
*/
|
||||
export const DefaultUpdateCommentsArray: DefaultUpdateCommentsArrayC = new t.Type<
|
||||
export const DefaultUpdateCommentsArray = new t.Type<
|
||||
UpdateCommentsArray,
|
||||
UpdateCommentsArray,
|
||||
unknown
|
||||
|
|
|
@ -39,7 +39,5 @@ export const EmptyStringArray = new t.Type<string[], string | undefined | null,
|
|||
String
|
||||
);
|
||||
|
||||
export type EmptyStringArrayC = typeof EmptyStringArray;
|
||||
|
||||
export type EmptyStringArrayEncoded = t.OutputOf<typeof EmptyStringArray>;
|
||||
export type EmptyStringArrayDecoded = t.TypeOf<typeof EmptyStringArray>;
|
||||
|
|
|
@ -9,11 +9,11 @@ import { left } from 'fp-ts/lib/Either';
|
|||
|
||||
import { foldLeftRight, getPaths } from '../../siem_common_deps';
|
||||
|
||||
import { NonEmptyStringArray, NonEmptyStringArrayEncoded } from './non_empty_string_array';
|
||||
import { NonEmptyStringArray } from './non_empty_string_array';
|
||||
|
||||
describe('non_empty_string_array', () => {
|
||||
test('it should NOT validate "null"', () => {
|
||||
const payload: NonEmptyStringArrayEncoded | null = null;
|
||||
const payload: NonEmptyStringArray | null = null;
|
||||
const decoded = NonEmptyStringArray.decode(payload);
|
||||
const message = pipe(decoded, foldLeftRight);
|
||||
|
||||
|
@ -24,7 +24,7 @@ describe('non_empty_string_array', () => {
|
|||
});
|
||||
|
||||
test('it should NOT validate "undefined"', () => {
|
||||
const payload: NonEmptyStringArrayEncoded | undefined = undefined;
|
||||
const payload: NonEmptyStringArray | undefined = undefined;
|
||||
const decoded = NonEmptyStringArray.decode(payload);
|
||||
const message = pipe(decoded, foldLeftRight);
|
||||
|
||||
|
@ -35,7 +35,7 @@ describe('non_empty_string_array', () => {
|
|||
});
|
||||
|
||||
test('it should NOT validate a single value of an empty string ""', () => {
|
||||
const payload: NonEmptyStringArrayEncoded = '';
|
||||
const payload: NonEmptyStringArray = '';
|
||||
const decoded = NonEmptyStringArray.decode(payload);
|
||||
const message = pipe(decoded, foldLeftRight);
|
||||
|
||||
|
@ -46,7 +46,7 @@ describe('non_empty_string_array', () => {
|
|||
});
|
||||
|
||||
test('it should validate a single value of "a" into an array of size 1 of ["a"]', () => {
|
||||
const payload: NonEmptyStringArrayEncoded = 'a';
|
||||
const payload: NonEmptyStringArray = 'a';
|
||||
const decoded = NonEmptyStringArray.decode(payload);
|
||||
const message = pipe(decoded, foldLeftRight);
|
||||
|
||||
|
@ -55,7 +55,7 @@ describe('non_empty_string_array', () => {
|
|||
});
|
||||
|
||||
test('it should validate 2 values of "a,b" into an array of size 2 of ["a", "b"]', () => {
|
||||
const payload: NonEmptyStringArrayEncoded = 'a,b';
|
||||
const payload: NonEmptyStringArray = 'a,b';
|
||||
const decoded = NonEmptyStringArray.decode(payload);
|
||||
const message = pipe(decoded, foldLeftRight);
|
||||
|
||||
|
@ -64,7 +64,7 @@ describe('non_empty_string_array', () => {
|
|||
});
|
||||
|
||||
test('it should validate 3 values of "a,b,c" into an array of size 3 of ["a", "b", "c"]', () => {
|
||||
const payload: NonEmptyStringArrayEncoded = 'a,b,c';
|
||||
const payload: NonEmptyStringArray = 'a,b,c';
|
||||
const decoded = NonEmptyStringArray.decode(payload);
|
||||
const message = pipe(decoded, foldLeftRight);
|
||||
|
||||
|
@ -84,7 +84,7 @@ describe('non_empty_string_array', () => {
|
|||
});
|
||||
|
||||
test('it should validate 3 values of " a, b, c " into an array of size 3 of ["a", "b", "c"] even though they have spaces', () => {
|
||||
const payload: NonEmptyStringArrayEncoded = ' a, b, c ';
|
||||
const payload: NonEmptyStringArray = ' a, b, c ';
|
||||
const decoded = NonEmptyStringArray.decode(payload);
|
||||
const message = pipe(decoded, foldLeftRight);
|
||||
|
||||
|
|
|
@ -35,7 +35,5 @@ export const NonEmptyStringArray = new t.Type<string[], string, unknown>(
|
|||
String
|
||||
);
|
||||
|
||||
export type NonEmptyStringArrayC = typeof NonEmptyStringArray;
|
||||
|
||||
export type NonEmptyStringArrayEncoded = t.OutputOf<typeof NonEmptyStringArray>;
|
||||
export type NonEmptyStringArray = t.OutputOf<typeof NonEmptyStringArray>;
|
||||
export type NonEmptyStringArrayDecoded = t.TypeOf<typeof NonEmptyStringArray>;
|
||||
|
|
|
@ -20,11 +20,3 @@ export type RequiredKeepUndefined<T> = { [K in keyof T]-?: [T[K]] } extends infe
|
|||
? { [K in keyof U]: U[K][0] }
|
||||
: never
|
||||
: never;
|
||||
|
||||
/**
|
||||
* This is just a helper to cleanup nasty intersections and unions to make them
|
||||
* readable from io.ts, it's an identity that strips away the uglyness of them.
|
||||
*/
|
||||
export type Identity<T> = {
|
||||
[P in keyof T]: T[P];
|
||||
};
|
||||
|
|
|
@ -10,7 +10,7 @@ import { LIST_ITEM_URL } from '../../common/constants';
|
|||
import { buildRouteValidation, buildSiemResponse, transformError } from '../siem_server_deps';
|
||||
import { validate } from '../../common/siem_common_deps';
|
||||
import {
|
||||
FindListItemSchemaPartialDecoded,
|
||||
FindListItemSchemaDecoded,
|
||||
findListItemSchema,
|
||||
foundListItemSchema,
|
||||
} from '../../common/schemas';
|
||||
|
@ -26,7 +26,7 @@ export const findListItemRoute = (router: IRouter): void => {
|
|||
},
|
||||
path: `${LIST_ITEM_URL}/_find`,
|
||||
validate: {
|
||||
query: buildRouteValidation<typeof findListItemSchema, FindListItemSchemaPartialDecoded>(
|
||||
query: buildRouteValidation<typeof findListItemSchema, FindListItemSchemaDecoded>(
|
||||
findListItemSchema
|
||||
),
|
||||
},
|
||||
|
|
|
@ -27,9 +27,10 @@ export const patchListItemRoute = (router: IRouter): void => {
|
|||
async (context, request, response) => {
|
||||
const siemResponse = buildSiemResponse(response);
|
||||
try {
|
||||
const { value, id, meta } = request.body;
|
||||
const { value, id, meta, _version } = request.body;
|
||||
const lists = getListClient(context);
|
||||
const listItem = await lists.updateListItem({
|
||||
_version,
|
||||
id,
|
||||
meta,
|
||||
value,
|
||||
|
|
|
@ -27,9 +27,9 @@ export const patchListRoute = (router: IRouter): void => {
|
|||
async (context, request, response) => {
|
||||
const siemResponse = buildSiemResponse(response);
|
||||
try {
|
||||
const { name, description, id, meta } = request.body;
|
||||
const { name, description, id, meta, _version } = request.body;
|
||||
const lists = getListClient(context);
|
||||
const list = await lists.updateList({ description, id, meta, name });
|
||||
const list = await lists.updateList({ _version, description, id, meta, name });
|
||||
if (list == null) {
|
||||
return siemResponse.error({
|
||||
body: `list id: "${id}" found found`,
|
||||
|
|
|
@ -41,6 +41,7 @@ export const updateEndpointListItemRoute = (router: IRouter): void => {
|
|||
meta,
|
||||
type,
|
||||
_tags,
|
||||
_version,
|
||||
comments,
|
||||
entries,
|
||||
item_id: itemId,
|
||||
|
@ -49,6 +50,7 @@ export const updateEndpointListItemRoute = (router: IRouter): void => {
|
|||
const exceptionLists = getExceptionListClient(context);
|
||||
const exceptionListItem = await exceptionLists.updateEndpointListItem({
|
||||
_tags,
|
||||
_version,
|
||||
comments,
|
||||
description,
|
||||
entries,
|
||||
|
|
|
@ -41,6 +41,7 @@ export const updateExceptionListItemRoute = (router: IRouter): void => {
|
|||
meta,
|
||||
type,
|
||||
_tags,
|
||||
_version,
|
||||
comments,
|
||||
entries,
|
||||
item_id: itemId,
|
||||
|
@ -50,6 +51,7 @@ export const updateExceptionListItemRoute = (router: IRouter): void => {
|
|||
const exceptionLists = getExceptionListClient(context);
|
||||
const exceptionListItem = await exceptionLists.updateExceptionListItem({
|
||||
_tags,
|
||||
_version,
|
||||
comments,
|
||||
description,
|
||||
entries,
|
||||
|
|
|
@ -36,6 +36,7 @@ export const updateExceptionListRoute = (router: IRouter): void => {
|
|||
try {
|
||||
const {
|
||||
_tags,
|
||||
_version,
|
||||
tags,
|
||||
name,
|
||||
description,
|
||||
|
@ -54,6 +55,7 @@ export const updateExceptionListRoute = (router: IRouter): void => {
|
|||
} else {
|
||||
const list = await exceptionLists.updateExceptionList({
|
||||
_tags,
|
||||
_version,
|
||||
description,
|
||||
id,
|
||||
listId,
|
||||
|
|
|
@ -27,9 +27,10 @@ export const updateListItemRoute = (router: IRouter): void => {
|
|||
async (context, request, response) => {
|
||||
const siemResponse = buildSiemResponse(response);
|
||||
try {
|
||||
const { value, id, meta } = request.body;
|
||||
const { value, id, meta, _version } = request.body;
|
||||
const lists = getListClient(context);
|
||||
const listItem = await lists.updateListItem({
|
||||
_version,
|
||||
id,
|
||||
meta,
|
||||
value,
|
||||
|
|
|
@ -27,9 +27,9 @@ export const updateListRoute = (router: IRouter): void => {
|
|||
async (context, request, response) => {
|
||||
const siemResponse = buildSiemResponse(response);
|
||||
try {
|
||||
const { name, description, id, meta } = request.body;
|
||||
const { name, description, id, meta, _version } = request.body;
|
||||
const lists = getListClient(context);
|
||||
const list = await lists.updateList({ description, id, meta, name });
|
||||
const list = await lists.updateList({ _version, description, id, meta, name });
|
||||
if (list == null) {
|
||||
return siemResponse.error({
|
||||
body: `list id: "${id}" found found`,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"list_id": "endpoint_list",
|
||||
"list_id": "simple_list",
|
||||
"_tags": ["endpoint", "process", "malware", "os:linux"],
|
||||
"tags": ["user added string for a tag", "malware"],
|
||||
"type": "endpoint",
|
||||
|
|
|
@ -131,6 +131,7 @@ export class ExceptionListClient {
|
|||
*/
|
||||
public updateEndpointListItem = async ({
|
||||
_tags,
|
||||
_version,
|
||||
comments,
|
||||
description,
|
||||
entries,
|
||||
|
@ -145,6 +146,7 @@ export class ExceptionListClient {
|
|||
await this.createEndpointList();
|
||||
return updateExceptionListItem({
|
||||
_tags,
|
||||
_version,
|
||||
comments,
|
||||
description,
|
||||
entries,
|
||||
|
@ -198,6 +200,7 @@ export class ExceptionListClient {
|
|||
|
||||
public updateExceptionList = async ({
|
||||
_tags,
|
||||
_version,
|
||||
id,
|
||||
description,
|
||||
listId,
|
||||
|
@ -210,6 +213,7 @@ export class ExceptionListClient {
|
|||
const { savedObjectsClient, user } = this;
|
||||
return updateExceptionList({
|
||||
_tags,
|
||||
_version,
|
||||
description,
|
||||
id,
|
||||
listId,
|
||||
|
@ -270,6 +274,7 @@ export class ExceptionListClient {
|
|||
|
||||
public updateExceptionListItem = async ({
|
||||
_tags,
|
||||
_version,
|
||||
comments,
|
||||
description,
|
||||
entries,
|
||||
|
@ -284,6 +289,7 @@ export class ExceptionListClient {
|
|||
const { savedObjectsClient, user } = this;
|
||||
return updateExceptionListItem({
|
||||
_tags,
|
||||
_version,
|
||||
comments,
|
||||
description,
|
||||
entries,
|
||||
|
|
|
@ -38,6 +38,7 @@ import {
|
|||
UpdateCommentsArray,
|
||||
_Tags,
|
||||
_TagsOrUndefined,
|
||||
_VersionOrUndefined,
|
||||
} from '../../../common/schemas';
|
||||
|
||||
export interface ConstructorOptions {
|
||||
|
@ -64,6 +65,7 @@ export interface CreateExceptionListOptions {
|
|||
|
||||
export interface UpdateExceptionListOptions {
|
||||
_tags: _TagsOrUndefined;
|
||||
_version: _VersionOrUndefined;
|
||||
id: IdOrUndefined;
|
||||
listId: ListIdOrUndefined;
|
||||
namespaceType: NamespaceType;
|
||||
|
@ -130,6 +132,7 @@ export interface CreateEndpointListItemOptions {
|
|||
|
||||
export interface UpdateExceptionListItemOptions {
|
||||
_tags: _TagsOrUndefined;
|
||||
_version: _VersionOrUndefined;
|
||||
comments: UpdateCommentsArray;
|
||||
entries: EntriesArrayOrUndefined;
|
||||
id: IdOrUndefined;
|
||||
|
@ -144,6 +147,7 @@ export interface UpdateExceptionListItemOptions {
|
|||
|
||||
export interface UpdateEndpointListItemOptions {
|
||||
_tags: _TagsOrUndefined;
|
||||
_version: _VersionOrUndefined;
|
||||
comments: UpdateCommentsArray;
|
||||
entries: EntriesArrayOrUndefined;
|
||||
id: IdOrUndefined;
|
||||
|
|
|
@ -18,6 +18,7 @@ import {
|
|||
NamespaceType,
|
||||
TagsOrUndefined,
|
||||
_TagsOrUndefined,
|
||||
_VersionOrUndefined,
|
||||
} from '../../../common/schemas';
|
||||
|
||||
import { getSavedObjectType, transformSavedObjectUpdateToExceptionList } from './utils';
|
||||
|
@ -26,6 +27,7 @@ import { getExceptionList } from './get_exception_list';
|
|||
interface UpdateExceptionListOptions {
|
||||
id: IdOrUndefined;
|
||||
_tags: _TagsOrUndefined;
|
||||
_version: _VersionOrUndefined;
|
||||
name: NameOrUndefined;
|
||||
description: DescriptionOrUndefined;
|
||||
savedObjectsClient: SavedObjectsClientContract;
|
||||
|
@ -40,6 +42,7 @@ interface UpdateExceptionListOptions {
|
|||
|
||||
export const updateExceptionList = async ({
|
||||
_tags,
|
||||
_version,
|
||||
id,
|
||||
savedObjectsClient,
|
||||
namespaceType,
|
||||
|
@ -67,6 +70,9 @@ export const updateExceptionList = async ({
|
|||
tags,
|
||||
type,
|
||||
updated_by: user,
|
||||
},
|
||||
{
|
||||
version: _version,
|
||||
}
|
||||
);
|
||||
return transformSavedObjectUpdateToExceptionList({ exceptionList, savedObject });
|
||||
|
|
|
@ -20,6 +20,7 @@ import {
|
|||
TagsOrUndefined,
|
||||
UpdateCommentsArrayOrUndefined,
|
||||
_TagsOrUndefined,
|
||||
_VersionOrUndefined,
|
||||
} from '../../../common/schemas';
|
||||
|
||||
import {
|
||||
|
@ -33,6 +34,7 @@ interface UpdateExceptionListItemOptions {
|
|||
id: IdOrUndefined;
|
||||
comments: UpdateCommentsArrayOrUndefined;
|
||||
_tags: _TagsOrUndefined;
|
||||
_version: _VersionOrUndefined;
|
||||
name: NameOrUndefined;
|
||||
description: DescriptionOrUndefined;
|
||||
entries: EntriesArrayOrUndefined;
|
||||
|
@ -48,6 +50,7 @@ interface UpdateExceptionListItemOptions {
|
|||
|
||||
export const updateExceptionListItem = async ({
|
||||
_tags,
|
||||
_version,
|
||||
comments,
|
||||
entries,
|
||||
id,
|
||||
|
@ -89,6 +92,9 @@ export const updateExceptionListItem = async ({
|
|||
tags,
|
||||
type,
|
||||
updated_by: user,
|
||||
},
|
||||
{
|
||||
version: _version,
|
||||
}
|
||||
);
|
||||
return transformSavedObjectUpdateToExceptionListItem({
|
||||
|
|
|
@ -72,6 +72,7 @@ export const transformSavedObjectToExceptionList = ({
|
|||
}): ExceptionListSchema => {
|
||||
const dateNow = new Date().toISOString();
|
||||
const {
|
||||
version: _version,
|
||||
attributes: {
|
||||
_tags,
|
||||
created_at,
|
||||
|
@ -93,6 +94,7 @@ export const transformSavedObjectToExceptionList = ({
|
|||
// TODO: Do a throw if after the decode this is not the correct "list_type: list"
|
||||
return {
|
||||
_tags,
|
||||
_version,
|
||||
created_at,
|
||||
created_by,
|
||||
description,
|
||||
|
@ -118,6 +120,7 @@ export const transformSavedObjectUpdateToExceptionList = ({
|
|||
}): ExceptionListSchema => {
|
||||
const dateNow = new Date().toISOString();
|
||||
const {
|
||||
version: _version,
|
||||
attributes: { _tags, description, meta, name, tags, type, updated_by: updatedBy },
|
||||
id,
|
||||
updated_at: updatedAt,
|
||||
|
@ -127,6 +130,7 @@ export const transformSavedObjectUpdateToExceptionList = ({
|
|||
// TODO: Do a throw if after the decode this is not the correct "list_type: list"
|
||||
return {
|
||||
_tags: _tags ?? exceptionList._tags,
|
||||
_version,
|
||||
created_at: exceptionList.created_at,
|
||||
created_by: exceptionList.created_by,
|
||||
description: description ?? exceptionList.description,
|
||||
|
@ -150,6 +154,7 @@ export const transformSavedObjectToExceptionListItem = ({
|
|||
}): ExceptionListItemSchema => {
|
||||
const dateNow = new Date().toISOString();
|
||||
const {
|
||||
version: _version,
|
||||
attributes: {
|
||||
_tags,
|
||||
comments,
|
||||
|
@ -174,6 +179,7 @@ export const transformSavedObjectToExceptionListItem = ({
|
|||
// TODO: Do a throw if item_id or entries is not defined.
|
||||
return {
|
||||
_tags,
|
||||
_version,
|
||||
comments: comments ?? [],
|
||||
created_at,
|
||||
created_by,
|
||||
|
@ -202,6 +208,7 @@ export const transformSavedObjectUpdateToExceptionListItem = ({
|
|||
}): ExceptionListItemSchema => {
|
||||
const dateNow = new Date().toISOString();
|
||||
const {
|
||||
version: _version,
|
||||
attributes: {
|
||||
_tags,
|
||||
comments,
|
||||
|
@ -223,6 +230,7 @@ export const transformSavedObjectUpdateToExceptionListItem = ({
|
|||
// defaulting
|
||||
return {
|
||||
_tags: _tags ?? exceptionListItem._tags,
|
||||
_version,
|
||||
comments: comments ?? exceptionListItem.comments,
|
||||
created_at: exceptionListItem.created_at,
|
||||
created_by: exceptionListItem.created_by,
|
||||
|
|
|
@ -18,6 +18,7 @@ import {
|
|||
Type,
|
||||
} from '../../../common/schemas';
|
||||
import { transformListItemToElasticQuery } from '../utils';
|
||||
import { encodeHitVersion } from '../utils/encode_hit_version';
|
||||
|
||||
export interface CreateListItemOptions {
|
||||
deserializer: DeserializerOrUndefined;
|
||||
|
@ -75,6 +76,7 @@ export const createListItem = async ({
|
|||
});
|
||||
|
||||
return {
|
||||
_version: encodeHitVersion(response),
|
||||
id: response._id,
|
||||
type,
|
||||
value,
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
import { LegacyAPICaller } from 'kibana/server';
|
||||
import { SearchResponse } from 'elasticsearch';
|
||||
|
||||
import {
|
||||
Filter,
|
||||
|
@ -82,7 +83,10 @@ export const findListItem = async ({
|
|||
});
|
||||
|
||||
if (scroll.validSearchAfterFound) {
|
||||
const response = await callCluster<SearchEsListItemSchema>('search', {
|
||||
// Note: This typing of response = await callCluster<SearchResponse<SearchEsListSchema>>
|
||||
// is because when you pass in seq_no_primary_term: true it does a "fall through" type and you have
|
||||
// to explicitly define the type <T>.
|
||||
const response = await callCluster<SearchResponse<SearchEsListItemSchema>>('search', {
|
||||
body: {
|
||||
query,
|
||||
search_after: scroll.searchAfter,
|
||||
|
@ -90,6 +94,7 @@ export const findListItem = async ({
|
|||
},
|
||||
ignoreUnavailable: true,
|
||||
index: listItemIndex,
|
||||
seq_no_primary_term: true,
|
||||
size: perPage,
|
||||
});
|
||||
return {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
import { LegacyAPICaller } from 'kibana/server';
|
||||
import { SearchResponse } from 'elasticsearch';
|
||||
|
||||
import { Id, ListItemSchema, SearchEsListItemSchema } from '../../../common/schemas';
|
||||
import { transformElasticToListItem } from '../utils';
|
||||
|
@ -21,7 +22,10 @@ export const getListItem = async ({
|
|||
callCluster,
|
||||
listItemIndex,
|
||||
}: GetListItemOptions): Promise<ListItemSchema | null> => {
|
||||
const listItemES = await callCluster<SearchEsListItemSchema>('search', {
|
||||
// Note: This typing of response = await callCluster<SearchResponse<SearchEsListSchema>>
|
||||
// is because when you pass in seq_no_primary_term: true it does a "fall through" type and you have
|
||||
// to explicitly define the type <T>.
|
||||
const listItemES = await callCluster<SearchResponse<SearchEsListItemSchema>>('search', {
|
||||
body: {
|
||||
query: {
|
||||
term: {
|
||||
|
@ -31,6 +35,7 @@ export const getListItem = async ({
|
|||
},
|
||||
ignoreUnavailable: true,
|
||||
index: listItemIndex,
|
||||
seq_no_primary_term: true,
|
||||
});
|
||||
|
||||
if (listItemES.hits.hits.length) {
|
||||
|
|
|
@ -15,6 +15,7 @@ import {
|
|||
} from '../../../common/constants.mock';
|
||||
|
||||
export const getUpdateListItemOptionsMock = (): UpdateListItemOptions => ({
|
||||
_version: undefined,
|
||||
callCluster: getCallClusterMock(),
|
||||
dateNow: DATE_NOW,
|
||||
id: LIST_ITEM_ID,
|
||||
|
|
|
@ -12,12 +12,16 @@ import {
|
|||
ListItemSchema,
|
||||
MetaOrUndefined,
|
||||
UpdateEsListItemSchema,
|
||||
_VersionOrUndefined,
|
||||
} from '../../../common/schemas';
|
||||
import { transformListItemToElasticQuery } from '../utils';
|
||||
import { decodeVersion } from '../utils/decode_version';
|
||||
import { encodeHitVersion } from '../utils/encode_hit_version';
|
||||
|
||||
import { getListItem } from './get_list_item';
|
||||
|
||||
export interface UpdateListItemOptions {
|
||||
_version: _VersionOrUndefined;
|
||||
id: Id;
|
||||
value: string | null | undefined;
|
||||
callCluster: LegacyAPICaller;
|
||||
|
@ -28,6 +32,7 @@ export interface UpdateListItemOptions {
|
|||
}
|
||||
|
||||
export const updateListItem = async ({
|
||||
_version,
|
||||
id,
|
||||
value,
|
||||
callCluster,
|
||||
|
@ -57,6 +62,7 @@ export const updateListItem = async ({
|
|||
};
|
||||
|
||||
const response = await callCluster<CreateDocumentResponse>('update', {
|
||||
...decodeVersion(_version),
|
||||
body: {
|
||||
doc,
|
||||
},
|
||||
|
@ -65,6 +71,7 @@ export const updateListItem = async ({
|
|||
refresh: 'wait_for',
|
||||
});
|
||||
return {
|
||||
_version: encodeHitVersion(response),
|
||||
created_at: listItem.created_at,
|
||||
created_by: listItem.created_by,
|
||||
deserializer: listItem.deserializer,
|
||||
|
|
|
@ -8,6 +8,7 @@ import uuid from 'uuid';
|
|||
import { CreateDocumentResponse } from 'elasticsearch';
|
||||
import { LegacyAPICaller } from 'kibana/server';
|
||||
|
||||
import { encodeHitVersion } from '../utils/encode_hit_version';
|
||||
import {
|
||||
Description,
|
||||
DeserializerOrUndefined,
|
||||
|
@ -70,6 +71,7 @@ export const createList = async ({
|
|||
refresh: 'wait_for',
|
||||
});
|
||||
return {
|
||||
_version: encodeHitVersion(response),
|
||||
id: response._id,
|
||||
...body,
|
||||
};
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
import { LegacyAPICaller } from 'kibana/server';
|
||||
import { SearchResponse } from 'elasticsearch';
|
||||
|
||||
import {
|
||||
Filter,
|
||||
|
@ -71,7 +72,10 @@ export const findList = async ({
|
|||
});
|
||||
|
||||
if (scroll.validSearchAfterFound) {
|
||||
const response = await callCluster<SearchEsListSchema>('search', {
|
||||
// Note: This typing of response = await callCluster<SearchResponse<SearchEsListSchema>>
|
||||
// is because when you pass in seq_no_primary_term: true it does a "fall through" type and you have
|
||||
// to explicitly define the type <T>.
|
||||
const response = await callCluster<SearchResponse<SearchEsListSchema>>('search', {
|
||||
body: {
|
||||
query,
|
||||
search_after: scroll.searchAfter,
|
||||
|
@ -79,6 +83,7 @@ export const findList = async ({
|
|||
},
|
||||
ignoreUnavailable: true,
|
||||
index: listIndex,
|
||||
seq_no_primary_term: true,
|
||||
size: perPage,
|
||||
});
|
||||
return {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
import { LegacyAPICaller } from 'kibana/server';
|
||||
import { SearchResponse } from 'elasticsearch';
|
||||
|
||||
import { Id, ListSchema, SearchEsListSchema } from '../../../common/schemas';
|
||||
import { transformElasticToList } from '../utils/transform_elastic_to_list';
|
||||
|
@ -20,7 +21,10 @@ export const getList = async ({
|
|||
callCluster,
|
||||
listIndex,
|
||||
}: GetListOptions): Promise<ListSchema | null> => {
|
||||
const response = await callCluster<SearchEsListSchema>('search', {
|
||||
// Note: This typing of response = await callCluster<SearchResponse<SearchEsListSchema>>
|
||||
// is because when you pass in seq_no_primary_term: true it does a "fall through" type and you have
|
||||
// to explicitly define the type <T>.
|
||||
const response = await callCluster<SearchResponse<SearchEsListSchema>>('search', {
|
||||
body: {
|
||||
query: {
|
||||
term: {
|
||||
|
@ -30,6 +34,7 @@ export const getList = async ({
|
|||
},
|
||||
ignoreUnavailable: true,
|
||||
index: listIndex,
|
||||
seq_no_primary_term: true,
|
||||
});
|
||||
const list = transformElasticToList({ response });
|
||||
return list[0] ?? null;
|
||||
|
|
|
@ -395,6 +395,7 @@ export class ListClient {
|
|||
};
|
||||
|
||||
public updateListItem = async ({
|
||||
_version,
|
||||
id,
|
||||
value,
|
||||
meta,
|
||||
|
@ -402,6 +403,7 @@ export class ListClient {
|
|||
const { callCluster, user } = this;
|
||||
const listItemIndex = this.getListItemIndex();
|
||||
return updateListItem({
|
||||
_version,
|
||||
callCluster,
|
||||
id,
|
||||
listItemIndex,
|
||||
|
@ -412,6 +414,7 @@ export class ListClient {
|
|||
};
|
||||
|
||||
public updateList = async ({
|
||||
_version,
|
||||
id,
|
||||
name,
|
||||
description,
|
||||
|
@ -420,6 +423,7 @@ export class ListClient {
|
|||
const { callCluster, user } = this;
|
||||
const listIndex = this.getListIndex();
|
||||
return updateList({
|
||||
_version,
|
||||
callCluster,
|
||||
description,
|
||||
id,
|
||||
|
|
|
@ -26,6 +26,7 @@ import {
|
|||
SortFieldOrUndefined,
|
||||
SortOrderOrUndefined,
|
||||
Type,
|
||||
_VersionOrUndefined,
|
||||
} from '../../../common/schemas';
|
||||
import { ConfigType } from '../../config';
|
||||
|
||||
|
@ -106,12 +107,14 @@ export interface CreateListItemOptions {
|
|||
}
|
||||
|
||||
export interface UpdateListItemOptions {
|
||||
_version: _VersionOrUndefined;
|
||||
id: Id;
|
||||
value: string | null | undefined;
|
||||
meta: MetaOrUndefined;
|
||||
}
|
||||
|
||||
export interface UpdateListOptions {
|
||||
_version: _VersionOrUndefined;
|
||||
id: Id;
|
||||
name: NameOrUndefined;
|
||||
description: DescriptionOrUndefined;
|
||||
|
|
|
@ -16,6 +16,7 @@ import {
|
|||
} from '../../../common/constants.mock';
|
||||
|
||||
export const getUpdateListOptionsMock = (): UpdateListOptions => ({
|
||||
_version: undefined,
|
||||
callCluster: getCallClusterMock(),
|
||||
dateNow: DATE_NOW,
|
||||
description: DESCRIPTION,
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
import { CreateDocumentResponse } from 'elasticsearch';
|
||||
import { LegacyAPICaller } from 'kibana/server';
|
||||
|
||||
import { decodeVersion } from '../utils/decode_version';
|
||||
import { encodeHitVersion } from '../utils/encode_hit_version';
|
||||
import {
|
||||
DescriptionOrUndefined,
|
||||
Id,
|
||||
|
@ -14,11 +16,13 @@ import {
|
|||
MetaOrUndefined,
|
||||
NameOrUndefined,
|
||||
UpdateEsListSchema,
|
||||
_VersionOrUndefined,
|
||||
} from '../../../common/schemas';
|
||||
|
||||
import { getList } from '.';
|
||||
|
||||
export interface UpdateListOptions {
|
||||
_version: _VersionOrUndefined;
|
||||
id: Id;
|
||||
callCluster: LegacyAPICaller;
|
||||
listIndex: string;
|
||||
|
@ -30,6 +34,7 @@ export interface UpdateListOptions {
|
|||
}
|
||||
|
||||
export const updateList = async ({
|
||||
_version,
|
||||
id,
|
||||
name,
|
||||
description,
|
||||
|
@ -52,12 +57,14 @@ export const updateList = async ({
|
|||
updated_by: user,
|
||||
};
|
||||
const response = await callCluster<CreateDocumentResponse>('update', {
|
||||
...decodeVersion(_version),
|
||||
body: { doc },
|
||||
id,
|
||||
index: listIndex,
|
||||
refresh: 'wait_for',
|
||||
});
|
||||
return {
|
||||
_version: encodeHitVersion(response),
|
||||
created_at: list.created_at,
|
||||
created_by: list.created_by,
|
||||
description: description ?? list.description,
|
||||
|
|
37
x-pack/plugins/lists/server/services/utils/decode_version.ts
Normal file
37
x-pack/plugins/lists/server/services/utils/decode_version.ts
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Similar to the src/core/server/saved_objects/version/decode_version.ts
|
||||
// with the notable differences in that it is more tolerant and does not throw saved object specific errors
|
||||
// but rather just returns an empty object if it cannot parse the version or cannot find one.
|
||||
export const decodeVersion = (
|
||||
version: string | undefined
|
||||
):
|
||||
| {
|
||||
ifSeqNo: number;
|
||||
ifPrimaryTerm: number;
|
||||
}
|
||||
| {} => {
|
||||
if (version != null) {
|
||||
try {
|
||||
const decoded = Buffer.from(version, 'base64').toString('utf8');
|
||||
const parsed = JSON.parse(decoded);
|
||||
if (Array.isArray(parsed) && Number.isInteger(parsed[0]) && Number.isInteger(parsed[1])) {
|
||||
return {
|
||||
ifPrimaryTerm: parsed[1],
|
||||
ifSeqNo: parsed[0],
|
||||
};
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
} catch (err) {
|
||||
// do nothing here, this is on purpose and we want to return any empty object when we can't parse.
|
||||
return {};
|
||||
}
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
};
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Very similar to the encode_hit_version from saved object system from here:
|
||||
* src/core/server/saved_objects/version/encode_hit_version.ts
|
||||
*
|
||||
* with the most notably change is that it doesn't do any throws but rather just returns undefined
|
||||
* if _seq_no or _primary_term does not exist.
|
||||
* @param response The response to encode into a version by using _seq_no and _primary_term
|
||||
*/
|
||||
export const encodeHitVersion = <T>(hit: T): string | undefined => {
|
||||
// Have to do this "as cast" here as these two types aren't included in the SearchResponse hit type
|
||||
const { _seq_no: seqNo, _primary_term: primaryTerm } = (hit as unknown) as {
|
||||
_seq_no: number;
|
||||
_primary_term: number;
|
||||
};
|
||||
|
||||
if (seqNo == null || primaryTerm == null) {
|
||||
return undefined;
|
||||
} else {
|
||||
return Buffer.from(JSON.stringify([seqNo, primaryTerm]), 'utf8').toString('base64');
|
||||
}
|
||||
};
|
|
@ -8,6 +8,8 @@ import { SearchResponse } from 'elasticsearch';
|
|||
|
||||
import { ListArraySchema, SearchEsListSchema } from '../../../common/schemas';
|
||||
|
||||
import { encodeHitVersion } from './encode_hit_version';
|
||||
|
||||
export interface TransformElasticToListOptions {
|
||||
response: SearchResponse<SearchEsListSchema>;
|
||||
}
|
||||
|
@ -17,6 +19,7 @@ export const transformElasticToList = ({
|
|||
}: TransformElasticToListOptions): ListArraySchema => {
|
||||
return response.hits.hits.map((hit) => {
|
||||
return {
|
||||
_version: encodeHitVersion(hit),
|
||||
id: hit._id,
|
||||
...hit._source,
|
||||
};
|
||||
|
|
|
@ -9,6 +9,7 @@ import { SearchResponse } from 'elasticsearch';
|
|||
import { ListItemArraySchema, SearchEsListItemSchema, Type } from '../../../common/schemas';
|
||||
import { ErrorWithStatusCode } from '../../error_with_status_code';
|
||||
|
||||
import { encodeHitVersion } from './encode_hit_version';
|
||||
import { findSourceValue } from './find_source_value';
|
||||
|
||||
export interface TransformElasticToListItemOptions {
|
||||
|
@ -40,6 +41,7 @@ export const transformElasticToListItem = ({
|
|||
throw new ErrorWithStatusCode(`Was expected ${type} to not be null/undefined`, 400);
|
||||
} else {
|
||||
return {
|
||||
_version: encodeHitVersion(hit),
|
||||
created_at,
|
||||
created_by,
|
||||
deserializer,
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue