Skip to content

Commit f7ea7a2

Browse files
Merge pull request #51 from MislavReversingLabs/main
2.6.2
2 parents 7c8c65f + 0717b87 commit f7ea7a2

File tree

6 files changed

+582
-36
lines changed

6 files changed

+582
-36
lines changed

CHANGELOG.md

+7
Original file line numberDiff line numberDiff line change
@@ -310,5 +310,12 @@ v2.5.1 (2024-04-02)
310310
2.6.1 (2024-07-03)
311311
-------------------
312312

313+
#### Improvements
314+
- Added more unit tests for all currently available modules.
315+
316+
317+
2.6.2 (2024-07-10)
318+
-------------------
319+
313320
#### Improvements
314321
- Added more unit tests for all currently available modules.

ReversingLabs/SDK/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@
55
A Python SDK for communicating with ReversingLabs services.
66
"""
77

8-
__version__ = "2.6.1"
8+
__version__ = "2.6.2"

ReversingLabs/SDK/ticloud.py

+19-21
Original file line numberDiff line numberDiff line change
@@ -5879,47 +5879,45 @@ def feed_query(self, category, filter, weeks=0, all_time=False):
58795879
filtered by category. The service can return a list of malware family names
58805880
newly added to each category, the number of unieque new samples added for each
58815881
malware family in a category, and a list of top 20 malware families per category
5882-
param: category: Corresponds to the verticals feed category the user is requesting to access.
5882+
:param category: Corresponds to the verticals feed category the user is requesting to access.
58835883
Only one category can be requested in each query. Note that the response for the 'exploit'
58845884
category contains addional 'scanner_coverage' data not found in other categories.
58855885
Enum: 'financial', 'retail', 'ransomware', 'apt', 'exploit', 'configuration'
5886-
type: category: str
5887-
param: filter: applied to filter data to request. Enum: 'first_seen', 'counts', 'top_list'
5888-
type: filter: str
5889-
param: weeks: specifies the number of weeks for which the data will be returned in response
5890-
type: weeks: int
5891-
param: all_time: Instructs the service to return all available data for the requested category
5892-
type all_time: boolean
5886+
:type category: str
5887+
:param filter: applied to filter data to request. Enum: 'first_seen', 'counts', 'top_list'
5888+
:type filter: str
5889+
:param weeks: specifies the number of weeks for which the data will be returned in response
5890+
:type weeks: int
5891+
:param all_time: Instructs the service to return all available data for the requested category
5892+
:type all_time: boolean
58935893
"""
58945894
if category not in VERTICAL_FEEDS_CATEGORIES:
58955895
raise WrongInputError("Only the following categories are allowed: {category}".format(
58965896
category=VERTICAL_FEEDS_CATEGORIES))
58975897

5898-
if filter.lower() not in ("counts", "top_list", "first_seen"):
5898+
if filter not in ("counts", "top_list", "first_seen"):
58995899
raise WrongInputError("Only the following filters are allowed: 'counts', 'top_list' and 'first_seen'")
59005900

5901+
query_params = {
5902+
"format": "json"
5903+
}
5904+
59015905
if isinstance(weeks, int):
59025906

59035907
if weeks not in range(0, 30):
59045908
raise WrongInputError("The value for weeks can be a number between 0 and 30")
59055909

5906-
query_params = {
5907-
"weeks": weeks,
5908-
"format": "json"
5909-
}
5910-
5911-
raise WrongInputError("Weeks needs to be provided as integer")
5910+
query_params["weeks"] = weeks
59125911

59135912
if all_time:
5913+
query_params["all_time"] = "true"
59145914

5915-
query_params = {
5916-
"all_time": "true",
5917-
"format": "json"
5918-
}
5915+
if "weeks" in query_params:
5916+
raise WrongInputError("The all_time parameter can not be used together with weeks.")
59195917

59205918
endpoint = self.__API_FEED_ENDPOINT.format(
5921-
category = category,
5922-
filter = filter
5919+
category=category,
5920+
filter=filter
59235921
)
59245922

59255923
url = self._url.format(endpoint=endpoint)

tests/test_a1000.py

+80-1
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,60 @@ def test_sample_from_url(self, requests_mock):
8989
files=None
9090
)
9191

