Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[fr] ability to manage multi valued customfields #253

Merged
merged 3 commits into from
Aug 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from thehive4py.types.alert import InputAlert, OutputAlert
from thehive4py.types.case import InputCase, OutputCase
from thehive4py.types.comment import OutputComment
from thehive4py.types.custom_field import OutputCustomField
from thehive4py.types.observable import InputObservable, OutputObservable
from thehive4py.types.procedure import OutputProcedure
from thehive4py.types.profile import OutputProfile
Expand Down Expand Up @@ -233,3 +234,17 @@ def test_profile(thehive_admin: TheHiveApi) -> OutputProfile:
return thehive_admin.profile.create(
profile={"name": "my-read-only", "permissions": []}
)


@pytest.fixture
def test_custom_field(thehive_admin: TheHiveApi) -> OutputCustomField:
return thehive_admin.custom_field.create(
custom_field={
"name": "test-field",
"type": "string",
"displayName": "Test Field",
"description": "...",
"group": "default",
"options": [],
}
)
50 changes: 50 additions & 0 deletions tests/test_custom_field_endpoint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import pytest
from thehive4py.client import TheHiveApi
from thehive4py.errors import TheHiveError
from thehive4py.types.custom_field import InputUpdateCustomField, OutputCustomField


class TestTaskLogEndpoint:
def test_create_and_list(self, thehive_admin: TheHiveApi):
created_custom_field = thehive_admin.custom_field.create(
custom_field={
"name": "my-field",
"displayName": "My Field",
"description": "...",
"group": "default",
"type": "string",
"options": [],
}
)

custom_fields = thehive_admin.custom_field.list()
assert created_custom_field in custom_fields

def test_delete(
self, thehive_admin: TheHiveApi, test_custom_field: OutputCustomField
):
thehive_admin.custom_field.delete(custom_field_id=test_custom_field["_id"])

with pytest.raises(TheHiveError):
thehive_admin.task_log.get(task_log_id=test_custom_field["_id"])

def test_update(
self, thehive_admin: TheHiveApi, test_custom_field: OutputCustomField
):

custom_field_id = test_custom_field["_id"]
update_fields: InputUpdateCustomField = {
"displayName": "something else ...",
"type": "float",
}
thehive_admin.custom_field.update(
custom_field_id=custom_field_id, fields=update_fields
)
updated_custom_field = [
cf
for cf in thehive_admin.custom_field.list()
if cf["_id"] == custom_field_id
][0]

for key, value in update_fields.items():
assert updated_custom_field.get(key) == value
7 changes: 6 additions & 1 deletion tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def build_container_url(container_name: str) -> str:


def run_hive_container(
container_name: str, container_image: str = "thehive4py-thehive:5.0.1"
container_name: str, container_image: str = "thehive4py-thehive:5.0.9"
):
subprocess.run(
shlex.split(
Expand Down Expand Up @@ -107,12 +107,17 @@ def reinit_hive_container(client: TheHiveApi) -> None:
profiles = client.profile.find(
filters=~Eq("name", "analyst") & ~Eq("name", "read-only")
)
custom_fields = client.custom_field.list()
with ThreadPoolExecutor() as executor:
executor.map(client.alert.delete, [alert["_id"] for alert in alerts])
executor.map(client.case.delete, [case["_id"] for case in cases])
executor.map(client.user.delete, [user["_id"] for user in users])
executor.map(
client.profile.delete, [profile["_id"] for profile in profiles]
)
executor.map(
client.custom_field.delete,
[custom_field["_id"] for custom_field in custom_fields],
)

client.session_organisation = original_session_organisation
4 changes: 4 additions & 0 deletions thehive4py/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
UserEndpoint,
)
from thehive4py.endpoints.cortex import CortexEndpoint
from thehive4py.endpoints.custom_field import CustomFieldEndpoint
from thehive4py.session import TheHiveSession


Expand Down Expand Up @@ -51,6 +52,9 @@ def __init__(
self.organisation = OrganisationEndpoint(self.session)
self.profile = ProfileEndpoint(self.session)

# entity endpoints
self.custom_field = CustomFieldEndpoint(self.session)

# connector endpoints
self.cortex = CortexEndpoint(self.session)

Expand Down
1 change: 1 addition & 0 deletions thehive4py/endpoints/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from .case import CaseEndpoint
from .comment import CommentEndpoint
from .cortex import CortexEndpoint
from .custom_field import CustomFieldEndpoint
from .observable import ObservableEndpoint
from .organisation import OrganisationEndpoint
from .procedure import ProcedureEndpoint
Expand Down
28 changes: 28 additions & 0 deletions thehive4py/endpoints/custom_field.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from typing import List

from thehive4py.endpoints._base import EndpointBase
from thehive4py.types.custom_field import (
InputCustomField,
InputUpdateCustomField,
OutputCustomField,
)


class CustomFieldEndpoint(EndpointBase):
def create(self, custom_field: InputCustomField) -> OutputCustomField:
return self._session.make_request(
"POST", path="/api/v1/customField", json=custom_field
)

def list(self) -> List[OutputCustomField]:
return self._session.make_request("GET", path="/api/v1/customField")

def delete(self, custom_field_id: str) -> None:
return self._session.make_request(
"DELETE", path=f"/api/v1/customField/{custom_field_id}"
)

def update(self, custom_field_id: str, fields: InputUpdateCustomField) -> None:
return self._session.make_request(
"PATCH", path=f"/api/v1/customField/{custom_field_id}", json=fields
)
41 changes: 41 additions & 0 deletions thehive4py/types/custom_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,44 @@ class OutputCustomFieldValue(TypedDict):
type: str
value: Any
order: int


class InputCustomFieldRequired(TypedDict):
name: str
group: str
description: str
type: str


class InputCustomField(InputCustomFieldRequired, total=False):
displayName: str
mandatory: bool
options: list


class OutputCustomFieldRequired(TypedDict):
_id: str
_type: str
_createdBy: str
_createdAt: int
name: str
displayName: str
group: str
description: str
type: str
mandatory: bool


class OutputCustomField(OutputCustomFieldRequired, total=False):
_updatedBy: str
_updatedAt: int
options: list


class InputUpdateCustomField(TypedDict, total=False):
displayName: str
group: str
description: str
type: str
options: list
mandatory: bool