assemblyline-v4-service 4.6.1.dev231__py3-none-any.whl → 4.6.1.dev248__py3-none-any.whl

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.
@@ -1 +1 @@
1
- 4.6.1.dev231
1
+ 4.6.1.dev248
@@ -164,12 +164,11 @@ class PrivilegedServiceAPI:
164
164
  def get_safelist(self, tag_list=None):
165
165
  if DEVELOPMENT_MODE:
166
166
  return {}
167
- tag_types = None
168
167
 
169
168
  if tag_list and not isinstance(tag_list, list):
170
169
  raise ValueError("Parameter tag_list should be a list of strings.")
171
170
 
172
- return self.safelist_client.get_safelisted_tags(tag_types)
171
+ return self.safelist_client.get_safelisted_tags(tag_list)
173
172
 
174
173
  def lookup_safelist(self, qhash):
175
174
  if DEVELOPMENT_MODE:
@@ -2,7 +2,8 @@ from __future__ import annotations
2
2
 
3
3
  import json
4
4
  import logging
5
- from typing import TYPE_CHECKING, Any, Dict, List, Optional, TextIO, Union
5
+ from enum import Enum
6
+ from typing import TYPE_CHECKING, Any, Dict, List, Literal, Optional, TextIO, Union
6
7
 
7
8
  from assemblyline.common import log as al_log
8
9
  from assemblyline.common.attack_map import attack_map, group_map, revoke_map, software_map
@@ -39,7 +40,8 @@ BODY_FORMAT = StringTable('BODY_FORMAT', [
39
40
  ('MULTI', 9),
40
41
  ('DIVIDER', 10), # This is not a real result section and can only be use inside a multi section
41
42
  ('ORDERED_KEY_VALUE', 11),
42
- ('TIMELINE', 12)
43
+ ('TIMELINE', 12),
44
+ ('SANDBOX', 13),
43
45
  ])
44
46
 
45
47
  # This is a StringTable representation of the PROMOTE_TO set of keys in
@@ -410,6 +412,542 @@ class ProcessTreeSectionBody(SectionBody):
410
412
  self._data.append(process.as_primitives())
411
413
 
412
414
 
