psengine 2.8.2__tar.gz → 2.8.4__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 (164) hide show
  1. {psengine-2.8.2 → psengine-2.8.4}/PKG-INFO +3 -2
  2. {psengine-2.8.2 → psengine-2.8.4}/psengine/analyst_notes/markdown.py +1 -2
  3. {psengine-2.8.2 → psengine-2.8.4}/psengine/classic_alerts/markdown/markdown.py +1 -1
  4. {psengine-2.8.2 → psengine-2.8.4}/psengine/markdown/markdown.py +2 -2
  5. psengine-2.8.4/psengine/markdown/markdown_strings.py +163 -0
  6. {psengine-2.8.2 → psengine-2.8.4}/psengine/playbook_alerts/markdown/markdown.py +1 -2
  7. {psengine-2.8.2 → psengine-2.8.4}/psengine/playbook_alerts/markdown/markdown_code_repo.py +1 -2
  8. {psengine-2.8.2 → psengine-2.8.4}/psengine/playbook_alerts/markdown/markdown_cyber_vulnerability.py +1 -2
  9. {psengine-2.8.2 → psengine-2.8.4}/psengine/playbook_alerts/markdown/markdown_domain_abuse.py +1 -2
  10. {psengine-2.8.2 → psengine-2.8.4}/psengine/playbook_alerts/markdown/markdown_geopolitics_facility.py +1 -2
  11. {psengine-2.8.2 → psengine-2.8.4}/psengine/playbook_alerts/markdown/markdown_identity_exposure.py +1 -2
  12. {psengine-2.8.2 → psengine-2.8.4}/psengine/playbook_alerts/markdown/markdown_malware_report.py +1 -2
  13. {psengine-2.8.2 → psengine-2.8.4}/psengine/playbook_alerts/markdown/markdown_third_party_risk.py +1 -2
  14. {psengine-2.8.2 → psengine-2.8.4}/pyproject.toml +5 -3
  15. {psengine-2.8.2 → psengine-2.8.4}/README.md +0 -0
  16. {psengine-2.8.2 → psengine-2.8.4}/psengine/__init__.py +0 -0
  17. {psengine-2.8.2 → psengine-2.8.4}/psengine/_sdk_id.py +0 -0
  18. {psengine-2.8.2 → psengine-2.8.4}/psengine/analyst_notes/__init__.py +0 -0
  19. {psengine-2.8.2 → psengine-2.8.4}/psengine/analyst_notes/constants.py +0 -0
  20. {psengine-2.8.2 → psengine-2.8.4}/psengine/analyst_notes/errors.py +0 -0
  21. {psengine-2.8.2 → psengine-2.8.4}/psengine/analyst_notes/helpers.py +0 -0
  22. {psengine-2.8.2 → psengine-2.8.4}/psengine/analyst_notes/models.py +0 -0
  23. {psengine-2.8.2 → psengine-2.8.4}/psengine/analyst_notes/note.py +0 -0
  24. {psengine-2.8.2 → psengine-2.8.4}/psengine/analyst_notes/note_mgr.py +0 -0
  25. {psengine-2.8.2 → psengine-2.8.4}/psengine/asi/__init__.py +0 -0
  26. {psengine-2.8.2 → psengine-2.8.4}/psengine/asi/asi.py +0 -0
  27. {psengine-2.8.2 → psengine-2.8.4}/psengine/asi/asi_mgr.py +0 -0
  28. {psengine-2.8.2 → psengine-2.8.4}/psengine/asi/client.py +0 -0
  29. {psengine-2.8.2 → psengine-2.8.4}/psengine/asi/constants.py +0 -0
  30. {psengine-2.8.2 → psengine-2.8.4}/psengine/asi/errors.py +0 -0
  31. {psengine-2.8.2 → psengine-2.8.4}/psengine/asi/models.py +0 -0
  32. {psengine-2.8.2 → psengine-2.8.4}/psengine/base_http_client.py +0 -0
  33. {psengine-2.8.2 → psengine-2.8.4}/psengine/classic_alerts/__init__.py +0 -0
  34. {psengine-2.8.2 → psengine-2.8.4}/psengine/classic_alerts/classic_alert.py +0 -0
  35. {psengine-2.8.2 → psengine-2.8.4}/psengine/classic_alerts/classic_alert_mgr.py +0 -0
  36. {psengine-2.8.2 → psengine-2.8.4}/psengine/classic_alerts/constants.py +0 -0
  37. {psengine-2.8.2 → psengine-2.8.4}/psengine/classic_alerts/errors.py +0 -0
  38. {psengine-2.8.2 → psengine-2.8.4}/psengine/classic_alerts/helpers.py +0 -0
  39. {psengine-2.8.2 → psengine-2.8.4}/psengine/classic_alerts/markdown/__init__.py +0 -0
  40. {psengine-2.8.2 → psengine-2.8.4}/psengine/classic_alerts/models.py +0 -0
  41. {psengine-2.8.2 → psengine-2.8.4}/psengine/collective_insights/__init__.py +0 -0
  42. {psengine-2.8.2 → psengine-2.8.4}/psengine/collective_insights/collective_insights.py +0 -0
  43. {psengine-2.8.2 → psengine-2.8.4}/psengine/collective_insights/constants.py +0 -0
  44. {psengine-2.8.2 → psengine-2.8.4}/psengine/collective_insights/errors.py +0 -0
  45. {psengine-2.8.2 → psengine-2.8.4}/psengine/collective_insights/insight.py +0 -0
  46. {psengine-2.8.2 → psengine-2.8.4}/psengine/collective_insights/models.py +0 -0
  47. {psengine-2.8.2 → psengine-2.8.4}/psengine/common_models.py +0 -0
  48. {psengine-2.8.2 → psengine-2.8.4}/psengine/config/__init__.py +0 -0
  49. {psengine-2.8.2 → psengine-2.8.4}/psengine/config/config.py +0 -0
  50. {psengine-2.8.2 → psengine-2.8.4}/psengine/config/errors.py +0 -0
  51. {psengine-2.8.2 → psengine-2.8.4}/psengine/constants.py +0 -0
  52. {psengine-2.8.2 → psengine-2.8.4}/psengine/detection/__init__.py +0 -0
  53. {psengine-2.8.2 → psengine-2.8.4}/psengine/detection/detection_mgr.py +0 -0
  54. {psengine-2.8.2 → psengine-2.8.4}/psengine/detection/detection_rule.py +0 -0
  55. {psengine-2.8.2 → psengine-2.8.4}/psengine/detection/errors.py +0 -0
  56. {psengine-2.8.2 → psengine-2.8.4}/psengine/detection/helpers.py +0 -0
  57. {psengine-2.8.2 → psengine-2.8.4}/psengine/detection/models.py +0 -0
  58. {psengine-2.8.2 → psengine-2.8.4}/psengine/endpoints.py +0 -0
  59. {psengine-2.8.2 → psengine-2.8.4}/psengine/enrich/__init__.py +0 -0
  60. {psengine-2.8.2 → psengine-2.8.4}/psengine/enrich/constants.py +0 -0
  61. {psengine-2.8.2 → psengine-2.8.4}/psengine/enrich/errors.py +0 -0
  62. {psengine-2.8.2 → psengine-2.8.4}/psengine/enrich/lookup.py +0 -0
  63. {psengine-2.8.2 → psengine-2.8.4}/psengine/enrich/lookup_mgr.py +0 -0
  64. {psengine-2.8.2 → psengine-2.8.4}/psengine/enrich/models/__init__.py +0 -0
  65. {psengine-2.8.2 → psengine-2.8.4}/psengine/enrich/models/base_enriched_entity.py +0 -0
  66. {psengine-2.8.2 → psengine-2.8.4}/psengine/enrich/models/lookup.py +0 -0
  67. {psengine-2.8.2 → psengine-2.8.4}/psengine/enrich/models/soar.py +0 -0
  68. {psengine-2.8.2 → psengine-2.8.4}/psengine/enrich/soar.py +0 -0
  69. {psengine-2.8.2 → psengine-2.8.4}/psengine/enrich/soar_mgr.py +0 -0
  70. {psengine-2.8.2 → psengine-2.8.4}/psengine/entity_lists/__init__.py +0 -0
  71. {psengine-2.8.2 → psengine-2.8.4}/psengine/entity_lists/constants.py +0 -0
  72. {psengine-2.8.2 → psengine-2.8.4}/psengine/entity_lists/entity_list.py +0 -0
  73. {psengine-2.8.2 → psengine-2.8.4}/psengine/entity_lists/entity_list_mgr.py +0 -0
  74. {psengine-2.8.2 → psengine-2.8.4}/psengine/entity_lists/errors.py +0 -0
  75. {psengine-2.8.2 → psengine-2.8.4}/psengine/entity_lists/models.py +0 -0
  76. {psengine-2.8.2 → psengine-2.8.4}/psengine/entity_match/__init__.py +0 -0
  77. {psengine-2.8.2 → psengine-2.8.4}/psengine/entity_match/entity_match.py +0 -0
  78. {psengine-2.8.2 → psengine-2.8.4}/psengine/entity_match/entity_match_mgr.py +0 -0
  79. {psengine-2.8.2 → psengine-2.8.4}/psengine/entity_match/errors.py +0 -0
  80. {psengine-2.8.2 → psengine-2.8.4}/psengine/entity_match/models.py +0 -0
  81. {psengine-2.8.2 → psengine-2.8.4}/psengine/errors.py +0 -0
  82. {psengine-2.8.2 → psengine-2.8.4}/psengine/fusion/__init__.py +0 -0
  83. {psengine-2.8.2 → psengine-2.8.4}/psengine/fusion/errors.py +0 -0
  84. {psengine-2.8.2 → psengine-2.8.4}/psengine/fusion/fusion_mgr.py +0 -0
  85. {psengine-2.8.2 → psengine-2.8.4}/psengine/fusion/models.py +0 -0
  86. {psengine-2.8.2 → psengine-2.8.4}/psengine/helpers/__init__.py +0 -0
  87. {psengine-2.8.2 → psengine-2.8.4}/psengine/helpers/helpers.py +0 -0
  88. {psengine-2.8.2 → psengine-2.8.4}/psengine/identity/__init__.py +0 -0
  89. {psengine-2.8.2 → psengine-2.8.4}/psengine/identity/constants.py +0 -0
  90. {psengine-2.8.2 → psengine-2.8.4}/psengine/identity/errors.py +0 -0
  91. {psengine-2.8.2 → psengine-2.8.4}/psengine/identity/identity.py +0 -0
  92. {psengine-2.8.2 → psengine-2.8.4}/psengine/identity/identity_mgr.py +0 -0
  93. {psengine-2.8.2 → psengine-2.8.4}/psengine/identity/models/__init__.py +0 -0
  94. {psengine-2.8.2 → psengine-2.8.4}/psengine/identity/models/common_models.py +0 -0
  95. {psengine-2.8.2 → psengine-2.8.4}/psengine/identity/models/detections.py +0 -0
  96. {psengine-2.8.2 → psengine-2.8.4}/psengine/identity/models/incident_report.py +0 -0
  97. {psengine-2.8.2 → psengine-2.8.4}/psengine/identity/models/lookup.py +0 -0
  98. {psengine-2.8.2 → psengine-2.8.4}/psengine/links/__init__.py +0 -0
  99. {psengine-2.8.2 → psengine-2.8.4}/psengine/links/errors.py +0 -0
  100. {psengine-2.8.2 → psengine-2.8.4}/psengine/links/links.py +0 -0
  101. {psengine-2.8.2 → psengine-2.8.4}/psengine/links/links_mgr.py +0 -0
  102. {psengine-2.8.2 → psengine-2.8.4}/psengine/links/models.py +0 -0
  103. {psengine-2.8.2 → psengine-2.8.4}/psengine/logger/__init__.py +0 -0
  104. {psengine-2.8.2 → psengine-2.8.4}/psengine/logger/constants.py +0 -0
  105. {psengine-2.8.2 → psengine-2.8.4}/psengine/logger/errors.py +0 -0
  106. {psengine-2.8.2 → psengine-2.8.4}/psengine/logger/rf_logger.py +0 -0
  107. {psengine-2.8.2 → psengine-2.8.4}/psengine/malware_intel/__init__.py +0 -0
  108. {psengine-2.8.2 → psengine-2.8.4}/psengine/malware_intel/auto_sigma_mgr.py +0 -0
  109. {psengine-2.8.2 → psengine-2.8.4}/psengine/malware_intel/auto_yara_mgr.py +0 -0
  110. {psengine-2.8.2 → psengine-2.8.4}/psengine/malware_intel/constants.py +0 -0
  111. {psengine-2.8.2 → psengine-2.8.4}/psengine/malware_intel/errors.py +0 -0
  112. {psengine-2.8.2 → psengine-2.8.4}/psengine/malware_intel/helpers.py +0 -0
  113. {psengine-2.8.2 → psengine-2.8.4}/psengine/malware_intel/malware_intel.py +0 -0
  114. {psengine-2.8.2 → psengine-2.8.4}/psengine/malware_intel/malware_intel_mgr.py +0 -0
  115. {psengine-2.8.2 → psengine-2.8.4}/psengine/malware_intel/models.py +0 -0
  116. {psengine-2.8.2 → psengine-2.8.4}/psengine/markdown/__init__.py +0 -0
  117. {psengine-2.8.2 → psengine-2.8.4}/psengine/markdown/models.py +0 -0
  118. {psengine-2.8.2 → psengine-2.8.4}/psengine/playbook_alerts/__init__.py +0 -0
  119. {psengine-2.8.2 → psengine-2.8.4}/psengine/playbook_alerts/constants.py +0 -0
  120. {psengine-2.8.2 → psengine-2.8.4}/psengine/playbook_alerts/errors.py +0 -0
  121. {psengine-2.8.2 → psengine-2.8.4}/psengine/playbook_alerts/helpers.py +0 -0
  122. {psengine-2.8.2 → psengine-2.8.4}/psengine/playbook_alerts/mappings.py +0 -0
  123. {psengine-2.8.2 → psengine-2.8.4}/psengine/playbook_alerts/markdown/__init__.py +0 -0
  124. {psengine-2.8.2 → psengine-2.8.4}/psengine/playbook_alerts/models/__init__.py +0 -0
  125. {psengine-2.8.2 → psengine-2.8.4}/psengine/playbook_alerts/models/common_models.py +0 -0
  126. {psengine-2.8.2 → psengine-2.8.4}/psengine/playbook_alerts/models/panel_log.py +0 -0
  127. {psengine-2.8.2 → psengine-2.8.4}/psengine/playbook_alerts/models/panel_status.py +0 -0
  128. {psengine-2.8.2 → psengine-2.8.4}/psengine/playbook_alerts/models/pba_code_repo_leak.py +0 -0
  129. {psengine-2.8.2 → psengine-2.8.4}/psengine/playbook_alerts/models/pba_cyber_vulnerability.py +0 -0
  130. {psengine-2.8.2 → psengine-2.8.4}/psengine/playbook_alerts/models/pba_domain_abuse.py +0 -0
  131. {psengine-2.8.2 → psengine-2.8.4}/psengine/playbook_alerts/models/pba_geopolitics_facility.py +0 -0
  132. {psengine-2.8.2 → psengine-2.8.4}/psengine/playbook_alerts/models/pba_identity_exposures.py +0 -0
  133. {psengine-2.8.2 → psengine-2.8.4}/psengine/playbook_alerts/models/pba_malware_report.py +0 -0
  134. {psengine-2.8.2 → psengine-2.8.4}/psengine/playbook_alerts/models/pba_third_party_risk.py +0 -0
  135. {psengine-2.8.2 → psengine-2.8.4}/psengine/playbook_alerts/models/search_endpoint.py +0 -0
  136. {psengine-2.8.2 → psengine-2.8.4}/psengine/playbook_alerts/pa_category.py +0 -0
  137. {psengine-2.8.2 → psengine-2.8.4}/psengine/playbook_alerts/playbook_alert_mgr.py +0 -0
  138. {psengine-2.8.2 → psengine-2.8.4}/psengine/playbook_alerts/playbook_alerts.py +0 -0
  139. {psengine-2.8.2 → psengine-2.8.4}/psengine/py.typed +0 -0
  140. {psengine-2.8.2 → psengine-2.8.4}/psengine/rf_client.py +0 -0
  141. {psengine-2.8.2 → psengine-2.8.4}/psengine/risk_history/__init__.py +0 -0
  142. {psengine-2.8.2 → psengine-2.8.4}/psengine/risk_history/errors.py +0 -0
  143. {psengine-2.8.2 → psengine-2.8.4}/psengine/risk_history/models.py +0 -0
  144. {psengine-2.8.2 → psengine-2.8.4}/psengine/risk_history/risk_history_mgr.py +0 -0
  145. {psengine-2.8.2 → psengine-2.8.4}/psengine/risklists/__init__.py +0 -0
  146. {psengine-2.8.2 → psengine-2.8.4}/psengine/risklists/constants.py +0 -0
  147. {psengine-2.8.2 → psengine-2.8.4}/psengine/risklists/errors.py +0 -0
  148. {psengine-2.8.2 → psengine-2.8.4}/psengine/risklists/models.py +0 -0
  149. {psengine-2.8.2 → psengine-2.8.4}/psengine/risklists/risklist_mgr.py +0 -0
  150. {psengine-2.8.2 → psengine-2.8.4}/psengine/stix2/__init__.py +0 -0
  151. {psengine-2.8.2 → psengine-2.8.4}/psengine/stix2/base_stix_entity.py +0 -0
  152. {psengine-2.8.2 → psengine-2.8.4}/psengine/stix2/complex_entity.py +0 -0
  153. {psengine-2.8.2 → psengine-2.8.4}/psengine/stix2/constants.py +0 -0
  154. {psengine-2.8.2 → psengine-2.8.4}/psengine/stix2/enriched_indicator.py +0 -0
  155. {psengine-2.8.2 → psengine-2.8.4}/psengine/stix2/errors.py +0 -0
  156. {psengine-2.8.2 → psengine-2.8.4}/psengine/stix2/helpers.py +0 -0
  157. {psengine-2.8.2 → psengine-2.8.4}/psengine/stix2/rf_bundle.py +0 -0
  158. {psengine-2.8.2 → psengine-2.8.4}/psengine/stix2/simple_entity.py +0 -0
  159. {psengine-2.8.2 → psengine-2.8.4}/psengine/stix2/util.py +0 -0
  160. {psengine-2.8.2 → psengine-2.8.4}/psengine/threat_maps/__init__.py +0 -0
  161. {psengine-2.8.2 → psengine-2.8.4}/psengine/threat_maps/errors.py +0 -0
  162. {psengine-2.8.2 → psengine-2.8.4}/psengine/threat_maps/models.py +0 -0
  163. {psengine-2.8.2 → psengine-2.8.4}/psengine/threat_maps/threat_map.py +0 -0
  164. {psengine-2.8.2 → psengine-2.8.4}/psengine/threat_maps/threat_map_mgr.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: psengine
