Repository: log2timeline/dftimewolf

Issue:
Change AttributeContainer "attributes" to a Dict and rename
The container base class `dftimewolf.lib.containers.interface.AttributeContainer` has a generic `attributes` attribute for subclasses to use as "A list of generic attributes that can be used for passing metadata between collection/processing module and output modules."

This attribute is currently a list but looking at current uses of this feature, it would be more useful as a Dict. 

Also the term "attributes" is overloaded in this context and leads to confusing code.

As this feature is only used in a couple of modules I suggest renaming it to `container_meta` or similar to make it clearer what this feature should be used for.

Discussion:

Patch:
diff --git a/dftimewolf/lib/containers/containers.py b/dftimewolf/lib/containers/containers.py
index ef0557f..555e18f 100644
--- a/dftimewolf/lib/containers/containers.py
+++ b/dftimewolf/lib/containers/containers.py
@@ -68,7 +68,7 @@ class Report(interface.AttributeContainer):
       module_name: str,
       text: str,
       text_format: str = 'plaintext',
-      attributes: Optional[List[Dict[str, Any]]] = None) -> None:
+      metadata: Optional[Dict[str, Any]] = None) -> None:
     """Initializes the analysis report.
 
     Args:
@@ -76,10 +76,10 @@ class Report(interface.AttributeContainer):
       text (str): report text.
       text_format (str): format of text in the report. Must be either
         'plaintext' or 'markdown'.
-      attributes (list): attribute list of dicts that must contain 'name',
-        'type', 'values' keys.
+      metadata (dict): a dict for optional report metadata to be used by
+        exporter modules.
     """
-    super(Report, self).__init__(attributes=attributes)
+    super(Report, self).__init__(metadata=metadata)
     self.module_name = module_name
     self.text = text
     self.text_format = text_format
diff --git a/dftimewolf/lib/containers/interface.py b/dftimewolf/lib/containers/interface.py
index b31f6e7..4b12d28 100644
--- a/dftimewolf/lib/containers/interface.py
+++ b/dftimewolf/lib/containers/interface.py
@@ -17,23 +17,23 @@ class AttributeContainer():
   and private class members are not to be serialized.
 
   Attributes:
-    attributes: A list of generic attributes that can be used for passing
+    metadata: A dict of container metadata that can be used for passing
       metadata between collection/processing module and output modules.
   """
   CONTAINER_TYPE = None  # type: str
-  attributes = []  # type: List[Dict[str, Any]]
+  metadata = {}  # type: Dict[str, Any]
 
-  def __init__(self, attributes: Optional[List[Dict[str, Any]]] = None):
+  def __init__(self, metadata: Optional[Dict[str, Any]] = None):
     """Initializes an AttributeContainer.
 
     Args:
-      attributes: A list of generic attributes that can be used for passing
-        metadata between collection/processing module and output modules.
+    metadata: A dict of container metadata that can be used for passing
+      metadata between collection/processing module and output modules.
     """
-    if attributes is None:
-      self.attributes = []
+    if metadata is None:
+      self.metadata = {}
     else:
-      self.attributes = attributes
+      self.metadata = metadata
 
   # TODO: note that this method is only used by tests.
   def GetAttributeNames(self) -> List[str]:
diff --git a/dftimewolf/lib/enhancers/timesketch.py b/dftimewolf/lib/enhancers/timesketch.py
index ac7e9f5..170fd7a 100644
--- a/dftimewolf/lib/enhancers/timesketch.py
+++ b/dftimewolf/lib/enhancers/timesketch.py
@@ -474,10 +474,10 @@ class TimesketchEnhancer(module.BaseModule):
         completed_ids.add(result.id)
       summary_lines.append(self._formatter.IndentEnd())
 
-    report_attributes = [{'update_comment': True}]
+    report_attributes = {'update_comment': True}
     self.state.StoreContainer(containers.Report(
         module_name='TimesketchEnhancer', text_format=self._formatter.FORMAT,
-        text='\n'.join(summary_lines), attributes=report_attributes))
+        text='\n'.join(summary_lines), metadata=report_attributes))
     self.logger.info('Analyzer reports generated')
 
 


Test patch:
diff --git a/tests/lib/containers/containers.py b/tests/lib/containers/containers.py
index e36ea4a..28bb2e9 100644
--- a/tests/lib/containers/containers.py
+++ b/tests/lib/containers/containers.py
@@ -13,7 +13,7 @@ class ReportDataTest(unittest.TestCase):
     attribute_container = containers.Report(module_name='name', text='text')
 
     expected_attribute_names = [
-        'attributes', 'module_name', 'text', 'text_format']
+        'metadata', 'module_name', 'text', 'text_format']
 
     attribute_names = sorted(attribute_container.GetAttributeNames())
 
@@ -30,7 +30,7 @@ class ThreatIntelligenceDataTest(unittest.TestCase):
         indicator='.*',
         path='/')
 
-    expected_attribute_names = ['attributes', 'indicator', 'name', 'path']
+    expected_attribute_names = ['indicator', 'metadata', 'name', 'path']
 
     attribute_names = sorted(attribute_container.GetAttributeNames())
 
@@ -44,7 +44,7 @@ class FSPathDataTest(unittest.TestCase):
     """Tests the GetAttributeNames function."""
     attribute_container = containers.FSPath(path='name')
 
-    expected_attribute_names = ['attributes', 'path']
+    expected_attribute_names = ['metadata', 'path']
 
     attribute_names = sorted(attribute_container.GetAttributeNames())
 
@@ -58,7 +58,7 @@ class RemoteFSPathDataTest(unittest.TestCase):
     """Tests the GetAttributeNames function."""
     attribute_container = containers.RemoteFSPath(path='name', hostname='host')
 
-    expected_attribute_names = ['attributes', 'hostname', 'path']
+    expected_attribute_names = ['hostname', 'metadata', 'path']
 
     attribute_names = sorted(attribute_container.GetAttributeNames())
 
@@ -74,7 +74,7 @@ class OsqueryQueryDataTest(unittest.TestCase):
         query='', name='', description='', platforms=[])
 
     expected_attribute_names = [
-        'attributes', 'description', 'name', 'platforms', 'query']
+        'description', 'metadata', 'name', 'platforms', 'query']
 
     attribute_names = sorted(attribute_container.GetAttributeNames())
 
diff --git a/tests/lib/containers/interface.py b/tests/lib/containers/interface.py
index fbdc8a0..7d14071 100644
--- a/tests/lib/containers/interface.py
+++ b/tests/lib/containers/interface.py
@@ -17,7 +17,7 @@ class AttributeContainerTest(unittest.TestCase):
     attribute_container.attribute_value = 'attribute_value'
 
     expected_attribute_names = [
-        'attribute_name', 'attribute_value', 'attributes']
+        'attribute_name', 'attribute_value', 'metadata']
 
     attribute_names = sorted(attribute_container.GetAttributeNames())