From 3bd5d9b5c7a31581a70b92644f411e2c18b5a0c0 Mon Sep 17 00:00:00 2001 From: BocognanoSarah Date: Mon, 20 Jan 2025 12:49:24 +0100 Subject: [PATCH 1/2] [backend/frontend] Threat actor group should not be part-of threat actor individual (#9576) --- .../threat_actors_group/ThreatActorGroupDetails.jsx | 8 +++++++- opencti-platform/opencti-graphql/src/database/stix.ts | 7 ------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/opencti-platform/opencti-front/src/private/components/threats/threat_actors_group/ThreatActorGroupDetails.jsx b/opencti-platform/opencti-front/src/private/components/threats/threat_actors_group/ThreatActorGroupDetails.jsx index 562f52844e47..2e035263725f 100644 --- a/opencti-platform/opencti-front/src/private/components/threats/threat_actors_group/ThreatActorGroupDetails.jsx +++ b/opencti-platform/opencti-front/src/private/components/threats/threat_actors_group/ThreatActorGroupDetails.jsx @@ -12,12 +12,14 @@ import ListItem from '@mui/material/ListItem'; import ListItemIcon from '@mui/material/ListItemIcon'; import { BullseyeArrow, ArmFlexOutline, DramaMasks } from 'mdi-material-ui'; import ListItemText from '@mui/material/ListItemText'; +import Tooltip from '@mui/material/Tooltip'; import ExpandableMarkdown from '../../../../components/ExpandableMarkdown'; import inject18n from '../../../../components/i18n'; import ItemOpenVocab from '../../../../components/ItemOpenVocab'; import FieldOrEmpty from '../../../../components/FieldOrEmpty'; import ImageCarousel from '../../../../components/ImageCarousel'; import ThreatActorGroupLocation from './ThreatActorGroupLocation'; +import { truncate } from '../../../../utils/String'; const styles = (theme) => ({ paper: { @@ -200,7 +202,11 @@ class ThreatActorGroupDetailsComponent extends Component { {goal} +
+                              
+                                {truncate(goal, 12)}
+                              
+                            
} /> diff --git a/opencti-platform/opencti-graphql/src/database/stix.ts b/opencti-platform/opencti-graphql/src/database/stix.ts index ed3689c6812c..957c21f90b88 100644 --- a/opencti-platform/opencti-graphql/src/database/stix.ts +++ b/opencti-platform/opencti-graphql/src/database/stix.ts @@ -825,9 +825,7 @@ export const stixCoreRelationshipsMapping: RelationshipMappings = { { name: RELATION_USES, type: REL_BUILT_IN } ], [`${ENTITY_TYPE_THREAT_ACTOR}_${ENTITY_TYPE_THREAT_ACTOR}`]: [ - { name: RELATION_PART_OF, type: REL_NEW }, { name: RELATION_COOPERATES_WITH, type: REL_NEW }, - { name: RELATION_DERIVED_FROM, type: REL_BUILT_IN } ], [`${ENTITY_TYPE_THREAT_ACTOR}_${ENTITY_TYPE_THREAT_ACTOR_GROUP}`]: [ { name: RELATION_PART_OF, type: REL_NEW }, @@ -835,9 +833,7 @@ export const stixCoreRelationshipsMapping: RelationshipMappings = { { name: RELATION_DERIVED_FROM, type: REL_BUILT_IN } ], [`${ENTITY_TYPE_THREAT_ACTOR}_${ENTITY_TYPE_THREAT_ACTOR_INDIVIDUAL}`]: [ - { name: RELATION_PART_OF, type: REL_NEW }, { name: RELATION_COOPERATES_WITH, type: REL_NEW }, - { name: RELATION_DERIVED_FROM, type: REL_BUILT_IN } ], [`${ENTITY_TYPE_THREAT_ACTOR}_${ENTITY_TYPE_TOOL}`]: [ { name: RELATION_USES, type: REL_BUILT_IN } @@ -911,7 +907,6 @@ export const stixCoreRelationshipsMapping: RelationshipMappings = { { name: RELATION_USES, type: REL_BUILT_IN } ], [`${ENTITY_TYPE_THREAT_ACTOR_GROUP}_${ENTITY_TYPE_THREAT_ACTOR}`]: [ - { name: RELATION_PART_OF, type: REL_NEW }, { name: RELATION_COOPERATES_WITH, type: REL_NEW }, { name: RELATION_DERIVED_FROM, type: REL_BUILT_IN } ], @@ -921,9 +916,7 @@ export const stixCoreRelationshipsMapping: RelationshipMappings = { { name: RELATION_DERIVED_FROM, type: REL_BUILT_IN } ], [`${ENTITY_TYPE_THREAT_ACTOR_GROUP}_${ENTITY_TYPE_THREAT_ACTOR_INDIVIDUAL}`]: [ - { name: RELATION_PART_OF, type: REL_NEW }, { name: RELATION_COOPERATES_WITH, type: REL_NEW }, - { name: RELATION_DERIVED_FROM, type: REL_BUILT_IN } ], [`${ENTITY_TYPE_THREAT_ACTOR_GROUP}_${ENTITY_TYPE_TOOL}`]: [ { name: RELATION_USES, type: REL_BUILT_IN } From d84eeaeb63608634125715102e606115df87d344 Mon Sep 17 00:00:00 2001 From: BocognanoSarah Date: Fri, 24 Jan 2025 10:22:28 +0100 Subject: [PATCH 2/2] [backend] relationships model updated, migration wip --- .../opencti-graphql/src/database/stix.ts | 21 +--- .../migration-threat-actors-relationships.js | 117 ++++++++++++++++++ .../threatActorIndividual.ts | 4 - 3 files changed, 118 insertions(+), 24 deletions(-) create mode 100644 opencti-platform/opencti-graphql/src/migrations/migration-threat-actors-relationships.js diff --git a/opencti-platform/opencti-graphql/src/database/stix.ts b/opencti-platform/opencti-graphql/src/database/stix.ts index 957c21f90b88..3fd7b4e7c85a 100644 --- a/opencti-platform/opencti-graphql/src/database/stix.ts +++ b/opencti-platform/opencti-graphql/src/database/stix.ts @@ -824,17 +824,6 @@ export const stixCoreRelationshipsMapping: RelationshipMappings = { [`${ENTITY_TYPE_THREAT_ACTOR}_${ENTITY_TYPE_MALWARE}`]: [ { name: RELATION_USES, type: REL_BUILT_IN } ], - [`${ENTITY_TYPE_THREAT_ACTOR}_${ENTITY_TYPE_THREAT_ACTOR}`]: [ - { name: RELATION_COOPERATES_WITH, type: REL_NEW }, - ], - [`${ENTITY_TYPE_THREAT_ACTOR}_${ENTITY_TYPE_THREAT_ACTOR_GROUP}`]: [ - { name: RELATION_PART_OF, type: REL_NEW }, - { name: RELATION_COOPERATES_WITH, type: REL_NEW }, - { name: RELATION_DERIVED_FROM, type: REL_BUILT_IN } - ], - [`${ENTITY_TYPE_THREAT_ACTOR}_${ENTITY_TYPE_THREAT_ACTOR_INDIVIDUAL}`]: [ - { name: RELATION_COOPERATES_WITH, type: REL_NEW }, - ], [`${ENTITY_TYPE_THREAT_ACTOR}_${ENTITY_TYPE_TOOL}`]: [ { name: RELATION_USES, type: REL_BUILT_IN } ], @@ -906,17 +895,9 @@ export const stixCoreRelationshipsMapping: RelationshipMappings = { [`${ENTITY_TYPE_THREAT_ACTOR_GROUP}_${ENTITY_TYPE_MALWARE}`]: [ { name: RELATION_USES, type: REL_BUILT_IN } ], - [`${ENTITY_TYPE_THREAT_ACTOR_GROUP}_${ENTITY_TYPE_THREAT_ACTOR}`]: [ - { name: RELATION_COOPERATES_WITH, type: REL_NEW }, - { name: RELATION_DERIVED_FROM, type: REL_BUILT_IN } - ], - [`${ENTITY_TYPE_THREAT_ACTOR_GROUP}_${ENTITY_TYPE_THREAT_ACTOR_GROUP}`]: [ - { name: RELATION_PART_OF, type: REL_NEW }, - { name: RELATION_COOPERATES_WITH, type: REL_NEW }, - { name: RELATION_DERIVED_FROM, type: REL_BUILT_IN } - ], [`${ENTITY_TYPE_THREAT_ACTOR_GROUP}_${ENTITY_TYPE_THREAT_ACTOR_INDIVIDUAL}`]: [ { name: RELATION_COOPERATES_WITH, type: REL_NEW }, + { name: RELATION_DERIVED_FROM, type: REL_BUILT_IN } ], [`${ENTITY_TYPE_THREAT_ACTOR_GROUP}_${ENTITY_TYPE_TOOL}`]: [ { name: RELATION_USES, type: REL_BUILT_IN } diff --git a/opencti-platform/opencti-graphql/src/migrations/migration-threat-actors-relationships.js b/opencti-platform/opencti-graphql/src/migrations/migration-threat-actors-relationships.js new file mode 100644 index 000000000000..c5fd280c8a70 --- /dev/null +++ b/opencti-platform/opencti-graphql/src/migrations/migration-threat-actors-relationships.js @@ -0,0 +1,117 @@ +import { logApp } from '../config/conf'; +import { elReindexByQueryForMigration, elUpdateByQueryForMigration, elDeleteByQueryForMigration } from '../database/engine'; +import { READ_INDEX_STIX_CORE_RELATIONSHIPS, READ_RELATIONSHIPS_INDICES } from '../database/utils'; +import { RELATION_RELATED_TO } from '../schema/stixCoreRelationship'; +import { executionContext } from '../utils/access'; + +export const up = async (next) => { + const context = executionContext('migration'); + logApp.info('[MIGRATION] Transform invalid relationships to "related-to"'); + + // Définition des relations valides avec direction + const validRelations = [ + { fromType: 'Threat-Actor-Individual', toType: 'Threat-Actor-Group', relationType: 'part-of' }, + { fromType: 'Threat-Actor-Individual', toType: 'Threat-Actor-Group', relationType: 'employed-by' }, + { fromType: 'Threat-Actor-Individual', toType: 'Threat-Actor-Group', relationType: 'cooperates-with' }, + { fromType: 'Threat-Actor-Individual', toType: 'Threat-Actor-Group', relationType: 'derived-from' }, + { fromType: 'Threat-Actor-Individual', toType: 'Threat-Actor-Group', relationType: 'related-to' }, + { fromType: 'Threat-Actor-Individual', toType: 'Threat-Actor-Individual', relationType: 'known-as' }, + { fromType: 'Threat-Actor-Individual', toType: 'Threat-Actor-Individual', relationType: 'reports-to' }, + { fromType: 'Threat-Actor-Individual', toType: 'Threat-Actor-Individual', relationType: 'supports' }, + { fromType: 'Threat-Actor-Individual', toType: 'Threat-Actor-Group', relationType: 'supports' }, + { fromType: 'Threat-Actor-Group', toType: 'Threat-Actor-Individual', relationType: 'cooperates-with' }, + { fromType: 'Threat-Actor-Group', toType: 'Threat-Actor-Individual', relationType: 'derived-from' }, + { fromType: 'Threat-Actor-Group', toType: 'Threat-Actor-Individual', relationType: 'related-to' }, + ]; + + // Étape 1 : Identifier les relations invalides + const invalidRelationshipsQuery = { + bool: { + must_not: validRelations.map((relation) => ({ + bool: { + must: [ + { term: { 'fromType.keyword': relation.fromType } }, + { term: { 'toType.keyword': relation.toType } }, + { term: { 'relationship_type.keyword': relation.relationType } }, + ], + }, + })), + }, + }; + + // Étape 2 : Reindexer les relations invalides + const reindexInvalidRelationshipsSource = ` + ctx._source.relationship_type = params.newRelType; + ctx._source.entity_type = params.newRelType; + ctx._source.parent_types = params.parentTypes; + for (connection in ctx._source.connections) { + connection.role = connection.role.replace(connection.role, "related-to_" + connection.role.split("_")[1]); + } + `; + const reindexInvalidRelationshipsQuery = { + source: { + index: READ_INDEX_STIX_CORE_RELATIONSHIPS, + query: invalidRelationshipsQuery, + }, + dest: { + index: READ_INDEX_STIX_CORE_RELATIONSHIPS, + }, + script: { + source: reindexInvalidRelationshipsSource, + params: { + newRelType: RELATION_RELATED_TO, + parentTypes: ['basic-relationship', 'stix-relationship', 'stix-core-relationship'], + }, + }, + }; + + logApp.info('[MIGRATION] Reindexing invalid relationships to "related-to"'); + await elReindexByQueryForMigration( + '[MIGRATION] Reindexing invalid relationships', + null, + reindexInvalidRelationshipsQuery + ); + + // Étape 3 : Mise à jour des connexions dans les entités + const updateInvalidConnectionsSource = ` + if (!params.validRelations.some( + r => r.fromType == ctx._source.fromType && r.toType == ctx._source.toType && r.relationType == ctx._source.relationship_type)) { + ctx._source.relationship_type = params.newRelType; + ctx._source.entity_type = params.newRelType; + for (connection in ctx._source.connections) { + connection.role = connection.role.replace(connection.role, "related-to_" + connection.role.split("_")[1]); + } + } + `; + const updateInvalidConnectionsQuery = { + script: { + source: updateInvalidConnectionsSource, + params: { validRelations, newRelType: RELATION_RELATED_TO }, + }, + query: invalidRelationshipsQuery, + }; + + logApp.info('[MIGRATION] Updating invalid relationships in entities'); + await elUpdateByQueryForMigration( + '[MIGRATION] Updating invalid relationships in entities', + [READ_RELATIONSHIPS_INDICES], + updateInvalidConnectionsQuery + ); + + // Étape 4 : Suppression des relations invalides d'origine + logApp.info('[MIGRATION] Deleting old invalid relationships'); + await elDeleteByQueryForMigration( + '[MIGRATION] Deleting invalid relationships', + [READ_INDEX_STIX_CORE_RELATIONSHIPS], + { + query: invalidRelationshipsQuery, + } + ); + + logApp.info('[MIGRATION] Transform invalid relationships to "related-to" completed'); + next(); +}; + +export const down = async (next) => { + next(); +}; diff --git a/opencti-platform/opencti-graphql/src/modules/threatActorIndividual/threatActorIndividual.ts b/opencti-platform/opencti-graphql/src/modules/threatActorIndividual/threatActorIndividual.ts index 1ac1cc4b784f..0104b30f4e8d 100644 --- a/opencti-platform/opencti-graphql/src/modules/threatActorIndividual/threatActorIndividual.ts +++ b/opencti-platform/opencti-graphql/src/modules/threatActorIndividual/threatActorIndividual.ts @@ -232,14 +232,12 @@ const THREAT_ACTOR_INDIVIDUAL_DEFINITION: ModuleDefinition