3
- Version: 2.8.2
3
+ Version: 2.8.4
4
4
  Summary: psengine is a simple, yet elegant, library for rapid development of integrations with Recorded Future.
5
5
  Keywords: API,Recorded Future,Cyber Security Engineering,Threat Intelligence
6
6
  Author: Moise Medici, Patrick Kinsella, Ernest Bartosevic
@@ -18,13 +18,14 @@ Classifier: Programming Language :: Python :: 3.13
18
18
  Classifier: Programming Language :: Python :: 3.14
19
19
  Requires-Dist: typing-extensions>=4.8.0
20
20
  Requires-Dist: requests>=2.33.1
21
+ Requires-Dist: urllib3>=2.7.0
22
+ Requires-Dist: idna>=3.15
21
23
  Requires-Dist: jsonpath-ng>=1.5.3,<=1.8.0
22
24
  Requires-Dist: stix2~=3.0.2
23
25
  Requires-Dist: python-dateutil>=2.7.0
24
26
  Requires-Dist: more-itertools>=9.0.0,<=11.0.2
25
27
  Requires-Dist: pydantic>=2.7,<3.0.0
26
28
  Requires-Dist: pydantic-settings[toml]>=2.14.2,<2.15.0
27
- Requires-Dist: markdown-strings==3.4.0
28
29
  Requires-Python: >=3.10, <3.15
