Skip to content

Commit

Permalink
Added new custom scripts APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
t0mz06 committed Jan 11, 2024
1 parent c140b6d commit 249c287
Show file tree
Hide file tree
Showing 15 changed files with 373 additions and 129 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,6 @@ jobs:
with:
python-version: "3.7"
- name: Install dependencies
run: pip install --upgrade pip mypy==1.0.1 pydantic==1.10.4
run: pip install --upgrade pip mypy pydantic
- name: Run mypy
run: mypy --install-types --non-interactive ./src
3 changes: 1 addition & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,12 @@ jobs:
git checkout main
git merge --no-ff ${{ env.BRANCH }}
git tag -a v${{ env.VERSION }} -m "Release ${{ env.VERSION }}"
git push --atomic origin main refs/tags/v${{ env.VERSION }}
# Try to merge back release branch
git checkout ${{ env.BRANCH }}
git merge --ff-only main
git checkout develop
git merge --no-ff ${{ env.BRANCH }}
git push origin develop :${{ env.BRANCH }}
git push --atomic origin main develop refs/tags/v${{ env.VERSION }} :${{ env.BRANCH }}
- name: Publish package to PyPI
uses: pypa/gh-action-pypi-publish@v1.5.2
with:
Expand Down
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ ResultCode.SUCCESS