415
+ class SandboxMachineMetadata:
416
+ """Metadata about the machine where the sandbox analysis took place."""
417
+
418
+ def __init__(
419
+ self,
420
+ # The IP of the machine used for analysis.
421
+ ip: Optional[str] = None,
422
+
423
+ # The hypervisor of the machine used for analysis.
424
+ hypervisor: Optional[str] = None,
425
+
426
+ # The name of the machine used for analysis.
427
+ hostname: Optional[str] = None,
428
+
429
+ # The platform of the machine used for analysis.
430
+ platform: Optional[str] = None,
431
+
432
+ # The version of the operating system of the machine used for analysis.
433
+ version: Optional[str] = None,
434
+
435
+ # The architecture of the machine used for analysis.
436
+ architecture: Optional[str] = None,
437
+ ):
438
+ self.ip = ip
439
+ self.hypervisor = hypervisor
440
+ self.hostname = hostname
441
+ self.platform = platform
442
+ self.version = version
443
+ self.architecture = architecture
444
+
445
+ def as_primitives(self) -> Dict:
446
+ """Return a JSON-serializable representation."""
447
+ return {
448
+ "ip": self.ip,
449
+ "hypervisor": self.hypervisor,
450
+ "hostname": self.hostname,
451
+ "platform": self.platform,
452
+ "version": self.version,
453
+ "architecture": self.architecture,
454
+ }
455
+
456
+
457
+ class SandboxAnalysisMetadata:
458
+ """Metadata regarding the sandbox analysis task."""
459
+
460
+ def __init__(
461
+ self,
462
+ # The ID used for identifying the analysis task.
463
+ task_id: Optional[str] = None,
464
+
465
+ # The start time of the analysis (ISO format).
466
+ start_time: str = "",
467
+
468
+ # The end time of the analysis (ISO format).
469
+ end_time: Optional[str] = None,
470
+
471
+ # The routing used in the sandbox setup. (e.g., Spoofed, Internet, Tor, VPN)
472
+ routing: Optional[str] = None,
473
+
474
+ # The resolution used for the analysis.
475
+ window_size: Optional[str] = None,
476
+ ):
477
+ self.task_id = task_id
478
+ self.start_time = start_time
479
+ self.end_time = end_time
480
+ self.routing = routing
481
+ self.window_size = window_size
482
+
483
+ def as_primitives(self) -> Dict:
484
+ """Return a JSON-serializable representation."""
485
+ return {
486
+ "task_id": self.task_id,
487
+ "start_time": self.start_time,
488
+ "end_time": self.end_time,
489
+ "routing": self.routing,
490
+ "window_size": self.window_size,
491
+ }
492
+
493
+
494
+ class SandboxProcessItem:
495
+ """Represents a process observed during sandbox execution."""
496
+
497
+ def __init__(
498
+ self,
499
+
500
+ # The image of the process. Default: "<unknown_image>".
501
+ image: str,
502
+
503
+ # The time of creation for the process. (ISO date format)
504
+ start_time: str,
505
+
506
+ # The process ID of the parent process.
507
+ ppid: Optional[int] = None,
508
+
509
+ # The process ID.
510
+ pid: Optional[int] = None,
511
+
512
+ # The command line that the process ran.
513
+ command_line: Optional[str] = None,
514
+
515
+ # The time of termination for the process. (ISO date format)
516
+ end_time: Optional[str] = None,
517
+
518
+ # The integrity level of the process.
519
+ integrity_level: Optional[str] = None,
520
+
521
+ # The hash of the file run.
522
+ image_hash: Optional[str] = None,
523
+
524
+ # The original name of the file.
525
+ original_file_name: Optional[str] = None,
526
+
527
+ # Whether this process was safelisted.
528
+ safelisted: Optional[bool] = False,
529
+
530
+ # Number of files this process interacted with
531
+ file_count: int = 0,
532
+
533
+ # Number of registries this process interacted with
534
+ registry_count: int = 0,
535
+ ):
536
+ # ----------------------------
537
+ # Core process information
538
+ # ----------------------------
539
+ self.image = image or "<unknown_image>"
540
+ self.start_time = start_time
541
+
542
+ # Parent process information
543
+ self.ppid = ppid
544
+
545
+ # Current process information
546
+ self.pid = pid
547
+ self.command_line = command_line
548
+ self.end_time = end_time
549
+ self.integrity_level = integrity_level
550
+ self.image_hash = image_hash
551
+ self.original_file_name = original_file_name
552
+ self.safelisted = safelisted
553
+
554
+ # ----------------------------
555
+ # Relationships & statistics
556
+ # ----------------------------
557
+ self.file_count = file_count
558
+ self.registry_count = registry_count
559
+
560
+ def as_primitives(self) -> Dict:
561
+ """Return a JSON-serializable dictionary representation of this process."""
562
+ return {
563
+ "image": self.image,
564
+ "start_time": self.start_time,
565
+ "ppid": self.ppid,
566
+ "pid": self.pid,
567
+ "command_line": self.command_line,
568
+ "end_time": self.end_time,
569
+ "integrity_level": self.integrity_level,
570
+ "image_hash": self.image_hash,
571
+ "original_file_name": self.original_file_name,
572
+ "safelisted": self.safelisted,
573
+ "file_count": self.file_count,
574
+ "registry_count": self.registry_count,
575
+ }
576
+
577
+
578
+ LookupType = Literal[
579
+ "A", "AAAA", "AFSDB", "APL", "CAA", "CDNSKEY", "CDS", "CERT", "CNAME", "CSYNC",
580
+ "DHCID", "DLV", "DNAME", "DNSKEY", "DS", "EUI48", "EUI64", "HINFO", "HIP",
581
+ "HTTPS", "IPSECKEY", "KEY", "KX", "LOC", "MX", "NAPTR", "NS", "NSEC", "NSEC3",
582
+ "NSEC3PARAM", "OPENPGPKEY", "PTR", "RRSIG", "RP", "SIG", "SMIMEA", "SOA",
583
+ "SRV", "SSHFP", "SVCB", "TA", "TKEY", "TLSA", "TSIG", "TXT", "URI", "ZONEMD"
584
+ ]
585
+
586
+ RequestMethod = Literal[
587
+ "GET", "POST", "PUT", "DELETE", "HEAD", "CONNECT", "OPTIONS", "TRACE", "PATCH",
588
+ "BCOPY", "BDELETE", "BMOVE", "BPROPFIND", "BPROPPATCH", "COPY", "LOCK",
589
+ "MKCOL", "MOVE", "NOTIFY", "POLL", "PROPFIND", "PROPPATCH", "SEARCH",
590
+ "SUBSCRIBE", "UNLOCK", "UNSUBSCRIBE", "X-MS-ENUMATTS"
591
+ ]
592
+
593
+ ConnectionType = Literal["http", "dns", "tls", "smtp"]
594
+
595
+ ConnectionDirection = Literal["outbound", "inbound", "unknown"]
596
+
597
+
598
+ class SandboxNetworkDNS:
599
+ """Details for a DNS request."""
600
+
601
+ def __init__(
602
+ self,
603
+ domain: str,
604
+ lookup_type: LookupType,
605
+ resolved_ips: Optional[List[str]] = None,
606
+ resolved_domains: Optional[List[str]] = None,
607
+ ):
608
+ # The domain requested.
609
+ self.domain = domain
610
+
611
+ # A list of IPs that were resolved.
612
+ self.resolved_ips = resolved_ips or []
613
+
614
+ # A list of domains that were resolved.
615
+ self.resolved_domains = resolved_domains or []
616
+
617
+ # The type of DNS request.
618
+ self.lookup_type = lookup_type
619
+
620
+ def as_primitives(self) -> Dict:
621
+ return {
622
+ "domain": self.domain,
623
+ "resolved_ips": self.resolved_ips,
624
+ "resolved_domains": self.resolved_domains,
625
+ "lookup_type": self.lookup_type,
626
+ }
627
+
628
+
629
+ class SandboxNetworkHTTP:
630
+ """Details for an HTTP request."""
631
+
632
+ def __init__(
633
+ self,
634
+ request_uri: str,
635
+ request_headers: Optional[Dict[str, object]] = None,
636
+ request_method: Optional[RequestMethod] = None,
637
+ response_headers: Optional[Dict[str, object]] = None,
638
+ request_body: Optional[str] = None,
639
+ response_status_code: Optional[int] = None,
640
+ response_body: Optional[str] = None,
641
+ response_content_fileinfo: Optional[Dict] = None,
642
+ response_content_mimetype: Optional[str] = None,
643
+ ):
644
+ # The URI requested.
645
+ self.request_uri = request_uri
646
+
647
+ # Headers included in the request.
648
+ self.request_headers = request_headers or {}
649
+
650
+ # The method of the request.
651
+ self.request_method = request_method
652
+
653
+ # Headers included in the response.
654
+ self.response_headers = response_headers or {}
655
+
656
+ # The body of the request.
657
+ self.request_body = request_body
658
+
659
+ # The status code of the response.
660
+ self.response_status_code = response_status_code
661
+
662
+ # The body of the response.
663
+ self.response_body = response_body
664
+
665
+ # File information of the response content.
666
+ self.response_content_fileinfo = response_content_fileinfo
667
+
668
+ # MIME type returned by the server.
669
+ self.response_content_mimetype = response_content_mimetype
670
+
671
+ def as_primitives(self) -> Dict:
672
+ return {
673
+ "request_uri": self.request_uri,
674
+ "request_headers": self.request_headers,
675
+ "request_method": self.request_method,
676
+ "response_headers": self.response_headers,
677
+ "request_body": self.request_body,
678
+ "response_status_code": self.response_status_code,
679
+ "response_body": self.response_body,
680
+ "response_content_fileinfo": self.response_content_fileinfo,
681
+ "response_content_mimetype": self.response_content_mimetype,
682
+ }
683
+
684
+
685
+ class SandboxNetworkSMTP:
686
+ """Details for an SMTP request."""
687
+
688
+ def __init__(
689
+ self,
690
+ mail_from: str,
691
+ mail_to: List[str],
692
+ attachments: Optional[List[Dict]] = None,
693
+ ):
694
+ # Sender of the email.
695
+ self.mail_from = mail_from
696
+
697
+ # Recipients of the email.
698
+ self.mail_to = mail_to
699
+
700
+ # File information about the attachments.
701
+ self.attachments = attachments or []
702
+
703
+ def as_primitives(self) -> Dict:
704
+ return {
705
+ "mail_from": self.mail_from,
706
+ "mail_to": self.mail_to,
707
+ "attachments": self.attachments,
708
+ }
709
+
710
+
711
+ class SandboxNetflowItem:
712
+ """Details about a low-level network connection by IP."""
713
+
714
+ def __init__(
715
+ self,
716
+
717
+ # The destination IP of the connection.
718
+ destination_ip: Optional[str] = None,
719
+
720
+ # The destination port of the connection.
721
+ destination_port: Optional[int] = None,
722
+
723
+ # The transport layer protocol (e.g., tcp, udp).
724
+ transport_layer_protocol: Optional[Literal["tcp", "udp"]] = None,
725
+
726
+ # The direction of the network connection.
727
+ direction: Optional[ConnectionDirection] = None,
728
+
729
+ # PID of the process that spawned the network connection.
730
+ pid: Optional[int] = None,
731
+
732
+ # The source IP of the connection.
733
+ source_ip: Optional[str] = None,
734
+
735
+ # The source port of the connection.
736
+ source_port: Optional[int] = None,
737
+
738
+ time_observed: str = None,
739
+
740
+ # HTTP-specific details of the request.
741
+ http_details: Optional[SandboxNetworkHTTP] = None,
742
+
743
+ # DNS-specific details of the request.
744
+ dns_details: Optional[SandboxNetworkDNS] = None,
745
+
746
+ # SMTP-specific details of the request.
747
+ smtp_details: Optional[SandboxNetworkSMTP] = None,
748
+
749
+ # Type of connection being made.
750
+ connection_type: Optional[ConnectionType] = None,
751
+ ):
752
+ self.destination_ip = destination_ip
753
+ self.destination_port = destination_port
754
+ self.transport_layer_protocol = transport_layer_protocol
755
+ self.direction = direction
756
+ self.pid = pid
757
+ self.source_ip = source_ip
758
+ self.source_port = source_port
759
+ self.time_observed = time_observed
760
+ self.http_details = http_details
761
+ self.dns_details = dns_details
762
+ self.smtp_details = smtp_details
763
+ self.connection_type = connection_type
764
+
765
+ def as_primitives(self) -> Dict:
766
+ """Return a JSON-serializable representation."""
767
+ data: Dict[str, Any] = {
768
+ "destination_ip": self.destination_ip,
769
+ "destination_port": self.destination_port,
770
+ "transport_layer_protocol": self.transport_layer_protocol,
771
+ "direction": self.direction,
772
+ "pid": self.pid,
773
+ "source_ip": self.source_ip,
774
+ "source_port": self.source_port,
775
+ "time_observed": self.time_observed,
776
+ "connection_type": self.connection_type,
777
+ }
778
+
779
+ if self.http_details is not None:
780
+ data["http_details"] = self.http_details.as_primitives()
781
+
782
+ if self.dns_details is not None:
783
+ data["dns_details"] = self.dns_details.as_primitives()
784
+
785
+ if self.smtp_details is not None:
786
+ data["smtp_details"] = self.smtp_details.as_primitives()
787
+
788
+ return data
789
+
790
+
791
+ class SandboxAttackItem:
792
+ """Represents a MITRE ATT&CK technique or pattern."""
793
+
794
+ def __init__(
795
+ self,
796
+ attack_id: str,
797
+ pattern: str = None,
798
+ categories: List[str] = [],
799
+ ):
800
+ self.attack_id = attack_id
801
+ self.pattern = pattern
802
+ self.categories = categories or []
803
+
804
+ def as_primitives(self) -> Dict[str, Any]:
805
+ return {
806
+ "attack_id": self.attack_id,
807
+ "pattern": self.pattern,
808
+ "categories": self.categories,
809
+ }
810
+
811
+
812
+ class SandboxSignatureItem:
813
+ """A signature that was raised during the analysis of the task."""
814
+
815
+ def __init__(
816
+ self,
817
+
818
+ # The name of the signature.
819
+ name: str,
820
+
821
+ # Type of signature. One of: "CUCKOO", "YARA", "SIGMA", "SURICATA".
822
+ type: Literal["CUCKOO", "YARA", "SIGMA", "SURICATA"],
823
+
824
+ # Classification of signature (e.g., "malicious", "benign").
825
+ classification: str,
826
+
827
+ # A list of ATT&CK patterns and categories of the signature.
828
+ attacks: Optional[List[SandboxAttackItem]] = [],
829
+
830
+ # List of actors of the signature.
831
+ actors: Optional[List[str]] = [],
832
+
833
+ # List of malware families of the signature.
834
+ malware_families: Optional[List[str]] = [],
835
+
836
+ # ID of the signature.
837
+ signature_id: Optional[str] = None,
838
+
839
+ # Optional human-readable message.
840
+ message: Optional[str] = None,
841
+
842
+ # PIDs of the processes that generated the signature.
843
+ pids: Optional[List[int]] = [],
844
+
845
+ # Score of the heuristic this signature belongs to
846
+ score: int = None,
847
+ ):
848
+ self.name = name
849
+ self.type = type
850
+ self.classification = classification
851
+ self.attacks = attacks
852
+ self.actors = actors
853
+ self.malware_families = malware_families
854
+ self.signature_id = signature_id
855
+ self.message = message
856
+ self.pids = pids
857
+ self.score = score
858
+
859
+ def as_primitives(self) -> Dict[str, Any]:
860
+ return {
861
+ "name": self.name,
862
+ "type": self.type,
863
+ "classification": self.classification,
864
+ "attacks": [a.as_primitives() for a in self.attacks] if self.attacks else None,
865
+ "actors": self.actors,
866
+ "malware_families": self.malware_families,
867
+ "signature_id": self.signature_id,
868
+ "message": self.message,
869
+ "pids": self.pids,
870
+ "score": self.score,
871
+ }
872
+
873
+
874
+
875
+
876
+ class SandboxSectionBody(SectionBody):
877
+ """
878
+ Represents the structured body of a sandbox analysis section.
879
+ Collects all sandbox-relevant entities: sandbox metadata, processes, network flows, and signatures.
880
+ """
881
+
882
+ def __init__(self) -> None:
883
+ super().__init__(BODY_FORMAT.SANDBOX, body={
884
+ "sandbox_name": None,
885
+ "sandbox_version": None,
886
+ "machine_metadata": None,
887
+ "analysis_metadata": None,
888
+ "processes": [],
889
+ "netflows": [],
890
+ "signatures": [],
891
+ })
892
+
893
+ def set_sandbox(self, name: str, version: Optional[str], machine_metadata: SandboxMachineMetadata, analysis_metadata: SandboxAnalysisMetadata) -> None:
894
+ """Set the sandbox metadata (name, version, machine info, and analysis info)."""
895
+ self._data["sandbox_name"] = name
896
+ self._data["sandbox_version"] = version
897
+ self._data["machine_metadata"] = (
898
+ machine_metadata.as_primitives() if machine_metadata else None
899
+ )
900
+ self._data["analysis_metadata"] = (
901
+ analysis_metadata.as_primitives() if analysis_metadata else None
902
+ )
903
+
904
+ def add_process(self, process: SandboxProcessItem) -> None:
905
+ """Add a single process to the sandbox result."""
906
+ if not isinstance(process, SandboxProcessItem):
907
+ raise TypeError("Expected SandboxProcessItem")
908
+ self._data["processes"].append(process.as_primitives())
909
+
910
+ def add_processes(self, processes: List[SandboxProcessItem]) -> None:
911
+ """Add multiple processes at once."""
912
+ for proc in processes:
913
+ self.add_process(proc)
914
+
915
+ def add_netflow(self, netflow: SandboxNetflowItem) -> None:
916
+ """Add a network flow to the sandbox result."""
917
+ if not isinstance(netflow, SandboxNetflowItem):
918
+ raise TypeError("Expected SandboxNetflowItem")
919
+ self._data["netflows"].append(netflow.as_primitives())
920
+
921
+ def add_netflows(self, netflows: List[SandboxNetflowItem]) -> None:
922
+ """Add multiple network flows at once."""
923
+ for nf in netflows:
924
+ self.add_netflow(nf)
925
+
926
+ def add_signature(self, signature: SandboxSignatureItem) -> None:
927
+ """Add a detection signature to the sandbox result."""
928
+ if not isinstance(signature, SandboxSignatureItem):
929
+ raise TypeError("Expected SandboxSignatureItem")
930
+ self._data["signatures"].append(signature.as_primitives())
931
+
932
+ def add_signatures(self, signatures: List[SandboxSignatureItem]) -> None:
933
+ """Add multiple detection signatures at once."""
934
+ for sig in signatures:
935
+ self.add_signature(sig)
936
+
937
+
938
+ def as_primitives(self) -> Dict[str, Any]:
939
+ """Return a fully JSON-serializable structure."""
940
+ return {
941
+ "sandbox_name": self._data["sandbox_name"],
942
+ "sandbox_version": self._data["sandbox_version"],
943
+ "machine_metadata": self._data["machine_metadata"],
944
+ "analysis_metadata": self._data["analysis_metadata"],
945
+ "processes": self._data["processes"],
946
+ "netflows": self._data["netflows"],
947
+ "signatures": self._data["signatures"],
948
+ }
949
+
950
+
413
951
  class TableRow(dict):