29
30
  Project-URL: Homepage, https://recordedfuture-professionalservices.github.io/psengine/latest/
30
31
  Project-URL: Changelog, https://recordedfuture-professionalservices.github.io/psengine/latest/CHANGELOG/
@@ -16,11 +16,10 @@ from collections import defaultdict
16
16
  from itertools import chain
17
17
  from typing import TYPE_CHECKING
18
18
 
19
- from markdown_strings import bold, unordered_list
20
-
21
19
  from ..constants import TIMESTAMP_STR
22
20
  from ..endpoints import EP_ANALYST_NOTE_LOOKUP
23
21
  from ..markdown.markdown import MarkdownMaker, divider, html_collapsible
22
+ from ..markdown.markdown_strings import bold, unordered_list
24
23
 
25
24
  if TYPE_CHECKING:
26
25
  from ..analyst_notes import AnalystNote
@@ -15,7 +15,7 @@ import re
15
15
  from itertools import chain
16
16
  from typing import TYPE_CHECKING
17
17
 
18
- from markdown_strings import blockquote, bold, esc_format, link
18
+ from ...markdown.markdown_strings import blockquote, bold, esc_format, link
19
19
 
20
20
  if TYPE_CHECKING:
21
21
  from ...classic_alerts.classic_alert import ClassicAlert
