Skip to content

Commit c682d4b

Browse files
committed
Merge branch 'master' of github.com:demisto/content into skip-mail-sender
2 parents e04403b + 370720e commit c682d4b

File tree

232 files changed

+48275
-3016
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

232 files changed

+48275
-3016
lines changed

.github/github_workflow_scripts/parse_junit_per_pack.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ def parse_pack_name(class_name: str):
2424
return parsed_pack_name
2525

2626

27-
def parse_xml(path: Path = Path(".report_pytest.xml")) -> dict[str, float]:
27+
def parse_xml(path: Path = Path("report_pytest.xml")) -> dict[str, float]:
2828
pack_times: defaultdict[str, float] = defaultdict(int)
2929

3030
for suite in ET.parse(path).getroot().findall("testsuite"):

.github/workflows/pre-commit-reuse.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ jobs:
7676
id: check-pytest-junit-exists
7777
uses: andstor/file-existence-action@v2
7878
with:
79-
files: ".report_pytest.xml"
79+
files: "report_pytest.xml"
8080

8181
- name: Create pack-wise pytest report
8282
run: poetry run python .github/github_workflow_scripts/parse_junit_per_pack.py
@@ -86,7 +86,7 @@ jobs:
8686
github.event.pull_request.head.repo.fork == false
8787
8888
- name: Upload junit & pack-wise pytest report
89-
uses: actions/upload-artifact@v4
89+
uses: PaloAltoNetworks/upload-secure-artifact@v1.0.5
9090
if: |
9191
always() &&
9292
steps.check-pytest-junit-exists.outputs.files_exists == 'true' &&
@@ -95,7 +95,7 @@ jobs:
9595
name: pytest
9696
path: |
9797
packwise_pytest_time.csv
98-
.report_pytest.xml
98+
report_pytest.xml
9999
if-no-files-found: error
100100

101101
- name: Pytest coverage comment
@@ -108,7 +108,7 @@ jobs:
108108
continue-on-error: true # may fail on output > 65k chars
109109
with:
110110
pytest-xml-coverage-path: coverage_report/coverage.xml
111-
junitxml-path: .report_pytest.xml
111+
junitxml-path: report_pytest.xml
112112

113113
- uses: actions/cache/save@v3
114114
if: always()

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ Packs/Whois/Integrations/Whois/test_data/microsocks
8484
.pre-commit-config-content.yaml
8585
.report.json
8686
.report_pytest.xml
87+
report_pytest.xml
8788
.report_mypy.xml
8889
coverage.xml
8990
Packs/**/Integrations/**/.pytest.ini

.pre-commit-config_template.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ repos:
154154
- -v
155155
- --override-ini='asyncio_mode=auto'
156156
- --rootdir=/src
157-
- --junitxml=/src/.pre-commit/pytest-junit/.report_pytest.xml
157+
- --junitxml=/src/.pre-commit/pytest-junit/report_pytest.xml
158158
- --color=yes
159159
- --files
160160
args:docker_autoupdate:
@@ -163,7 +163,7 @@ repos:
163163
- -v
164164
- --override-ini='asyncio_mode=auto'
165165
- --rootdir=/src
166-
- --junitxml=/src/.pre-commit/pytest-junit/.report_pytest.xml
166+
- --junitxml=/src/.pre-commit/pytest-junit/report_pytest.xml
167167
- --color=yes
168168
- --files
169169
copy_files:
@@ -193,7 +193,7 @@ repos:
193193
- -v
194194
- --override-ini='asyncio_mode=auto'
195195
- --rootdir=/src
196-
- --junitxml=/src/.pre-commit/pytest-junit/.report_pytest.xml
196+
- --junitxml=/src/.pre-commit/pytest-junit/report_pytest.xml
197197
- --color=yes
198198
copy_files:
199199
- Tests/scripts/dev_envs/pytest/conftest.py

Packs/AlienVault_OTX/Integrations/AlienVault_OTX_v2/AlienVault_OTX_v2.py

Lines changed: 61 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from CommonServerPython import *
22

33
''' IMPORTS '''
4-
from typing import Dict, Tuple, Union
54
import urllib3
65

76
# Disable insecure warnings
@@ -26,24 +25,25 @@
2625

2726
class Client(BaseClient):
2827
def __init__(self, base_url, headers, verify, proxy, default_threshold, max_indicator_relationships,
29-
reliability, create_relationships=True):
28+
reliability, create_relationships=True, should_error=True):
3029