414
952
  def __init__(self, *args, **kwargs) -> None:
415
953
  data = {}
@@ -474,7 +1012,7 @@ class TimelineSectionBody(SectionBody):
474
1012
  def add_node(self, title: str, content: str, opposite_content: str,
475
1013
  icon: str = None, signatures: List[str] = [], score: int = 0) -> None:
476
1014
  self._data.append(dict(title=title, content=content, opposite_content=opposite_content,
477
- icon=icon, signatures=signatures, score=score))
1015
+ icon=icon, signatures=signatures, score=score))
478
1016
 
479
1017
 
480
1018
  class ResultSection:
@@ -795,6 +1333,59 @@ class ResultProcessTreeSection(TypeSpecificResultSection):
795
1333
  self.section_body.add_process(process)
796
1334
 
797
1335
 
1336
+ class ResultSandboxSection(TypeSpecificResultSection):
1337
+ """
1338
+ Represents a result section specifically designed for sandbox analysis data.
1339
+ Provides a typed interface to manipulate the underlying SandboxSectionBody.
1340
+ """
1341
+
1342
+ def __init__(self, title_text: Union[str, List], **kwargs):
1343
+ self.section_body: SandboxSectionBody
1344
+ super().__init__(title_text, SandboxSectionBody(), **kwargs)
1345
+
1346
+ def set_sandbox(
1347
+ self,
1348
+ name: str,
1349
+ version: Optional[str],
1350
+ machine_metadata: Optional[SandboxMachineMetadata],
1351
+ analysis_metadata: Optional[SandboxAnalysisMetadata],
1352
+ ) -> None:
1353
+ """Set the sandbox metadata (name, version, machine info, and analysis info)."""
1354
+ self.section_body.set_sandbox(name, version, machine_metadata, analysis_metadata)
1355
+
1356
+ def add_process(self, process: SandboxProcessItem) -> None:
1357
+ """Add a single process to the sandbox result."""
1358
+ self.section_body.add_process(process)
1359
+
1360
+ def add_processes(self, processes: List[SandboxProcessItem]) -> None:
1361
+ """Add multiple processes at once."""
1362
+ self.section_body.add_processes(processes)
1363
+
1364
+ def add_netflow(self, netflow: SandboxNetflowItem) -> None:
1365
+ """Add a single network flow to the sandbox result."""
1366
+ self.section_body.add_netflow(netflow)
1367
+
1368
+ def add_netflows(self, netflows: List[SandboxNetflowItem]) -> None:
1369
+ """Add multiple network flows at once."""
1370
+ self.section_body.add_netflows(netflows)
1371
+
1372
+ def add_signature(self, signature: SandboxSignatureItem) -> None:
1373
+ """Add a detection signature to the sandbox result."""
1374
+ self.section_body.add_signature(signature)
1375
+
1376
+ def add_signatures(self, signatures: List[SandboxSignatureItem]) -> None:
1377
+ """Add multiple detection signatures at once."""
1378
+ self.section_body.add_signatures(signatures)
1379
+
1380
+ def add_heuristic(self, heuristic: SandboxHeuristicItem) -> None:
1381
+ """Add a heuristic to the sandbox result."""
1382
+ self.section_body.add_heuristic(heuristic)
1383
+
1384
+ def add_heuristics(self, heuristics: List[SandboxHeuristicItem]) -> None:
1385
+ """Add multiple heuristics at once."""
1386
+ self.section_body.add_heuristics(heuristics)
1387
+
1388
+
798
1389
  class ResultTableSection(TypeSpecificResultSection):