@@ -14,11 +14,11 @@
14
14
  import html
15
15
  from typing import Annotated
16
16
 
17
- import markdown_strings
18
- from markdown_strings import header
19
17
  from pydantic import validate_call
20
18
  from typing_extensions import Doc
21
19
 
20
+ from . import markdown_strings
21
+ from .markdown_strings import header
22
22
  from .models import Section
23
23
 
24
24
  TITLE_HEADER_LEVEL = 2
@@ -0,0 +1,163 @@
1
+ ##################################### TERMS OF USE ###########################################
2
+ # The following code is provided for demonstration purpose only, and should not be used #
3
+ # without independent verification. Recorded Future makes no representations or warranties, #
4
+ # express, implied, statutory, or otherwise, regarding any aspect of this code or of the #
5
+ # information it may retrieve, and provides it both strictly “as-is” and without assuming #
6
+ # responsibility for any information it may retrieve. Recorded Future shall not be liable #
7
+ # for, and you assume all risk of using, the foregoing. By using this code, Customer #
8
+ # represents that it is solely responsible for having all necessary licenses, permissions, #
9
+ # rights, and/or consents to connect to third party APIs, and that it is solely responsible #
10
+ # for having all necessary licenses, permissions, rights, and/or consents to any data #
11
+ # accessed from any third party API. #
12
+ ##############################################################################################
13
+
14
+
15
+ def esc_format(text, esc):
16
+ """Return text with markdown formatting characters escaped."""
17
+ if esc:
18
+ return str(text).replace('_', r'\_').replace('*', r'\*').replace('`', r'\`')
19
+ return text
20
+
21
+
22
+ def header(header_text, header_level, style='atx', esc=True):
23
+ """Return a header of the specified level and style."""
24
+ if not isinstance(header_level, int):
25
+ raise TypeError('header_level must be int')
26
+ if not isinstance(header_text, str):
27
+ raise TypeError('header_text must be str')
28
+ if style == 'atx':
29
+ if not 1 <= header_level <= 6:
30
+ raise ValueError(f'Invalid level {header_level} for atx')
31
+ return f'{"#" * header_level} {esc_format(header_text, esc)}'
32
+ if style == 'setext':
33
+ if not 0 < header_level < 3:
34
+ raise ValueError(f'Invalid level {header_level} for setext')
35
+ header_character = '=' if header_level == 1 else '-'
36
+ header_string = (header_character * 3) + header_character * (len(header_text) - 3)
37
+ return f'{esc_format(header_text, esc)}\n{header_string}'
38
+ raise ValueError(f"Invalid style {style} (choose 'atx' or 'setext')")
39
+
40
+
41
+ def italics(text, esc=True):
42
+ """Return italics formatted text."""
43
+ return f'_{esc_format(text, esc)}_'
44
+
45
+
46
+ def bold(text, esc=True):
47
+ """Return bold formatted text."""
48
+ return f'**{esc_format(text, esc)}**'
49
+
50
+
51
+ def inline_code(text):
52
+ """Return formatted inline code."""
53
+ return f'`{str(text)}`'
54
+
55
+
56
+ def code_block(text, language=''):
57
+ """Return a code block, fenced if a language is specified."""
58
+ if language:
59
+ return f'```{language}\n{text}\n```'
60
+ return '\n'.join([f' {item}' for item in text.split('\n')])
61
+
62
+
63
+ def link(text, link_url, esc=True):
64
+ """Return an inline link."""
65
+ return f'[{esc_format(text, esc)}]({link_url})'
66
+
67
+
68
+ def image(alt_text, link_url, title='', esc=True):
69
+ """Return an inline image."""
70
+ image_string = f'![{esc_format(alt_text, esc)}]({link_url})'
71
+ if title:
72
+ image_string += f' "{esc_format(title, esc)}"'
73
+ return image_string
74
+
75
+
76
+ def unordered_list(text_list, esc=True):
77
+ """Return an unordered list from a list."""
78
+ return '\n'.join([f'- {esc_format(item, esc)}' for item in text_list])
79
+
80
+
81
+ def ordered_list(text_list, esc=True):
82
+ """Return an ordered list from a list."""
83
+ ordered_list = []
84
+ for number, item in enumerate(text_list):
85
+ ordered_list.append(
86
+ f'{(f"{esc_format(number + 1, esc)}.").ljust(3)} {esc_format(item, esc)}'
87
+ )
88
+ return '\n'.join(ordered_list)
89
+
90
+
91
+ def blockquote(text, esc=True):
92
+ """Return a blockquote."""
93
+ return '\n'.join([f'> {esc_format(item, esc)}' for item in text.split('\n')])
94
+
95
+
96
+ def horizontal_rule(length=79, style='_'):
97
+ """Return a horizontal rule of the specified length and style."""
98
+ if style not in ('_', '*'):
99
+ raise ValueError("Invalid style (choose '_' or '*')")
100
+ if length < 3:
101
+ raise ValueError('Length must be >= 3')
102
+ return style * length
103
+
104
+
105
+ def strikethrough(text, esc=True):
106
+ """Return text with strike-through formatting."""
107
+ return f'~{esc_format(text, esc)}~'
108
+
109
+
110
+ def task_list(task_list, esc=True):
111
+ """Return a task list from a 2-dimensional list of (text, completed) pairs."""
112
+ tasks = []
113
+ for item, completed in task_list:
114
+ tasks.append(f'- [{"X" if completed else " "}] {esc_format(item, esc)}')
115
+ return '\n'.join(tasks)
116
+
117
+
118
+ def table_row(text_list, pad=None, esc=True):
119
+ """Return a single table row, optionally padded."""
120
+ if pad is None:
121
+ pad = [0] * len(text_list)
122
+ row = '|'
123
+ for column_number in range(len(text_list)):
124
+ padding = pad[column_number] + 1
125
+ row += (' ' + esc_format(text_list[column_number], esc)).ljust(padding) + ' |'
126
+ return row
127
+
128
+
129
+ def table_delimiter_row(number_of_columns, column_lengths=None):
130
+ """Return a delimiter row for use in a table."""
131
+ if column_lengths is None:
132
+ column_lengths = [0] * number_of_columns
133
+ if number_of_columns != len(column_lengths):
134
+ raise ValueError('number_of_columns must be the number of columns in column_lengths')
135
+ delimiter_row = [
136
+ '---' + '-' * (column_lengths[column_number] - 3)
137
+ for column_number in range(number_of_columns)
138
+ ]
139
+ return table_row(delimiter_row)
140
+
141
+
142
+ def table(table_list):
143
+ """Return a formatted table generated from a 2-dimensional list of columns."""
144
+ number_of_columns = len(table_list)
145
+ number_of_rows_in_column = [len(column) for column in table_list]
146
+ string_list = [[str(cell) for cell in column] for column in table_list]
147
+ column_lengths = [len(max(column, key=len)) for column in string_list]
148
+ table = []
149
+
150
+ row_list = [column[0] for column in string_list]
151
+ table.append(table_row(row_list, pad=column_lengths))
152
+
153
+ table.append(table_delimiter_row(len(column_lengths), column_lengths=column_lengths))
154
+
155
+ for row in range(1, max(number_of_rows_in_column)):
156
+ row_list = []
157
+ for column_number in range(number_of_columns):
158
+ if number_of_rows_in_column[column_number] > row:
159
+ row_list.append(string_list[column_number][row])
160
+ else:
161
+ row_list.append('')
162
+ table.append(table_row(row_list, pad=column_lengths))
163
+ return '\n'.join(table)
@@ -11,12 +11,11 @@
11
11
  # accessed from any third party API. #