3130
BaseClient.__init__(self, base_url=base_url, headers=headers, verify=verify, proxy=proxy, )
3231

3332
self.reliability = reliability
3433
self.create_relationships = create_relationships
3534
self.default_threshold = default_threshold
3635
self.max_indicator_relationships = 0 if not max_indicator_relationships else max_indicator_relationships
36+
self.should_error = should_error
3737

38-
def test_module(self) -> Dict:
38+
def test_module(self) -> dict:
3939
"""Performs basic GET request to check if the API is reachable and authentication is successful.
4040
4141
Returns:
4242
Response json
4343
"""
4444
return self.query(section='IPv4', argument='8.8.8.8')
4545

46-
def query(self, section: str, argument: str = None, sub_section: str = 'general', params: dict = None) -> Dict:
46+
def query(self, section: str, argument: str = None, sub_section: str = 'general', params: dict = None) -> dict:
4747
"""Query the specified kwargs.
4848
4949
Args:
@@ -89,7 +89,7 @@ def query(self, section: str, argument: str = None, sub_section: str = 'general'
8989
''' HELPER FUNCTIONS '''
9090

9191

92-
def calculate_dbot_score(client: Client, raw_response: Union[dict, None]) -> float:
92+
def calculate_dbot_score(client: Client, raw_response: dict | None) -> float:
9393
"""
9494
calculate DBot score for query
9595
@@ -267,7 +267,7 @@ def create_relationships(client: Client, relevant_field: list, entity_a: str,
267267
return relationships
268268

269269

270-
def delete_duplicated_entities(entities_list: List[Dict], field_name: str):
270+
def delete_duplicated_entities(entities_list: List[dict], field_name: str):
271271
"""delete duplicated results from a response
272272
273273
Args:
@@ -277,14 +277,14 @@ def delete_duplicated_entities(entities_list: List[Dict], field_name: str):
277277
Returns:
278278
a list without duplicated entities.
279279
"""
280-
unique_dict: Dict = {}
280+
unique_dict: dict = {}
281281
for entity_dict in entities_list:
282-
if isinstance(entity_dict, dict) and (ind_value := entity_dict.get(field_name)) not in unique_dict.keys():
282+
if isinstance(entity_dict, dict) and (ind_value := entity_dict.get(field_name)) not in unique_dict:
283283
unique_dict[ind_value] = entity_dict
284284
return list(unique_dict.values())
285285

286286

287-
def validate_string_is_not_url(entities_list: List[Dict], field_name: str):
287+
def validate_string_is_not_url(entities_list: List[dict], field_name: str):
288288
"""delete url type entities from a given list.
289289
290290
Args:
@@ -294,18 +294,44 @@ def validate_string_is_not_url(entities_list: List[Dict], field_name: str):
294294
Returns:
295295
a list without url type entities.
296296
"""
297-
return [dict for dict in entities_list if not auto_detect_indicator_type(dict.get(field_name)) == "URL"]
297+
return [dict for dict in entities_list if auto_detect_indicator_type(dict.get(field_name)) != 'URL']
298298

299299

300300
def lowercase_protocol_callback(pattern: re.Match) -> str:
301301
return pattern.group(0).lower()
302302

303303

304+
def reputation_with_handling_error(client, section, argument, sub_section=None):
305+
"""Query data while handling ReadTimeout errors.
306+
307+
Args:
308+
client: The client object used to perform the query.
309+
section: The section to query (e.g., 'domain', 'file', 'url', etc.).
310+
argument: The argument for the query (e.g., domain name, file hash, URL, or IP).
311+
sub_section: (Optional) A sub-section for more specific queries (e.g., 'analysis' for file reputation).
312+
313+
Returns:
314+
The raw response from the query if successful, or an empty dictionary if a ReadTimeout occurs.
315+
"""
316+
try:
317+
if sub_section:
318+
return client.query(section=section, argument=argument, sub_section=sub_section)
319+
return client.query(section=section, argument=argument)
320+
except requests.exceptions.ReadTimeout as e:
321+
if client.should_error:
322+
raise e
323+
demisto.info(f"An error was raised {e=}")
324+
return_warning(f"{e}")
325+
if section == 'url':
326+
return 404
327+
return {}
328+
329+
304330
''' COMMANDS '''
305331

306332

307333
@logger
308-
def test_module_command(client: Client, *_) -> Tuple[None, None, str]:
334+
def test_module_command(client: Client, *_) -> tuple[None, None, str]:
309335
"""Performs a basic GET request to check if the API is reachable and authentication is successful.
310336
311337
Args:
@@ -342,8 +368,8 @@ def ip_command(client: Client, ip_address: str, ip_version: str) -> List[Command
342368
command_results: List[CommandResults] = []
343369

344370
for ip_ in ips_list:
345-
raw_response = client.query(section=ip_version,
346-
argument=ip_)
371+
raw_response = reputation_with_handling_error(client=client, section=ip_version, argument=ip_)
372+
347373
if raw_response and raw_response != 404:
348374
ip_version = FeedIndicatorType.IP if ip_version == 'IPv4' else FeedIndicatorType.IPv6
349375
relationships = relationships_manager(client, entity_a=ip_, entity_a_type=ip_version,
@@ -411,7 +437,8 @@ def domain_command(client: Client, domain: str) -> List[CommandResults]:
411437
command_results: List[CommandResults] = []
412438

413439
for domain in domains_list:
414-
raw_response = client.query(section='domain', argument=domain)
440+
raw_response = reputation_with_handling_error(client=client, section='domain', argument=domain)
441+
415442
if raw_response and raw_response != 404:
416443
relationships = relationships_manager(client, entity_a=domain, indicator_type='domain',
417444
entity_a_type=FeedIndicatorType.Domain, indicator=domain,
@@ -469,11 +496,14 @@ def file_command(client: Client, file: str) -> List[CommandResults]:
469496
command_results: List[CommandResults] = []
470497

471498
for hash_ in hashes_list:
472-
raw_response_analysis = client.query(section='file',
473-
argument=hash_,
474-
sub_section='analysis')
475-
raw_response_general = client.query(section='file',
476-
argument=hash_)
499+
raw_response_analysis = reputation_with_handling_error(client=client,
500+
section='file',
501+
argument=hash_,
502+
sub_section='analysis')
503+
raw_response_general = reputation_with_handling_error(client=client,
504+
section='file',
505+
argument=hash_)
506+
477507
if raw_response_analysis and raw_response_general and (
478508
shortcut := dict_safe_get(raw_response_analysis, ['analysis', 'info', 'results'],
479509
{})) and raw_response_general != 404 and raw_response_analysis != 404:
@@ -544,7 +574,8 @@ def url_command(client: Client, url: str) -> List[CommandResults]:
544574

545575
for url in urls_list:
546576
url = re.sub(r'(\w+)://', lowercase_protocol_callback, url)
547-
raw_response = client.query(section='url', argument=url)
577+
raw_response = reputation_with_handling_error(client=client, section='url', argument=url)
578+
548579
if raw_response:
549580
if raw_response == 404:
550581
command_results.append(create_indicator_result_with_dbotscore_unknown(indicator=url,
@@ -597,7 +628,7 @@ def url_command(client: Client, url: str) -> List[CommandResults]:
597628

598629

599630
@logger
600-
def alienvault_search_hostname_command(client: Client, hostname: str) -> Tuple[str, Dict, Dict]:
631+
def alienvault_search_hostname_command(client: Client, hostname: str) -> tuple[str, dict, dict]:
601632
"""Search for hostname details
602633
603634
Args:
@@ -639,7 +670,7 @@ def alienvault_search_hostname_command(client: Client, hostname: str) -> Tuple[s
639670

640671

641672
@logger
642-
def alienvault_search_cve_command(client: Client, cve_id: str) -> Tuple[str, Dict, Dict]:
673+
def alienvault_search_cve_command(client: Client, cve_id: str) -> tuple[str, dict, dict]:
643674
"""Get Common Vulnerabilities and Exposures by id
644675
645676
Args:
@@ -680,7 +711,7 @@ def alienvault_search_cve_command(client: Client, cve_id: str) -> Tuple[str, Dic
680711
@logger
681712
def alienvault_get_related_urls_by_indicator_command(client: Client, indicator_type: str, indicator: str,
682713
limit: str = '') \
683-
-> Tuple[str, Dict, Dict]:
714+
-> tuple[str, dict, dict]:
684715
"""Get related urls by indicator (IPv4,IPv6,domain,hostname,url)
685716
686717
Args:
@@ -717,7 +748,7 @@ def alienvault_get_related_urls_by_indicator_command(client: Client, indicator_t
717748
@logger
718749
def alienvault_get_related_hashes_by_indicator_command(client: Client, indicator_type: str, indicator: str,
719750
limit: str = '') \
720-
-> Tuple[str, Dict, Dict]:
751+
-> tuple[str, dict, dict]:
721752
"""Get related file hashes by indicator (IPv4,IPv6,domain,hostname)
722753
723754
Args:
@@ -755,7 +786,7 @@ def alienvault_get_related_hashes_by_indicator_command(client: Client, indicator
755786

756787
@logger
757788
def alienvault_get_passive_dns_data_by_indicator_command(client: Client, indicator_type: str, indicator: str,
758-
limit: str = '') -> Tuple[str, Dict, Dict]:
789+
limit: str = '') -> tuple[str, dict, dict]:
759790
"""Get related file hashes by indicator (IPv4,IPv6,domain,hostname)
760791
761792
Args:
@@ -794,7 +825,7 @@ def alienvault_get_passive_dns_data_by_indicator_command(client: Client, indicat
794825

795826

796827
@logger
797-
def alienvault_search_pulses_command(client: Client, page: str) -> Tuple[str, Dict, Dict]:
828+
def alienvault_search_pulses_command(client: Client, page: str) -> tuple[str, dict, dict]:
798829
"""Get pulse page by number of the page
799830
800831
Args:
@@ -825,7 +856,7 @@ def alienvault_search_pulses_command(client: Client, page: str) -> Tuple[str, Di
825856

826857

827858
@logger
828-
def alienvault_get_pulse_details_command(client: Client, pulse_id: str) -> Tuple[str, Dict, Dict]:
859+
def alienvault_get_pulse_details_command(client: Client, pulse_id: str) -> tuple[str, dict, dict]:
829860
"""Get pulse by ID
830861
831862
Args:
@@ -879,6 +910,7 @@ def main():
879910
reliability = DBotScoreReliability.get_dbot_score_reliability_from_str(reliability)
880911
else:
881912
Exception("Please provide a valid value for the Source Reliability parameter.")
913+
should_error = argToBoolean(params.get('should_error', True))
882914

883915
client = Client(
884916
base_url=base_url,
@@ -888,7 +920,8 @@ def main():
888920
default_threshold=default_threshold,
889921
reliability=reliability,
890922
create_relationships=argToBoolean(params.get('create_relationships')),
891-
max_indicator_relationships=max_indicator_relationships
923+
max_indicator_relationships=max_indicator_relationships,
924+
should_error=should_error
892925
)
893926

894927
command = demisto.command()

Packs/AlienVault_OTX/Integrations/AlienVault_OTX_v2/AlienVault_OTX_v2.yml

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,14 @@ configuration:
6262
section: Collect
6363
advanced: true
6464
required: false
65+
- defaultvalue: 'true'
66+
additionalinfo: The AlienVault OTX API raise an error when an item is not found. Disable this parameter in order to return a warning instead.
67+
display: Should Error When Not Found
68+
name: should_error
69+
type: 8
70+
section: Connect
71+
advanced: true
72+
required: false
6573
- display: Trust any certificate (not secure)
6674
name: insecure
6775
type: 8
@@ -106,7 +114,7 @@ script:
106114
description: The reputation of the IP address.
107115
type: String
108116
- contextPath: AlienVaultOTX.IP.IP
109-
description: IP address
117+
description: IP address.
110118
type: String
111119
- contextPath: DBotScore.Score
112120
description: The actual score.
@@ -505,7 +513,7 @@ script:
505513
description: The domain data for the Alexa URL.
506514
type: String
507515
- contextPath: AlienVaultOTX.URL.Url
508-
description: Url
516+
description: Url.
509517
type: String
510518
- contextPath: AlienVaultOTX.URL.Whois
511519
description: The Whois URL for domain data.
@@ -537,7 +545,7 @@ script:
537545
- contextPath: URL.Relationships.EntityBType
538546
description: The type of the destination of the relationship.
539547
type: string
540-
dockerimage: demisto/python3:3.11.10.115186
548+
dockerimage: demisto/python3:3.12.8.1983910
541549
runonce: false
542550
script: '-'
543551
type: python

0 commit comments

Comments
 (0)