psengine 2.4.2__tar.gz → 2.5.0__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 (157) hide show
  1. {psengine-2.4.2 → psengine-2.5.0}/PKG-INFO +4 -3
  2. {psengine-2.4.2 → psengine-2.5.0}/README.md +1 -0
  3. {psengine-2.4.2 → psengine-2.5.0}/psengine/__init__.py +0 -1
  4. {psengine-2.4.2 → psengine-2.5.0}/psengine/_sdk_id.py +2 -2
  5. psengine-2.5.0/psengine/asi/__init__.py +29 -0
  6. psengine-2.5.0/psengine/asi/asi.py +290 -0
  7. psengine-2.5.0/psengine/asi/asi_mgr.py +861 -0
  8. psengine-2.5.0/psengine/asi/client.py +288 -0
  9. psengine-2.5.0/psengine/asi/constants.py +46 -0
  10. psengine-2.5.0/psengine/asi/errors.py +34 -0
  11. psengine-2.5.0/psengine/asi/models.py +345 -0
  12. {psengine-2.4.2 → psengine-2.5.0}/psengine/config/config.py +3 -1
  13. {psengine-2.4.2 → psengine-2.5.0}/psengine/constants.py +3 -0
  14. {psengine-2.4.2 → psengine-2.5.0}/psengine/endpoints.py +12 -0
  15. {psengine-2.4.2 → psengine-2.5.0}/psengine/playbook_alerts/constants.py +0 -2
  16. {psengine-2.4.2 → psengine-2.5.0}/psengine/playbook_alerts/markdown/markdown.py +1 -1
  17. {psengine-2.4.2 → psengine-2.5.0}/psengine/playbook_alerts/models/common_models.py +6 -0
  18. {psengine-2.4.2 → psengine-2.5.0}/psengine/playbook_alerts/models/panel_status.py +2 -0
  19. {psengine-2.4.2 → psengine-2.5.0}/psengine/playbook_alerts/models/pba_geopolitics_facility.py +2 -2
  20. {psengine-2.4.2 → psengine-2.5.0}/psengine/playbook_alerts/models/search_endpoint.py +2 -0
  21. {psengine-2.4.2 → psengine-2.5.0}/psengine/playbook_alerts/playbook_alert_mgr.py +6 -4
  22. {psengine-2.4.2 → psengine-2.5.0}/psengine/playbook_alerts/playbook_alerts.py +1 -1
  23. {psengine-2.4.2 → psengine-2.5.0}/psengine.egg-info/PKG-INFO +4 -3
  24. {psengine-2.4.2 → psengine-2.5.0}/psengine.egg-info/SOURCES.txt +7 -1
  25. {psengine-2.4.2 → psengine-2.5.0}/pyproject.toml +4 -3
  26. psengine-2.4.2/psengine/_version.py +0 -14
  27. {psengine-2.4.2 → psengine-2.5.0}/LICENSE +0 -0
  28. {psengine-2.4.2 → psengine-2.5.0}/psengine/analyst_notes/__init__.py +0 -0
  29. {psengine-2.4.2 → psengine-2.5.0}/psengine/analyst_notes/constants.py +0 -0
  30. {psengine-2.4.2 → psengine-2.5.0}/psengine/analyst_notes/errors.py +0 -0
  31. {psengine-2.4.2 → psengine-2.5.0}/psengine/analyst_notes/helpers.py +0 -0
  32. {psengine-2.4.2 → psengine-2.5.0}/psengine/analyst_notes/markdown.py +0 -0
  33. {psengine-2.4.2 → psengine-2.5.0}/psengine/analyst_notes/models.py +0 -0
  34. {psengine-2.4.2 → psengine-2.5.0}/psengine/analyst_notes/note.py +0 -0
  35. {psengine-2.4.2 → psengine-2.5.0}/psengine/analyst_notes/note_mgr.py +0 -0
  36. {psengine-2.4.2 → psengine-2.5.0}/psengine/base_http_client.py +0 -0
  37. {psengine-2.4.2 → psengine-2.5.0}/psengine/classic_alerts/__init__.py +0 -0
  38. {psengine-2.4.2 → psengine-2.5.0}/psengine/classic_alerts/classic_alert.py +0 -0
  39. {psengine-2.4.2 → psengine-2.5.0}/psengine/classic_alerts/classic_alert_mgr.py +0 -0
  40. {psengine-2.4.2 → psengine-2.5.0}/psengine/classic_alerts/constants.py +0 -0
  41. {psengine-2.4.2 → psengine-2.5.0}/psengine/classic_alerts/errors.py +0 -0
  42. {psengine-2.4.2 → psengine-2.5.0}/psengine/classic_alerts/helpers.py +0 -0
  43. {psengine-2.4.2 → psengine-2.5.0}/psengine/classic_alerts/markdown/__init__.py +0 -0
  44. {psengine-2.4.2 → psengine-2.5.0}/psengine/classic_alerts/markdown/markdown.py +0 -0
  45. {psengine-2.4.2 → psengine-2.5.0}/psengine/classic_alerts/models.py +0 -0
  46. {psengine-2.4.2 → psengine-2.5.0}/psengine/collective_insights/__init__.py +0 -0
  47. {psengine-2.4.2 → psengine-2.5.0}/psengine/collective_insights/collective_insights.py +0 -0
  48. {psengine-2.4.2 → psengine-2.5.0}/psengine/collective_insights/constants.py +0 -0
  49. {psengine-2.4.2 → psengine-2.5.0}/psengine/collective_insights/errors.py +0 -0
  50. {psengine-2.4.2 → psengine-2.5.0}/psengine/collective_insights/insight.py +0 -0
  51. {psengine-2.4.2 → psengine-2.5.0}/psengine/collective_insights/models.py +0 -0
  52. {psengine-2.4.2 → psengine-2.5.0}/psengine/common_models.py +0 -0
  53. {psengine-2.4.2 → psengine-2.5.0}/psengine/config/__init__.py +0 -0
  54. {psengine-2.4.2 → psengine-2.5.0}/psengine/config/errors.py +0 -0
  55. {psengine-2.4.2 → psengine-2.5.0}/psengine/detection/__init__.py +0 -0
  56. {psengine-2.4.2 → psengine-2.5.0}/psengine/detection/detection_mgr.py +0 -0
  57. {psengine-2.4.2 → psengine-2.5.0}/psengine/detection/detection_rule.py +0 -0
  58. {psengine-2.4.2 → psengine-2.5.0}/psengine/detection/errors.py +0 -0
  59. {psengine-2.4.2 → psengine-2.5.0}/psengine/detection/helpers.py +0 -0
  60. {psengine-2.4.2 → psengine-2.5.0}/psengine/detection/models.py +0 -0
  61. {psengine-2.4.2 → psengine-2.5.0}/psengine/enrich/__init__.py +0 -0
  62. {psengine-2.4.2 → psengine-2.5.0}/psengine/enrich/constants.py +0 -0
  63. {psengine-2.4.2 → psengine-2.5.0}/psengine/enrich/errors.py +0 -0
  64. {psengine-2.4.2 → psengine-2.5.0}/psengine/enrich/lookup.py +0 -0
  65. {psengine-2.4.2 → psengine-2.5.0}/psengine/enrich/lookup_mgr.py +0 -0
  66. {psengine-2.4.2 → psengine-2.5.0}/psengine/enrich/models/__init__.py +0 -0
  67. {psengine-2.4.2 → psengine-2.5.0}/psengine/enrich/models/base_enriched_entity.py +0 -0
  68. {psengine-2.4.2 → psengine-2.5.0}/psengine/enrich/models/lookup.py +0 -0
  69. {psengine-2.4.2 → psengine-2.5.0}/psengine/enrich/models/soar.py +0 -0
  70. {psengine-2.4.2 → psengine-2.5.0}/psengine/enrich/soar.py +0 -0
  71. {psengine-2.4.2 → psengine-2.5.0}/psengine/enrich/soar_mgr.py +0 -0
  72. {psengine-2.4.2 → psengine-2.5.0}/psengine/entity_lists/__init__.py +0 -0
  73. {psengine-2.4.2 → psengine-2.5.0}/psengine/entity_lists/constants.py +0 -0
  74. {psengine-2.4.2 → psengine-2.5.0}/psengine/entity_lists/entity_list.py +0 -0
  75. {psengine-2.4.2 → psengine-2.5.0}/psengine/entity_lists/entity_list_mgr.py +0 -0
  76. {psengine-2.4.2 → psengine-2.5.0}/psengine/entity_lists/errors.py +0 -0
  77. {psengine-2.4.2 → psengine-2.5.0}/psengine/entity_lists/models.py +0 -0
  78. {psengine-2.4.2 → psengine-2.5.0}/psengine/entity_match/__init__.py +0 -0
  79. {psengine-2.4.2 → psengine-2.5.0}/psengine/entity_match/entity_match.py +0 -0
  80. {psengine-2.4.2 → psengine-2.5.0}/psengine/entity_match/entity_match_mgr.py +0 -0
  81. {psengine-2.4.2 → psengine-2.5.0}/psengine/entity_match/errors.py +0 -0
  82. {psengine-2.4.2 → psengine-2.5.0}/psengine/entity_match/models.py +0 -0
  83. {psengine-2.4.2 → psengine-2.5.0}/psengine/errors.py +0 -0
  84. {psengine-2.4.2 → psengine-2.5.0}/psengine/fusion/__init__.py +0 -0
  85. {psengine-2.4.2 → psengine-2.5.0}/psengine/fusion/errors.py +0 -0
  86. {psengine-2.4.2 → psengine-2.5.0}/psengine/fusion/fusion_mgr.py +0 -0
  87. {psengine-2.4.2 → psengine-2.5.0}/psengine/fusion/models.py +0 -0
  88. {psengine-2.4.2 → psengine-2.5.0}/psengine/helpers/__init__.py +0 -0
  89. {psengine-2.4.2 → psengine-2.5.0}/psengine/helpers/helpers.py +0 -0
  90. {psengine-2.4.2 → psengine-2.5.0}/psengine/identity/__init__.py +0 -0
  91. {psengine-2.4.2 → psengine-2.5.0}/psengine/identity/constants.py +0 -0
  92. {psengine-2.4.2 → psengine-2.5.0}/psengine/identity/errors.py +0 -0
  93. {psengine-2.4.2 → psengine-2.5.0}/psengine/identity/identity.py +0 -0
  94. {psengine-2.4.2 → psengine-2.5.0}/psengine/identity/identity_mgr.py +0 -0
  95. {psengine-2.4.2 → psengine-2.5.0}/psengine/identity/models/__init__.py +0 -0
  96. {psengine-2.4.2 → psengine-2.5.0}/psengine/identity/models/common_models.py +0 -0
  97. {psengine-2.4.2 → psengine-2.5.0}/psengine/identity/models/detections.py +0 -0
  98. {psengine-2.4.2 → psengine-2.5.0}/psengine/identity/models/incident_report.py +0 -0
  99. {psengine-2.4.2 → psengine-2.5.0}/psengine/identity/models/lookup.py +0 -0
  100. {psengine-2.4.2 → psengine-2.5.0}/psengine/logger/__init__.py +0 -0
  101. {psengine-2.4.2 → psengine-2.5.0}/psengine/logger/constants.py +0 -0
  102. {psengine-2.4.2 → psengine-2.5.0}/psengine/logger/errors.py +0 -0
  103. {psengine-2.4.2 → psengine-2.5.0}/psengine/logger/rf_logger.py +0 -0
  104. {psengine-2.4.2 → psengine-2.5.0}/psengine/malware_intel/__init__.py +0 -0
  105. {psengine-2.4.2 → psengine-2.5.0}/psengine/malware_intel/errors.py +0 -0
  106. {psengine-2.4.2 → psengine-2.5.0}/psengine/malware_intel/malware_intel.py +0 -0
  107. {psengine-2.4.2 → psengine-2.5.0}/psengine/malware_intel/malware_intel_mgr.py +0 -0
  108. {psengine-2.4.2 → psengine-2.5.0}/psengine/malware_intel/models.py +0 -0
  109. {psengine-2.4.2 → psengine-2.5.0}/psengine/markdown/__init__.py +0 -0
  110. {psengine-2.4.2 → psengine-2.5.0}/psengine/markdown/markdown.py +0 -0
  111. {psengine-2.4.2 → psengine-2.5.0}/psengine/markdown/models.py +0 -0
  112. {psengine-2.4.2 → psengine-2.5.0}/psengine/playbook_alerts/__init__.py +0 -0
  113. {psengine-2.4.2 → psengine-2.5.0}/psengine/playbook_alerts/errors.py +0 -0
  114. {psengine-2.4.2 → psengine-2.5.0}/psengine/playbook_alerts/helpers.py +0 -0
  115. {psengine-2.4.2 → psengine-2.5.0}/psengine/playbook_alerts/mappings.py +0 -0
  116. {psengine-2.4.2 → psengine-2.5.0}/psengine/playbook_alerts/markdown/__init__.py +0 -0
  117. {psengine-2.4.2 → psengine-2.5.0}/psengine/playbook_alerts/markdown/markdown_code_repo.py +0 -0
  118. {psengine-2.4.2 → psengine-2.5.0}/psengine/playbook_alerts/markdown/markdown_cyber_vulnerability.py +0 -0
  119. {psengine-2.4.2 → psengine-2.5.0}/psengine/playbook_alerts/markdown/markdown_domain_abuse.py +0 -0
  120. {psengine-2.4.2 → psengine-2.5.0}/psengine/playbook_alerts/markdown/markdown_geopolitics_facility.py +0 -0
  121. {psengine-2.4.2 → psengine-2.5.0}/psengine/playbook_alerts/markdown/markdown_identity_exposure.py +0 -0
  122. {psengine-2.4.2 → psengine-2.5.0}/psengine/playbook_alerts/markdown/markdown_malware_report.py +0 -0
  123. {psengine-2.4.2 → psengine-2.5.0}/psengine/playbook_alerts/markdown/markdown_third_party_risk.py +0 -0
  124. {psengine-2.4.2 → psengine-2.5.0}/psengine/playbook_alerts/models/__init__.py +0 -0
  125. {psengine-2.4.2 → psengine-2.5.0}/psengine/playbook_alerts/models/panel_log.py +0 -0
  126. {psengine-2.4.2 → psengine-2.5.0}/psengine/playbook_alerts/models/pba_code_repo_leak.py +0 -0
  127. {psengine-2.4.2 → psengine-2.5.0}/psengine/playbook_alerts/models/pba_cyber_vulnerability.py +0 -0
  128. {psengine-2.4.2 → psengine-2.5.0}/psengine/playbook_alerts/models/pba_domain_abuse.py +0 -0
  129. {psengine-2.4.2 → psengine-2.5.0}/psengine/playbook_alerts/models/pba_identity_exposures.py +0 -0
  130. {psengine-2.4.2 → psengine-2.5.0}/psengine/playbook_alerts/models/pba_malware_report.py +0 -0
  131. {psengine-2.4.2 → psengine-2.5.0}/psengine/playbook_alerts/models/pba_third_party_risk.py +0 -0
  132. {psengine-2.4.2 → psengine-2.5.0}/psengine/playbook_alerts/pa_category.py +0 -0
  133. {psengine-2.4.2 → psengine-2.5.0}/psengine/py.typed +0 -0
  134. {psengine-2.4.2 → psengine-2.5.0}/psengine/rf_client.py +0 -0
  135. {psengine-2.4.2 → psengine-2.5.0}/psengine/risk_history/__init__.py +0 -0
  136. {psengine-2.4.2 → psengine-2.5.0}/psengine/risk_history/errors.py +0 -0
  137. {psengine-2.4.2 → psengine-2.5.0}/psengine/risk_history/models.py +0 -0
  138. {psengine-2.4.2 → psengine-2.5.0}/psengine/risk_history/risk_history_mgr.py +0 -0
  139. {psengine-2.4.2 → psengine-2.5.0}/psengine/risklists/__init__.py +0 -0
  140. {psengine-2.4.2 → psengine-2.5.0}/psengine/risklists/constants.py +0 -0
  141. {psengine-2.4.2 → psengine-2.5.0}/psengine/risklists/errors.py +0 -0
  142. {psengine-2.4.2 → psengine-2.5.0}/psengine/risklists/models.py +0 -0
  143. {psengine-2.4.2 → psengine-2.5.0}/psengine/risklists/risklist_mgr.py +0 -0
  144. {psengine-2.4.2 → psengine-2.5.0}/psengine/stix2/__init__.py +0 -0
  145. {psengine-2.4.2 → psengine-2.5.0}/psengine/stix2/base_stix_entity.py +0 -0
  146. {psengine-2.4.2 → psengine-2.5.0}/psengine/stix2/complex_entity.py +0 -0
  147. {psengine-2.4.2 → psengine-2.5.0}/psengine/stix2/constants.py +0 -0
  148. {psengine-2.4.2 → psengine-2.5.0}/psengine/stix2/enriched_indicator.py +0 -0
  149. {psengine-2.4.2 → psengine-2.5.0}/psengine/stix2/errors.py +0 -0
  150. {psengine-2.4.2 → psengine-2.5.0}/psengine/stix2/helpers.py +0 -0
  151. {psengine-2.4.2 → psengine-2.5.0}/psengine/stix2/rf_bundle.py +0 -0
  152. {psengine-2.4.2 → psengine-2.5.0}/psengine/stix2/simple_entity.py +0 -0
  153. {psengine-2.4.2 → psengine-2.5.0}/psengine/stix2/util.py +0 -0
  154. {psengine-2.4.2 → psengine-2.5.0}/psengine.egg-info/dependency_links.txt +0 -0
  155. {psengine-2.4.2 → psengine-2.5.0}/psengine.egg-info/requires.txt +0 -0
  156. {psengine-2.4.2 → psengine-2.5.0}/psengine.egg-info/top_level.txt +0 -0
  157. {psengine-2.4.2 → psengine-2.5.0}/setup.cfg +0 -0