92+
def test_sample_from_file(self):
93+
with pytest.raises(WrongInputError, match=r"file_source parameter must be a file open in 'rb' mode."):
94+
self.a1000.upload_sample_from_file(file_source="/path/to/file")
95+
96+
def test_file_status(self, requests_mock):
97+
self.a1000.file_analysis_status(sample_hashes=[SHA1, SHA1], sample_status="MALICIOUS")
98+
99+
expected_url = f"{self.host}/api/samples/status/"
100+
101+
requests_mock.post.assert_called_with(
102+
url=expected_url,
103+
verify=True,
104+
proxies=None,
105+
headers={"User-Agent": DEFAULT_USER_AGENT, "Authorization": f"Token {self.token}"},
106+
params={"status": "MALICIOUS"},
107+
json=None,
108+
data={"hash_values": [SHA1, SHA1]},
109+
files=None
110+
)
111+
112+
def test_url_status(self, requests_mock):
113+
self.a1000.check_submitted_url_status(task_id="aaa")
114+
115+
expected_url = f"{self.host}/api/uploads/v2/url-samples/aaa"
116+
117+
requests_mock.get.assert_called_with(
118+
url=expected_url,
119+
verify=True,
120+
proxies=None,
121+
headers={"User-Agent": DEFAULT_USER_AGENT, "Authorization": f"Token {self.token}"},
122+
params=None
123+
)
124+
125+
def test_url_report(self, requests_mock):
126+
with pytest.raises(WrongInputError, match=r"task_id parameter must be a string."):
127+
self.a1000.get_submitted_url_report(task_id=123, retry=False)
128+
129+
def test_detailed_report(self, requests_mock):
130+
with pytest.raises(WrongInputError, match=r"fields parameter must be a list of strings."):
131+
self.a1000.get_detailed_report_v2(sample_hashes=SHA1, fields="field1,field2")
132+
133+
def test_download_sample(self, requests_mock):
134+
self.a1000.download_sample(sample_hash=SHA1)
135+
136+
expected_url = f"{self.host}/api/samples/{SHA1}/download/"
137+
138+
requests_mock.get.assert_called_with(
139+
url=expected_url,
140+
verify=True,
141+
proxies=None,
142+
headers={"User-Agent": DEFAULT_USER_AGENT, "Authorization": f"Token {self.token}"},
143+
params=None
144+
)
145+
92146
def test_wrong_id(self, requests_mock):
93147
with pytest.raises(WrongInputError, match=r"task_id parameter must be a string."):
94148
self.a1000.get_submitted_url_report(task_id=123, retry=False)
@@ -304,6 +358,9 @@ def test_start_yara_retro(self, requests_mock):
304358
files=None
305359
)
306360

361+
def test_yara_retro_status(self, requests_mock):
362+
pass
363+
307364
def test_wrong_operation(self, requests_mock):
308365
with pytest.raises(WrongInputError, match=r"operation parameter must be either 'START' or 'STOP'"):
309366
self.a1000.start_or_stop_yara_local_retro_scan("BEGIN")
@@ -343,7 +400,7 @@ def test_list_containers(self, requests_mock):
343400
files=None
344401
)
345402

346-
def test_network_report(self, requests_mock):
403+
def test_domain_report(self, requests_mock):
347404
domain = "some.test.domain"
348405

349406
self.a1000.network_domain_report(domain)
@@ -357,3 +414,25 @@ def test_network_report(self, requests_mock):
357414
headers={"User-Agent": DEFAULT_USER_AGENT, "Authorization": f"Token {self.token}"},
358415
params=None
359416
)
417+
418+
def test_ip_to_domain(self, requests_mock):
419+
self.a1000.network_ip_to_domain("1.2.3.4")
420+
421+
params = {
422+
"page": None,
423+
"page_size": 500
424+
}
425+
426+
expected_url = f"{self.host}/api/network-threat-intel/ip/1.2.3.4/resolutions/"
427+
428+
requests_mock.get.assert_called_with(
429+
url=expected_url,
430+
verify=True,
431+
proxies=None,
432+
headers={"User-Agent": DEFAULT_USER_AGENT, "Authorization": f"Token {self.token}"},
433+
params=params
434+
)
435+
436+
def test_files_from_ip(self, requests_mock):
437+
with pytest.raises(WrongInputError, match=r"is allowed as the classification input"):
438+
self.a1000.network_files_from_ip(ip_addr="1.2.3.4", classification="KNOWN")

0 commit comments

Comments
 (0)