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 28 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
a596566
Add: Support for the openvasd HTTP API
timopollmeier Apr 3, 2025
048b51e
Add documentation for HTTP APIs, small refactoring
timopollmeier Apr 4, 2025
320caeb
Reformat HTTP package and tests
timopollmeier Apr 4, 2025
89a14ab
Address linter warnings
timopollmeier Apr 4, 2025
a961bea
Break some overlong docstring lines
timopollmeier Apr 4, 2025
2e28788
Address linter warnings in HTTP tests
timopollmeier Apr 4, 2025
3636a33
Use workaround for typing.Self missing in older Python versions
timopollmeier Apr 4, 2025
73ffbba
Move misplaced assertion in test_create_scan to correct place
timopollmeier Apr 4, 2025
44f67ea
Clean up type hints for HTTP APIs
timopollmeier Apr 4, 2025
1c1ac5b
Reformat gvm/http/core/_api.py
timopollmeier Apr 4, 2025
0709d37
Use correct vts list in test_create_scan assertions
timopollmeier Apr 4, 2025
8a1bab3
Reorganize imports
timopollmeier Apr 4, 2025
e11fd5f
Make type hints for mock HTTP responses work in older Python
timopollmeier Apr 4, 2025
ec59911
Move types-requests to dev dependencies
timopollmeier Apr 4, 2025
9d3da00
Use httpx library instead of requests
timopollmeier Apr 11, 2025
3bafb5a
Move http package into protocols
timopollmeier Apr 11, 2025
cf62121
Fix type hints for change to httpx
timopollmeier Apr 11, 2025
6dbe31d
Move http module in imports and mock patches
timopollmeier Apr 11, 2025
bd3edc8
Merge branch 'main' into add-openvasd
timopollmeier Apr 14, 2025
b531a15
Remove: remove core package from protocols.http
ozgen Jun 20, 2025
5723175
Add http2 packages to poetry files.
ozgen Jun 20, 2025
ee3ef10
Remove old implementation of openvasd1
ozgen Jun 23, 2025
0701223
Add: Add new HTTP API structure and introduce modular sub-APIs
ozgen Jun 23, 2025
3246e52
Doc: update and fix openvasd API documentation pages
ozgen Jun 23, 2025
80ad3c7
Merge branch 'main' into add-openvasd
ozgen Jun 23, 2025
7e8ffbf
Merge branch 'main' into add-openvasd
ozgen Jun 23, 2025
eb4d729
fix the conflict in the poetry.lock
ozgen Jun 23, 2025
0de6177
fix the documentation removing protocols.md
ozgen Jun 23, 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
7 changes: 7 additions & 0 deletions docs/api/health.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Health API
==========

.. automodule:: gvm.protocols.http.openvasd.health
:members:
:undoc-members:
:show-inheritance:
11 changes: 11 additions & 0 deletions docs/api/http.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.. _http:

HTTP APIs
---------

.. automodule:: gvm.protocols.http

.. toctree::
:maxdepth: 1

openvasdv1
7 changes: 7 additions & 0 deletions docs/api/metadata.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Metadata API
============

.. automodule:: gvm.protocols.http.openvasd.metadata
:members:
:undoc-members:
:show-inheritance:
7 changes: 7 additions & 0 deletions docs/api/notus.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Notus API
=========

.. automodule:: gvm.protocols.http.openvasd.notus
:members:
:undoc-members:
:show-inheritance:
21 changes: 21 additions & 0 deletions docs/api/openvasdv1.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.. _openvasdv1:

openvasd v1
^^^^^^^^^^^

.. automodule:: gvm.protocols.http.openvasd.openvasdv1
:members:
:undoc-members:
:show-inheritance:

Submodules
----------

.. toctree::
:maxdepth: 1

health
metadata
notus
scans
vts
32 changes: 0 additions & 32 deletions docs/api/protocols.md

This file was deleted.

30 changes: 30 additions & 0 deletions docs/api/protocols.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
.. _protocols:

Protocols
---------

.. automodule:: gvm.protocols

.. toctree::
:maxdepth: 1

http
gmp
ospv1

Dynamic
^^^^^^^

To dynamically use the supported GMP version of the manager daemon see
:mod:`gvm.protocols.gmp` for details.

"latest" protocols
^^^^^^^^^^^^^^^^^^

.. automodule:: gvm.protocols.latest


"next" protocols
^^^^^^^^^^^^^^^^

.. automodule:: gvm.protocols.next
7 changes: 7 additions & 0 deletions docs/api/scans.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Scans API
=========

.. automodule:: gvm.protocols.http.openvasd.scans
:members:
:undoc-members:
:show-inheritance:
7 changes: 7 additions & 0 deletions docs/api/vts.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Vts API
=======

.. automodule:: gvm.protocols.http.openvasd.vts
:members:
:undoc-members:
:show-inheritance:
12 changes: 12 additions & 0 deletions gvm/protocols/http/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# SPDX-FileCopyrightText: 2025 Greenbone AG
#
# SPDX-License-Identifier: GPL-3.0-or-later

"""
Package for supported Greenbone HTTP APIs.

Currently only `openvasd version 1`_ is supported.

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

"""
Package for sending requests to openvasd and handling HTTP API responses.

Modules:
- :class:`OpenvasdHttpApiV1` – Main class for communicating with OpenVASD API v1.

Usage:
from gvm.protocols.http.openvasd import OpenvasdHttpApiV1
"""
81 changes: 81 additions & 0 deletions gvm/protocols/http/openvasd/_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# SPDX-FileCopyrightText: 2025 Greenbone AG
#
# SPDX-License-Identifier: GPL-3.0-or-later

"""
Client wrapper for initializing a connection to the openvasd HTTP API using optional mTLS authentication.
"""

import ssl
from typing import Optional, Tuple, Union

from httpx import Client


class OpenvasdClient:
"""
The client wrapper around `httpx.Client` configured for mTLS-secured access or API KEY
to an openvasd HTTP API instance.
"""

def __init__(
self,
host_name: str,
*,
api_key: Optional[str] = None,
server_ca_path: Optional[str] = None,
client_cert_paths: Optional[Union[str, Tuple[str, str]]] = None,
port: int = 3000,
):
"""
Initialize the OpenVASD HTTP client with optional mTLS and API key.

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}"

self.client = Client(
base_url=base_url,
headers=headers,
verify=verify,
http2=True,
timeout=10.0,
)
101 changes: 101 additions & 0 deletions gvm/protocols/http/openvasd/health.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# 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


class HealthAPI:
"""
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 __init__(self, client: httpx.Client):
"""
Create a new HealthAPI instance.

Args:
client: An initialized `httpx.Client` configured for communicating
with the openvasd server.
"""
self._client = client

def get_alive(self, safe: bool = False) -> int:
"""
Check if the scanner process is alive.

Args:
safe: If True, suppress exceptions and return structured error responses.

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

Raises:
httpx.HTTPStatusError: If the server response indicates failure and safe is False.

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 safe:
return e.response.status_code
raise

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

Args:
safe: If True, suppress exceptions and return structured error responses.

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

Raises:
httpx.HTTPStatusError: If the server response indicates failure and safe is False.

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 safe:
return e.response.status_code
raise

def get_started(self, safe: bool = False) -> int:
"""
Check if the scanner has fully started.

Args:
safe: If True, suppress exceptions and return structured error responses.

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

Raises:
httpx.HTTPStatusError: If the server response indicates failure and safe is False.

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 safe:
return e.response.status_code
raise
Loading
Loading