799
1390
  def __init__(self, title_text: Union[str, List], **kwargs):
800
1391
  self.section_body: TableSectionBody
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: assemblyline-v4-service
3
- Version: 4.6.1.dev231
3
+ Version: 4.6.1.dev248
4
4
  Summary: Assemblyline 4 - Service base
5
5
  Home-page: https://github.com/CybercentreCanada/assemblyline-v4-service/
6
6
  Author: CCCS Assemblyline development team
@@ -1,17 +1,17 @@
1
- assemblyline_v4_service/VERSION,sha256=8DtAyK44jTf2L83IBmIrZvpo7UPaxJnP23exVsiQSO8,13
1
+ assemblyline_v4_service/VERSION,sha256=SUMkvqKXjKag4psmpJRWlFSvoaGc4RwLKM7YQCSl-zU,13
2
2
  assemblyline_v4_service/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  assemblyline_v4_service/healthz.py,sha256=3QGBg0EZuXC6UN411HFwpLNEop9UvS9feFhvBUTP-k4,1576
4
4
  assemblyline_v4_service/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  assemblyline_v4_service/run_privileged_service.py,sha256=un2zcZjQVKYwMWihLLmeUc3IMJ6ALnFbR1FPeMW1U2A,14486
6
6
  assemblyline_v4_service/run_service.py,sha256=XfdABk3hEZsIw31tmFcJc-FbcxvBF9tiDIlg9oHCtZA,5900