12
12
  ##############################################################################################
13
13
 
14
- from markdown_strings import bold, link
15
-
16
14
  from ...constants import TIMESTAMP_STR, TRUNCATE_COMMENT
17
15
  from ...markdown import (
18
16
  MarkdownMaker,
19
17
  )
18
+ from ...markdown.markdown_strings import bold, link
20
19
  from ..pa_category import PACategory
21
20
  from .markdown_code_repo import _code_repo_markdown
22
21
  from .markdown_cyber_vulnerability import _cyber_vulnerability_markdown
@@ -14,10 +14,9 @@
14
14
  from collections import defaultdict
15
15
  from typing import TYPE_CHECKING
16
16
 
17
- from markdown_strings import blockquote, bold
18
-
19
17
  from ...constants import TIMESTAMP_STR
20
18
  from ...markdown import MarkdownMaker, clean_text, divider, html_textarea
19
+ from ...markdown.markdown_strings import blockquote, bold
21
20
 
22
21
  if TYPE_CHECKING:
23
22
  from ...playbook_alerts.playbook_alerts import PBA_CodeRepoLeakage
@@ -14,14 +14,13 @@
14
14
  import itertools
15
15
  from typing import TYPE_CHECKING
16
16
 
17
- from markdown_strings import bold, unordered_list
18
-
19
17
  from ...analyst_notes import AnalystNote
