Skip to content

Commit

Permalink
#301 - Add client, alert and api reference docs
Browse files Browse the repository at this point in the history
  • Loading branch information
Kamforka committed Oct 18, 2024
1 parent 12116cf commit 61d3b5d
Show file tree
Hide file tree
Showing 33 changed files with 1,037 additions and 78 deletions.
13 changes: 5 additions & 8 deletions .github/workflows/_deploy-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,16 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Compare tag and package version
run: |
TAG=${GITHUB_REF#refs/*/}
VERSION=$(grep -Po '(?<=version = ")[^"]*' pyproject.toml)
if [ "$TAG" != "$VERSION" ]; then
echo "Tag value and package version are different: ${TAG} != ${VERSION}"
exit 1
fi
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: 3.13
- name: Install build dependencies
run: pip install --no-cache-dir -U pip .['docs']
- name: Configure git
run: |
git fetch origin gh-pages --depth=1
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
- name: Deploy to github pages
run: ./scripts/cd.py --deploy-docs
9 changes: 5 additions & 4 deletions .github/workflows/main-cicd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ jobs:
uses: ./.github/workflows/_build-package.yml
build-docs:
uses: ./.github/workflows/_build-docs.yml
deploy-docs:
if: startsWith(github.ref, 'refs/heads/main')
uses: ./.github/workflows/_deploy-docs.yml
needs: [build-docs, build-package, integration-tests, static-checks]
upload-package:
if: startsWith(github.ref, 'refs/tags/')
uses: ./.github/workflows/_upload-package.yml
needs: [static-checks, integration-tests, build-package, build-docs]
needs: [build-docs, build-package, integration-tests, static-checks]
secrets:
PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }}
deploy-docs:
uses: ./.github/workflows/_deploy-docs.yml
needs: [upload-package]
67 changes: 39 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,42 @@
<p align="center">
<a href="https://github.com/TheHive-Project/TheHive4py"><img src="https://strangebee.com/wp-content/uploads/2024/07/Icon4Nav_TheHive.png" alt="TheHive Logo"></a>
</p>
<p align="center">
<em>thehive4py - the de facto Python API client of <a href="https://strangebee.com/thehive/">TheHive</a></em>
</p>
<p align="center">
<a href="https://github.com/TheHive-Project/TheHive4py/releases" target="_blank">
<img src="https://img.shields.io/github/v/release/Thehive-project/thehive4py?logo=github&logoColor=FFC72C&labelColor=0049D4" alt="release">
</a>
<a href="https://github.com/TheHive-Project/TheHive4py/actions/workflows/main-cicd.yml" target="_blank">
<img src="https://img.shields.io/github/actions/workflow/status/TheHive-Project/TheHive4py/main-cicd.yml?logo=github&logoColor=FFC72C&labelColor=0049D4" alt="build">
</a>
<a href="https://app.codecov.io/github/TheHive-Project/TheHive4py" target="_blank">
<img src="https://img.shields.io/codecov/c/gh/TheHive-Project/TheHive4py?logo=codecov&logoColor=FFC72C&labelColor=0049D4" alt="codecov">
</a>
<a href="https://pypi.org/project/thehive4py" target="_blank">
<img src="https://img.shields.io/pypi/dm/thehive4py?logo=python&logoColor=FFC72C&labelColor=0049D4" alt="pypi">
</a>
<a href="./LICENSE" target="_blank">
<img src="https://img.shields.io/github/license/TheHive-Project/TheHive4py?logo=unlicense&logoColor=FFC72C&labelColor=0049D4" alt="license">
</a>
<a href="https://discord.com/invite/XhxG3vzM44" target="_blank">
<img src="https://img.shields.io/discord/779945042039144498?logo=discord&logoColor=FFC72C&labelColor=0049D4" alt="discord">
</a>
</p>

# thehive4py
<div align="center">
<a href="https://github.com/TheHive-Project/TheHive4py" target="_blank">
<img src="https://strangebee.com/wp-content/uploads/2024/07/Icon4Nav_TheHive.png" alt="TheHive Logo">
</a>
<b style="display: block; font-size: 2rem">TheHive4py</b>
</p>
<p align="center">
<em>the de facto Python API client of <a href="https://strangebee.com/thehive/">TheHive</a></em>
</p>
<p align="center">
<a href="https://github.com/TheHive-Project/TheHive4py/releases" target="_blank">
<img src="https://img.shields.io/github/v/release/Thehive-project/thehive4py?logo=github&logoColor=FFC72C&labelColor=0049D4" alt="release">
</a>
<a href="https://github.com/TheHive-Project/TheHive4py/actions/workflows/main-cicd.yml" target="_blank">
<img src="https://img.shields.io/github/actions/workflow/status/TheHive-Project/TheHive4py/main-cicd.yml?logo=github&logoColor=FFC72C&labelColor=0049D4" alt="build">
</a>
<a href="https://app.codecov.io/github/TheHive-Project/TheHive4py" target="_blank">
<img src="https://img.shields.io/codecov/c/gh/TheHive-Project/TheHive4py?logo=codecov&logoColor=FFC72C&labelColor=0049D4" alt="codecov">
</a>
<a href="https://pypi.org/project/thehive4py" target="_blank">
<img src="https://img.shields.io/pypi/dm/thehive4py?logo=python&logoColor=FFC72C&labelColor=0049D4" alt="pypi">
</a>
<a href="./LICENSE" target="_blank">
<img src="https://img.shields.io/github/license/TheHive-Project/TheHive4py?logo=unlicense&logoColor=FFC72C&labelColor=0049D4" alt="license">
</a>
<a href="https://discord.com/invite/XhxG3vzM44" target="_blank">
<img src="https://img.shields.io/discord/779945042039144498?logo=discord&logoColor=FFC72C&labelColor=0049D4" alt="discord">
</a>
</p>
</div>

---
**Documentation**: <a href="https://thehive-project.github.io/TheHive4py" target="_blank">https://thehive-project.github.io/TheHive4py</a>

**Source Code**: <a href="https://github.com/TheHive-Project/TheHive4py" target="_blank">https://github.com/TheHive-Project/TheHive4py</a>

---

# Introduction

> [!IMPORTANT]
> thehive4py v1.x is not maintained anymore as TheHive v3 and v4 are end of life. thehive4py v2.x is a complete rewrite and is not compatible with thehive4py v1.x. The library is still in beta phase.
Expand Down
208 changes: 208 additions & 0 deletions docs/examples/alert.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
# Alert

## A simple alert

A new alert requires at least these fields to be defined:

- `type`: The type of the alert.
- `source`: The source of the alert.
- `sourceRef`: A unique reference for the alert.
- `title`: A descriptive title for the alert.
- `description`: Additional information describing the alert.

Here's an example that demonstrates how to create the most simplistic alert possible using the [alert.create][thehive4py.endpoints.alert.AlertEndpoint.create] method:

```python
--8<-- "examples/alert/simple.py"
```

## An advanced alert

In the previous example we really kept things simple and only specified the required alert fields inline in the create method call.
With a more advanced example this can become complicated and hard to read.
Fortunately we can use `thehive4py`'s type hints to the rescue and specify more complex input alerts outside of the method call.

Here's how:
```python
--8<-- "examples/alert/advanced.py"
```

In the above snippet `input_alert` is created before the create call and later passed to the `alert` argument.
Finally after the creation of the alert we saved the response in the `output_alert` to be able to use it later.

!!! note
While the above alert is a bit more advanced it's still far from the most complex example possible.
In case you want to see the what the Alert API offers please check out the [official alert docs](https://docs.strangebee.com/thehive/api-docs/#tag/Alert).


## Alert observables

TheHive API provides multiple ways to add observables to alerts, let them be textual or file based observables.

### Add observables during alert creation

We can add observables already during alert creation. This is a great way to combine alert and observable creation in a simple and atomic way:

Let's create an alert with an `ip` and a `domain` observable:

```python
--8<-- "examples/alert/observable_during_alerting.py"
```

### Add observables to an existing alert

While it's probably the most convenient way to combine alert and observable creation in a single call, sometimes we don't have all the observables at hand during alert creation time.

Fortunately TheHive API supports alert observable creation on already existing alerts. Let's repeat the previous example, but this time add the two observables to an existing alert using the [alert.create_observable][thehive4py.endpoints.alert.AlertEndpoint.create_observable] method:


```python
--8<-- "examples/alert/observable_after_alerting.py"
```

### Add file based observables

In the previous examples we've seen how to handle simple observables without attachments. Next we will create a temporary directory with a dummy file and some dummy content that will represent our file based observable and add it to an alert:


```python
--8<-- "examples/alert/observable_from_file.py"
```

As we can see from the above example a file based observable must specify the `attachment` property with a key that links it to the attachment specified in the `attachment_map` dictionary.

This way TheHive will know which attachment to pair with which observable behind the scenes.

In our example `attachment_key` is used to specify the relationship between the observable and the actual file. In this case its value is a uuid, however it can be any arbitrary value, though it's important that it should uniquely identify the attachment and the observable we would like to pair in TheHive.

## Update single and bulk

Sometimes an existing alert needs to be updated. TheHive offers multiple ways to accomplish this task either with a single alert or multiple ones.

### Update single

A single alert can be updated using [alert.update][thehive4py.endpoints.alert.AlertEndpoint.update] method. The method requires the `alert_id` of the alert to be updated and the `fields` to update.

```python
--8<-- "examples/alert/update_single.py"
```

In the above example we've updated the `title` and the `tags` fields.

Be mindful though, `thehive4py` is a lightweight wrapper around TheHive API and offers no object relationship mapping functionalities, meaning that the original `original_alert` won't reflect the changes of the update.

To work with the updated alert we fetched the latest version using the [alert.get][thehive4py.endpoints.alert.AlertEndpoint.get] method and stored it in the `updated_alert` variable.

Now the content of `updated_alert` should reflect the changes we made with our update request.

!!! tip
To see the full list of supported update fields please consult the [official docs](https://docs.strangebee.com/thehive/api-docs/#tag/Alert/operation/Update%20Alert).

### Update bulk

To update the **same fields** with the **same values** on multiple alerts at the same time, one can use [alert.bulk_update][thehive4py.endpoints.alert.AlertEndpoint.bulk_update] method.
The method accepts the same `fields` dictionary with an additional `ids` field on it, which should contain the list of ids of the alerts to be bulk updated.

```python
--8<-- "examples/alert/update_bulk.py"
```

In the example we prepare two alerts for the bulk update, and collect their ids in the `original_alert_ids` list.
Then we update the fields `title` and `tags` on both alerts using the bulk update method.

## Get and find

There are multiple ways to retrieve already existing alerts:

### Get a single alert

To get a single alert one can use the [alert.get][thehive4py.endpoints.alert.AlertEndpoint.get] method with the alert's id as follows:

```python
--8<-- "examples/alert/fetch_with_get.py"
```

### Find multiple alerts

To fetch multiple alerts based on arbitrary conditions one can use the [alert.find][thehive4py.endpoints.alert.AlertEndpoint.find] method which is an abstraction on top of TheHive's Query API.

In the next example we will create two alerts with different tags. The first alert will get the `antivirus` tag while the second one will get the `phishing` tag.

Then we will construct a query filter that will look for alerts with these tags on them:

```python
--8<-- "examples/alert/fetch_with_find.py"
```

The above example demonstrates two ways to construct query filters.

One is to provide a raw dict based filter which is the plain format of [TheHive's Query API](https://docs.strangebee.com/thehive/api-docs/#tag/Query-and-Export). This is demonstrated in the `raw_filters` variable.

However this can be cumbersome to remember, that's why `thehive4py` provides filter builders to conveniently build filter expressions on the client side. This alternative approach is demonstrated in the `class_filters` variable.

These filter expressions can be chained together with different operators, just like we did with the `|` (`or`) operator in the example.

Currently, the filter classes support the following operators:

- `&`: Used for the Query API's `_and` construct.
- `|`: Used for the Query API's `_or` construct.
- `~`: Used for the Query API's `_not` construct.

The full list of the filter builders can be found in the [query.filters][thehive4py.query.filters] module.

## Promote and merge into a case

In TheHive alerts usually represent signals of compromise while cases provide a higher level entity to group these signals into one object.
Therefore we can promote an alert into a case or merge new alerts into an existing case for a more organised investigation.

### Promote to case

To create a case from an alert we can use [alert.promote_to_case][thehive4py.endpoints.alert.AlertEndpoint.promote_to_case] method.

```python
--8<-- "examples/alert/case_promote.py"
```

!!! tip
For additional control the method accepts a `fields` argument which can be used to modify properties on the case.
To see all available options please consult the [official docs](https://docs.strangebee.com/thehive/api-docs/#tag/Alert/operation/Create%20Case%20from%20Alert).

### Merge into case

Oftentimes new alerts correspond to an already existing case. Fortunately we have the option to merge such alerts into a parent case using the [alert.merge_into_case][thehive4py.endpoints.alert.AlertEndpoint.merge_into_case] method.

```python
--8<-- "examples/alert/case_merge.py"
```

In the above example we prepared a `parent_case` to which we merge the `new_alert` using their ids and finally save the updated case in the `updated_parent_case` variable.

!!! tip
It can happen that multiple new alerts belong to the same parent case. In such situation we can use the [alert.bulk_merge_into_case][thehive4py.endpoints.alert.AlertEndpoint.bulk_merge_into_case] method for a more convenient merge process.


## Delete single and bulk

`thehive4py` provides two different ways to delete alerts:

- delete a single alert
- delete alerts in bulk

### Delete single

To delete a single alert the [alert.delete][thehive4py.endpoints.alert.AlertEndpoint.delete] method can be used as follows:

```python
--8<-- "examples/alert/delete_single.py"
```


### Delete in bulk

To delete multiple alerts via a single request one can use the [alert.bulk_delete][thehive4py.endpoints.alert.AlertEndpoint.bulk_delete] method as follows:

```python
--8<-- "examples/alert/delete_bulk.py"
```

In the above example we created two alerts and saved their ids in the `alert_ids_to_delete` variable just to pass it in the bulk deletion method.
74 changes: 74 additions & 0 deletions docs/examples/client.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Client

## Authentication

TheHive API provides two ways to authenticate the client:

- apikey auth
- username and password auth

### Auth with apikey

```python
--8<-- "examples/client/auth_with_apikey.py"
```

### Auth with username and password

```python
--8<-- "examples/client/auth_with_username_and_password.py"
```

## Organisation

The client will use the default organisation of the user. However in case the user belongs to multiple organisation the client also provides options to specify which organisation to use.


### Specify the organisation during init

In this example we will instaniate a client with the `admin` organisation explicitly:

```python
--8<-- "examples/client/org_via_constructor.py"
```

### Switch organisations during runtime

In this example we will instantiate a client without explicitly specifying an organisation and switch to another organisation using the [session_organisation][thehive4py.client.TheHiveApi.session_organisation] property:

```python
--8<-- "examples/client/org_during_runtime.py"
```

!!! warning
The [session_organisation][thehive4py.client.TheHiveApi.session_organisation] property is not thread-safe and it's almost always better to instantiate more clients if one wants to work with multiple organisations in parallel.


## SSL Verification

By default the client verifies if the connection is going through SSL.
In case one needs to pass a custom certificate bundle or directory it's possible via the `verify` argument like:

```python
--8<-- "examples/client/ssl.py"
```

!!! note
It's also possible to disable SSL verification completely by setting `verify` to `False`.
However this is greatly discouraged as it's a security bad practice.


## Retries

The client comes with a sensible retry mechanism by default that will try to cover the most common use cases.
However it's also possible to configure a tailored retry mechanism via the `max_retries` argument.

The below example will configure a custom retry mechanism with 5 total attempts, a backoff factor of 0.3 seconds on GET methods and 500 status codes:

```python
--8<-- "examples/client/retries.py"
```

To learn more about the `urllib3.Retry` object please consult the official documentation [here](https://urllib3.readthedocs.io/en/stable/reference/urllib3.util.html#urllib3.util.Retry).


Loading

0 comments on commit 61d3b5d

Please sign in to comment.