7
7
  assemblyline_v4_service/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
- assemblyline_v4_service/common/api.py,sha256=Xzp8j4HCCfjPvNSGKiZl5ttH2_Itg47cjlH0NXNtth0,6849
8
+ assemblyline_v4_service/common/api.py,sha256=59XcuHxOpR4gSZI0foNqOaRh7IINTGvWD-pjEUrU-jU,6823
9
9
  assemblyline_v4_service/common/base.py,sha256=psivTxiOeN2jqL3G3I26oY9JFK-qPuwrg5y_y_d7xYs,14127
10
10
  assemblyline_v4_service/common/helper.py,sha256=xs9quuf-M1JOdKieBqOmWaOece0CtzXFhhe85xQYmuY,3289
11
11
  assemblyline_v4_service/common/ocr.py,sha256=NgkFqAq2lRzIveYUulKJmiiWYqwf4siYbL59n1Ow02o,8350
12
12
  assemblyline_v4_service/common/ontology_helper.py,sha256=9Ad81qbddg_pRMupT8o_KzxbKgpodaRqpc3mPoEKLtw,8494
13
13
  assemblyline_v4_service/common/request.py,sha256=W7fqC2xQE3i5i2jlCDyUDp3ZqJQQqSshNW0mQfJMkFg,11792
