Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[backend] Fix No error when merging two entities with a higher confidence level (#6502) #6565

Merged
merged 3 commits into from
Apr 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1333,7 +1333,7 @@ export const mergeEntities = async (context, user, targetEntityId, sourceEntityI
if (mergedIds.length !== mergedInstances.length) {
throw FunctionalError('Cannot access all entities for merging');
}

mergedInstances.forEach((instance) => controlUserConfidenceAgainstElement(user, instance));
if (mergedInstances.some(({ entity_type, builtIn }) => entity_type === ENTITY_TYPE_VOCABULARY && Boolean(builtIn))) {
throw FunctionalError('Cannot merge builtin vocabularies');
}
Expand Down
8 changes: 3 additions & 5 deletions opencti-platform/opencti-graphql/src/domain/backgroundTask.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import { ENTITY_TYPE_NOTIFICATION } from '../modules/notification/notification-types';
import { ENTITY_TYPE_CASE_TEMPLATE } from '../modules/case/case-template/case-template-types';
import { ENTITY_TYPE_LABEL } from '../schema/stixMetaObject';
import { adaptFiltersWithUserConfidence } from '../utils/confidence-level';

export const DEFAULT_ALLOWED_TASK_ENTITY_TYPES = [
ABSTRACT_STIX_CORE_OBJECT,
Expand Down Expand Up @@ -45,22 +44,21 @@
return listEntities(context, user, [ENTITY_TYPE_BACKGROUND_TASK], args);
};

const buildQueryFilters = async (user, filters, search, taskPosition) => {
const buildQueryFilters = async (filters, search, taskPosition) => {
const inputFilters = filters ? JSON.parse(filters) : undefined;
const finalFilters = adaptFiltersWithUserConfidence(user, inputFilters);
// Construct filters
return {
types: DEFAULT_ALLOWED_TASK_ENTITY_TYPES,
first: MAX_TASK_ELEMENTS,
orderMode: 'asc',
orderBy: 'created_at',
after: taskPosition,
filters: finalFilters,
filters: inputFilters,

Check warning on line 56 in opencti-platform/opencti-graphql/src/domain/backgroundTask.js

View check run for this annotation

Codecov / codecov/patch

opencti-platform/opencti-graphql/src/domain/backgroundTask.js#L56

Added line #L56 was not covered by tests
search: search && search.length > 0 ? search : null,
};
};
export const executeTaskQuery = async (context, user, filters, search, start = null) => {
const options = await buildQueryFilters(user, filters, search, start);
const options = await buildQueryFilters(filters, search, start);

Check warning on line 61 in opencti-platform/opencti-graphql/src/domain/backgroundTask.js

View check run for this annotation

Codecov / codecov/patch

opencti-platform/opencti-graphql/src/domain/backgroundTask.js#L61

Added line #L61 was not covered by tests
return elPaginate(context, user, READ_DATA_INDICES_WITHOUT_INFERRED, options);
};

Expand Down
7 changes: 1 addition & 6 deletions opencti-platform/opencti-graphql/src/manager/taskManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@
import { askElementEnrichmentForConnector } from '../domain/stixCoreObject';
import { RELATION_GRANTED_TO, RELATION_OBJECT } from '../schema/stixRefRelationship';
import { ACTION_TYPE_DELETE, ACTION_TYPE_SHARE, ACTION_TYPE_UNSHARE, TASK_TYPE_LIST, TASK_TYPE_QUERY, TASK_TYPE_RULE } from '../domain/backgroundTask-common';
import { controlUserConfidenceAgainstElement } from '../utils/confidence-level';
import { validateUpdatableAttribute } from '../schema/schema-validator';
import { schemaRelationsRefDefinition } from '../schema/schema-relationsRef';

Expand Down Expand Up @@ -163,11 +162,7 @@
const elementToResolve = ids[indexId];
const element = await internalLoadById(context, user, elementToResolve, { type: DEFAULT_ALLOWED_TASK_ENTITY_TYPES });
if (element) {
// only process elements allowed by confidence control (no throw)
const isConfidenceMatch = controlUserConfidenceAgainstElement(user, element, true);
if (isConfidenceMatch) {
processingElements.push({ element, next: element.id });
}
processingElements.push({ element, next: element.id });

Check warning on line 165 in opencti-platform/opencti-graphql/src/manager/taskManager.js

View check run for this annotation

Codecov / codecov/patch

opencti-platform/opencti-graphql/src/manager/taskManager.js#L165

Added line #L165 was not covered by tests
}
}
return { actions, elements: processingElements };
Expand Down
47 changes: 0 additions & 47 deletions opencti-platform/opencti-graphql/src/utils/confidence-level.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import { isEmptyField } from '../database/utils';
import { FunctionalError, LockTimeoutError } from '../config/errors';
import { logApp } from '../config/conf';
import { schemaAttributesDefinition } from '../schema/schema-attributes';
import { type Filter, type FilterGroup, FilterMode, FilterOperator } from '../generated/graphql';
import { isFilterGroupNotEmpty } from './filtering/filtering-utils';
import { isBypassUser } from './access';

type ObjectWithConfidence = {
Expand Down Expand Up @@ -194,48 +192,3 @@ export const adaptUpdateInputsConfidence = <T extends ObjectWithConfidence>(user

return newInputs;
};

/**
* Narrow the input filter with a AND on the user's max confidence.
* Result filter will filter out any element without the required confidence (+ input filter).
*/
export const adaptFiltersWithUserConfidence = (user: AuthUser, filters: FilterGroup): FilterGroup => {
if (isEmptyField(user.effective_confidence_level?.max_confidence)) {
throw LockTimeoutError({ user_id: user.id }, 'User has no effective max confidence level and cannot run this filter');
}
const userMaxConfidenceLevel = user.effective_confidence_level?.max_confidence as number;

// we will filter to get only elements that have...
// ... no confidence attribute (no control to do)
const entitiesWithoutConfidence: Filter = {
key: [
'entity_type'
],
operator: FilterOperator.NotEq,
values: ['Stix-Domain-Object', 'Stix-Relationship'] // only types with confidence judging from schema
};
// ... a confidence level lower or equal to the user's level
const userConfidenceFilter: Filter = {
key: ['confidence'],
operator: FilterOperator.Lte,
values: [userMaxConfidenceLevel]
};
// ... or no confidence level at all (might happen when inserting data with the API with version <6.0, we consider zero)
const nilConfidenceFilter: Filter = {
key: ['confidence'],
operator: FilterOperator.Nil,
values: [],
};
const orFilterGroup: FilterGroup = {
mode: FilterMode.Or,
filters: [entitiesWithoutConfidence, userConfidenceFilter, nilConfidenceFilter,],
filterGroups: [],
};

// nest: this filter AND the input filters
return {
mode: FilterMode.And,
filters: [],
filterGroups: isFilterGroupNotEmpty(filters) ? [orFilterGroup, filters] : [orFilterGroup],
};
};
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import { describe, expect, it } from 'vitest';
import {
adaptFiltersWithUserConfidence,
adaptUpdateInputsConfidence,
computeUserEffectiveConfidenceLevel,
controlCreateInputWithUserConfidence,
controlUpsertInputWithUserConfidence,
controlUserConfidenceAgainstElement
} from '../../../src/utils/confidence-level';
import type { AuthUser } from '../../../src/types/user';
import { type FilterGroup, FilterMode, FilterOperator } from '../../../src/generated/graphql';
import { BYPASS } from '../../../src/utils/access';

const makeUser = (confidence: number | null) => ({
Expand Down Expand Up @@ -253,54 +251,4 @@ describe('Confidence level utilities', () => {
expect(adaptUpdateInputsConfidence(makeUser(10), makeConfidenceInput(30), makeElement(null)))
.toEqual([{ key: 'confidence', value: ['10'] }]); // capped / no need to inject user's confidence
});

it('getConfidenceFilterForUser shall produce correct filters', () => {
const emptyFilterGroup: FilterGroup = {
mode: FilterMode.And,
filterGroups: [],
filters: [],
};
const exampleFilterGroup: FilterGroup = {
mode: FilterMode.Or,
filterGroups: [],
filters: [
{ key: ['name'], operator: FilterOperator.Contains, mode: FilterMode.Or, values: ['aa', 'bb', 'cc'] },
{ key: ['score'], operator: FilterOperator.Gte, mode: FilterMode.And, values: [70] }
],
};
const injectedFilters: FilterGroup = {
mode: FilterMode.Or,
filterGroups: [],
filters: [
{
key: ['entity_type'],
operator: FilterOperator.NotEq,
values: ['Stix-Domain-Object', 'Stix-Relationship'],
},
{
key: ['confidence'],
operator: FilterOperator.Lte,
values: [50],
},
{
key: ['confidence'],
operator: FilterOperator.Nil,
values: [],
},
],
};

expect(adaptFiltersWithUserConfidence(makeUser(50), emptyFilterGroup))
.toEqual({
mode: FilterMode.And,
filters: [],
filterGroups: [injectedFilters]
});
expect(adaptFiltersWithUserConfidence(makeUser(50), exampleFilterGroup))
.toEqual({
mode: FilterMode.And,
filters: [],
filterGroups: [injectedFilters, exampleFilterGroup]
});
});
});