psengine 2.4.1__tar.gz → 2.4.3__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.
- {psengine-2.4.1 → psengine-2.4.3}/PKG-INFO +3 -3
- {psengine-2.4.1 → psengine-2.4.3}/psengine/__init__.py +0 -1
- {psengine-2.4.1 → psengine-2.4.3}/psengine/_sdk_id.py +2 -2
- {psengine-2.4.1 → psengine-2.4.3}/psengine/constants.py +1 -1
- {psengine-2.4.1 → psengine-2.4.3}/psengine/detection/detection_mgr.py +1 -1
- {psengine-2.4.1 → psengine-2.4.3}/psengine/malware_intel/malware_intel.py +5 -1
- {psengine-2.4.1 → psengine-2.4.3}/psengine/malware_intel/malware_intel_mgr.py +4 -2
- {psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/constants.py +0 -2
- {psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/markdown/markdown.py +1 -1
- {psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/models/common_models.py +6 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/models/panel_status.py +2 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/models/pba_geopolitics_facility.py +2 -2
- {psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/models/search_endpoint.py +2 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/playbook_alert_mgr.py +11 -9
- {psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/playbook_alerts.py +1 -1
- {psengine-2.4.1 → psengine-2.4.3}/psengine/rf_client.py +15 -1
- {psengine-2.4.1 → psengine-2.4.3}/psengine.egg-info/PKG-INFO +3 -3
- {psengine-2.4.1 → psengine-2.4.3}/psengine.egg-info/SOURCES.txt +0 -1
- {psengine-2.4.1 → psengine-2.4.3}/pyproject.toml +4 -3
- psengine-2.4.1/psengine/_version.py +0 -14
- {psengine-2.4.1 → psengine-2.4.3}/LICENSE +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/README.md +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/analyst_notes/__init__.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/analyst_notes/constants.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/analyst_notes/errors.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/analyst_notes/helpers.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/analyst_notes/markdown.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/analyst_notes/models.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/analyst_notes/note.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/analyst_notes/note_mgr.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/base_http_client.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/classic_alerts/__init__.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/classic_alerts/classic_alert.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/classic_alerts/classic_alert_mgr.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/classic_alerts/constants.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/classic_alerts/errors.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/classic_alerts/helpers.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/classic_alerts/markdown/__init__.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/classic_alerts/markdown/markdown.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/classic_alerts/models.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/collective_insights/__init__.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/collective_insights/collective_insights.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/collective_insights/constants.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/collective_insights/errors.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/collective_insights/insight.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/collective_insights/models.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/common_models.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/config/__init__.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/config/config.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/config/errors.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/detection/__init__.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/detection/detection_rule.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/detection/errors.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/detection/helpers.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/detection/models.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/endpoints.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/enrich/__init__.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/enrich/constants.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/enrich/errors.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/enrich/lookup.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/enrich/lookup_mgr.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/enrich/models/__init__.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/enrich/models/base_enriched_entity.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/enrich/models/lookup.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/enrich/models/soar.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/enrich/soar.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/enrich/soar_mgr.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/entity_lists/__init__.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/entity_lists/constants.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/entity_lists/entity_list.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/entity_lists/entity_list_mgr.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/entity_lists/errors.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/entity_lists/models.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/entity_match/__init__.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/entity_match/entity_match.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/entity_match/entity_match_mgr.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/entity_match/errors.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/entity_match/models.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/errors.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/fusion/__init__.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/fusion/errors.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/fusion/fusion_mgr.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/fusion/models.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/helpers/__init__.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/helpers/helpers.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/identity/__init__.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/identity/constants.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/identity/errors.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/identity/identity.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/identity/identity_mgr.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/identity/models/__init__.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/identity/models/common_models.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/identity/models/detections.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/identity/models/incident_report.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/identity/models/lookup.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/logger/__init__.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/logger/constants.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/logger/errors.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/logger/rf_logger.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/malware_intel/__init__.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/malware_intel/errors.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/malware_intel/models.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/markdown/__init__.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/markdown/markdown.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/markdown/models.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/__init__.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/errors.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/helpers.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/mappings.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/markdown/__init__.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/markdown/markdown_code_repo.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/markdown/markdown_cyber_vulnerability.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/markdown/markdown_domain_abuse.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/markdown/markdown_geopolitics_facility.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/markdown/markdown_identity_exposure.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/markdown/markdown_malware_report.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/markdown/markdown_third_party_risk.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/models/__init__.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/models/panel_log.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/models/pba_code_repo_leak.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/models/pba_cyber_vulnerability.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/models/pba_domain_abuse.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/models/pba_identity_exposures.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/models/pba_malware_report.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/models/pba_third_party_risk.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/pa_category.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/py.typed +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/risk_history/__init__.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/risk_history/errors.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/risk_history/models.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/risk_history/risk_history_mgr.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/risklists/__init__.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/risklists/constants.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/risklists/errors.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/risklists/models.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/risklists/risklist_mgr.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/stix2/__init__.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/stix2/base_stix_entity.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/stix2/complex_entity.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/stix2/constants.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/stix2/enriched_indicator.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/stix2/errors.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/stix2/helpers.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/stix2/rf_bundle.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/stix2/simple_entity.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine/stix2/util.py +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine.egg-info/dependency_links.txt +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine.egg-info/requires.txt +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/psengine.egg-info/top_level.txt +0 -0
- {psengine-2.4.1 → psengine-2.4.3}/setup.cfg +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: psengine
|
|
3
|
-
Version: 2.4.
|
|
3
|
+
Version: 2.4.3
|
|
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.
|
|
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
|
|
@@ -11,6 +11,6 @@
|
|
|
11
11
|
# accessed from any third party API. #
|
|
12
12
|
##############################################################################################
|
|
13
13
|
|
|
14
|
-
from .
|
|
14
|
+
from importlib.metadata import version
|
|
15
15
|
|
|
16
|
-
SDK_ID = f'psengine-py/{
|
|
16
|
+
SDK_ID = f'psengine-py/{version("psengine")}'
|
|
@@ -23,7 +23,7 @@ DEFAULT_MAX_WORKERS = 10
|
|
|
23
23
|
# Recorded Future API
|
|
24
24
|
#####################
|
|
25
25
|
RF_TOKEN_ENV_VAR = 'RF_TOKEN' # noqa: S105
|
|
26
|
-
RF_TOKEN_VALIDATION_REGEX = r'^[a-
|
|
26
|
+
RF_TOKEN_VALIDATION_REGEX = r'^[a-z0-9]{32}$' # noqa: S105
|
|
27
27
|
|
|
28
28
|
#####################
|
|
29
29
|
# Recorded Future Portal
|
|
@@ -89,6 +89,8 @@ class SandboxReport(RFBaseModel):
|
|
|
89
89
|
|
|
90
90
|
|
|
91
91
|
def _split_time(value: str):
|
|
92
|
+
if not value:
|
|
93
|
+
return value
|
|
92
94
|
return value.split('T')[0]
|
|
93
95
|
|
|
94
96
|
|
|
@@ -101,7 +103,9 @@ class MalwareReportIn(RFBaseModel):
|
|
|
101
103
|
str, BeforeValidator(Validators.convert_relative_time), AfterValidator(_split_time)
|
|
102
104
|
]
|
|
103
105
|
end_date: Annotated[
|
|
104
|
-
str,
|
|
106
|
+
Optional[str],
|
|
107
|
+
BeforeValidator(Validators.convert_relative_time),
|
|
108
|
+
AfterValidator(_split_time),
|
|
105
109
|
]
|
|
106
110
|
my_enterprise: bool
|
|
107
111
|
limit: int = Field(ge=1, le=10)
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
##############################################################################################
|
|
13
13
|
|
|
14
14
|
import logging
|
|
15
|
-
from typing import Annotated
|
|
15
|
+
from typing import Annotated, Optional
|
|
16
16
|
|
|
17
17
|
from pydantic import validate_call
|
|
18
18
|
from typing_extensions import Doc
|
|
@@ -48,7 +48,9 @@ class MalwareIntelMgr:
|
|
|
48
48
|
start_date: Annotated[
|
|
49
49
|
str, Doc('The starting date, format YYYY-MM-DD or relative like -1d.')
|
|
50
50
|
],
|
|
51
|
-
end_date: Annotated[
|
|
51
|
+
end_date: Annotated[
|
|
52
|
+
Optional[str], Doc('The ending date, format YYYY-MM-DD or relative like -1d.')
|
|
53
|
+
] = None,
|
|
52
54
|
my_enterprise: Annotated[
|
|
53
55
|
bool, Doc('If the report has been submitted by your enterprise.')
|
|
54
56
|
] = False,
|
|
@@ -42,7 +42,7 @@ MARKDOWN_BY_PBA_TYPE = {
|
|
|
42
42
|
|
|
43
43
|
|
|
44
44
|
def _generic_pba_summary(pba, md_maker: MarkdownMaker):
|
|
45
|
-
md_maker.add_title(pba.panel_status.
|
|
45
|
+
md_maker.add_title(pba.panel_status.alert_rule.name or pba.panel_status.alert_rule.label)
|
|
46
46
|
id_ = pba.playbook_alert_id
|
|
47
47
|
general_info = [
|
|
48
48
|
f'{bold("ID:")} {id_} ',
|
|
@@ -19,6 +19,7 @@ from pydantic import model_validator
|
|
|
19
19
|
|
|
20
20
|
from ...common_models import RFBaseModel
|
|
21
21
|
from ..models.common_models import ResolvedEntity
|
|
22
|
+
from .common_models import AlertRule
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
class Organisation(RFBaseModel):
|
|
@@ -42,6 +43,7 @@ class PanelStatus(RFBaseModel):
|
|
|
42
43
|
updated: datetime
|
|
43
44
|
case_rule_id: Optional[str] = None
|
|
44
45
|
case_rule_label: Optional[str] = None
|
|
46
|
+
alert_rule: AlertRule
|
|
45
47
|
creator_name: Optional[str] = None
|
|
46
48
|
creator_id: Optional[str] = None
|
|
47
49
|
owner_organisation_details: Optional[OwnerOrganisationDetails] = None
|
{psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/models/pba_geopolitics_facility.py
RENAMED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
from datetime import datetime
|
|
15
15
|
from typing import Optional
|
|
16
16
|
|
|
17
|
-
from pydantic import Field
|
|
17
|
+
from pydantic import Field
|
|
18
18
|
|
|
19
19
|
from ...common_models import RFBaseModel
|
|
20
20
|
from ..models.panel_status import PanelStatus
|
|
@@ -28,7 +28,7 @@ class Assessment(RFBaseModel):
|
|
|
28
28
|
class Event(RFBaseModel):
|
|
29
29
|
text: str = None
|
|
30
30
|
source: str = None
|
|
31
|
-
url:
|
|
31
|
+
url: str = None
|
|
32
32
|
assessments: list[Assessment] = []
|
|
33
33
|
document_id: str = None
|
|
34
34
|
time: datetime = None
|
|
@@ -19,6 +19,7 @@ from pydantic import Field, model_validator
|
|
|
19
19
|
|
|
20
20
|
from ...common_models import RFBaseModel
|
|
21
21
|
from ..models.panel_status import OwnerOrganisationDetails
|
|
22
|
+
from .common_models import AlertRule
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
class DatetimeRange(RFBaseModel):
|
|
@@ -33,6 +34,7 @@ class SearchStatus(RFBaseModel):
|
|
|
33
34
|
|
|
34
35
|
class SearchData(RFBaseModel):
|
|
35
36
|
playbook_alert_id: str
|
|
37
|
+
alert_rule: AlertRule
|
|
36
38
|
status: str
|
|
37
39
|
priority: str
|
|
38
40
|
reopen: Optional[str] = None
|
|
@@ -30,7 +30,6 @@ from ..helpers import TimeHelpers, connection_exceptions, debug_call
|
|
|
30
30
|
from ..rf_client import RFClient
|
|
31
31
|
from .constants import (
|
|
32
32
|
ALERTS_PER_PAGE,
|
|
33
|
-
BULK_LOOKUP_BATCH_SIZE,
|
|
34
33
|
PBA_WITH_IMAGES_INST,
|
|
35
34
|
PBA_WITH_IMAGES_TYPE,
|
|
36
35
|
PBA_WITH_IMAGES_VALIDATOR,
|
|
@@ -141,9 +140,9 @@ class PlaybookAlertMgr:
|
|
|
141
140
|
alerts_per_page: Annotated[
|
|
142
141
|
Optional[int], Doc('Number of alerts per page (pagination).')
|
|
143
142
|
] = Field(ge=1, le=10000, default=ALERTS_PER_PAGE),
|
|
144
|
-
max_results: Annotated[
|
|
145
|
-
|
|
146
|
-
|
|
143
|
+
max_results: Annotated[Optional[int], Doc('Maximum number of alerts to fetch.')] = Field(
|
|
144
|
+
ge=1, le=10_000, default=DEFAULT_LIMIT
|
|
145
|
+
),
|
|
147
146
|
order_by: Annotated[
|
|
148
147
|
Optional[str], Doc('Field to order alerts by, e.g. `created` or `updated`.')
|
|
149
148
|
] = None,
|
|
@@ -208,7 +207,9 @@ class PlaybookAlertMgr:
|
|
|
208
207
|
in_cat_alerts = filter(lambda x: x['category'] == cat, alerts)
|
|
209
208
|
in_cat_ids = [x['id'] for x in in_cat_alerts]
|
|
210
209
|
try:
|
|
211
|
-
fetched_alerts.extend(
|
|
210
|
+
fetched_alerts.extend(
|
|
211
|
+
self._do_bulk(in_cat_ids, cat, fetch_images, panels or [], alerts_per_page)
|
|
212
|
+
)
|
|
212
213
|
except (PlaybookAlertBulkFetchError, PlaybookAlertRetrieveImageError) as err: # noqa: PERF203
|
|
213
214
|
errors += 1
|
|
214
215
|
self.log.error(err)
|
|
@@ -229,7 +230,7 @@ class PlaybookAlertMgr:
|
|
|
229
230
|
),
|
|
230
231
|
max_results: Annotated[
|
|
231
232
|
Optional[int], Doc('Maximum total number of alerts to fetch.')
|
|
232
|
-
] = DEFAULT_LIMIT,
|
|
233
|
+
] = Field(ge=1, le=10_000, default=DEFAULT_LIMIT),
|
|
233
234
|
order_by: Annotated[
|
|
234
235
|
Optional[str], Doc('Field to order alerts by, e.g. `created` or `updated`.')
|
|
235
236
|
] = None,
|
|
@@ -286,7 +287,7 @@ class PlaybookAlertMgr:
|
|
|
286
287
|
data=request_body,
|
|
287
288
|
max_results=max_results,
|
|
288
289
|
results_path='data',
|
|
289
|
-
offset_key='
|
|
290
|
+
offset_key='offset',
|
|
290
291
|
)
|
|
291
292
|
|
|
292
293
|
# To avoid a breaking change have to reconstruct the SearchResponse model manually
|
|
@@ -547,7 +548,7 @@ class PlaybookAlertMgr:
|
|
|
547
548
|
@validate_call
|
|
548
549
|
@connection_exceptions(ignore_status_code=[], exception_to_raise=PlaybookAlertBulkFetchError)
|
|
549
550
|
def _do_bulk(
|
|
550
|
-
self, alert_ids: list, category: str, fetch_image: bool, panels: list
|
|
551
|
+
self, alert_ids: list, category: str, fetch_image: bool, panels: list, alerts_per_page: int
|
|
551
552
|
) -> list[PLAYBOOK_ALERT_TYPE]:
|
|
552
553
|
"""Does bulk fetch (used by bulk() after alert IDs have been sorted by category).
|
|
553
554
|
|
|
@@ -556,6 +557,7 @@ class PlaybookAlertMgr:
|
|
|
556
557
|
category (str): Category of alert to fetch
|
|
557
558
|
fetch_image (bool): Whether to fetch images for Domain Abuse alerts
|
|
558
559
|
panels (list): List of panels to fetch
|
|
560
|
+
alerts_per_page (int): Number of alerts to fetch per page for bulk search results
|
|
559
561
|
|
|
560
562
|
Raises:
|
|
561
563
|
ValidationError: if any supplied parameter is of incorrect type
|
|
@@ -576,7 +578,7 @@ class PlaybookAlertMgr:
|
|
|
576
578
|
self.log.info(f'Fetching {len(alert_ids)} {category} alerts')
|
|
577
579
|
|
|
578
580
|
results = []
|
|
579
|
-
for batch in batched(alert_ids,
|
|
581
|
+
for batch in batched(alert_ids, alerts_per_page):
|
|
580
582
|
data['playbook_alert_ids'] = batch
|
|
581
583
|
response = self.rf_client.request('post', url=CATEGORY_ENDPOINTS[category], data=data)
|
|
582
584
|
results += response.json()['data']
|
|
@@ -127,7 +127,7 @@ class PBA_Generic(RFBaseModel):
|
|
|
127
127
|
return (
|
|
128
128
|
f'Playbook Alert ID: {self.playbook_alert_id}, '
|
|
129
129
|
f'Updated: {self.panel_status.updated.strftime(TIMESTAMP_STR)}, '
|
|
130
|
-
f'Category: {self.panel_status.
|
|
130
|
+
f'Category: {self.panel_status.alert_rule.name or self.panel_status.alert_rule.label}, '
|
|
131
131
|
f'Lookup Status: {self.panel_status.status}'
|
|
132
132
|
)
|
|
133
133
|
|
|
@@ -184,8 +184,13 @@ class RFClient(BaseHTTPClient):
|
|
|
184
184
|
**kwargs,
|
|
185
185
|
):
|
|
186
186
|
if 'next_offset' in json_response:
|
|
187
|
+
current_len = 0
|
|
187
188
|
while 'next_offset' in json_response:
|
|
188
189
|
data[offset_key] = json_response['next_offset']
|
|
190
|
+
data['limit'] = min(data['limit'], max_results - current_len)
|
|
191
|
+
if data['limit'] <= 0:
|
|
192
|
+
break
|
|
193
|
+
|
|
189
194
|
json_response = self.request(
|
|
190
195
|
method=method,
|
|
191
196
|
url=url,
|
|
@@ -202,11 +207,15 @@ class RFClient(BaseHTTPClient):
|
|
|
202
207
|
if any(len(v) >= max_results for v in dict_results.values()):
|
|
203
208
|
dict_results = {k: v[:max_results] for k, v in dict_results.items()}
|
|
204
209
|
break
|
|
210
|
+
current_len = max(len(v) for v in dict_results.values())
|
|
211
|
+
|
|
205
212
|
else:
|
|
206
213
|
all_results += self._get_matches(results_expr, json_response)
|
|
207
|
-
|
|
214
|
+
current_len = len(all_results)
|
|
215
|
+
if current_len >= max_results:
|
|
208
216
|
all_results = all_results[:max_results]
|
|
209
217
|
break
|
|
218
|
+
|
|
210
219
|
else:
|
|
211
220
|
seen = json_response['counts']['returned']
|
|
212
221
|
if json_response['counts']['total'] > max_results:
|
|
@@ -324,6 +333,9 @@ class RFClient(BaseHTTPClient):
|
|
|
324
333
|
with suppress(KeyError):
|
|
325
334
|
dict_results[str(expr)].extend(self._get_matches(expr, json_response))
|
|
326
335
|
|
|
336
|
+
if len(all_results) >= max_results:
|
|
337
|
+
return all_results[:max_results]
|
|
338
|
+
|
|
327
339
|
if method.lower() == 'get':
|
|
328
340
|
return self._request_paged_get(
|
|
329
341
|
url=url,
|
|
@@ -340,6 +352,8 @@ class RFClient(BaseHTTPClient):
|
|
|
340
352
|
)
|
|
341
353
|
|
|
342
354
|
if method.lower() == 'post':
|
|
355
|
+
data['limit'] = min(data['limit'], max_results - len(all_results))
|
|
356
|
+
|
|
343
357
|
return self._request_paged_post(
|
|
344
358
|
url=url,
|
|
345
359
|
method=method,
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: psengine
|
|
3
|
-
Version: 2.4.
|
|
3
|
+
Version: 2.4.3
|
|
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.
|
|
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
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "psengine"
|
|
3
|
-
version = "2.4.
|
|
3
|
+
version = "2.4.3"
|
|
4
4
|
readme = "README.md"
|
|
5
5
|
license = "MIT"
|
|
6
6
|
requires-python = ">=3.9, <3.14"
|
|
7
7
|
description = "psengine is a simple, yet elegant, library for rapid development of integrations with Recorded Future."
|
|
8
|
+
|
|
8
9
|
authors = [
|
|
9
10
|
{name = "Moise Medici", email = "moise.medici@recordedfuture.com"},
|
|
10
11
|
{name = "Patrick Kinsella", email = "patrick.kinsella@recordedfuture.com"},
|
|
@@ -77,8 +78,8 @@ requires = [
|
|
|
77
78
|
build-backend = "setuptools.build_meta"
|
|
78
79
|
|
|
79
80
|
[project.urls]
|
|
80
|
-
Homepage = "https://github.
|
|
81
|
-
Changelog = "https://recordedfuture-professionalservices.github.io/psengine/CHANGELOG/"
|
|
81
|
+
Homepage = "https://recordedfuture-professionalservices.github.io/psengine/latest/"
|
|
82
|
+
Changelog = "https://recordedfuture-professionalservices.github.io/psengine/latest/CHANGELOG/"
|
|
82
83
|
|
|
83
84
|
[tool.setuptools]
|
|
84
85
|
packages = [
|
|
@@ -1,14 +0,0 @@
|
|
|
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
|
-
__version__ = '2.4.1'
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
{psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/markdown/markdown_cyber_vulnerability.py
RENAMED
|
File without changes
|
{psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/markdown/markdown_domain_abuse.py
RENAMED
|
File without changes
|
{psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/markdown/markdown_geopolitics_facility.py
RENAMED
|
File without changes
|
{psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/markdown/markdown_identity_exposure.py
RENAMED
|
File without changes
|
{psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/markdown/markdown_malware_report.py
RENAMED
|
File without changes
|
{psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/markdown/markdown_third_party_risk.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{psengine-2.4.1 → psengine-2.4.3}/psengine/playbook_alerts/models/pba_cyber_vulnerability.py
RENAMED
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|