20
18
  from ...analyst_notes.markdown import _cleanup_insikt_note_text
21
19
  from ...constants import TIMESTAMP_STR
22
20
  from ...enrich.lookup import CVSS, CVSSV3, EnrichmentData
23
21
  from ...markdown import MarkdownMaker
24
22
  from ...markdown.markdown import divider, header, html_collapsible
23
+ from ...markdown.markdown_strings import bold, unordered_list
25
24
 
26
25
  if TYPE_CHECKING:
27
26
  from ...playbook_alerts.playbook_alerts import PBA_CyberVulnerability
@@ -14,12 +14,11 @@
14
14
  import base64
15
15
  from typing import TYPE_CHECKING
16
16
 
17
- from markdown_strings import bold
18
-
19
17
  from ...constants import TIMESTAMP_STR
20
18
  from ...helpers import FormattingHelpers
21
19
  from ...markdown import MarkdownMaker
22
20
  from ...markdown.markdown import divider, table_from_rows
21
+ from ...markdown.markdown_strings import bold
23
22
  from ..models.pba_domain_abuse import ValueServer
24
23
 
25
24
  if TYPE_CHECKING:
@@ -15,9 +15,8 @@ import base64
15
15
  from datetime import datetime
16
16
  from typing import TYPE_CHECKING