@@ -1,11 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: psengine
3
- Version: 2.4.2
3
+ Version: 2.5.0
4
4
  Summary: psengine is a simple, yet elegant, library for rapid development of integrations with Recorded Future.
5
5
  Author-email: Moise Medici <moise.medici@recordedfuture.com>, Patrick Kinsella <patrick.kinsella@recordedfuture.com>, Ernest Bartosevic <ernest.bartosevic@recordedfuture.com>
6
6
  License-Expression: MIT
7
- Project-URL: Homepage, https://github.com/RecordedFuture-ProfessionalServices/psengine
8
- Project-URL: Changelog, https://recordedfuture-professionalservices.github.io/psengine/CHANGELOG/
7
+ Project-URL: Homepage, https://recordedfuture-professionalservices.github.io/psengine/latest/
8
+ Project-URL: Changelog, https://recordedfuture-professionalservices.github.io/psengine/latest/CHANGELOG/
9
9
  Keywords: API,Recorded Future,Cyber Security Engineering,Threat Intelligence
10
10
  Classifier: Development Status :: 5 - Production/Stable
11
11
  Classifier: Programming Language :: Python
@@ -87,6 +87,7 @@ PSEngine is ready for the demands of building robust and reliable integrations.
87
87
  It can easily interact with the following Recorded Future datasets:
