new: Add all missing endpoints, update existing ones.
Some checks failed
Python application - MyPy / Python 3.10 sample (push) Has been cancelled
Python application - MyPy / Python 3.11 sample (push) Has been cancelled
Python application - MyPy / Python 3.12 sample (push) Has been cancelled
Python application - MyPy / Python 3.13 sample (push) Has been cancelled
Python application - Test Public Interface / Python 3.10 sample (push) Has been cancelled
Python application - Test Public Interface / Python 3.11 sample (push) Has been cancelled
Python application - Test Public Interface / Python 3.12 sample (push) Has been cancelled
Python application - Test Public Interface / Python 3.13 sample (push) Has been cancelled

This commit is contained in:
Raphaël Vinot 2024-11-19 13:15:36 +01:00
parent 97ca98f4ff
commit 51bcb96d61
2 changed files with 150 additions and 26 deletions

View file

@ -65,6 +65,20 @@ class PyVulnerabilityLookup():
r = self.session.get(urljoin(self.root_url, 'redis_up'))
return r.json()
# #### DB status ####
def get_info(self) -> dict[str, Any]:
'''Get more information about the current databases in use and when it was updated'''
r = self.session.get(urljoin(self.root_url, 'info'))
return r.json()
def get_config_info(self) -> dict[str, Any]:
'''Get more information about the current databases in use and when it was updated'''
r = self.session.get(urljoin(self.root_url, 'configInfo'))
return r.json()
# #### Vulnerabilities ####
def get_vulnerability(self, vulnerability_id: str) -> dict[str, Any]:
'''Get a vulnerability
@ -90,16 +104,6 @@ class PyVulnerabilityLookup():
r = self.session.delete(urljoin(self.root_url, str(PurePosixPath('vulnerability', vulnerability_id))))
return r.status_code
def get_info(self) -> dict[str, Any]:
'''Get more information about the current databases in use and when it was updated'''
r = self.session.get(urljoin(self.root_url, 'info'))
return r.json()
def get_config_info(self) -> dict[str, Any]:
'''Get more information about the current databases in use and when it was updated'''
r = self.session.get(urljoin(self.root_url, 'configInfo'))
return r.json()
def get_last(self, number: int | None=None, source: str | None = None) -> list[dict[str, Any]]:
'''Get the last vulnerabilities
@ -115,7 +119,7 @@ class PyVulnerabilityLookup():
return r.json()
def get_vendors(self) -> list[str]:
'''Get the list of known vendors'''
'''Get the known vendors'''
r = self.session.get(urljoin(self.root_url, str(PurePosixPath('api', 'browse'))))
return r.json()
@ -136,15 +140,42 @@ class PyVulnerabilityLookup():
r = self.session.get(urljoin(self.root_url, str(PurePosixPath('api', 'search', vendor, product))))
return r.json()
# NOTE: endpoints /api/cve/*, /api/dbInfo, /api/last are alises for backward compat.
# #### Comments ####
def create_comment(self, comment: dict[str, Any]) -> dict[str, Any]:
def create_comment(self, /, *, comment: dict[str, Any] | None=None, description: str | None=None,
description_format: str | None = None, meta: dict[str, str] | None = None,
related_vulnerabilities: list[str] | None=None, title: str | None=None,
uuid: str | None=None, vulnerability: str | None = None) -> dict[str, Any]:
'''Create a comment.
:param comment: The comment
:param description: The description of the comment
:param description_format: Description format (markdown or text).
:param meta: Zero or more meta-fields.
:param related_vulnerabilities: Zero or more related vulnerabilities.
:param title: The title of the comment
:param uuid: The UUID of the comment
:param vulnerability: The vulnerability ID of the comment
'''
r = self.session.post(urljoin(self.root_url, str(PurePosixPath('api', 'comment'))),
json=comment)
if not comment:
comment = {}
if description:
comment['description'] = description
if description_format:
comment['description_format'] = description_format
if meta:
comment['meta'] = meta
if related_vulnerabilities:
comment['related_vulnerabilities'] = related_vulnerabilities
if title:
comment['title'] = title
if uuid:
comment['uuid'] = uuid
if vulnerability:
comment['vulnerability'] = vulnerability
r = self.session.post(urljoin(self.root_url, str(PurePosixPath('api', 'comment'))), json=comment)
return r.json()
def get_comments(self, uuid: str | None = None, vuln_id: str | None = None,
@ -159,6 +190,15 @@ class PyVulnerabilityLookup():
params={'uuid': uuid, 'vuln_id': vuln_id, 'author': author})
return r.json()
def get_comment(self, comment_uuid: str) -> dict[str, Any]:
'''Get a comment
:param comment_uuid: The UUID of the comment
'''
r = self.session.get(urljoin(self.root_url, str(PurePosixPath('api', 'comment', comment_uuid)))
)
return r.json()
def delete_comment(self, comment_uuid: str) -> int:
'''Delete a comment.
@ -167,25 +207,65 @@ class PyVulnerabilityLookup():
r = self.session.delete(urljoin(self.root_url, str(PurePosixPath('api', 'comment', comment_uuid))))
return r.status_code
def create_bundle(self, bundle: dict[str, Any]) -> dict[str, Any]:
# #### Bundles ####
def create_bundle(self, /, *, bundle: dict[str, Any] | None=None, description: str | None=None,
meta: dict[str, str] | None=None, name: str | None=None, related_vulnerabilities: list[str] | None=None,
uuid: str | None=None) -> dict[str, Any]:
'''Create a bundle.
:param bundle: The bundle
'''
if not bundle:
bundle = {}
if description:
bundle['description'] = description
if meta:
bundle['meta'] = meta
if name:
bundle['name'] = name
if related_vulnerabilities:
bundle['related_vulnerabilities'] = related_vulnerabilities
if uuid:
bundle['uuid'] = uuid
r = self.session.post(urljoin(self.root_url, str(PurePosixPath('api', 'bundle'))),
json=bundle)
return r.json()
def get_bundles(self, uuid: str | None = None, vuln_id: str | None = None,
author: str | None = None) -> dict[str, Any]:
author: str | None = None, per_page: int | None=None,
meta: list[dict[str, str]] | None=None) -> dict[str, Any]:
'''Get bundle(s)
:param uuid: The UUID a specific bundle
:param vuln_id: The vulnerability ID to get bundles of
:param author: The author of the bundle(s)
:param per_page: The number of bundles to get per page
:param meta: Query for the meta JSON field. Example: meta=[{tags: [tcp]}]
'''
r = self.session.get(urljoin(self.root_url, str(PurePosixPath('api', 'bundle'))),
params={'uuid': uuid, 'vuln_id': vuln_id, 'author': author})
params: dict[str, Any] = {}
if uuid:
params['uuid'] = uuid
if vuln_id:
params['vuln_id'] = vuln_id
if author:
params['author'] = author
if per_page is not None:
params['per_page'] = per_page
if meta:
params['meta'] = meta
r = self.session.get(urljoin(self.root_url, str(PurePosixPath('api', 'bundle'))), params=params)
return r.json()
def get_bundle(self, bundle_uuid: str) -> dict[str, Any]:
'''Get a bundle
:param bundle_uuid: The UUID of the bundle
'''
r = self.session.get(urljoin(self.root_url, str(PurePosixPath('api', 'bundle', bundle_uuid))))
return r.json()
def delete_bundle(self, bundle_uuid: str) -> int:
@ -196,7 +276,11 @@ class PyVulnerabilityLookup():
r = self.session.delete(urljoin(self.root_url, str(PurePosixPath('api', 'bundle', bundle_uuid))))
return r.status_code
def create_user(self, login: str, name: str, organisation: str, email: str) -> dict[str, Any]:
# #### Users ####
def create_user(self, /, *, user: dict[str, Any] | None=None,
login: str | None=None, name: str | None=None,
organisation: str | None=None, email: str | None=None) -> dict[str, Any]:
'''Create a user.
:param login: The login of the user
@ -204,11 +288,26 @@ class PyVulnerabilityLookup():
:param organisation: The organisation of the user
:param email: The email of the user
'''
r = self.session.post(urljoin(self.root_url, str(PurePosixPath('api', 'user'))),
json={'login': login, 'name': name, 'organisation': organisation, 'email': email})
if not user:
user = {}
if login:
user['login'] = login
if name:
user['name'] = name
if organisation:
user['organisation'] = organisation
if email:
user['email'] = email
r = self.session.post(urljoin(self.root_url, str(PurePosixPath('api', 'user'))), json=user)
return r.json()
def list_users(self) -> dict[str, Any]:
# Alias this one to get_users for consistency
return self.get_users()
def get_users(self) -> dict[str, Any]:
'''List users'''
r = self.session.get(urljoin(self.root_url, str(PurePosixPath('api', 'user'))))
return r.json()
@ -218,6 +317,20 @@ class PyVulnerabilityLookup():
r = self.session.get(urljoin(self.root_url, str(PurePosixPath('api', 'user', 'me'))))
return r.json()
def reset_api_key(self) -> dict[str, Any]:
'''Reset the API key'''
r = self.session.get(urljoin(self.root_url, str(PurePosixPath('api', 'user', 'api_key'))))
return r.json()
def delete_user(self, user_id: str) -> int:
'''Delete a user.
:param user_id: The user ID
'''
r = self.session.delete(urljoin(self.root_url, str(PurePosixPath('api', 'user', user_id)))
)
return r.status_code
# #### Sightings ####
def get_sighting(self, sighting_uuid: str) -> dict[str, Any]:
@ -298,3 +411,13 @@ class PyVulnerabilityLookup():
r = self.session.post(urljoin(self.root_url, str(PurePosixPath('api', 'sighting'))),
json=sighting)
return r.json()
# #### EPSS ####
def get_epss(self, vulnerability: str) -> dict[str, Any]:
'''Get the EPSS for a vulnerability
:param vulnerability: The vulnerability ID
'''
r = self.session.get(urljoin(self.root_url, str(PurePosixPath('api', 'epss', vulnerability))))
return r.json()

View file

@ -127,7 +127,7 @@ class TestPublic(unittest.TestCase):
"vulnerability": "CVE-2024-20401",
"related_vulnerabilities": ["ghsa-4rcj-fmjg-q9fv"],
}
comments = self.client.create_comment(comment)
comments = self.client.create_comment(comment=comment)
self.assertTrue(len(comments["data"]) == 1)
self.assertEqual(
comments["data"][0]["uuid"], "a309d024-2714-4a81-a425-60f83f6d5740"
@ -215,7 +215,7 @@ class TestPublic(unittest.TestCase):
"description_format": "markdown",
"related_vulnerabilities": ["ghsa-4rcj-fmjg-q9fv", "CVE-2024-39573"],
}
bundles = self.client.create_bundle(bundle)
bundles = self.client.create_bundle(bundle=bundle)
self.assertTrue(len(bundles["data"]) == 1)
self.assertEqual(
bundles["data"][0]["uuid"], "a23cbcad-e890-4df8-8736-9332ed4c3d47"
@ -293,7 +293,8 @@ class TestPublic(unittest.TestCase):
if not instance_config.get('registration'):
return None
user = self.client.create_user('test Name', 'test Login', 'test Organization', 'test@testorg.lu')
user = self.client.create_user(name='test Name', login='test Login',
organisation='test Organization', email='test@testorg.lu')
self.assertTrue(user)
self.assertTrue('login' in user, user)
self.assertTrue('apikey' in user, user)
@ -303,7 +304,7 @@ class TestPublic(unittest.TestCase):
comment = {'title': 'test', 'description': 'test',
'vulnerability': 'CVE-2024-20401',
'related_vulnerabilities': ['CVE-2024-20402']}
created_comment = self.client.create_comment(comment)
created_comment = self.client.create_comment(comment=comment)
new_comment_uuid = created_comment['data'][0]['uuid']
comments = self.client.get_comments(uuid=new_comment_uuid)
self.assertTrue(len(comments['data']) == 0, comments)