assemblyline-core 4.6.1.dev16__tar.gz → 4.6.1.dev21__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/PKG-INFO +1 -1
  2. assemblyline_core-4.6.1.dev21/assemblyline_core/VERSION +1 -0
  3. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/dispatching/dispatcher.py +35 -8
  4. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/scaler/controllers/docker_ctl.py +9 -4
  5. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core.egg-info/PKG-INFO +1 -1
  6. assemblyline_core-4.6.1.dev16/assemblyline_core/VERSION +0 -1
  7. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/LICENCE.md +0 -0
  8. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/README.md +0 -0
  9. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/__init__.py +0 -0
  10. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/alerter/__init__.py +0 -0
  11. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/alerter/processing.py +0 -0
  12. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/alerter/run_alerter.py +0 -0
  13. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/archiver/__init__.py +0 -0
  14. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/archiver/run_archiver.py +0 -0
  15. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/badlist_client.py +0 -0
  16. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/dispatching/__init__.py +0 -0
  17. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/dispatching/__main__.py +0 -0
  18. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/dispatching/client.py +0 -0
  19. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/dispatching/schedules.py +0 -0
  20. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/dispatching/timeout.py +0 -0
  21. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/expiry/__init__.py +0 -0
  22. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/expiry/run_expiry.py +0 -0
  23. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/ingester/__init__.py +0 -0
  24. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/ingester/__main__.py +0 -0
  25. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/ingester/constants.py +0 -0
  26. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/ingester/ingester.py +0 -0
  27. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/metrics/__init__.py +0 -0
  28. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/metrics/es_metrics.py +0 -0
  29. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/metrics/heartbeat_formatter.py +0 -0
  30. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/metrics/helper.py +0 -0
  31. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/metrics/metrics_server.py +0 -0
  32. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/metrics/run_heartbeat_manager.py +0 -0
  33. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/metrics/run_metrics_aggregator.py +0 -0
  34. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/metrics/run_statistics_aggregator.py +0 -0
  35. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/plumber/__init__.py +0 -0
  36. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/plumber/run_plumber.py +0 -0
  37. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/replay/__init__.py +0 -0
  38. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/replay/client.py +0 -0
  39. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/replay/creator/__init__.py +0 -0
  40. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/replay/creator/run.py +0 -0
  41. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/replay/creator/run_worker.py +0 -0
  42. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/replay/loader/__init__.py +0 -0
  43. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/replay/loader/run.py +0 -0
  44. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/replay/loader/run_worker.py +0 -0
  45. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/replay/replay.py +0 -0
  46. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/safelist_client.py +0 -0
  47. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/scaler/__init__.py +0 -0
  48. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/scaler/collection.py +0 -0
  49. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/scaler/controllers/__init__.py +0 -0
  50. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/scaler/controllers/interface.py +0 -0
  51. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/scaler/controllers/kubernetes_ctl.py +0 -0
  52. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/scaler/run_scaler.py +0 -0
  53. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/scaler/scaler_server.py +0 -0
  54. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/server_base.py +0 -0
  55. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/signature_client.py +0 -0
  56. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/submission_client.py +0 -0
  57. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/tasking_client.py +0 -0
  58. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/updater/__init__.py +0 -0
  59. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/updater/helper.py +0 -0
  60. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/updater/run_updater.py +0 -0
  61. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/vacuum/__init__.py +0 -0
  62. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/vacuum/crawler.py +0 -0
  63. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/vacuum/department_map.py +0 -0
  64. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/vacuum/safelist.py +0 -0
  65. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/vacuum/stream_map.py +0 -0
  66. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/vacuum/worker.py +0 -0
  67. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/workflow/__init__.py +0 -0
  68. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core/workflow/run_workflow.py +0 -0
  69. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core.egg-info/SOURCES.txt +0 -0
  70. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core.egg-info/dependency_links.txt +0 -0
  71. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core.egg-info/requires.txt +0 -0
  72. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/assemblyline_core.egg-info/top_level.txt +0 -0
  73. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/setup.cfg +0 -0
  74. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/setup.py +0 -0
  75. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/test/test_alerter.py +0 -0
  76. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/test/test_badlist_client.py +0 -0
  77. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/test/test_dispatcher.py +0 -0
  78. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/test/test_expiry.py +0 -0
  79. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/test/test_plumber.py +0 -0
  80. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/test/test_replay.py +0 -0
  81. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/test/test_safelist_client.py +0 -0
  82. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/test/test_scaler.py +0 -0
  83. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/test/test_scheduler.py +0 -0
  84. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/test/test_signature_client.py +0 -0
  85. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/test/test_simulation.py +0 -0
  86. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/test/test_tasking_client.py +0 -0
  87. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/test/test_vacuum.py +0 -0
  88. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/test/test_worker_ingest.py +0 -0
  89. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/test/test_worker_submit.py +0 -0
  90. {assemblyline_core-4.6.1.dev16 → assemblyline_core-4.6.1.dev21}/test/test_workflow.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: assemblyline-core
3
- Version: 4.6.1.dev16
3
+ Version: 4.6.1.dev21
4
4
  Summary: Assemblyline 4 - Core components
5
5
  Home-page: https://github.com/CybercentreCanada/assemblyline-core/
6
6
  Author: CCCS Assemblyline development team
@@ -0,0 +1 @@
1
+ 4.6.1.dev21
@@ -54,7 +54,7 @@ from assemblyline.odm.messages.task import Task as ServiceTask
54
54
  from assemblyline.odm.models.error import Error
55
55
  from assemblyline.odm.models.result import Result
56
56
  from assemblyline.odm.models.service import Service
57
- from assemblyline.odm.models.submission import Submission
57
+ from assemblyline.odm.models.submission import Submission, TraceEvent
58
58
  from assemblyline.odm.models.user import User
59
59
  from assemblyline.remote.datatypes.events import EventWatcher
60
60
  from assemblyline.remote.datatypes.exporting_counter import export_metrics_once
@@ -311,6 +311,16 @@ class SubmissionTask:
311
311
  """Shortcut to read submission SID"""
312
312
  return self.submission.sid
313
313
 
314
+ def trace(self, event_type: str, sha256: Optional[str] = None,
315
+ service: Optional[str] = None, message: Optional[str] = None) -> None:
316
+ if self.submission.params.trace:
317
+ self.submission.tracing_events.append(TraceEvent({
318
+ 'event_type': event_type,
319
+ 'service': service,
320
+ 'file': sha256,
321
+ 'message': message,
322
+ }))
323
+
314
324
  def forbid_for_children(self, sha256: str, service_name: str):
315
325
  """Mark that children of a given file should not be routed to a service."""
316
326
  try:
@@ -729,6 +739,7 @@ class Dispatcher(ThreadedCoreBase):
729
739
 
730
740
  if not self.active_submissions.exists(sid):
731
741
  self.log.info("[%s] New submission received", sid)
742
+ task.trace('submission_start')
732
743
  self.active_submissions.add(sid, {
733
744
  'completed_queue': task.completed_queue,
734
745
  'submission': submission.as_primitives()
@@ -742,6 +753,7 @@ class Dispatcher(ThreadedCoreBase):
742
753
  }).as_primitives())
743
754
 
744
755
  else:
756
+ task.trace('submission_start', message='Received a pre-existing submission')
745
757
  self.log.warning(f"[{sid}] Received a pre-existing submission, check if it is complete")
746
758
 
747
759
  # Refresh the quota hold
@@ -840,6 +852,7 @@ class Dispatcher(ThreadedCoreBase):
840
852
  sid = submission.sid
841
853
  if self.apm_client:
842
854
  elasticapm.label(sid=sid, sha256=sha256)
855
+ task.trace('dispatch_file', sha256=sha256)
843
856
 
844
857
  file_depth: int = task.file_depth[sha256]
845
858
  # If its the first time we've seen this file, we won't have a schedule for it
@@ -859,6 +872,8 @@ class Dispatcher(ThreadedCoreBase):
859
872
  task.file_schedules[sha256] = self.scheduler.build_schedule(submission, file_info.type,
860
873
  file_depth, forbidden_services,
861
874
  task.service_access_control)