#### Build the project
Set virtual env
```console
python3 -m venv venv
source venv/bin/activate
```
Install dependencies
```console
pip install -e ".[dev]"
Expand Down Expand Up @@ -89,7 +94,12 @@ Supported APIs
| `get_base_task_result` | [Download response task results](https://automation.trendmicro.com/xdr/api-v3#tag/Common/paths/~1v3.0~1response~1tasks~1%7Bid%7D/get) |
| `get_task_result` | [Download response task results](https://automation.trendmicro.com/xdr/api-v3#tag/Common/paths/~1v3.0~1response~1tasks~1{id}/get) |
| **Custom Scripts** | |
| `run_custom_script` | [Run Custom Script](https://automation.trendmicro.com/xdr/api-v3#tag/Custom-Script/paths/~1v3.0~1response~1endpoints~1runScript/post) |
| `get_custom_script_list` | [List custom scripts](https://automation.trendmicro.com/xdr/api-v3#tag/Custom-Script/paths/~1v3.0~1response~1customScripts/get) |
| `add_custom_script` | [Add custom script](https://automation.trendmicro.com/xdr/api-v3#tag/Custom-Script/paths/~1v3.0~1response~1customScripts/post) |
| `update_custom_script` | [Update custom script](https://automation.trendmicro.com/xdr/api-v3#tag/Custom-Script/paths/~1v3.0~1response~1customScripts~1%7Bid%7D~1update/post) |
| `download_custom_script` | [Download custom script](https://automation.trendmicro.com/xdr/api-v3#tag/Custom-Script/paths/~1v3.0~1response~1customScripts~1%7Bid%7D/get) |
| `delete_custom_script` | [Delete custom script](https://automation.trendmicro.com/xdr/api-v3#tag/Custom-Script/paths/~1v3.0~1response~1customScripts~1%7Bid%7D/delete) |
| `run_custom_script` | [Run custom script](https://automation.trendmicro.com/xdr/api-v3#tag/Custom-Script/paths/~1v3.0~1response~1endpoints~1runScript/post) |
| **Domain Account** | |
| `disable_account` | [Disable user account](https://automation.trendmicro.com/xdr/api-v3#tag/Domain-Account/paths/~1v3.0~1response~1domainAccounts~1disable/post) |
| `enable_account` | [Enable user account](https://automation.trendmicro.com/xdr/api-v3#tag/Domain-Account/paths/~1v3.0~1response~1domainAccounts~1enable/post) |
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ classifiers = [
dependencies = [
"beautifulsoup4 ~= 4.11.1",
"requests ~= 2.31.0",
"pydantic ~= 1.10.4",
"pydantic ~= 2.5.3",
]

[project.optional-dependencies]
Expand Down
8 changes: 8 additions & 0 deletions src/pytmv1/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
EntityType,
EventID,
EventSubID,
FileType,
Iam,
IntegrityLevel,
InvestigationStatus,
Expand Down Expand Up @@ -67,6 +68,7 @@
from .model.responses import (
AccountTaskResp,
AddAlertNoteResp,
AddCustomScriptResp,
BaseTaskResp,
BlockListTaskResp,
BytesResp,
Expand All @@ -78,6 +80,7 @@
EndpointTaskResp,
GetAlertDetailsResp,
GetAlertListResp,
GetCustomScriptListResp,
GetEmailActivityDataCountResp,
GetEmailActivityDataResp,
GetEndpointActivityDataCountResp,
Expand All @@ -94,6 +97,7 @@
SandboxSuspiciousListResp,
SubmitFileToSandboxResp,
TerminateProcessTaskResp,
TextResp,
)
from .results import MultiResult, Result, ResultCode

Expand All @@ -105,6 +109,7 @@
"AccountTask",
"AccountTaskResp",
"AddAlertNoteResp",
"AddCustomScriptResp",
"Alert",
"BaseTaskResp",
"BlockListTaskResp",
Expand Down Expand Up @@ -133,6 +138,7 @@
"FileTask",
"GetAlertDetailsResp",
"GetAlertListResp",
"GetCustomScriptListResp",
"GetEmailActivityDataResp",
"GetEmailActivityDataCountResp",
"GetEndpointActivityDataResp",
Expand All @@ -142,6 +148,7 @@
"GetSuspiciousListResp",
"HostInfo",
"Iam",
"FileType",
"ImpactScope",
"Indicator",
"IntegrityLevel",
Expand Down Expand Up @@ -187,6 +194,7 @@
"SuspiciousObjectTask",
"TaskAction",
"TerminateProcessTaskResp",
"TextResp",
"TiAlert",
"TiIndicator",
"Value",
Expand Down
134 changes: 134 additions & 0 deletions src/pytmv1/caller.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@
EndpointActivity,
ExceptionObject,
SaeAlert,
Script,
SuspiciousObject,
TiAlert,
)
from .model.enums import (
Api,
FileType,
HttpMethod,
InvestigationStatus,
QueryOp,
Expand All @@ -36,12 +38,14 @@
)
from .model.responses import (
AddAlertNoteResp,
AddCustomScriptResp,
BaseTaskResp,
BytesResp,
ConnectivityResp,
ConsumeLinkableResp,
GetAlertDetailsResp,
GetAlertListResp,
GetCustomScriptListResp,
GetEmailActivityDataCountResp,
GetEmailActivityDataResp,
GetEndpointActivityDataCountResp,
Expand All @@ -57,6 +61,7 @@
SandboxSubmissionStatusResp,
SandboxSuspiciousListResp,
SubmitFileToSandboxResp,
TextResp,
)
from .results import MultiResult, Result

Expand Down Expand Up @@ -131,6 +136,36 @@ def add_alert_note(
json={"content": note},
)

def add_custom_script(
self,
file_type: FileType,
file_name: str,
file: bytes,
description: Optional[str] = None,
) -> Result[AddCustomScriptResp]:
"""
Uploads a custom script. Supported file extensions: .ps1, .sh.
Note: Custom scripts must use UTF-8 encoding.
:param file_type: File type.
:type file_type: FileType
:param file_name: File name.
:type file_name: str
:param file: Raw content in bytes.
:type file: bytes
:param description: Description.
:type description: Optional[str]
:return: Result[AddACustomScriptResp]
"""
return self._core.send(
AddCustomScriptResp,
Api.ADD_CUSTOM_SCRIPT,
HttpMethod.POST,
data=utils.filter_none(
{"fileType": file_type, "description": description}
),
files={"file": (file_name, file, "text/plain")},
)

def add_to_block_list(
self, *objects: ObjectTask
) -> MultiResult[MultiResp]:
Expand Down Expand Up @@ -220,6 +255,30 @@ def consume_alert_list(
),
)

def consume_custom_script_list(
self,
consumer: Callable[[Script], None],
op: QueryOp = QueryOp.AND,
**fields: str,
) -> Result[ConsumeLinkableResp]:
"""Retrieves and consume cust. scripts filtered by provided values.
:param consumer: Function which will consume every record in result.
:type consumer: Callable[[Script], None]
:param op: Operator to apply between fields (ie: ... OR ...).
:type op: QueryOp
:param fields: Field/value used to filter result (i.e:fileName="1.sh"),
check Vision One API documentation for full list of supported fields.
:type fields: Dict[str, str]
:return: Result[ConsumeLinkableResp]
"""
return self._core.send_linkable(
GetCustomScriptListResp,
Api.GET_CUSTOM_SCRIPT_LIST,
consumer,
params={"filter": utils.custom_script_query(op, **fields)},
)

def consume_email_activity_data(
self,
consumer: Callable[[EmailActivity], None],
Expand Down Expand Up @@ -368,6 +427,19 @@ def consume_suspicious_list(
GetSuspiciousListResp, Api.GET_SUSPICIOUS_LIST, consumer
)

def delete_custom_script(self, script_id: str) -> Result[NoContentResp]:
"""Deletes custom script.
:param script_id: Unique string that identifies a script file.
:type script_id: str
:return: Result[NoContentResp]
"""
return self._core.send(
NoContentResp,
Api.DELETE_CUSTOM_SCRIPT.value.format(script_id),
HttpMethod.DELETE,
)

def delete_email_message(
self, *messages: Union[EmailMessageUIdTask, EmailMessageIdTask]
) -> MultiResult[MultiResp]:
Expand Down Expand Up @@ -405,6 +477,17 @@ def disable_account(
],
)

def download_custom_script(self, script_id: str) -> Result[TextResp]:
"""Downloads custom script.
:param script_id: Unique string that identifies a script file.
:type script_id: str
:return: Result[BytesResp]
"""
return self._core.send(
TextResp, Api.DOWNLOAD_CUSTOM_SCRIPT.value.format(script_id)
)

def download_sandbox_analysis_result(
self,
submit_id: str,
Expand Down Expand Up @@ -565,6 +648,24 @@ def get_base_task_result(
BaseTaskResp, task_id, poll, poll_time_sec
)

def get_custom_script_list(
self, op: QueryOp = QueryOp.AND, **fields: str
) -> Result[GetCustomScriptListResp]:
"""Retrieves scripts in a paginated list filtered by provided values.
:param op: Operator to apply between fields (ie: ... OR ...).
:type op: QueryOp
:param fields: Field/value used to filter result (i.e:fileName="1.sh"),
check Vision One API documentation for full list of supported fields.
:type fields: Dict[str, str]
:return: Result[GetCustomScriptsResp]
"""
return self._core.send(
GetCustomScriptListResp,
Api.GET_CUSTOM_SCRIPT_LIST,
params={"filter": utils.custom_script_query(op, **fields)},
)

def get_email_activity_data(
self,
start_time: Optional[str] = None,
Expand Down Expand Up @@ -1093,6 +1194,39 @@ def terminate_process(
Api.TERMINATE_ENDPOINT_PROCESS, *processes
)

def update_custom_script(
self,
script_id: str,
file_type: FileType,
file_name: str,
file: bytes,
description: Optional[str] = None,
) -> Result[NoContentResp]:
"""
Updates a custom script. Supported file extensions: .ps1, .sh.
Note: Custom scripts must use UTF-8 encoding.
:param script_id: Unique string that identifies a script file.
:type script_id: str
:param file_type: File type.
:type file_type: FileType
:param file_name: File name.
:type file_name: str
:param file: Raw content in bytes.
:type file: bytes
:param description: Description.
:type description: Optional[str]
:return: Result[NoContentResp]
"""
return self._core.send(
NoContentResp,
Api.UPDATE_CUSTOM_SCRIPT.value.format(script_id),
HttpMethod.POST,
data=utils.filter_none(
{"fileType": file_type, "description": description}
),
files={"file": (file_name, file, "text/plain")},
)

def check_connectivity(self) -> Result[ConnectivityResp]:
"""Checks the connection to the API service
and verifies if your authentication token is valid.
Expand Down
Loading

0 comments on commit 249c287

Please sign in to comment.