Skip to content

Add: Support for the openvasd HTTP API #1215

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

Open
wants to merge 33 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
3f9290c
Add: Support for the openvasd HTTP API
timopollmeier Apr 3, 2025
f83a1d0
Add documentation for HTTP APIs, small refactoring
timopollmeier Apr 4, 2025
0340b84
Reformat HTTP package and tests
timopollmeier Apr 4, 2025
dc76dae
Address linter warnings
timopollmeier Apr 4, 2025
8484c80
Break some overlong docstring lines
timopollmeier Apr 4, 2025
bdf2eb1
Address linter warnings in HTTP tests
timopollmeier Apr 4, 2025
bb8d175
Use workaround for typing.Self missing in older Python versions
timopollmeier Apr 4, 2025
ae985bd
Move misplaced assertion in test_create_scan to correct place
timopollmeier Apr 4, 2025
b05f62b
Clean up type hints for HTTP APIs
timopollmeier Apr 4, 2025
ac4d607
Reformat gvm/http/core/_api.py
timopollmeier Apr 4, 2025
318e064
Use correct vts list in test_create_scan assertions
timopollmeier Apr 4, 2025
7777f2e
Reorganize imports
timopollmeier Apr 4, 2025
39a0f85
Make type hints for mock HTTP responses work in older Python
timopollmeier Apr 4, 2025
14000fa
Move types-requests to dev dependencies
timopollmeier Apr 4, 2025
c7bc657
Use httpx library instead of requests
timopollmeier Apr 11, 2025
893cb7f
Move http package into protocols
timopollmeier Apr 11, 2025
6aa74ff
Fix type hints for change to httpx
timopollmeier Apr 11, 2025
41ad4dc
Move http module in imports and mock patches
timopollmeier Apr 11, 2025
0c28724
Remove: remove core package from protocols.http
ozgen Jun 20, 2025
f586770
Add http2 packages to poetry files.
ozgen Jun 20, 2025
6092792
Remove old implementation of openvasd1
ozgen Jun 23, 2025
3a7eab7
Add: Add new HTTP API structure and introduce modular sub-APIs
ozgen Jun 23, 2025
7af2fc1
Doc: update and fix openvasd API documentation pages
ozgen Jun 23, 2025
6b2bbb0
fix the conflict in the poetry.lock
ozgen Jun 23, 2025
e938209
Rename versioned module and drop Client class
bjoernricks Jul 8, 2025
e108e88
Rename openvasd API class
bjoernricks Jul 8, 2025
84a0232
Mark OpenvasdHttpAPIv1 as public for gvm.protocols.http.openvasd
bjoernricks Jul 8, 2025
d392695
Mark all modules of openvasd API as private
bjoernricks Jul 8, 2025
1df0864
change: Require httpx as direct dependency for openvasd API
bjoernricks Jul 8, 2025
1602d0e
Cleanup and improve the openvasd API
bjoernricks Jul 8, 2025
6d1197a
Improve docs for openvasd http v1 API
bjoernricks Jul 8, 2025
0694afb
Improve returned objects of Metadata API methods
bjoernricks Jul 8, 2025
e493212
docs: Add sphinx autobuild for auto rebuilding the docs in a local se…
bjoernricks Jul 8, 2025
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
5 changes: 4 additions & 1 deletion docs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ BUILDDIR = build
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

.PHONY: help Makefile
.PHONY: help Makefile livehtml

livehtml:
sphinx-autobuild "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
Expand Down
16 changes: 16 additions & 0 deletions docs/api/http.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
(http)=

# HTTP APIs

```{eval-rst}
.. automodule:: gvm.protocols.http
```

The following modules are provided:

```{eval-rst}
.. toctree::
:maxdepth: 1

openvasdv1
```
18 changes: 18 additions & 0 deletions docs/api/openvasdv1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
(openvasdv1)=

# openvasd v1

```{eval-rst}
.. automodule:: gvm.protocols.http.openvasd
:members:
```

```{toctree}
:hidden:

openvasdv1/health
openvasdv1/metadata
openvasdv1/notus
openvasdv1/scans
openvasdv1/vts
```
6 changes: 6 additions & 0 deletions docs/api/openvasdv1/health.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Health API

```{eval-rst}
.. automodule:: gvm.protocols.http.openvasd._health
:members:
```
6 changes: 6 additions & 0 deletions docs/api/openvasdv1/metadata.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Metadata API

```{eval-rst}
.. automodule:: gvm.protocols.http.openvasd._metadata
:members:
```
6 changes: 6 additions & 0 deletions docs/api/openvasdv1/notus.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Notus API

```{eval-rst}
.. automodule:: gvm.protocols.http.openvasd._notus
:members:
```
6 changes: 6 additions & 0 deletions docs/api/openvasdv1/scans.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Scans API

```{eval-rst}
.. automodule:: gvm.protocols.http.openvasd._scans
:members:
```
6 changes: 6 additions & 0 deletions docs/api/openvasdv1/vts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# VTs API

```{eval-rst}
.. automodule:: gvm.protocols.http.openvasd._vts
:members:
```
1 change: 1 addition & 0 deletions docs/api/protocols.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

gmp
ospv1
http
```

## Dynamic
Expand Down
9 changes: 9 additions & 0 deletions gvm/protocols/http/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# SPDX-FileCopyrightText: 2025 Greenbone AG
#
# SPDX-License-Identifier: GPL-3.0-or-later

"""
Package for supported Greenbone HTTP APIs.

Currently only `openvasd version 1 <https://greenbone.github.io/scanner-api/#/>`_ is supported.
"""
18 changes: 18 additions & 0 deletions gvm/protocols/http/openvasd/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# SPDX-FileCopyrightText: 2025 Greenbone AG
#
# SPDX-License-Identifier: GPL-3.0-or-later

"""
High-level API interface for interacting with openvasd HTTP services via
logical modules (health, metadata, scans, etc.).

