From 1dce13d61bc92afa5d9cca9b2a7b0c20007fcf01 Mon Sep 17 00:00:00 2001 From: Christian Studer Date: Wed, 30 Oct 2024 15:10:53 +0100 Subject: [PATCH 01/11] fix: [AnalystData] Avoiding issues with analyst data objects --- pymisp/mispevent.py | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index 362fd1e..20ad33b 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -60,28 +60,35 @@ class AnalystDataBehaviorMixin(AbstractMISP): def add_note(self, note: str, language: str | None = None, **kwargs) -> MISPNote: # type: ignore[no-untyped-def] the_note = MISPNote() - the_note.from_dict(note=note, language=language, - object_uuid=self.uuid, object_type=self.analyst_data_object_type, - **kwargs) + the_note.from_dict( + note=note, language=language, object_uuid=self.uuid, + object_type=self.analyst_data_object_type, contained=True, + **kwargs + ) self.notes.append(the_note) self.edited = True return the_note def add_opinion(self, opinion: int, comment: str | None = None, **kwargs) -> MISPOpinion: # type: ignore[no-untyped-def] the_opinion = MISPOpinion() - the_opinion.from_dict(opinion=opinion, comment=comment, - object_uuid=self.uuid, object_type=self.analyst_data_object_type, - **kwargs) + the_opinion.from_dict( + opinion=opinion, comment=comment, object_uuid=self.uuid, + object_type=self.analyst_data_object_type, contained=True, + **kwargs + ) self.opinions.append(the_opinion) self.edited = True return the_opinion def add_relationship(self, related_object_type: AbstractMISP | str, related_object_uuid: str | None, relationship_type: str, **kwargs) -> MISPRelationship: # type: ignore[no-untyped-def] the_relationship = MISPRelationship() - the_relationship.from_dict(related_object_type=related_object_type, related_object_uuid=related_object_uuid, - relationship_type=relationship_type, - object_uuid=self.uuid, object_type=self.analyst_data_object_type, - **kwargs) + the_relationship.from_dict( + related_object_type=related_object_type, + related_object_uuid=related_object_uuid, + relationship_type=relationship_type, object_uuid=self.uuid, + object_type=self.analyst_data_object_type, contained=True, + **kwargs + ) self.relationships.append(the_relationship) self.edited = True return the_relationship @@ -2591,8 +2598,8 @@ class MISPNote(AnalystDataBehaviorMixin, MISPAnalystData): self.language: str super().__init__(**kwargs) - def from_dict(self, **kwargs) -> None: # type: ignore[no-untyped-def] - if 'Note' in kwargs: + def from_dict(self, contained=False, **kwargs) -> None: # type: ignore[no-untyped-def] + if not conainted and 'Note' in kwargs: kwargs = kwargs['Note'] self.note = kwargs.pop('note', None) if self.note is None: @@ -2616,8 +2623,8 @@ class MISPOpinion(AnalystDataBehaviorMixin, MISPAnalystData): self.comment: str super().__init__(**kwargs) - def from_dict(self, **kwargs) -> None: # type: ignore[no-untyped-def] - if 'Opinion' in kwargs: + def from_dict(self, contained=False, **kwargs) -> None: # type: ignore[no-untyped-def] + if not contained and 'Opinion' in kwargs: kwargs = kwargs['Opinion'] self.opinion = kwargs.pop('opinion', None) if self.opinion is not None: @@ -2651,8 +2658,8 @@ class MISPRelationship(AnalystDataBehaviorMixin, MISPAnalystData): self.relationship_type: str super().__init__(**kwargs) - def from_dict(self, **kwargs) -> None: # type: ignore[no-untyped-def] - if 'Relationship' in kwargs: + def from_dict(self, contained=False, **kwargs) -> None: # type: ignore[no-untyped-def] + if not contained and 'Relationship' in kwargs: kwargs = kwargs['Relationship'] self.related_object_type = kwargs.pop('related_object_type', None) if self.related_object_type is None: From 8e288a43231d35a9852a1383f64ec36c9a3771e2 Mon Sep 17 00:00:00 2001 From: Christian Studer Date: Wed, 30 Oct 2024 17:00:22 +0100 Subject: [PATCH 02/11] fix: [AnalystData] Typo... --- pymisp/mispevent.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index 20ad33b..3b31087 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -2599,7 +2599,7 @@ class MISPNote(AnalystDataBehaviorMixin, MISPAnalystData): super().__init__(**kwargs) def from_dict(self, contained=False, **kwargs) -> None: # type: ignore[no-untyped-def] - if not conainted and 'Note' in kwargs: + if not contained and 'Note' in kwargs: kwargs = kwargs['Note'] self.note = kwargs.pop('note', None) if self.note is None: From df39554208739586bf25b6803c9011f85e7aefd9 Mon Sep 17 00:00:00 2001 From: Christian Studer Date: Tue, 19 Nov 2024 13:49:53 +0100 Subject: [PATCH 03/11] chg: [AnalystData] Flattening analyst data based on the recent changes on MISP standard format - Adding a note or an opinion will always add the new analyst data object to the list of notes or opinions at the parent data layer level - `from_dict` on a JSON blob is also able to parse properly analyst data and generate flat lists regardless of whether the given data described in the new flat or previously nested format --- pymisp/mispevent.py | 86 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 69 insertions(+), 17 deletions(-) diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index 3b31087..86e8f70 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -38,9 +38,6 @@ class AnalystDataBehaviorMixin(AbstractMISP): super().__init__(**kwargs) self.uuid: str # Created in the child class self._analyst_data_object_type: str # Must be defined in the child class - self.Note: list[MISPNote] = [] - self.Opinion: list[MISPOpinion] = [] - self.Relationship: list[MISPRelationship] = [] @property def analyst_data_object_type(self) -> str: @@ -60,10 +57,11 @@ class AnalystDataBehaviorMixin(AbstractMISP): def add_note(self, note: str, language: str | None = None, **kwargs) -> MISPNote: # type: ignore[no-untyped-def] the_note = MISPNote() + object_uuid = kwargs.pop('object_uuid', self.uuid) + object_type = kwargs.pop('object_type', self.analyst_data_object_type) the_note.from_dict( - note=note, language=language, object_uuid=self.uuid, - object_type=self.analyst_data_object_type, contained=True, - **kwargs + note=note, language=language, object_uuid=object_uuid, + object_type=object_type, contained=True, parent=self, **kwargs ) self.notes.append(the_note) self.edited = True @@ -71,10 +69,11 @@ class AnalystDataBehaviorMixin(AbstractMISP): def add_opinion(self, opinion: int, comment: str | None = None, **kwargs) -> MISPOpinion: # type: ignore[no-untyped-def] the_opinion = MISPOpinion() + object_uuid = kwargs.pop('object_uuid', self.uuid) + object_type = kwargs.pop('object_type', self.analyst_data_object_type) the_opinion.from_dict( - opinion=opinion, comment=comment, object_uuid=self.uuid, - object_type=self.analyst_data_object_type, contained=True, - **kwargs + opinion=opinion, comment=comment, object_uuid=object_uuid, + object_type=object_type, contained=True, parent=self, **kwargs ) self.opinions.append(the_opinion) self.edited = True @@ -87,7 +86,7 @@ class AnalystDataBehaviorMixin(AbstractMISP): related_object_uuid=related_object_uuid, relationship_type=relationship_type, object_uuid=self.uuid, object_type=self.analyst_data_object_type, contained=True, - **kwargs + parent=self, **kwargs ) self.relationships.append(the_relationship) self.edited = True @@ -100,12 +99,8 @@ class AnalystDataBehaviorMixin(AbstractMISP): relationships = kwargs.pop('Relationship', []) super().from_dict(**kwargs) for note in notes: - note.pop('object_uuid', None) - note.pop('object_type', None) self.add_note(**note) for opinion in opinions: - opinion.pop('object_uuid', None) - opinion.pop('object_type', None) self.add_opinion(**opinion) for relationship in relationships: relationship.pop('object_uuid', None) @@ -338,6 +333,9 @@ class MISPAttribute(AnalystDataBehaviorMixin): self.Sighting: list[MISPSighting] = [] self.Tag: list[MISPTag] = [] self.Galaxy: list[MISPGalaxy] = [] + self.Note: list[MISPNote] = [] + self.Opinion: list[MISPOpinion] = [] + self.Relationship: list[MISPRelationship] = [] self.expand: str self.timestamp: float | int | datetime @@ -794,6 +792,9 @@ class MISPObject(AnalystDataBehaviorMixin): self.ObjectReference: list[MISPObjectReference] = [] self._standalone: bool = False self.Attribute: list[MISPObjectAttribute] = [] + self.Note: list[MISPNote] = [] + self.Opinion: list[MISPOpinion] = [] + self.Relationship: list[MISPRelationship] = [] self.SharingGroup: MISPSharingGroup self._default_attributes_parameters: dict[str, Any] if isinstance(default_attributes_parameters, MISPAttribute): @@ -1180,6 +1181,9 @@ class MISPEventReport(AnalystDataBehaviorMixin): def __init__(self, **kwargs): super().__init__(**kwargs) self.uuid: str = str(uuid.uuid4()) + self.Note: list[MISPNote] = [] + self.Opinion: list[MISPOpinion] = [] + self.Relationship: list[MISPRelationship] = [] def from_dict(self, **kwargs) -> None: # type: ignore[no-untyped-def] if 'EventReport' in kwargs: @@ -1588,6 +1592,9 @@ class MISPEvent(AnalystDataBehaviorMixin): self.EventReport: list[MISPEventReport] = [] self.Tag: list[MISPTag] = [] self.Galaxy: list[MISPGalaxy] = [] + self.Note: list[MISPNote] = [] + self.Opinion: list[MISPOpinion] = [] + self.Relationship: list[MISPRelationship] = [] self.publish_timestamp: float | int | datetime self.timestamp: float | int | datetime @@ -2496,6 +2503,10 @@ class MISPAnalystData(AbstractMISP): 'Object', 'Note', 'Opinion', 'Relationship', 'Organisation', 'SharingGroup'} + @property + def analyst_data_object_type(self) -> str: + return self._analyst_data_object_type + @property def org(self) -> MISPOrganisation: return self.Org @@ -2511,6 +2522,10 @@ class MISPAnalystData(AbstractMISP): else: raise PyMISPError('Orgc must be of type MISPOrganisation.') + @property + def parent(self) -> MISPAttribute | MISPEvent | MISPEventReport | MISPObject: + return self.__parent + def __new__(cls, *args, **kwargs): if cls is MISPAnalystData: raise TypeError(f"only children of '{cls.__name__}' may be instantiated") @@ -2525,8 +2540,38 @@ class MISPAnalystData(AbstractMISP): self.created: float | int | datetime self.modified: float | int | datetime self.SharingGroup: MISPSharingGroup + self._analyst_data_object_type: str # Must be defined in the child class + + def add_note(self, note: str, language: str | None = None, **kwargs) -> MISPNote: + misp_note = MISPNote() + object_uuid = kwargs.pop('object_uuid', self.uuid) + object_type = kwargs.pop('object_type', self.analyst_data_object_type) + misp_note.from_dict( + note=note, language=language, object_uuid=object_uuid, + object_type=object_type, parent=kwargs.pop('parent', self.parent), + contained=True, **kwargs + ) + self.parent.notes.append(misp_note) + self.edited = True + return misp_note + + def add_opinion(self, opinion: int, comment: str | None = None, **kwargs) -> MISPOpinion: + misp_opinion = MISPOpinion() + object_uuid = kwargs.pop('object_uuid', self.uuid) + object_type = kwargs.pop('object_type', self.analyst_data_object_type) + misp_opinion.from_dict( + opinion=opinion, comment=comment, object_uuid=object_uuid, + object_type=object_type, parent=kwargs.pop('parent', self.parent), + contained=True, **kwargs + ) + self.parent.opinions.append(misp_opinion) + self.edited = True + return misp_opinion def from_dict(self, **kwargs) -> None: # type: ignore[no-untyped-def] + notes = kwargs.pop('Note', []) + opinions = kwargs.pop('Opinion', []) + self.__parent = kwargs.pop('parent') self.distribution = kwargs.pop('distribution', None) if self.distribution is not None: self.distribution = int(self.distribution) @@ -2580,6 +2625,13 @@ class MISPAnalystData(AbstractMISP): super().from_dict(**kwargs) + for note in notes: + note_value = note.pop('note') + self.add_note(note_value, parent=self.parent, **note) + for opinion in opinions: + opinion_value = opinion.pop('opinion') + self.add_opinion(opinion_value, parent=self.parent, **opinion) + def _set_default(self) -> None: if not hasattr(self, 'created'): self.created = datetime.timestamp(datetime.now()) @@ -2587,7 +2639,7 @@ class MISPAnalystData(AbstractMISP): self.modified = self.created -class MISPNote(AnalystDataBehaviorMixin, MISPAnalystData): +class MISPNote(MISPAnalystData): _fields_for_feed: set[str] = MISPAnalystData._fields_for_feed.union({'note', 'language'}) @@ -2612,7 +2664,7 @@ class MISPNote(AnalystDataBehaviorMixin, MISPAnalystData): return f'<{self.__class__.__name__}(NotInitialized)' -class MISPOpinion(AnalystDataBehaviorMixin, MISPAnalystData): +class MISPOpinion(MISPAnalystData): _fields_for_feed: set[str] = MISPAnalystData._fields_for_feed.union({'opinion', 'comment'}) @@ -2646,7 +2698,7 @@ class MISPOpinion(AnalystDataBehaviorMixin, MISPAnalystData): return f'<{self.__class__.__name__}(NotInitialized)' -class MISPRelationship(AnalystDataBehaviorMixin, MISPAnalystData): +class MISPRelationship(MISPAnalystData): _fields_for_feed: set[str] = MISPAnalystData._fields_for_feed.union({'related_object_uuid', 'related_object_type', 'relationship_type'}) From ea6ff20103f58730729f4f9c0a8e3c4c6654b5b9 Mon Sep 17 00:00:00 2001 From: Christian Studer Date: Wed, 20 Nov 2024 11:47:41 +0100 Subject: [PATCH 04/11] fix: [MISPAnalystData] Better handling of the different use cases - Additional checks for parent to support both the standalone and attached analyst data objects - Standalone Analyst data objects with nested notes or opinions are defined with the nesting as they have no parent. When they are added to a parent data layer, the nested objects are then flattened --- pymisp/mispevent.py | 48 +++++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index 86e8f70..7ecfaba 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -2542,36 +2542,52 @@ class MISPAnalystData(AbstractMISP): self.SharingGroup: MISPSharingGroup self._analyst_data_object_type: str # Must be defined in the child class - def add_note(self, note: str, language: str | None = None, **kwargs) -> MISPNote: + def add_note(self, note: str, language: str | None = None, object_uuid: str | None = None, object_type: str | None = None, parent: MISPEvent | MISPAttribute | MISPObject | MISPEventReport | None = None, **kwargs) -> MISPNote: misp_note = MISPNote() - object_uuid = kwargs.pop('object_uuid', self.uuid) - object_type = kwargs.pop('object_type', self.analyst_data_object_type) + if object_uuid is None: + object_uuid = self.uuid + if object_type is None: + object_type = self.analyst_data_object_type + if parent is None and hasattr(self, 'parent'): + parent = self.parent misp_note.from_dict( note=note, language=language, object_uuid=object_uuid, - object_type=object_type, parent=kwargs.pop('parent', self.parent), - contained=True, **kwargs + object_type=object_type, parent=parent, contained=True, **kwargs ) - self.parent.notes.append(misp_note) + if parent is None: + if not hasattr(self, 'Note'): + self.Note: list[MISPNote] = [] + self.Note.append(misp_note) + else: + self.parent.notes.append(misp_note) self.edited = True return misp_note - def add_opinion(self, opinion: int, comment: str | None = None, **kwargs) -> MISPOpinion: + def add_opinion(self, opinion: int, comment: str | None = None, object_uuid: str | None = None, object_type: str | None = None, parent: MISPEvent | MISPAttribute | MISPObject | MISPEventReport | None = None, **kwargs) -> MISPOpinion: misp_opinion = MISPOpinion() - object_uuid = kwargs.pop('object_uuid', self.uuid) - object_type = kwargs.pop('object_type', self.analyst_data_object_type) + if object_uuid is None: + object_uuid = self.uuid + if object_type is None: + object_type = self.analyst_data_object_type + if parent is None and hasattr(self, 'parent'): + parent = self.parent misp_opinion.from_dict( opinion=opinion, comment=comment, object_uuid=object_uuid, - object_type=object_type, parent=kwargs.pop('parent', self.parent), - contained=True, **kwargs + object_type=object_type, parent=parent, contained=True, **kwargs ) - self.parent.opinions.append(misp_opinion) + if parent is None: + if not hasattr(self, 'Opinion'): + self.Opinion: list[MISPOpinion] = [] + self.Opinion.append(misp_opinion) + else: + self.parent.opinions.append(misp_opinion) self.edited = True return misp_opinion def from_dict(self, **kwargs) -> None: # type: ignore[no-untyped-def] notes = kwargs.pop('Note', []) opinions = kwargs.pop('Opinion', []) - self.__parent = kwargs.pop('parent') + self.__parent = kwargs.pop('parent', None) self.distribution = kwargs.pop('distribution', None) if self.distribution is not None: self.distribution = int(self.distribution) @@ -2626,11 +2642,9 @@ class MISPAnalystData(AbstractMISP): super().from_dict(**kwargs) for note in notes: - note_value = note.pop('note') - self.add_note(note_value, parent=self.parent, **note) + self.add_note(**note) for opinion in opinions: - opinion_value = opinion.pop('opinion') - self.add_opinion(opinion_value, parent=self.parent, **opinion) + self.add_opinion(**opinion) def _set_default(self) -> None: if not hasattr(self, 'created'): From 6ca367dc2514140bc946f698e094cc5051ade3c3 Mon Sep 17 00:00:00 2001 From: Christian Studer Date: Wed, 20 Nov 2024 13:21:35 +0100 Subject: [PATCH 05/11] fix: [MISPAnalystData] Reverted the declaration of Analyst data objects lists back to the mixin parent class --- pymisp/mispevent.py | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index 7ecfaba..2cf15b2 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -38,6 +38,9 @@ class AnalystDataBehaviorMixin(AbstractMISP): super().__init__(**kwargs) self.uuid: str # Created in the child class self._analyst_data_object_type: str # Must be defined in the child class + self.Note: list[MISPNote] = [] + self.Opinion: list[MISPOpinion] = [] + self.Relationship: list[MISPRelationship] = [] @property def analyst_data_object_type(self) -> str: @@ -333,9 +336,6 @@ class MISPAttribute(AnalystDataBehaviorMixin): self.Sighting: list[MISPSighting] = [] self.Tag: list[MISPTag] = [] self.Galaxy: list[MISPGalaxy] = [] - self.Note: list[MISPNote] = [] - self.Opinion: list[MISPOpinion] = [] - self.Relationship: list[MISPRelationship] = [] self.expand: str self.timestamp: float | int | datetime @@ -792,9 +792,6 @@ class MISPObject(AnalystDataBehaviorMixin): self.ObjectReference: list[MISPObjectReference] = [] self._standalone: bool = False self.Attribute: list[MISPObjectAttribute] = [] - self.Note: list[MISPNote] = [] - self.Opinion: list[MISPOpinion] = [] - self.Relationship: list[MISPRelationship] = [] self.SharingGroup: MISPSharingGroup self._default_attributes_parameters: dict[str, Any] if isinstance(default_attributes_parameters, MISPAttribute): @@ -1181,9 +1178,6 @@ class MISPEventReport(AnalystDataBehaviorMixin): def __init__(self, **kwargs): super().__init__(**kwargs) self.uuid: str = str(uuid.uuid4()) - self.Note: list[MISPNote] = [] - self.Opinion: list[MISPOpinion] = [] - self.Relationship: list[MISPRelationship] = [] def from_dict(self, **kwargs) -> None: # type: ignore[no-untyped-def] if 'EventReport' in kwargs: @@ -1592,9 +1586,6 @@ class MISPEvent(AnalystDataBehaviorMixin): self.EventReport: list[MISPEventReport] = [] self.Tag: list[MISPTag] = [] self.Galaxy: list[MISPGalaxy] = [] - self.Note: list[MISPNote] = [] - self.Opinion: list[MISPOpinion] = [] - self.Relationship: list[MISPRelationship] = [] self.publish_timestamp: float | int | datetime self.timestamp: float | int | datetime From 90b8f5883a359fd93eaba7d51a10e2c356dcd625 Mon Sep 17 00:00:00 2001 From: Christian Studer Date: Wed, 20 Nov 2024 13:36:19 +0100 Subject: [PATCH 06/11] fix: [MISPAnalystData] Added missing typing --- pymisp/mispevent.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index 2cf15b2..bd466ed 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -2533,7 +2533,7 @@ class MISPAnalystData(AbstractMISP): self.SharingGroup: MISPSharingGroup self._analyst_data_object_type: str # Must be defined in the child class - def add_note(self, note: str, language: str | None = None, object_uuid: str | None = None, object_type: str | None = None, parent: MISPEvent | MISPAttribute | MISPObject | MISPEventReport | None = None, **kwargs) -> MISPNote: + def add_note(self, note: str, language: str | None = None, object_uuid: str | None = None, object_type: str | None = None, parent: MISPEvent | MISPAttribute | MISPObject | MISPEventReport | None = None, **kwargs: dict[str, Any]) -> MISPNote: misp_note = MISPNote() if object_uuid is None: object_uuid = self.uuid @@ -2554,7 +2554,7 @@ class MISPAnalystData(AbstractMISP): self.edited = True return misp_note - def add_opinion(self, opinion: int, comment: str | None = None, object_uuid: str | None = None, object_type: str | None = None, parent: MISPEvent | MISPAttribute | MISPObject | MISPEventReport | None = None, **kwargs) -> MISPOpinion: + def add_opinion(self, opinion: int, comment: str | None = None, object_uuid: str | None = None, object_type: str | None = None, parent: MISPEvent | MISPAttribute | MISPObject | MISPEventReport | None = None, **kwargs: dict[str, Any]) -> MISPOpinion: misp_opinion = MISPOpinion() if object_uuid is None: object_uuid = self.uuid From 1e9258eb4adc354c041d29c0b1227a800d7968fa Mon Sep 17 00:00:00 2001 From: Christian Studer Date: Wed, 18 Dec 2024 18:17:00 +0100 Subject: [PATCH 07/11] add: [tests] Testing Analyst Data in different scenarios - Testing different ways to attach analyst data - Testing that no matter what object type the analyst data is attached to, the `object_type` & `object_uuid` are correct, and the parent container does contain every analyst data object in flat lists with no nesting --- tests/test_analyst_data.py | 122 +++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 tests/test_analyst_data.py diff --git a/tests/test_analyst_data.py b/tests/test_analyst_data.py new file mode 100644 index 0000000..4672960 --- /dev/null +++ b/tests/test_analyst_data.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python + +import unittest +from pymisp import (MISPAttribute, MISPEvent, MISPEventReport, MISPNote, + MISPObject, MISPOpinion) +from uuid import uuid4 + + +class TestAnalystData(unittest.TestCase): + def setUp(self) -> None: + self.note_dict = { + "uuid": uuid4(), + "note": "note3" + } + self.opinion_dict = { + "uuid": uuid4(), + "opinion": 75, + "comment": "Agree" + } + + def test_analyst_data_on_attribute(self) -> None: + attribute = MISPAttribute() + attribute.from_dict(type='filename', value='foo.exe') + self._attach_analyst_data(attribute) + + def test_analyst_data_on_attribute_alternative(self) -> None: + event = MISPEvent() + event.info = 'Test on Attribute' + event.add_attribute('domain', 'foo.bar') + self._attach_analyst_data(event.attributes[0]) + + def test_analyst_data_on_event(self) -> None: + event = MISPEvent() + event.info = 'Test Event' + self._attach_analyst_data(event) + + def test_analyst_data_on_event_report(self) -> None: + event_report = MISPEventReport() + event_report.from_dict(name='Test Report', content='This is a report') + self._attach_analyst_data(event_report) + + def test_analyst_data_on_event_report_alternative(self) -> None: + event = MISPEvent() + event.info = 'Test on Event Report' + event.add_event_report('Test Report', 'This is a report') + self._attach_analyst_data(event.event_reports[0]) + + def test_analyst_data_on_object(self) -> None: + misp_object = MISPObject('file') + misp_object.add_attribute('filename', 'foo.exe') + self._attach_analyst_data(misp_object) + + def test_analyst_data_on_object_alternative(self) -> None: + event = MISPEvent() + event.info = 'Test on Object' + misp_object = MISPObject('file') + misp_object.add_attribute('filename', 'foo.exe') + event.add_object(misp_object) + self._attach_analyst_data(event.objects[0]) + + def test_analyst_data_on_object_attribute(self) -> None: + misp_object = MISPObject('file') + object_attribute = misp_object.add_attribute('filename', 'foo.exe') + self._attach_analyst_data(object_attribute) + + def test_analyst_data_object_object_attribute_alternative(self) -> None: + misp_object = MISPObject('file') + misp_object.add_attribute('filename', 'foo.exe') + self._attach_analyst_data(misp_object.attributes[0]) + + def _attach_analyst_data( + self, container: MISPAttribute | MISPEvent | MISPEventReport | MISPObject) -> None: + object_type = container._analyst_data_object_type + note1 = container.add_note(note='note1') + opinion1 = note1.add_opinion(opinion=25, comment='Disagree') + opinion2 = container.add_opinion(opinion=50, comment='Neutral') + note2 = opinion2.add_note(note='note2') + + dict_note = MISPNote() + dict_note.from_dict( + object_type=object_type, object_uuid=container.uuid, **self.note_dict + ) + note3 = container.add_note(**dict_note) + dict_opinion = MISPOpinion() + dict_opinion.from_dict( + object_type='Note', object_uuid=note3.uuid, **self.opinion_dict + ) + container.add_opinion(**dict_opinion) + + self.assertEqual(len(container.notes), 3) + self.assertEqual(len(container.opinions), 3) + + misp_note1, misp_note2, misp_note3 = container.notes + misp_opinion1, misp_opinion2, misp_opinion3 = container.opinions + + self.assertEqual(misp_note1.object_type, object_type) + self.assertEqual(misp_note1.object_uuid, container.uuid) + self.assertEqual(misp_note1.note, 'note1') + + self.assertEqual(misp_note2.object_type, 'Opinion') + self.assertEqual(misp_note2.object_uuid, opinion2.uuid) + self.assertEqual(misp_note2.note, 'note2') + + self.assertEqual(misp_note3.object_type, object_type) + self.assertEqual(misp_note3.object_uuid, container.uuid) + self.assertEqual(misp_note3.note, 'note3') + + self.assertEqual(misp_opinion1.object_type, 'Note') + self.assertEqual(misp_opinion1.object_uuid, note1.uuid) + self.assertEqual(misp_opinion1.opinion, 25) + self.assertEqual(misp_opinion1.comment, 'Disagree') + + self.assertEqual(misp_opinion2.object_type, object_type) + self.assertEqual(misp_opinion2.object_uuid, container.uuid) + self.assertEqual(misp_opinion2.opinion, 50) + self.assertEqual(misp_opinion2.comment, 'Neutral') + + self.assertEqual(misp_opinion3.object_type, 'Note') + self.assertEqual(misp_opinion3.object_uuid, note3.uuid) + self.assertEqual(misp_opinion3.opinion, 75) + self.assertEqual(misp_opinion3.comment, 'Agree') + From a7cf9dc3f03ffda5ee6c1b614792455fe43d8704 Mon Sep 17 00:00:00 2001 From: Christian Studer Date: Wed, 18 Dec 2024 18:24:06 +0100 Subject: [PATCH 08/11] fix: [tests] Removed typing --- tests/test_analyst_data.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/test_analyst_data.py b/tests/test_analyst_data.py index 4672960..d594c0f 100644 --- a/tests/test_analyst_data.py +++ b/tests/test_analyst_data.py @@ -68,8 +68,7 @@ class TestAnalystData(unittest.TestCase): misp_object.add_attribute('filename', 'foo.exe') self._attach_analyst_data(misp_object.attributes[0]) - def _attach_analyst_data( - self, container: MISPAttribute | MISPEvent | MISPEventReport | MISPObject) -> None: + def _attach_analyst_data(self, container) -> None: object_type = container._analyst_data_object_type note1 = container.add_note(note='note1') opinion1 = note1.add_opinion(opinion=25, comment='Disagree') From 23b5d3a328f056209253f0eaedba01e3b90f507a Mon Sep 17 00:00:00 2001 From: Christian Studer Date: Wed, 18 Dec 2024 18:28:37 +0100 Subject: [PATCH 09/11] Revert "fix: [tests] Removed typing" This reverts commit a7cf9dc3f03ffda5ee6c1b614792455fe43d8704. --- tests/test_analyst_data.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_analyst_data.py b/tests/test_analyst_data.py index d594c0f..4672960 100644 --- a/tests/test_analyst_data.py +++ b/tests/test_analyst_data.py @@ -68,7 +68,8 @@ class TestAnalystData(unittest.TestCase): misp_object.add_attribute('filename', 'foo.exe') self._attach_analyst_data(misp_object.attributes[0]) - def _attach_analyst_data(self, container) -> None: + def _attach_analyst_data( + self, container: MISPAttribute | MISPEvent | MISPEventReport | MISPObject) -> None: object_type = container._analyst_data_object_type note1 = container.add_note(note='note1') opinion1 = note1.add_opinion(opinion=25, comment='Disagree') From fb45f2a07b217c8441b1528ad4c1c7cd05aa7bd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Fri, 20 Dec 2024 15:27:38 +0100 Subject: [PATCH 10/11] chg: Bump deps --- poetry.lock | 90 +++++++++++++++++++++++++------------------------- pyproject.toml | 4 +-- 2 files changed, 47 insertions(+), 47 deletions(-) diff --git a/poetry.lock b/poetry.lock index 164020a..cdf3891 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1128,13 +1128,13 @@ test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.22)", "pa [[package]] name = "ipython" -version = "8.30.0" +version = "8.31.0" description = "IPython: Productive Interactive Computing" optional = false python-versions = ">=3.10" files = [ - {file = "ipython-8.30.0-py3-none-any.whl", hash = "sha256:85ec56a7e20f6c38fce7727dcca699ae4ffc85985aa7b23635a8008f918ae321"}, - {file = "ipython-8.30.0.tar.gz", hash = "sha256:cb0a405a306d2995a5cbb9901894d240784a9f341394c6ba3f4fe8c6eb89ff6e"}, + {file = "ipython-8.31.0-py3-none-any.whl", hash = "sha256:46ec58f8d3d076a61d128fe517a51eb730e3aaf0c184ea8c17d16e366660c6a6"}, + {file = "ipython-8.31.0.tar.gz", hash = "sha256:b6a2274606bec6166405ff05e54932ed6e5cfecaca1fc05f2cacde7bb074d70b"}, ] [package.dependencies] @@ -1327,13 +1327,13 @@ test = ["ipykernel", "pre-commit", "pytest (<8)", "pytest-cov", "pytest-timeout" [[package]] name = "jupyter-events" -version = "0.10.0" +version = "0.11.0" description = "Jupyter Event System library" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "jupyter_events-0.10.0-py3-none-any.whl", hash = "sha256:4b72130875e59d57716d327ea70d3ebc3af1944d3717e5a498b8a06c6c159960"}, - {file = "jupyter_events-0.10.0.tar.gz", hash = "sha256:670b8229d3cc882ec782144ed22e0d29e1c2d639263f92ca8383e66682845e22"}, + {file = "jupyter_events-0.11.0-py3-none-any.whl", hash = "sha256:36399b41ce1ca45fe8b8271067d6a140ffa54cec4028e95491c93b78a855cacf"}, + {file = "jupyter_events-0.11.0.tar.gz", hash = "sha256:c0bc56a37aac29c1fbc3bcfbddb8c8c49533f9cf11f1c4e6adadba936574ab90"}, ] [package.dependencies] @@ -1347,7 +1347,7 @@ traitlets = ">=5.3" [package.extras] cli = ["click", "rich"] -docs = ["jupyterlite-sphinx", "myst-parser", "pydata-sphinx-theme", "sphinxcontrib-spelling"] +docs = ["jupyterlite-sphinx", "myst-parser", "pydata-sphinx-theme (>=0.16)", "sphinx (>=8)", "sphinxcontrib-spelling"] test = ["click", "pre-commit", "pytest (>=7.0)", "pytest-asyncio (>=0.19.0)", "pytest-console-scripts", "rich"] [[package]] @@ -1367,13 +1367,13 @@ jupyter-server = ">=1.1.2" [[package]] name = "jupyter-server" -version = "2.14.2" +version = "2.15.0" description = "The backend—i.e. core services, APIs, and REST endpoints—to Jupyter web applications." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "jupyter_server-2.14.2-py3-none-any.whl", hash = "sha256:47ff506127c2f7851a17bf4713434208fc490955d0e8632e95014a9a9afbeefd"}, - {file = "jupyter_server-2.14.2.tar.gz", hash = "sha256:66095021aa9638ced276c248b1d81862e4c50f292d575920bbe960de1c56b12b"}, + {file = "jupyter_server-2.15.0-py3-none-any.whl", hash = "sha256:872d989becf83517012ee669f09604aa4a28097c0bd90b2f424310156c2cdae3"}, + {file = "jupyter_server-2.15.0.tar.gz", hash = "sha256:9d446b8697b4f7337a1b7cdcac40778babdd93ba614b6d68ab1c0c918f1c4084"}, ] [package.dependencies] @@ -1382,7 +1382,7 @@ argon2-cffi = ">=21.1" jinja2 = ">=3.0.3" jupyter-client = ">=7.4.4" jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" -jupyter-events = ">=0.9.0" +jupyter-events = ">=0.11.0" jupyter-server-terminals = ">=0.4.4" nbconvert = ">=6.4.4" nbformat = ">=5.3.0" @@ -1422,13 +1422,13 @@ test = ["jupyter-server (>=2.0.0)", "pytest (>=7.0)", "pytest-jupyter[server] (> [[package]] name = "jupyterlab" -version = "4.3.3" +version = "4.3.4" description = "JupyterLab computational environment" optional = false python-versions = ">=3.8" files = [ - {file = "jupyterlab-4.3.3-py3-none-any.whl", hash = "sha256:32a8fd30677e734ffcc3916a4758b9dab21b02015b668c60eb36f84357b7d4b1"}, - {file = "jupyterlab-4.3.3.tar.gz", hash = "sha256:76fa39e548fdac94dc1204af5956c556f54c785f70ee26aa47ea08eda4d5bbcd"}, + {file = "jupyterlab-4.3.4-py3-none-any.whl", hash = "sha256:b754c2601c5be6adf87cb5a1d8495d653ffb945f021939f77776acaa94dae952"}, + {file = "jupyterlab-4.3.4.tar.gz", hash = "sha256:f0bb9b09a04766e3423cccc2fc23169aa2ffedcdf8713e9e0fb33cac0b6859d0"}, ] [package.dependencies] @@ -1736,13 +1736,13 @@ files = [ [[package]] name = "nbclient" -version = "0.10.1" +version = "0.10.2" description = "A client library for executing notebooks. Formerly nbconvert's ExecutePreprocessor." optional = false -python-versions = ">=3.8.0" +python-versions = ">=3.9.0" files = [ - {file = "nbclient-0.10.1-py3-none-any.whl", hash = "sha256:949019b9240d66897e442888cfb618f69ef23dc71c01cb5fced8499c2cfc084d"}, - {file = "nbclient-0.10.1.tar.gz", hash = "sha256:3e93e348ab27e712acd46fccd809139e356eb9a31aab641d1a7991a6eb4e6f68"}, + {file = "nbclient-0.10.2-py3-none-any.whl", hash = "sha256:4ffee11e788b4a27fabeb7955547e4318a5298f34342a4bfd01f2e1faaeadc3d"}, + {file = "nbclient-0.10.2.tar.gz", hash = "sha256:90b7fc6b810630db87a6d0c2250b1f0ab4cf4d3c27a299b0cde78a4ed3fd9193"}, ] [package.dependencies] @@ -1753,8 +1753,8 @@ traitlets = ">=5.4" [package.extras] dev = ["pre-commit"] -docs = ["autodoc-traits", "flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "mock", "moto", "myst-parser", "nbconvert (>=7.0.0)", "pytest (>=7.0,<8)", "pytest-asyncio", "pytest-cov (>=4.0)", "sphinx (>=1.7)", "sphinx-book-theme", "sphinxcontrib-spelling", "testpath", "xmltodict"] -test = ["flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "nbconvert (>=7.0.0)", "pytest (>=7.0,<8)", "pytest-asyncio", "pytest-cov (>=4.0)", "testpath", "xmltodict"] +docs = ["autodoc-traits", "flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "mock", "moto", "myst-parser", "nbconvert (>=7.1.0)", "pytest (>=7.0,<8)", "pytest-asyncio", "pytest-cov (>=4.0)", "sphinx (>=1.7)", "sphinx-book-theme", "sphinxcontrib-spelling", "testpath", "xmltodict"] +test = ["flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "nbconvert (>=7.1.0)", "pytest (>=7.0,<8)", "pytest-asyncio", "pytest-cov (>=4.0)", "testpath", "xmltodict"] [[package]] name = "nbconvert" @@ -2109,32 +2109,32 @@ wcwidth = "*" [[package]] name = "psutil" -version = "6.1.0" +version = "6.1.1" description = "Cross-platform lib for process and system monitoring in Python." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "psutil-6.1.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ff34df86226c0227c52f38b919213157588a678d049688eded74c76c8ba4a5d0"}, - {file = "psutil-6.1.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:c0e0c00aa18ca2d3b2b991643b799a15fc8f0563d2ebb6040f64ce8dc027b942"}, - {file = "psutil-6.1.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:000d1d1ebd634b4efb383f4034437384e44a6d455260aaee2eca1e9c1b55f047"}, - {file = "psutil-6.1.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:5cd2bcdc75b452ba2e10f0e8ecc0b57b827dd5d7aaffbc6821b2a9a242823a76"}, - {file = "psutil-6.1.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:045f00a43c737f960d273a83973b2511430d61f283a44c96bf13a6e829ba8fdc"}, - {file = "psutil-6.1.0-cp27-none-win32.whl", hash = "sha256:9118f27452b70bb1d9ab3198c1f626c2499384935aaf55388211ad982611407e"}, - {file = "psutil-6.1.0-cp27-none-win_amd64.whl", hash = "sha256:a8506f6119cff7015678e2bce904a4da21025cc70ad283a53b099e7620061d85"}, - {file = "psutil-6.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6e2dcd475ce8b80522e51d923d10c7871e45f20918e027ab682f94f1c6351688"}, - {file = "psutil-6.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0895b8414afafc526712c498bd9de2b063deaac4021a3b3c34566283464aff8e"}, - {file = "psutil-6.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dcbfce5d89f1d1f2546a2090f4fcf87c7f669d1d90aacb7d7582addece9fb38"}, - {file = "psutil-6.1.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:498c6979f9c6637ebc3a73b3f87f9eb1ec24e1ce53a7c5173b8508981614a90b"}, - {file = "psutil-6.1.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d905186d647b16755a800e7263d43df08b790d709d575105d419f8b6ef65423a"}, - {file = "psutil-6.1.0-cp36-cp36m-win32.whl", hash = "sha256:6d3fbbc8d23fcdcb500d2c9f94e07b1342df8ed71b948a2649b5cb060a7c94ca"}, - {file = "psutil-6.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:1209036fbd0421afde505a4879dee3b2fd7b1e14fee81c0069807adcbbcca747"}, - {file = "psutil-6.1.0-cp37-abi3-win32.whl", hash = "sha256:1ad45a1f5d0b608253b11508f80940985d1d0c8f6111b5cb637533a0e6ddc13e"}, - {file = "psutil-6.1.0-cp37-abi3-win_amd64.whl", hash = "sha256:a8fb3752b491d246034fa4d279ff076501588ce8cbcdbb62c32fd7a377d996be"}, - {file = "psutil-6.1.0.tar.gz", hash = "sha256:353815f59a7f64cdaca1c0307ee13558a0512f6db064e92fe833784f08539c7a"}, + {file = "psutil-6.1.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:9ccc4316f24409159897799b83004cb1e24f9819b0dcf9c0b68bdcb6cefee6a8"}, + {file = "psutil-6.1.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ca9609c77ea3b8481ab005da74ed894035936223422dc591d6772b147421f777"}, + {file = "psutil-6.1.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:8df0178ba8a9e5bc84fed9cfa61d54601b371fbec5c8eebad27575f1e105c0d4"}, + {file = "psutil-6.1.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:1924e659d6c19c647e763e78670a05dbb7feaf44a0e9c94bf9e14dfc6ba50468"}, + {file = "psutil-6.1.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:018aeae2af92d943fdf1da6b58665124897cfc94faa2ca92098838f83e1b1bca"}, + {file = "psutil-6.1.1-cp27-none-win32.whl", hash = "sha256:6d4281f5bbca041e2292be3380ec56a9413b790579b8e593b1784499d0005dac"}, + {file = "psutil-6.1.1-cp27-none-win_amd64.whl", hash = "sha256:c777eb75bb33c47377c9af68f30e9f11bc78e0f07fbf907be4a5d70b2fe5f030"}, + {file = "psutil-6.1.1-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:fc0ed7fe2231a444fc219b9c42d0376e0a9a1a72f16c5cfa0f68d19f1a0663e8"}, + {file = "psutil-6.1.1-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0bdd4eab935276290ad3cb718e9809412895ca6b5b334f5a9111ee6d9aff9377"}, + {file = "psutil-6.1.1-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b6e06c20c05fe95a3d7302d74e7097756d4ba1247975ad6905441ae1b5b66003"}, + {file = "psutil-6.1.1-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97f7cb9921fbec4904f522d972f0c0e1f4fabbdd4e0287813b21215074a0f160"}, + {file = "psutil-6.1.1-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:33431e84fee02bc84ea36d9e2c4a6d395d479c9dd9bba2376c1f6ee8f3a4e0b3"}, + {file = "psutil-6.1.1-cp36-cp36m-win32.whl", hash = "sha256:384636b1a64b47814437d1173be1427a7c83681b17a450bfc309a1953e329603"}, + {file = "psutil-6.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:8be07491f6ebe1a693f17d4f11e69d0dc1811fa082736500f649f79df7735303"}, + {file = "psutil-6.1.1-cp37-abi3-win32.whl", hash = "sha256:eaa912e0b11848c4d9279a93d7e2783df352b082f40111e078388701fd479e53"}, + {file = "psutil-6.1.1-cp37-abi3-win_amd64.whl", hash = "sha256:f35cfccb065fff93529d2afb4a2e89e363fe63ca1e4a5da22b603a85833c2649"}, + {file = "psutil-6.1.1.tar.gz", hash = "sha256:cf8496728c18f2d0b45198f06895be52f36611711746b7f30c464b422b50e2f5"}, ] [package.extras] -dev = ["black", "check-manifest", "coverage", "packaging", "pylint", "pyperf", "pypinfo", "pytest-cov", "requests", "rstcheck", "ruff", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "virtualenv", "wheel"] +dev = ["abi3audit", "black", "check-manifest", "coverage", "packaging", "pylint", "pyperf", "pypinfo", "pytest-cov", "requests", "rstcheck", "ruff", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "virtualenv", "vulture", "wheel"] test = ["pytest", "pytest-xdist", "setuptools"] [[package]] @@ -2150,13 +2150,13 @@ files = [ [[package]] name = "publicsuffixlist" -version = "1.0.2.20241216" +version = "1.0.2.20241218" description = "publicsuffixlist implement" optional = true python-versions = ">=3.5" files = [ - {file = "publicsuffixlist-1.0.2.20241216-py2.py3-none-any.whl", hash = "sha256:8756ea50aab9c568221db353587545700336f251dfd049031aa8dcd65bed0e27"}, - {file = "publicsuffixlist-1.0.2.20241216.tar.gz", hash = "sha256:b74e2c9e381e6c438700c8a9c31b5336ce7c0584e5162790b104b5fd27c0a262"}, + {file = "publicsuffixlist-1.0.2.20241218-py2.py3-none-any.whl", hash = "sha256:4e1321b516893d31f5ff4d4e95fc62aa16223e8e1a34335199e89cc1a013932d"}, + {file = "publicsuffixlist-1.0.2.20241218.tar.gz", hash = "sha256:5aa4ed49e669090174c0b7fd1b050a6e111fd48bac758f46361eb0619f8fe351"}, ] [package.extras] @@ -3570,4 +3570,4 @@ virustotal = ["validators"] [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "a6a9b055f1acb36c5fc59a6fa389a84f79cdb1bf48389305ab08b89d86e37e4c" +content-hash = "d1948b993a9b8f5c1c8e8bf8dad7acebc7c5a73a2e556708765c20c58625b2ac" diff --git a/pyproject.toml b/pyproject.toml index 18800fe..39fdeec 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,7 +61,7 @@ docutils = {version = "^0.21.1", optional = true, python = ">=3.10"} recommonmark = {version = "^0.7.1", optional = true, python = ">=3.10"} reportlab = {version = "^4.2.5", optional = true} pyfaup = {version = "^1.2", optional = true} -publicsuffixlist = {version = "^1.0.2.20241216", optional = true} +publicsuffixlist = {version = "^1.0.2.20241218", optional = true} urllib3 = {extras = ["brotli"], version = "*", optional = true} Sphinx = [ {version = "^8", python = ">=3.10", optional = true} @@ -84,7 +84,7 @@ ipython = [ {version = "^8.18.0", python = "<3.10"}, {version = "^8.19.0", python = ">=3.10"} ] -jupyterlab = "^4.3.3" +jupyterlab = "^4.3.4" types-requests = "^2.32.0.20241016" types-python-dateutil = "^2.9.0.20241206" types-redis = "^4.6.0.20241004" From 17cac2b29c378b78f25ec165f100d0a3b6a4f3ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Vinot?= Date: Fri, 20 Dec 2024 15:38:25 +0100 Subject: [PATCH 11/11] chg: Make python 3.9 happy --- tests/test_analyst_data.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/test_analyst_data.py b/tests/test_analyst_data.py index 4672960..eaf9b34 100644 --- a/tests/test_analyst_data.py +++ b/tests/test_analyst_data.py @@ -1,5 +1,7 @@ #!/usr/bin/env python +from __future__ import annotations + import unittest from pymisp import (MISPAttribute, MISPEvent, MISPEventReport, MISPNote, MISPObject, MISPOpinion) @@ -67,7 +69,7 @@ class TestAnalystData(unittest.TestCase): misp_object = MISPObject('file') misp_object.add_attribute('filename', 'foo.exe') self._attach_analyst_data(misp_object.attributes[0]) - + def _attach_analyst_data( self, container: MISPAttribute | MISPEvent | MISPEventReport | MISPObject) -> None: object_type = container._analyst_data_object_type @@ -96,7 +98,7 @@ class TestAnalystData(unittest.TestCase): self.assertEqual(misp_note1.object_type, object_type) self.assertEqual(misp_note1.object_uuid, container.uuid) self.assertEqual(misp_note1.note, 'note1') - + self.assertEqual(misp_note2.object_type, 'Opinion') self.assertEqual(misp_note2.object_uuid, opinion2.uuid) self.assertEqual(misp_note2.note, 'note2') @@ -114,9 +116,8 @@ class TestAnalystData(unittest.TestCase): self.assertEqual(misp_opinion2.object_uuid, container.uuid) self.assertEqual(misp_opinion2.opinion, 50) self.assertEqual(misp_opinion2.comment, 'Neutral') - + self.assertEqual(misp_opinion3.object_type, 'Note') self.assertEqual(misp_opinion3.object_uuid, note3.uuid) self.assertEqual(misp_opinion3.opinion, 75) self.assertEqual(misp_opinion3.comment, 'Agree') -