17
17
 
18
- from markdown_strings import bold, link
19
-
20
18
  from ...markdown import MarkdownMaker, divider
19
+ from ...markdown.markdown_strings import bold, link
21
20
 
22
21
  if TYPE_CHECKING:
23
22
  from ...playbook_alerts.playbook_alerts import PBA_GeopoliticsFacility
@@ -13,11 +13,10 @@
13
13
 
14
14
  from typing import TYPE_CHECKING
15
15
 
16
- from markdown_strings import bold, unordered_list
17
-
18
16
  from ...constants import TIMESTAMP_STR
19
17
  from ...markdown import MarkdownMaker
20
18
  from ...markdown.markdown import divider
19
+ from ...markdown.markdown_strings import bold, unordered_list
21
20
 
22
21
  if TYPE_CHECKING:
23
22
  from ...playbook_alerts.playbook_alerts import PBA_IdentityNovelExposure
@@ -13,10 +13,9 @@
13
13
 
14
14
  from typing import TYPE_CHECKING
15
15
 
16
- from markdown_strings import bold, header
17
-
18
16
  from ...markdown import MarkdownMaker, divider
19
17
  from ...markdown.markdown import html_collapsible
18
+ from ...markdown.markdown_strings import bold, header
20
19
 
21
20
  if TYPE_CHECKING:
22
21
  from ...playbook_alerts.playbook_alerts import PBA_MalwareReport
@@ -15,14 +15,13 @@ import itertools
15
15
  from dataclasses import dataclass
16
16
  from typing import TYPE_CHECKING
17
17
 
18
- from markdown_strings import bold, unordered_list
19
-
20
18
  from ...analyst_notes import AnalystNote
21
19
  from ...analyst_notes.markdown import _cleanup_insikt_note_text
22
20
  from ...constants import TIMESTAMP_STR
23
21
  from ...enrich import EnrichedIP, EnrichmentData, SOAREnrichOut
24
22
  from ...markdown import MarkdownMaker
25
23
  from ...markdown.markdown import divider, header, html_collapsible
24
+ from ...markdown.markdown_strings import bold, unordered_list
26
25
  from ..models.pba_third_party_risk import TPRAssessment
27
26
 
28
27
  if TYPE_CHECKING:
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "psengine"
3
- version = "2.8.2"
3
+ version = "2.8.4"
4
4
  readme = "README.md"
5
5
  license = "MIT"
6
6
  requires-python = ">=3.10, <3.15"
@@ -29,13 +29,14 @@ classifiers=[
29
29
  dependencies = [
30
30
  "typing_extensions >= 4.8.0",
31
31
  "requests>=2.33.1",
32
+ "urllib3>=2.7.0",
33
+ "idna>=3.15",
32
34
  "jsonpath_ng>=1.5.3, <=1.8.0",
33
35
  "stix2~=3.0.2",
34
36
  "python-dateutil>=2.7.0",
35
37
  "more-itertools>=9.0.0, <=11.0.2",
36
38
  "pydantic>=2.7, <3.0.0",
37
39
  "pydantic-settings[toml]>=2.14.2,<2.15.0",
38
- "markdown-strings==3.4.0"
39
40
  ]
40
41
 
41
42
 
@@ -61,11 +62,12 @@ docs = [
61
62
  "mike>=2.1.4,<2.3.0",
62
63
  "mkdocs~=1.6.1",
63
64
  "mkdocs-material>=9.7.6,<9.8.0",
64
- "mkdocstrings[python]>=0.18",
65
+ "mkdocstrings[python]>=1.0.4",
65
66
  "griffe-typingdoc>=0.2.8,<0.4.0",
66
67
  "mkdocs-codeinclude-plugin~=0.2.1",
67
68
  "markdown-include~=0.8.1",
68
69
  "mkdocs-exclude~=1.0.2",
70
+ "pymdown-extensions~=10.21.3",
69
71
 
70
72
  # Tools for examples
71
73
  "rich==15.0.0",
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes