From fee8c4fc140dff7288ace6c4431530cacfc32821 Mon Sep 17 00:00:00 2001 From: Archidoit <75783086+Archidoit@users.noreply.github.com> Date: Thu, 22 Feb 2024 10:59:11 +0100 Subject: [PATCH] [backend/frontend] entity_type filter available for abstract types (#4939) --- .../src/utils/filters/useSearchEntities.tsx | 7 +++-- .../tests_e2e/filters/addFilter.spec.ts | 12 ++++++++ .../tests_e2e/model/filters.pageModel.ts | 14 +++++++++ .../src/domain/filterKeysSchema.ts | 29 ++++++++++--------- .../01-unit/domain/filterKeysSchema-test.ts | 9 +++++- 5 files changed, 55 insertions(+), 16 deletions(-) create mode 100644 opencti-platform/opencti-front/tests_e2e/filters/addFilter.spec.ts create mode 100644 opencti-platform/opencti-front/tests_e2e/model/filters.pageModel.ts diff --git a/opencti-platform/opencti-front/src/utils/filters/useSearchEntities.tsx b/opencti-platform/opencti-front/src/utils/filters/useSearchEntities.tsx index 043afe133bb2..753b6f51a03d 100644 --- a/opencti-platform/opencti-front/src/utils/filters/useSearchEntities.tsx +++ b/opencti-platform/opencti-front/src/utils/filters/useSearchEntities.tsx @@ -670,7 +670,7 @@ const useSearchEntities = ({ case 'fromTypes': case 'toTypes': case 'type': - if ( + if ( // case not abstract types availableEntityTypes && !availableEntityTypes.includes('Stix-Cyber-Observable') && !availableEntityTypes.includes('Stix-Domain-Object') @@ -694,8 +694,9 @@ const useSearchEntities = ({ })) .sort((a, b) => a.label.localeCompare(b.label)); unionSetEntities(filterKey, entitiesTypes); - } else { + } else { // case abstract types let result = [] as EntityWithLabelValue[]; + // push the observables if ( !availableEntityTypes || availableEntityTypes.includes('Stix-Core-Object') @@ -715,6 +716,7 @@ const useSearchEntities = ({ }, ]; } + // push the stix domain objects if ( !availableEntityTypes || availableEntityTypes.includes('Stix-Core-Object') @@ -734,6 +736,7 @@ const useSearchEntities = ({ ...result, ]; } + // push the relationship types if ( !availableEntityTypes || availableEntityTypes.includes('stix-core-relationship') diff --git a/opencti-platform/opencti-front/tests_e2e/filters/addFilter.spec.ts b/opencti-platform/opencti-front/tests_e2e/filters/addFilter.spec.ts new file mode 100644 index 000000000000..e2b608c72236 --- /dev/null +++ b/opencti-platform/opencti-front/tests_e2e/filters/addFilter.spec.ts @@ -0,0 +1,12 @@ +import { expect, test } from "../fixtures/baseFixtures"; +import { FiltersUtils } from '../model/filters.pageModel'; + +test('Add a new filter in the observables list and check the filter is still present when we come back to the page', async ({ page }) => { + await page.goto('/dashboard/observations/observables'); + const filterUtils = new FiltersUtils(page); + await filterUtils.addFilter('Entity type', 'Artifact'); + await expect(page.getByRole('button', { name: 'Entity type = Artifact' })).toBeVisible(); + await page.goto('/dashboard/'); + await page.goto('/dashboard/observations/observables'); + await expect(page.getByRole('button', { name: 'Entity type = Artifact' })).toBeVisible(); +}); \ No newline at end of file diff --git a/opencti-platform/opencti-front/tests_e2e/model/filters.pageModel.ts b/opencti-platform/opencti-front/tests_e2e/model/filters.pageModel.ts new file mode 100644 index 000000000000..04139def004a --- /dev/null +++ b/opencti-platform/opencti-front/tests_e2e/model/filters.pageModel.ts @@ -0,0 +1,14 @@ +import { Page } from '@playwright/test'; + +export class FiltersUtils { + constructor(private page: Page) { + } + async addFilter(filterKey: string, filterLabel: string) { + await this.page.getByLabel('Add filter').click(); + await this.page.getByRole('option', { name: filterKey }).click(); + await this.page.getByLabel(filterKey).click(); + await this.page.getByLabel(filterLabel).getByRole('checkbox').check(); + await this.page.locator('.MuiPopover-root > .MuiBackdrop-root').click(); + } + +} diff --git a/opencti-platform/opencti-graphql/src/domain/filterKeysSchema.ts b/opencti-platform/opencti-graphql/src/domain/filterKeysSchema.ts index 228d19cacc38..b47705de5ce4 100644 --- a/opencti-platform/opencti-graphql/src/domain/filterKeysSchema.ts +++ b/opencti-platform/opencti-graphql/src/domain/filterKeysSchema.ts @@ -198,12 +198,7 @@ const completeFilterDefinitionMapWithSpecialKeys = ( type: string, filterDefinitionsMap: Map, // filter definition map to complete subEntityTypes: string[], - isNotEnterpriseEdition: boolean, ) => { - // Entity type (only available for abstract entity types) - if (!isAbstract(type) && !isBasicRelationship(type)) { - filterDefinitionsMap.delete(TYPE_FILTER); - } if (isStixCoreObject(type)) { // In regards of (exist relationship of the given relationship types for the given entities) filterDefinitionsMap.set(INSTANCE_REGARDING_OF, { @@ -263,10 +258,6 @@ const completeFilterDefinitionMapWithSpecialKeys = ( elementsForFilterValuesSearch: [ENTITY_TYPE_STATUS_TEMPLATE], }); } - // Shared with (remove if not EE) - if (isNotEnterpriseEdition) { - filterDefinitionsMap.delete(INPUT_GRANTED_REFS); - } } if (type === ENTITY_TYPE_HISTORY) { // add context filters @@ -346,13 +337,24 @@ const completeFilterDefinitionMapWithSpecialKeys = ( } }; -const completeFilterDefinitionsMapForTypeAndSubtypes = (filterDefinitionsMap: Map, type: string, isNotEnterpriseEdition: boolean) => { +const handleRemoveSpecialKeysFromFilterDefinitionsMap = (filterDefinitionsMap: Map, type: string, isNotEnterpriseEdition: boolean) => { + // Shared with (remove if not EE) + if (isNotEnterpriseEdition) { + filterDefinitionsMap.delete(INPUT_GRANTED_REFS); + } + // Entity type (only available for abstract entity types) + if (!isAbstract(type) && !isBasicRelationship(type)) { + filterDefinitionsMap.delete(TYPE_FILTER); + } +}; + +const completeFilterDefinitionsMapForTypeAndSubtypes = (filterDefinitionsMap: Map, type: string) => { const subTypes = schemaTypesDefinition.hasChildren(type) ? schemaTypesDefinition.get(type) : []; // fetch the subtypes completeFilterDefinitionMapForType(filterDefinitionsMap, type, subTypes); // add attributes and relations refs of type - completeFilterDefinitionMapWithSpecialKeys(type, filterDefinitionsMap, subTypes.concat([type]), isNotEnterpriseEdition); // add or remove some special keys + completeFilterDefinitionMapWithSpecialKeys(type, filterDefinitionsMap, subTypes.concat([type])); // add or remove some special keys if (subTypes.length > 0) { // handle the filter definitions of the subtypes subTypes.forEach((subType) => { - completeFilterDefinitionsMapForTypeAndSubtypes(filterDefinitionsMap, subType, isNotEnterpriseEdition); + completeFilterDefinitionsMapForTypeAndSubtypes(filterDefinitionsMap, subType); }); } }; @@ -366,7 +368,8 @@ export const generateFilterKeysSchema = async () => { const registeredTypes = schemaAttributesDefinition.getRegisteredTypes(); registeredTypes.forEach((type) => { const filterDefinitionsMap: Map = new Map(); // map that will contain the filterKeys schema for the entity type - completeFilterDefinitionsMapForTypeAndSubtypes(filterDefinitionsMap, type, isNotEnterpriseEdition); + completeFilterDefinitionsMapForTypeAndSubtypes(filterDefinitionsMap, type); + handleRemoveSpecialKeysFromFilterDefinitionsMap(filterDefinitionsMap, type, isNotEnterpriseEdition); filterKeysSchema.set(type, filterDefinitionsMap); }); // B. add connectedToId special key (for instance triggers) diff --git a/opencti-platform/opencti-graphql/tests/01-unit/domain/filterKeysSchema-test.ts b/opencti-platform/opencti-graphql/tests/01-unit/domain/filterKeysSchema-test.ts index 6e646881303b..63de0a2f1ca1 100644 --- a/opencti-platform/opencti-graphql/tests/01-unit/domain/filterKeysSchema-test.ts +++ b/opencti-platform/opencti-graphql/tests/01-unit/domain/filterKeysSchema-test.ts @@ -16,7 +16,7 @@ import { ENTITY_TYPE_NOTIFICATION, ENTITY_TYPE_TRIGGER } from '../../../src/modu import { ENTITY_HASHED_OBSERVABLE_ARTIFACT, ENTITY_HASHED_OBSERVABLE_STIX_FILE, ENTITY_HASHED_OBSERVABLE_X509_CERTIFICATE } from '../../../src/schema/stixCyberObservable'; import { ENTITY_TYPE_CONTAINER_CASE } from '../../../src/modules/case/case-types'; import { ENTITY_TYPE_CONTAINER_GROUPING } from '../../../src/modules/grouping/grouping-types'; -import { ALIAS_FILTER, CONNECTED_TO_INSTANCE_FILTER, CONTEXT_OBJECT_LABEL_FILTER, INSTANCE_REGARDING_OF } from '../../../src/utils/filtering/filtering-constants'; +import { ALIAS_FILTER, CONNECTED_TO_INSTANCE_FILTER, CONTEXT_OBJECT_LABEL_FILTER, INSTANCE_REGARDING_OF, TYPE_FILTER } from '../../../src/utils/filtering/filtering-constants'; import { ENTITY_TYPE_HISTORY } from '../../../src/schema/internalObject'; describe('Filter keys schema generation testing', async () => { @@ -156,6 +156,13 @@ describe('Filter keys schema generation testing', async () => { expect(filterDefinition?.multiple).toEqual(true); expect(filterDefinition?.elementsForFilterValuesSearch.length).toEqual(1); expect(filterDefinition?.elementsForFilterValuesSearch[0]).toEqual(ABSTRACT_STIX_CORE_OBJECT); + // 'entity_type' filter for abstract types only + filterDefinition = filterKeysSchema.get(ABSTRACT_STIX_CORE_OBJECT)?.get(TYPE_FILTER); + expect(filterDefinition?.type).toEqual('string'); + filterDefinition = filterKeysSchema.get(ABSTRACT_STIX_CYBER_OBSERVABLE)?.get(TYPE_FILTER); + expect(filterDefinition?.type).toEqual('string'); + filterDefinition = filterKeysSchema.get(ENTITY_TYPE_MALWARE)?.get(TYPE_FILTER); + expect(filterDefinition).toBeUndefined(); }); it('should construct correct filter definition for abstract entity types', () => { // Containers