875
+ task.trace('schedule_built', sha256=sha256, message=str(task.file_schedules[sha256]))
876
+
862
877
 
863
878
  file_info = task.file_info[sha256]
864
879
  schedule: list = list(task.file_schedules[sha256])
@@ -990,9 +1005,9 @@ class Dispatcher(ThreadedCoreBase):
990
1005
 
991
1006
  if sent or enqueued or running:
992
1007
  # If we have confirmed that we are waiting, or have taken an action, log that.
993
- self.log.info(f"[{sid}] File {sha256} sent to: {sent} "
994
- f"already in queue for: {enqueued} "
995
- f"running on: {running}")
1008
+ logs = f"sent to: {sent} already in queue for: {enqueued} running on: {running}"
1009
+ self.log.info(f"[{sid}] File {sha256} {logs}")
1010
+ task.trace('dispatch_file_result', sha256=sha256, message=logs)
996
1011
  return False
997
1012
  elif skipped:
998
1013
  # Not waiting for anything, and have started skipping what is left over
@@ -1007,10 +1022,12 @@ class Dispatcher(ThreadedCoreBase):
1007
1022
 
1008
1023
  self.counter.increment('files_completed')
1009
1024
  if len(task.queue_keys) > 0 or len(task.running_services) > 0:
1010
- self.log.info(f"[{sid}] Finished processing file '{sha256}', submission incomplete "
1011
- f"(queued: {len(task.queue_keys)} running: {len(task.running_services)})")
1025
+ logs = f"queued: {len(task.queue_keys)} running: {len(task.running_services)}"
1026
+ self.log.info(f"[{sid}] Finished processing file '{sha256}', submission incomplete ({logs})")
1027
+ task.trace('file_finished', sha256=sha256, message=logs)
1012
1028
  else:
1013
1029
  self.log.info(f"[{sid}] Finished processing file '{sha256}', checking if submission complete")
1030
+ task.trace('file_finished', sha256=sha256)
1014
1031
  return self.check_submission(task)
1015
1032
  return False
1016
1033
 
@@ -1104,14 +1121,17 @@ class Dispatcher(ThreadedCoreBase):
1104
1121
  # file isn't done yet, and hasn't been filtered by any of the previous few steps
1105
1122
  # poke those files.
1106
1123
  if pending_files:
1124
+ task.trace('submission_check', message=f"Dispatching {list(pending_files)}")
1107
1125
  self.log.debug(f"[{task.submission.sid}] Dispatching {len(pending_files)} files: {list(pending_files)}")
1108
1126
  for file_hash in pending_files:
1109
1127
  if self.dispatch_file(task, file_hash):
1110
1128
  return True
1111
1129
  elif processing_files:
1130
+ task.trace('submission_check', message=f"Waiting for {list(processing_files)}")
1112
1131
  self.log.debug("[%s] Not finished waiting on %d files: %s",
1113
1132
  task.submission.sid, len(processing_files), list(processing_files))
1114
1133
  else:
1134
+ task.trace('submission_check', message="Finished")
1115
1135
  self.log.debug("[%s] Finalizing submission.", task.submission.sid)
1116
1136
  max_score = max(file_scores.values()) if file_scores else 0 # Submissions with no results have no score
1117
1137
  if self.tasks.pop(task.sid, None):
@@ -1341,6 +1361,8 @@ class Dispatcher(ThreadedCoreBase):
1341
1361
  self.log.warning(f'[{message.sid}] Service started missing data.')
1342
1362
  continue
1343
1363
 
1364
+ task.trace('service_start', sha256=message.sha, service=message.service_name,
1365
+ message=message.worker_id)
1344
1366
  key = (message.sha, message.service_name)
1345
1367
  if task.queue_keys.pop(key, None) is not None:
1346
1368
  # If this task is already finished (result message processed before start
@@ -1384,8 +1406,9 @@ class Dispatcher(ThreadedCoreBase):
1384
1406
  continue
1385
1407
 