Usage:

.. code-block:: python

from gvm.protocols.http.openvasd import OpenvasdHttpAPIv1
"""

from ._openvasd1 import OpenvasdHttpAPIv1

__all__ = ["OpenvasdHttpAPIv1"]
23 changes: 23 additions & 0 deletions gvm/protocols/http/openvasd/_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# SPDX-FileCopyrightText: 2025 Greenbone AG
#
# SPDX-License-Identifier: GPL-3.0-or-later


import httpx


class OpenvasdAPI:
def __init__(
self, client: httpx.Client, *, suppress_exceptions: bool = False
):
"""
Initialize the OpenvasdAPI entry point.

Args:
client: An initialized `httpx.Client` configured for communicating
with the openvasd server.
suppress_exceptions: If True, suppress exceptions and return structured error responses.
Default is False, which means exceptions will be raised.
"""
self._client = client
self._suppress_exceptions = suppress_exceptions
80 changes: 80 additions & 0 deletions gvm/protocols/http/openvasd/_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# SPDX-FileCopyrightText: 2025 Greenbone AG
#
# SPDX-License-Identifier: GPL-3.0-or-later

"""
http client for initializing a connection to the openvasd HTTP API using optional mTLS authentication.
"""

import ssl
from os import PathLike
from typing import Optional, Tuple, Union

from httpx import Client

StrOrPathLike = Union[str, PathLike[str]]


def create_openvasd_http_client(
host_name: str,
*,
api_key: Optional[str] = None,
server_ca_path: Optional[StrOrPathLike] = None,
client_cert_paths: Optional[
Union[StrOrPathLike, Tuple[StrOrPathLike, StrOrPathLike]]
] = None,
port: int = 3000,
) -> Client:
"""
Create a `httpx.Client` configured for mTLS-secured or API KEY access
to an openvasd HTTP API instance.

Args:
host_name: Hostname or IP of the OpenVASD server (e.g., "localhost").
api_key: Optional API key used for authentication via HTTP headers.
server_ca_path: Path to the server's CA certificate (for verifying the server).
client_cert_paths: Path to the client certificate (str) or a tuple of
(cert_path, key_path) for mTLS authentication.
port: The port to connect to (default: 3000).

Behavior:
- If both `server_ca_path` and `client_cert_paths` are set, an mTLS connection
is established using an SSLContext.
- If not, `verify` is set to False (insecure), and HTTP is used instead of HTTPS.
HTTP connection needs api_key for authorization.
"""
headers = {}

context: Optional[ssl.SSLContext] = None

# Prepare mTLS SSL context if needed
if client_cert_paths and server_ca_path:
context = ssl.create_default_context(
ssl.Purpose.SERVER_AUTH, cafile=server_ca_path
)
if isinstance(client_cert_paths, tuple):
context.load_cert_chain(
certfile=client_cert_paths[0], keyfile=client_cert_paths[1]
)
else:
context.load_cert_chain(certfile=client_cert_paths)

context.check_hostname = False
context.verify_mode = ssl.CERT_REQUIRED

# Set verify based on context presence
verify: Union[bool, ssl.SSLContext] = context if context else False

if api_key:
headers["X-API-KEY"] = api_key

protocol = "https" if context else "http"
base_url = f"{protocol}://{host_name}:{port}"

return Client(
base_url=base_url,
headers=headers,
verify=verify,
http2=True,
timeout=10.0,
)
87 changes: 87 additions & 0 deletions gvm/protocols/http/openvasd/_health.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# SPDX-FileCopyrightText: 2025 Greenbone AG
#
# SPDX-License-Identifier: GPL-3.0-or-later

"""
API wrapper for accessing the /health endpoints of the openvasd HTTP API.
"""

import httpx

from ._api import OpenvasdAPI


class HealthAPI(OpenvasdAPI):
"""
Provides access to the openvasd /health endpoints, which expose the
operational state of the scanner.

All methods return the HTTP status code of the response and raise an exception
if the server returns an error response (4xx or 5xx).
"""

def get_alive(self) -> int:
"""
Check if the scanner process is alive.

Returns:
HTTP status code (e.g., 200 if alive).

Raises:
httpx.HTTPStatusError: If the server response indicates failure and
exceptions are not suppressed.

See: GET /health/alive in the openvasd API documentation.
"""
try:
response = self._client.get("/health/alive")
response.raise_for_status()
return response.status_code
except httpx.HTTPStatusError as e:
if self._suppress_exceptions:
return e.response.status_code
raise

def get_ready(self) -> int:
"""
Check if the scanner is ready to accept requests (e.g., feed loaded).

Returns:
HTTP status code (e.g., 200 if ready).

Raises:
httpx.HTTPStatusError: If the server response indicates failure and
exceptions are not suppressed.

See: GET /health/ready in the openvasd API documentation.
"""
try:
response = self._client.get("/health/ready")
response.raise_for_status()
return response.status_code
except httpx.HTTPStatusError as e:
if self._suppress_exceptions:
return e.response.status_code
raise

def get_started(self) -> int:
"""
Check if the scanner has fully started.

Returns:
HTTP status code (e.g., 200 if started).

Raises:
httpx.HTTPStatusError: If the server response indicates failure and
exceptions are not suppressed.

See: GET /health/started in the openvasd API documentation.
"""
try:
response = self._client.get("/health/started")
response.raise_for_status()
return response.status_code
except httpx.HTTPStatusError as e:
if self._suppress_exceptions:
return e.response.status_code
raise
Loading
Loading