88
88
 
89
89
  - Analyst Notes
90
+ - Attack Surface Intelligence
90
91
  - Collective Insights
91
92
  - Classic & Playbook Alerts
92
93
  - Detection Rules
@@ -30,6 +30,7 @@ PSEngine is ready for the demands of building robust and reliable integrations.
30
30
  It can easily interact with the following Recorded Future datasets:
31
31
 
32
32
  - Analyst Notes
33
+ - Attack Surface Intelligence
33
34
  - Collective Insights
34
35
  - Classic & Playbook Alerts
35
36
  - Detection Rules
@@ -13,7 +13,6 @@
13
13
 
14
14
  import logging
15
15
 
16
- from ._version import __version__ as version
17
16
  from .base_http_client import BaseHTTPClient
18
17
  from .errors import ReadFileError, RecordedFutureError, WriteFileError
19
18
  from .rf_client import RFClient
@@ -11,6 +11,6 @@
11
11
  # accessed from any third party API. #
12
12
  ##############################################################################################
13
13
 
14
- from ._version import __version__
14
+ from importlib.metadata import version
15
15
 
16
- SDK_ID = f'psengine-py/{__version__}'
16
+ SDK_ID = f'psengine-py/{version("psengine")}'
@@ -0,0 +1,29 @@
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
+ from .asi import (
15
+ Asset,
16
+ AssetExposuresOut,
17
+ AssetResponse,
18
+ AssetWithExposureSearch,
19
+ ExposureSearchOut,
20
+ ProjectListOut,
21
+ )
22
+ from .asi_mgr import AttackSurfaceMgr
23
+ from .errors import (
24
+ ASIExposureSearchError,
25
+ ASIFetchAssetError,
26
+ ASIFetchExposureError,
27
+ ASIFetchProjectsError,
28
+ ASISearchAssetsError,
29
+ )
@@ -0,0 +1,290 @@
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
+ from datetime import datetime
15
+ from typing import Optional
16
+
17
+ from pydantic import Field
18
+
19
+ from ..common_models import RFBaseModel
20
+ from .models import (
21
+ ApiMeta,
22
+ AssetExposure,
23
+ AssetWithExposure,
24
+ CertificateInstance,
25
+ DefensiveControl,
26
+ DNSRecord,
27
+ Exposure,
28
+ ExposureSignature,
29
+ ScannedIP,
30
+ WHOISRecord,
31
+ )
32
+
33
+
34
+ class AssetWithExposureSearch(RFBaseModel):
35
+ """Validate data received from the `/projects/{project_id}/exposures/{signature_id}`
36
+ endpoint.
37
+
38
+ This class supports hashing, equality comparison, greater-than comparison, and string
39
+ representation of `AssetWithExposureSearch` instances.
40
+
41
+ Hashing:
42
+ Returns a hash value based on the exposure signature `id`.
43
+
44
+ Equality:
45
+ Checks equality between two `AssetWithExposureSearch` instances based on the exposure
46
+ signature `id`.
47
+
48
+ Greater-than Comparison:
49
+ Defines a greater-than comparison between two `AssetWithExposureSearch` instances based on
50
+ the signature severity and `id`.
51
+
52
+ String Representation:
53
+ Returns a string representation of the `AssetWithExposureSearch` instance including the
54
+ signature name, `id`, and severity.
55
+
56
+ ```python
57
+ >>> print(asset_with_exposure)
58
+ Name: Exposed Service, Id: exp-123, Severity: critical
59
+ ```
60
+ """
61
+
62
+ asset_exposures: Optional[list[AssetWithExposure]] = []
63
+ signature: ExposureSignature
64
+ meta: Optional[ApiMeta] = None
65
+
66
+ def __str__(self) -> str:
67
+ msg = 'Name: {}, Id: {}, Severity: {}'
68
+ return msg.format(
69
+ self.signature.name,
70
+ self.signature.id_,
71
+ self.signature.severity.value,
72
+ )
73
+
74
+ def __hash__(self) -> int:
75
+ return hash(self.signature.id_)
76
+
77
+ def __eq__(self, other: 'AssetWithExposureSearch'):
78
+ return self.signature.id_ == other.signature.id_
79
+
80
+ def __gt__(self, other: 'AssetWithExposureSearch'):
81
+ return (self.signature.severity.value, self.signature.id_) > (
82
+ other.signature.severity.value,
83
+ other.signature.id_,
84
+ )
85
+
86
+
87
+ class ExposureSearch(RFBaseModel):
88
+ """Validate data received from the `/projects/{project_id}/exposures` endpoint.
89
+
90
+ This class supports hashing, equality comparison, greater-than comparison, and string
91
+ representation of `ExposureSearch` instances.
92
+
93
+ Hashing:
94
+ Returns a hash value based on the exposure signature `id`.
95
+
96
+ Equality:
97
+ Checks equality between two `ExposureSearch` instances based on the exposure signature
98
+ `id`.
99
+
100
+ Greater-than Comparison:
101
+ Defines a greater-than comparison between two `ExposureSearch` instances based on the
102
+ signature severity, asset count, and `id`.
103
+
104
+ String Representation:
105
+ Returns a string representation of the `ExposureSearch` instance including the signature
106
+ name, `id`, severity, and asset count.
107
+
108
+ ```python
109
+ >>> print(exposure)
110
+ Name: Exposed Service, Id: exp-123, Severity: critical, Asset Count: 42
111
+ ```
112
+ """
113
+
114
+ asset_count: int
115
+ asset_exposures: Optional[list[AssetExposure]] = []
116
+ signature: ExposureSignature
117
+
118
+ def __str__(self) -> str:
119
+ msg = 'Name: {}, Id: {}, Severity: {}, Asset Count: {}'
120
+ return msg.format(
121
+ self.signature.name,
122
+ self.signature.id_,
123
+ self.signature.severity.value,
124
+ self.asset_count,
125
+ )
126
+
127
+ def __hash__(self) -> int:
128
+ return hash(self.signature.id_)
129
+
130
+ def __eq__(self, other: 'ExposureSearch'):
131
+ return self.signature.id_ == other.signature.id_
132
+
133
+ def __gt__(self, other: 'ExposureSearch'):
134
+ return (self.signature.severity.value, self.asset_count, self.signature.id_) > (
135
+ other.signature.severity.value,
136
+ other.asset_count,
137
+ other.signature.id_,
138
+ )
139
+
140
+
141
+ class ExposureSearchOut(RFBaseModel):
142
+ """Validate data received from the `/projects/{project_id}/exposures` endpoint."""
143
+
144
+ data: list[ExposureSearch]
145
+ meta: ApiMeta
146
+
147
+ def __str__(self) -> str:
148
+ return '\n'.join(str(c) for c in sorted(self.data))
149
+
150
+
151
+ class Asset(RFBaseModel):
152
+ """Validate data received from the `/projects/{project_id}/assets`,
153
+ `/projects/{project_id}/assets/{asset_id}`,
154
+ `/projects/{project_id}/assets/{asset_id}/exposures`, and
155
+ `/projects/{project_id}/assets/_search` endpoints.
156
+
157
+ This class supports hashing, equality comparison, greater-than comparison, and string
158
+ representation of `Asset` instances.
159
+
160
+ Hashing:
161
+ Returns a hash value based on the asset `id_` and `project_id`.
162
+
163
+ Equality:
164
+ Checks equality between two `Asset` instances based on the asset `id_` and `project_id`.
165
+
166
+ Greater-than Comparison:
167
+ Defines a greater-than comparison between two `Asset` instances based on the exposure
168
+ score and `id_`.
169
+
170
+ String Representation:
171
+ Returns a string representation of the `Asset` instance including the name, type, and
172
+ exposure score.
173
+
174
+ ```python
175
+ >>> print(asset)
176
+ Name: example.com, Type: domain, Exposure Score: 85
177
+ ```
178
+ """
179
+
180
+ project_id: str
181
+ id_: str = Field(alias='id')
182
+ name: str
183
+ type_: str = Field(alias='type')
184
+ discovered_at: Optional[datetime]
185
+ added_to_project_at: datetime
186
+ last_scanned_at: Optional[datetime] = None
187
+ apex_domain: Optional[str] = None
188
+ exposure_score: Optional[int] = None
189
+ is_static_asset: Optional[bool] = False
190
+ custom_tags: Optional[list[str]] = None
191
+ resolved_ips: Optional[list[str]] = None
192
+ dns_records: Optional[list[DNSRecord]] = None
193
+ whois: Optional[WHOISRecord] = None
194
+ certificates: Optional[list[CertificateInstance]] = None
195
+ defenses: Optional[list[DefensiveControl]] = None
196
+ exposures: Optional[list[Exposure]] = None
197
+ scanned_ips: Optional[list[ScannedIP]] = None
198
+
199
+ def __str__(self) -> str:
200
+ msg = 'Name: {}, Type: {}, Exposure Score: {}'
201
+ return msg.format(self.name, self.type_, self.exposure_score or 'N/A')
202
+
203
+ def __hash__(self) -> int:
204
+ return hash((self.id_, self.project_id))
205
+
206
+ def __eq__(self, other: 'Asset'):
207
+ return (self.id_, self.project_id) == (other.id_, other.project_id)
208
+
209
+ def __gt__(self, other: 'Asset'):
210
+ return (self.exposure_score or 0, self.id_) > (other.exposure_score or 0, other.id_)
211
+
212
+
213
+ class AssetResponse(RFBaseModel):
214
+ """Validate data received from the `/projects/{project_id}/assets` and
215
+ `/projects/{project_id}/assets/_search` endpoints.
216
+ """
217
+
218
+ data: list[Asset]
219
+ meta: ApiMeta
220
+
221
+ def __str__(self) -> str:
222
+ return '\n'.join(str(c) for c in sorted(self.data, reverse=True))
223
+
224
+
225
+ class Project(RFBaseModel):
226
+ """Validate data received from the `/projects` endpoint.
227
+
228
+ This class supports hashing, equality comparison, greater-than comparison, and string
229
+ representation of `Project` instances.
230
+
231
+ Hashing:
232
+ Returns a hash value based on the project `id`.
233
+
234
+ Equality:
235
+ Checks equality between two `Project` instances based on the project `id`.
236
+
237
+ Greater-than Comparison:
238
+ Defines a greater-than comparison between two `Project` instances based on the project
239
+ title.
240
+
241
+ String Representation:
242
+ Returns a string representation of the `Project` instance including the title, `id`, and
243
+ whether scanning is enabled.
244
+
245
+ ```python
246
+ >>> print(project)
247
+ Name: Example Project, Id: 123e4567-e89b-12d3-a456-426614174000, Enabled: True
248
+ ```
249
+ """
250
+
251
+ id_: str = Field(alias='id')
252
+ title: str
253
+ scanning_enabled: Optional[bool] = None
254
+ last_scanned_at: Optional[datetime] = None
255
+ inserted_at: Optional[datetime] = None
256
+ max_exposure_score: Optional[int] = None
257
+
258
+ def __str__(self) -> str:
259
+ msg = 'Name: {}, Id: {}, Enabled: {}'
260
+ return msg.format(
261
+ self.title,
262
+ self.id_,
263
+ self.scanning_enabled or 'False',
264
+ )
265
+
266
+ def __hash__(self) -> int:
267
+ return hash(self.id_)
268
+
269
+ def __eq__(self, other: 'Project'):
270
+ return self.id_ == other.id_
271
+
272
+ def __gt__(self, other: 'Project'):
273
+ return self.title > other.title
274
+
275
+
276
+ class ProjectListOut(RFBaseModel):
277
+ """Validate data received from the `/projects` endpoint."""
278
+
279
+ data: list[Project]
280
+ meta: ApiMeta
281
+
282
+ def __str__(self) -> str:
283
+ return '\n'.join(str(c) for c in sorted(self.data))
284
+
285
+
286
+ class AssetExposuresOut(RFBaseModel):
287
+ """Validate data received from the `/projects/{project_id}/assets/{asset_id}/exposures`."""
288
+
289
+ data: list[AssetWithExposure]
290
+ meta: ApiMeta