1386
1408
  if task:
1387
- task.service_logs[(message.sha, message.service_name)].append(
1388
- f'Service timeout at {now_as_iso()} on worker {message.worker_id}')
1409
+ log = f'Service timeout at {now_as_iso()} on worker {message.worker_id}'
1410
+ task.service_logs[(message.sha, message.service_name)].append(log)
1411
+ task.trace('service_timeout', sha256=message.sha, service=message.service_name, message=log)
1389
1412
  self.timeout_service(task, message.sha, message.service_name, message.worker_id)
1390
1413
 
1391
1414
  elif kind == Action.dispatch_file:
@@ -1429,6 +1452,8 @@ class Dispatcher(ThreadedCoreBase):
1429
1452
  self.log.exception(f"Malformed result message, missing key: {missing}")
1430
1453
  return
1431
1454
 
1455
+ task.trace('process_result', sha256=sha256, service=service_name, message="Processing result " + summary.key)
1456
+
1432
1457
  # Add SHA256s of files that allowed to run regardless of Dynamic Recursion Prevention
1433
1458
  task.dynamic_recursion_bypass = task.dynamic_recursion_bypass.union(set(dynamic_recursion_bypass))
1434
1459
 
@@ -1599,6 +1624,8 @@ class Dispatcher(ThreadedCoreBase):
1599
1624
  @elasticapm.capture_span(span_type='dispatcher')
1600
1625
  def process_service_error(self, task: SubmissionTask, error_key, error: Error):
1601
1626
  self.log.info(f'[{task.submission.sid}] Error from service {error.response.service_name} on {error.sha256}')
1627
+ task.trace('process_error', sha256=error.sha256, service=error.response.service_name,
1628
+ message="Service error " + error_key)
1602
1629
  self.clear_timeout(task, error.sha256, error.response.service_name)
1603
1630
  key = (error.sha256, error.response.service_name)
1604
1631
  if error.response.status == "FAIL_NONRECOVERABLE":
@@ -1,13 +1,16 @@
1
1
  from __future__ import annotations
2
- import docker
2
+
3
3
  import os
4
4
  import threading
5
5
  import time
6
- from collections import defaultdict
7
- from typing import List, Optional, Tuple, Dict
8
6
  import uuid
7
+ from collections import defaultdict
8
+ from typing import Dict, List, Optional, Tuple
9
+
10
+ import docker
9
11
 
10
12
  from assemblyline.odm.models.service import DependencyConfig, DockerConfig
13
+
11
14
  from .interface import ControllerInterface, ServiceControlError
12
15
 
13
16
  # Where to find the update directory inside this container.
@@ -382,7 +385,7 @@ class DockerController(ControllerInterface):
382
385
  container.labels]
383
386
  running = running[0:-delta]
384
387
  for container in running:
385
- container.kill()
388
+ container.kill(signal='SIGTERM')
386
389
 
387
390
  if delta > 0:
388
391
  # Start delta instances of the service
@@ -531,6 +534,7 @@ class DockerController(ControllerInterface):
531
534
  dynamically rather than in prepare_network.
532
535
  """
533
536
  from docker.errors import NotFound
537
+
534
538
  # Create network for service
535
539
  network_name = f'{COMPOSE_PROJECT}_service-net-{service_name}'
536
540
  try:
@@ -553,6 +557,7 @@ class DockerController(ControllerInterface):
553
557
  This lets us override the auth_config on a per image basis.
554
558
  """
555
559
  from docker.errors import ImageNotFound
560
+
556
561
  # Split the image string into "[registry/]image_name" and "tag"
557
562
  repository, _, tag = service.container_config.image.rpartition(':')
558
563
  if '/' in tag:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: assemblyline-core
3
- Version: 4.6.1.dev16
3
+ Version: 4.6.1.dev21
4
4
  Summary: Assemblyline 4 - Core components
5
5
  Home-page: https://github.com/CybercentreCanada/assemblyline-core/
6
6
  Author: CCCS Assemblyline development team
@@ -1 +0,0 @@
1
- 4.6.1.dev16