2023-05-19 13:21:11 +00:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
import unittest
|
2024-01-18 23:51:57 +00:00
|
|
|
import time
|
2024-07-25 12:42:37 +00:00
|
|
|
import os
|
2023-05-19 13:21:11 +00:00
|
|
|
|
2024-11-18 19:20:54 +00:00
|
|
|
from datetime import datetime, timezone, timedelta
|
|
|
|
|
2023-05-19 13:21:11 +00:00
|
|
|
from pyvulnerabilitylookup import PyVulnerabilityLookup
|
|
|
|
|
2024-07-30 15:20:54 +00:00
|
|
|
# NOTE:
|
|
|
|
# * to run the tests with a pre-configured admin key:
|
|
|
|
# API_KEY="<APIKEY>" pytest tests/test_web.py
|
|
|
|
# * to run the test against a local instance (fallback to public):
|
|
|
|
# INSTANCE_URL="http://0.0.0.0:10001" pytest tests/test_web.py
|
|
|
|
|
2023-05-19 13:21:11 +00:00
|
|
|
|
2024-07-23 13:01:35 +00:00
|
|
|
class TestPublic(unittest.TestCase):
|
2023-05-19 13:21:11 +00:00
|
|
|
|
2024-01-17 11:41:24 +00:00
|
|
|
def setUp(self) -> None:
|
2024-07-30 15:20:54 +00:00
|
|
|
self.admin_token = os.getenv("API_KEY", '').strip()
|
|
|
|
instance_url = os.getenv("INSTANCE_URL", 'https://vulnerability.circl.lu').strip()
|
|
|
|
self.public_test = instance_url == 'https://vulnerability.circl.lu'
|
|
|
|
self.client = PyVulnerabilityLookup(root_url=instance_url, token=self.admin_token)
|
2023-05-19 13:21:11 +00:00
|
|
|
|
2024-01-17 11:41:24 +00:00
|
|
|
def test_up(self) -> None:
|
2023-05-19 13:21:11 +00:00
|
|
|
self.assertTrue(self.client.is_up)
|
|
|
|
self.assertTrue(self.client.redis_up())
|
|
|
|
|
2024-01-17 11:41:24 +00:00
|
|
|
def test_get_vulnerability(self) -> None:
|
2024-01-18 23:51:57 +00:00
|
|
|
while True:
|
|
|
|
if vuln := self.client.get_vulnerability('PYSEC-2024-4'):
|
|
|
|
self.assertEqual(vuln['id'], 'PYSEC-2024-4')
|
|
|
|
break
|
|
|
|
print('waiting for pysec to be imported')
|
|
|
|
time.sleep(1)
|
2024-07-23 13:01:35 +00:00
|
|
|
|
|
|
|
def test_get_info(self) -> None:
|
|
|
|
info = self.client.get_info()
|
|
|
|
self.assertTrue(info['last_updates'])
|
|
|
|
self.assertTrue(info['db_sizes'])
|
|
|
|
|
|
|
|
def test_get_last(self) -> None:
|
|
|
|
last = self.client.get_last()
|
|
|
|
self.assertTrue(last)
|
|
|
|
self.assertTrue(isinstance(last, list))
|
|
|
|
last = self.client.get_last(number=1)
|
|
|
|
self.assertTrue(isinstance(last, list))
|
|
|
|
self.assertEqual(len(last), 1)
|
|
|
|
last = self.client.get_last(source='pysec')
|
|
|
|
for vuln in last:
|
|
|
|
self.assertTrue(vuln['id'].startswith('PYSEC'))
|
|
|
|
last = self.client.get_last(source='pysec', number=1)
|
|
|
|
self.assertEqual(len(last), 1)
|
|
|
|
self.assertTrue(last[-1]['id'].startswith('PYSEC'))
|
|
|
|
|
|
|
|
# TODO: POST Vulnerability / Delete vulnerability
|
|
|
|
# Test API
|
|
|
|
|
|
|
|
def test_get_vendors(self) -> None:
|
|
|
|
vendors = self.client.get_vendors()
|
|
|
|
self.assertTrue(isinstance(vendors, list))
|
|
|
|
|
|
|
|
def test_get_vendor_products(self) -> None:
|
2024-07-30 15:20:54 +00:00
|
|
|
if not self.public_test:
|
|
|
|
return None
|
2024-07-23 13:01:35 +00:00
|
|
|
products = self.client.get_vendor_products('misp')
|
|
|
|
self.assertTrue(isinstance(products, list))
|
|
|
|
self.assertTrue('misp' in products)
|
|
|
|
|
|
|
|
def test_get_vendor_product_vulnerabilities(self) -> None:
|
2024-07-30 15:20:54 +00:00
|
|
|
if not self.public_test:
|
|
|
|
return None
|
2024-07-23 13:01:35 +00:00
|
|
|
vulns = self.client.get_vendor_product_vulnerabilities('misp', 'misp')
|
|
|
|
self.assertTrue(isinstance(vulns, dict))
|
|
|
|
self.assertTrue('cvelistv5' in vulns)
|
|
|
|
|
|
|
|
# Test comments
|
|
|
|
|
2024-07-30 15:20:54 +00:00
|
|
|
def test_get_comments_public(self) -> None:
|
|
|
|
if not self.public_test:
|
|
|
|
return None
|
2024-07-23 13:01:35 +00:00
|
|
|
comments = self.client.get_comments()
|
|
|
|
self.assertTrue('metadata' in comments)
|
|
|
|
self.assertTrue('data' in comments)
|
|
|
|
self.assertTrue(len(comments['data']) > 0)
|
|
|
|
|
|
|
|
comments = self.client.get_comments(uuid='a309d024-2714-4a81-a425-60f83f6d5740')
|
|
|
|
self.assertTrue(len(comments['data']) == 1)
|
|
|
|
self.assertEqual(comments['data'][0]['uuid'], 'a309d024-2714-4a81-a425-60f83f6d5740')
|
|
|
|
|
|
|
|
comments = self.client.get_comments(vuln_id='CVE-2024-20401')
|
|
|
|
self.assertTrue(len(comments['data']) >= 1)
|
|
|
|
for comment in comments['data']:
|
|
|
|
self.assertEqual(comment['vulnerability'], 'CVE-2024-20401')
|
|
|
|
|
2024-11-18 18:50:24 +00:00
|
|
|
comments = self.client.get_comments(author='adulau')
|
2024-07-23 13:01:35 +00:00
|
|
|
self.assertTrue(len(comments['data']) >= 1)
|
|
|
|
for comment in comments['data']:
|
2024-11-18 18:50:24 +00:00
|
|
|
self.assertEqual(comment['author']['login'], 'adulau')
|
2024-07-23 13:01:35 +00:00
|
|
|
|
|
|
|
comments = self.client.get_comments(uuid='a309d024-2714-4a81-a425-60f83f6d5740',
|
|
|
|
vuln_id='CVE-2024-20401',
|
2024-11-18 18:50:24 +00:00
|
|
|
author='adulau')
|
2024-07-23 13:01:35 +00:00
|
|
|
self.assertTrue(len(comments['data']) == 1)
|
|
|
|
self.assertEqual(comments['data'][0]['uuid'], 'a309d024-2714-4a81-a425-60f83f6d5740')
|
|
|
|
self.assertEqual(comments['data'][0]['vulnerability'], 'CVE-2024-20401')
|
2024-11-18 18:50:24 +00:00
|
|
|
self.assertEqual(comments['data'][0]['author']['login'], 'adulau')
|
2024-07-23 13:01:35 +00:00
|
|
|
|
2024-07-30 15:20:54 +00:00
|
|
|
def test_comments_local(self) -> None:
|
|
|
|
if not self.admin_token:
|
|
|
|
# this test is only working if the admin token is set
|
|
|
|
return None
|
|
|
|
# Makes sure the userkey is set to the right one
|
|
|
|
self.client.set_apikey(self.admin_token)
|
2024-07-31 14:13:53 +00:00
|
|
|
comments = self.client.get_comments()
|
|
|
|
self.assertTrue("metadata" in comments)
|
|
|
|
self.assertTrue("data" in comments)
|
|
|
|
self.assertTrue(len(comments['data']) == 0)
|
|
|
|
self.assertEqual(comments['metadata']['count'], 0)
|
|
|
|
|
|
|
|
comment = {
|
|
|
|
"uuid": "a309d024-2714-4a81-a425-60f83f6d5740",
|
|
|
|
"title": "Comment",
|
|
|
|
"description": "Comment",
|
|
|
|
"description_format": "markdown",
|
|
|
|
"vulnerability": "CVE-2024-20401",
|
|
|
|
"related_vulnerabilities": ["ghsa-4rcj-fmjg-q9fv"],
|
|
|
|
}
|
2024-11-19 12:15:36 +00:00
|
|
|
comments = self.client.create_comment(comment=comment)
|
2024-07-31 14:13:53 +00:00
|
|
|
self.assertTrue(len(comments["data"]) == 1)
|
|
|
|
self.assertEqual(
|
|
|
|
comments["data"][0]["uuid"], "a309d024-2714-4a81-a425-60f83f6d5740"
|
|
|
|
)
|
|
|
|
|
|
|
|
comments = self.client.get_comments(uuid="a309d024-2714-4a81-a425-60f83f6d5740")
|
|
|
|
self.assertTrue(len(comments["data"]) == 1)
|
|
|
|
self.assertEqual(
|
|
|
|
comments["data"][0]["uuid"], "a309d024-2714-4a81-a425-60f83f6d5740"
|
|
|
|
)
|
|
|
|
|
|
|
|
comments = self.client.get_comments(vuln_id="CVE-2024-20401")
|
|
|
|
self.assertTrue(len(comments["data"]) >= 1)
|
|
|
|
for comment in comments["data"]:
|
|
|
|
self.assertEqual(comment["vulnerability"], "CVE-2024-20401")
|
|
|
|
|
|
|
|
# comments = self.client.get_comments(author='admin')
|
|
|
|
# self.assertTrue(len(comments['data']) >= 1)
|
|
|
|
# for comment in comments['data']:
|
|
|
|
# self.assertEqual(comment['author']['login'], 'admin') # type: ignore[call-overload]
|
|
|
|
|
|
|
|
comments = self.client.get_comments(
|
|
|
|
uuid="a309d024-2714-4a81-a425-60f83f6d5740", vuln_id="CVE-2024-20401"
|
|
|
|
)
|
|
|
|
self.assertTrue(len(comments["data"]) == 1)
|
|
|
|
self.assertEqual(
|
|
|
|
comments["data"][0]["uuid"], "a309d024-2714-4a81-a425-60f83f6d5740"
|
|
|
|
)
|
|
|
|
self.assertEqual(comments["data"][0]["vulnerability"], "CVE-2024-20401")
|
|
|
|
# self.assertEqual(comments['data'][0]['author']['login'], 'admin')
|
|
|
|
|
|
|
|
status_code = self.client.delete_comment("a309d024-2714-4a81-a425-60f83f6d5740")
|
|
|
|
self.assertTrue(status_code == 204)
|
|
|
|
comments = self.client.get_comments(uuid="a309d024-2714-4a81-a425-60f83f6d5740")
|
|
|
|
self.assertTrue(len(comments["data"]) == 0)
|
2024-07-23 13:01:35 +00:00
|
|
|
|
|
|
|
# Test bundles
|
|
|
|
|
2024-07-30 15:20:54 +00:00
|
|
|
def test_get_bundles_public(self) -> None:
|
|
|
|
if not self.public_test:
|
|
|
|
return None
|
2024-07-23 13:01:35 +00:00
|
|
|
bundles = self.client.get_bundles()
|
|
|
|
self.assertTrue('metadata' in bundles)
|
|
|
|
self.assertTrue('data' in bundles)
|
|
|
|
self.assertTrue(len(bundles['data']) > 0)
|
|
|
|
|
|
|
|
bundles = self.client.get_bundles(uuid='a23cbcad-e890-4df8-8736-9332ed4c3d47')
|
|
|
|
self.assertTrue(len(bundles['data']) == 1)
|
|
|
|
self.assertEqual(bundles['data'][0]['uuid'], 'a23cbcad-e890-4df8-8736-9332ed4c3d47')
|
|
|
|
|
|
|
|
bundles = self.client.get_bundles(vuln_id='CVE-2024-39573')
|
|
|
|
self.assertTrue(len(bundles['data']) >= 1)
|
|
|
|
for bundle in bundles['data']:
|
|
|
|
self.assertTrue('CVE-2024-39573' in bundle['related_vulnerabilities'])
|
|
|
|
|
2024-11-18 18:50:24 +00:00
|
|
|
bundles = self.client.get_bundles(author='adulau')
|
2024-07-23 13:01:35 +00:00
|
|
|
self.assertTrue(len(bundles['data']) >= 1)
|
|
|
|
for bundle in bundles['data']:
|
2024-11-18 18:50:24 +00:00
|
|
|
self.assertEqual(bundle['author']['login'], 'adulau')
|
2024-07-23 13:01:35 +00:00
|
|
|
|
|
|
|
bundles = self.client.get_bundles(uuid='a23cbcad-e890-4df8-8736-9332ed4c3d47',
|
|
|
|
vuln_id='CVE-2024-39573',
|
2024-11-18 18:50:24 +00:00
|
|
|
author='adulau')
|
2024-07-23 13:01:35 +00:00
|
|
|
self.assertTrue(len(bundles['data']) == 1)
|
|
|
|
self.assertEqual(bundles['data'][0]['uuid'], 'a23cbcad-e890-4df8-8736-9332ed4c3d47')
|
|
|
|
self.assertTrue('CVE-2024-39573' in bundles['data'][0]['related_vulnerabilities'])
|
2024-11-18 18:50:24 +00:00
|
|
|
self.assertEqual(bundles['data'][0]['author']['login'], 'adulau')
|
2024-07-30 15:20:54 +00:00
|
|
|
|
|
|
|
def test_bundles_local(self) -> None:
|
|
|
|
if not self.admin_token:
|
|
|
|
# this test is only working if the admin token is set
|
|
|
|
return None
|
|
|
|
# Makes sure the userkey is set to the right one
|
|
|
|
self.client.set_apikey(self.admin_token)
|
2024-07-31 14:13:53 +00:00
|
|
|
bundles = self.client.get_bundles()
|
|
|
|
self.assertTrue("metadata" in bundles)
|
|
|
|
self.assertTrue("data" in bundles)
|
|
|
|
self.assertTrue(len(bundles['data']) == 0)
|
|
|
|
self.assertEqual(bundles['metadata']['count'], 0)
|
|
|
|
|
|
|
|
bundle = {
|
|
|
|
"uuid": "a23cbcad-e890-4df8-8736-9332ed4c3d47",
|
|
|
|
"name": "Bundle",
|
|
|
|
"description": "Bundle",
|
|
|
|
"description_format": "markdown",
|
|
|
|
"related_vulnerabilities": ["ghsa-4rcj-fmjg-q9fv", "CVE-2024-39573"],
|
|
|
|
}
|
2024-11-19 12:15:36 +00:00
|
|
|
bundles = self.client.create_bundle(bundle=bundle)
|
2024-07-31 14:13:53 +00:00
|
|
|
self.assertTrue(len(bundles["data"]) == 1)
|
|
|
|
self.assertEqual(
|
|
|
|
bundles["data"][0]["uuid"], "a23cbcad-e890-4df8-8736-9332ed4c3d47"
|
|
|
|
)
|
|
|
|
|
|
|
|
bundles = self.client.get_bundles(uuid="a23cbcad-e890-4df8-8736-9332ed4c3d47")
|
|
|
|
self.assertTrue(len(bundles["data"]) == 1)
|
|
|
|
self.assertEqual(
|
|
|
|
bundles["data"][0]["uuid"], "a23cbcad-e890-4df8-8736-9332ed4c3d47"
|
|
|
|
)
|
|
|
|
|
|
|
|
bundles = self.client.get_bundles(vuln_id="CVE-2024-39573")
|
|
|
|
self.assertTrue(len(bundles["data"]) >= 1)
|
|
|
|
for bundle in bundles["data"]:
|
|
|
|
self.assertTrue("CVE-2024-39573" in bundle["related_vulnerabilities"])
|
|
|
|
|
|
|
|
# bundles = self.client.get_bundles(author='admin')
|
|
|
|
# self.assertTrue(len(bundles['data']) >= 1)
|
|
|
|
# for bundle in bundles['data']:
|
|
|
|
# self.assertEqual(bundle['author']['login'], 'admin') # type: ignore[call-overload]
|
|
|
|
|
|
|
|
bundles = self.client.get_bundles(
|
|
|
|
uuid="a23cbcad-e890-4df8-8736-9332ed4c3d47", vuln_id="CVE-2024-39573"
|
|
|
|
)
|
|
|
|
self.assertTrue(len(bundles["data"]) == 1)
|
|
|
|
self.assertEqual(
|
|
|
|
bundles["data"][0]["uuid"], "a23cbcad-e890-4df8-8736-9332ed4c3d47"
|
|
|
|
)
|
|
|
|
self.assertTrue(
|
|
|
|
"CVE-2024-39573" in bundles["data"][0]["related_vulnerabilities"]
|
|
|
|
)
|
|
|
|
# self.assertEqual(bundles['data'][0]['author']['login'], 'admin')
|
|
|
|
|
|
|
|
status_code = self.client.delete_bundle("a23cbcad-e890-4df8-8736-9332ed4c3d47")
|
|
|
|
self.assertTrue(status_code == 204)
|
|
|
|
comments = self.client.get_comments(uuid="a23cbcad-e890-4df8-8736-9332ed4c3d47")
|
|
|
|
self.assertTrue(len(comments["data"]) == 0)
|
2024-07-30 15:20:54 +00:00
|
|
|
|
|
|
|
# Test User
|
2024-07-31 14:29:34 +00:00
|
|
|
def test_users_info(self) -> None:
|
|
|
|
if not self.admin_token:
|
|
|
|
# this test is only working if the admin token is set
|
|
|
|
return None
|
|
|
|
# Makes sure the userkey is set to the right one
|
|
|
|
self.client.set_apikey(self.admin_token)
|
|
|
|
user_info = self.client.get_user_information()
|
|
|
|
self.assertTrue(isinstance(user_info, dict))
|
|
|
|
self.assertTrue('login' in user_info)
|
|
|
|
self.assertTrue('apikey' in user_info)
|
|
|
|
self.assertEqual(user_info['apikey'], self.admin_token)
|
|
|
|
|
2024-07-30 15:20:54 +00:00
|
|
|
def test_list_users(self) -> None:
|
|
|
|
if not self.admin_token:
|
|
|
|
# this test is only working if the admin token is set
|
|
|
|
return None
|
|
|
|
# Makes sure the userkey is set to the right one
|
|
|
|
self.client.set_apikey(self.admin_token)
|
|
|
|
users = self.client.list_users()
|
|
|
|
self.assertTrue(isinstance(users, dict))
|
|
|
|
self.assertTrue(len(users['data']) > 0)
|
|
|
|
got_admin = False
|
|
|
|
for user in users['data']:
|
|
|
|
self.assertTrue('login' in user)
|
|
|
|
self.assertTrue('apikey' in user)
|
|
|
|
if user['apikey'] == self.admin_token:
|
|
|
|
self.assertTrue(user['is_admin'])
|
|
|
|
got_admin = True
|
|
|
|
self.assertTrue(got_admin)
|
|
|
|
|
|
|
|
def test_create_user_comment(self) -> None:
|
|
|
|
if self.public_test:
|
|
|
|
# Do not run that test against the public instance, it would create users.
|
|
|
|
return None
|
|
|
|
instance_config = self.client.get_config_info()
|
|
|
|
if not instance_config.get('registration'):
|
|
|
|
return None
|
|
|
|
|
2024-11-19 12:15:36 +00:00
|
|
|
user = self.client.create_user(name='test Name', login='test Login',
|
|
|
|
organisation='test Organization', email='test@testorg.lu')
|
2024-07-30 15:20:54 +00:00
|
|
|
self.assertTrue(user)
|
|
|
|
self.assertTrue('login' in user, user)
|
|
|
|
self.assertTrue('apikey' in user, user)
|
|
|
|
self.assertTrue('is_commenter' in user, user)
|
|
|
|
self.assertTrue(user['is_commenter'])
|
|
|
|
self.client.set_apikey(user['apikey'])
|
|
|
|
comment = {'title': 'test', 'description': 'test',
|
|
|
|
'vulnerability': 'CVE-2024-20401',
|
|
|
|
'related_vulnerabilities': ['CVE-2024-20402']}
|
2024-11-19 12:15:36 +00:00
|
|
|
created_comment = self.client.create_comment(comment=comment)
|
2024-07-30 15:20:54 +00:00
|
|
|
new_comment_uuid = created_comment['data'][0]['uuid']
|
|
|
|
comments = self.client.get_comments(uuid=new_comment_uuid)
|
|
|
|
self.assertTrue(len(comments['data']) == 0, comments)
|
|
|
|
deleted_comment = self.client.delete_comment(new_comment_uuid)
|
|
|
|
self.assertTrue(deleted_comment < 300)
|
2024-11-18 19:20:54 +00:00
|
|
|
|
|
|
|
# test Sightings
|
|
|
|
def test_sightings(self) -> None:
|
|
|
|
sighting_cve = self.client.get_sighting('6febe45d-d8de-4df7-b3ba-6cf7acd2e2b5')
|
|
|
|
self.assertTrue(sighting_cve)
|
|
|
|
self.assertTrue('uuid' in sighting_cve)
|
|
|
|
self.assertEqual(sighting_cve['uuid'], '6febe45d-d8de-4df7-b3ba-6cf7acd2e2b5')
|
|
|
|
|
|
|
|
sighting_cve_list = self.client.get_sightings(sighting_uuid='6febe45d-d8de-4df7-b3ba-6cf7acd2e2b5')
|
|
|
|
self.assertTrue(sighting_cve_list)
|
|
|
|
self.assertTrue('data' in sighting_cve_list)
|
|
|
|
self.assertTrue(len(sighting_cve_list['data']) == 1)
|
|
|
|
self.assertEqual(sighting_cve_list['data'][0], sighting_cve)
|
|
|
|
|
|
|
|
sighting_cve_list = self.client.get_sightings(vuln_id='CVE-2020-3532')
|
|
|
|
self.assertTrue(sighting_cve_list)
|
|
|
|
self.assertTrue('data' in sighting_cve_list)
|
|
|
|
self.assertTrue(len(sighting_cve_list['data']) > 0)
|
|
|
|
|
|
|
|
sighting_cve_list = self.client.get_sightings(author='automation')
|
|
|
|
self.assertTrue(sighting_cve_list)
|
|
|
|
self.assertTrue('data' in sighting_cve_list)
|
|
|
|
self.assertTrue(len(sighting_cve_list['data']) > 0)
|
|
|
|
|
|
|
|
sighting_cve_list = self.client.get_sightings(author='automation', vuln_id='CVE-2020-3532')
|
|
|
|
self.assertTrue(sighting_cve_list)
|
|
|
|
self.assertTrue('data' in sighting_cve_list)
|
|
|
|
self.assertTrue(len(sighting_cve_list['data']) > 0)
|
|
|
|
|
|
|
|
sighting_cve_list = self.client.get_sightings(author='automation', date_from=datetime.now(tz=timezone.utc) - timedelta(days=1), date_to=datetime.now(tz=timezone.utc))
|
|
|
|
self.assertTrue(sighting_cve_list)
|
|
|
|
self.assertTrue('data' in sighting_cve_list)
|
|
|
|
self.assertTrue(len(sighting_cve_list['data']) > 0)
|