14
- assemblyline_v4_service/common/result.py,sha256=9AqM6qCYiia_Bpyn_fBFhzNQMcqJbtFSiGjp57fXW2E,32713
14
+ assemblyline_v4_service/common/result.py,sha256=zxZx8-RggtbB1RXGuZht-jHIFw4lCQBhzlC3aRSJsxo,52754
15
15
  assemblyline_v4_service/common/task.py,sha256=dJsvRpW0x88CCF_LW6w87jQ_UKTVaOs2Gb117IDNiU8,14233
16
16
  assemblyline_v4_service/common/utils.py,sha256=FDFsFcI6wt-pWyeQYnDWivsPbtme5RqVyofmNiggh6Y,3922
17
17
  assemblyline_v4_service/dev/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -24,7 +24,7 @@ assemblyline_v4_service/updater/client.py,sha256=tLY84gaGdFBVIDaMgRHIEa7x2S8jBl7
24
24
  assemblyline_v4_service/updater/gunicorn_config.py,sha256=p3j2KPBeD5jvMw9O5i7vAtlRgPSVVxIG9AO0DfN82J8,1247
25
25
  assemblyline_v4_service/updater/helper.py,sha256=OTV6WA77wBDOSVWaxijNg-HpwvEwnZozH03S3Q4oUns,10764
26
26
  assemblyline_v4_service/updater/updater.py,sha256=XiqabDp89-t_J6C3U33R-RvA5lMIahFW_MsAVUGyXok,31876
27
- assemblyline_v4_service-4.6.1.dev231.dist-info/licenses/LICENCE.md,sha256=NSkYo9EH8h5oOkzg4VhjAHF4339MqPP2cQ8msTPgl-c,1396
27
+ assemblyline_v4_service-4.6.1.dev248.dist-info/licenses/LICENCE.md,sha256=NSkYo9EH8h5oOkzg4VhjAHF4339MqPP2cQ8msTPgl-c,1396
28
28
  test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
29
  test/conftest.py,sha256=W3SieQpZsZpGEmtLqY4aIlxREDSsHceyCrFcFsWUM0U,1851
30
30
  test/test_healthz.py,sha256=DkeLUlrb7rGx3nZ04aADU9HXXu5mZTf_DBwT0xhzIv4,7
@@ -40,7 +40,7 @@ test/test_common/test_request.py,sha256=HiDU1n4Rjso_U0qDME4ohA_9j7rpfqLSD1-e2Rfq
40
40
  test/test_common/test_result.py,sha256=ZtLUddBDA_BTIjG3Jasbq78_AdEjCRe4cb85XLBwH5o,43585
41
41
  test/test_common/test_task.py,sha256=P44mNcSe-3tJgDk9ppN3KbM7oN4LBVIuhONG-Gveh74,19007
42
42
  test/test_common/test_utils.py,sha256=TbnBxqpS_ZC5ptXR9XJX3xtbItD0mTbtiBxxdyP8J5k,5904
43
- assemblyline_v4_service-4.6.1.dev231.dist-info/METADATA,sha256=IonPDpmHPmwNmIfb2yW_EC1DFE7kVDXGmjz0BufwTbI,5625
44
- assemblyline_v4_service-4.6.1.dev231.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
45
- assemblyline_v4_service-4.6.1.dev231.dist-info/top_level.txt,sha256=LpTOEaVCatkrvbVq3EZseMSIa2PQZU-2rhuO_FTpZgY,29
46
- assemblyline_v4_service-4.6.1.dev231.dist-info/RECORD,,
43
+ assemblyline_v4_service-4.6.1.dev248.dist-info/METADATA,sha256=rFuHv74YlUeeTNvqE78Vq_3TJKJO_VyVyHfbbPFk5To,5625
44
+ assemblyline_v4_service-4.6.1.dev248.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
45
+ assemblyline_v4_service-4.6.1.dev248.dist-info/top_level.txt,sha256=LpTOEaVCatkrvbVq3EZseMSIa2PQZU-2rhuO_FTpZgY,29
46
+ assemblyline_v4_service-4.6.1.dev248.dist-info/RECORD,,