From e897955a2f9f111ce2df805603be679b462a56bf Mon Sep 17 00:00:00 2001 From: Dante Acosta Date: Wed, 4 Sep 2024 11:45:35 -0300 Subject: [PATCH 01/37] removed license_version --- CHANGELOG/current/7763.json | 4 ++++ faraday/__init__.py | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 CHANGELOG/current/7763.json diff --git a/CHANGELOG/current/7763.json b/CHANGELOG/current/7763.json new file mode 100644 index 00000000000..55349122694 --- /dev/null +++ b/CHANGELOG/current/7763.json @@ -0,0 +1,4 @@ +{ + "level": "community", + "md": "[MOD] Removed __license_version__ from init.py" +} diff --git a/faraday/__init__.py b/faraday/__init__.py index 3a674cf4542..573b929c8b8 100644 --- a/faraday/__init__.py +++ b/faraday/__init__.py @@ -5,4 +5,3 @@ """ __version__ = '5.6.1' -__license_version__ = __version__ From 91fada911b942b600e90f86e3315a03a653fa8bc Mon Sep 17 00:00:00 2001 From: Pablo Date: Fri, 6 Sep 2024 16:46:06 -0300 Subject: [PATCH 02/37] Fix Changelog --- CHANGELOG/current/7763.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG/current/7763.json b/CHANGELOG/current/7763.json index 55349122694..f91242c5ba0 100644 --- a/CHANGELOG/current/7763.json +++ b/CHANGELOG/current/7763.json @@ -1,4 +1,4 @@ { "level": "community", - "md": "[MOD] Removed __license_version__ from init.py" + "md": "[MOD] Removed __license_version__ from init.py. #7763" } From 06886061a3844135d2ee0f69a6e4aaf1da507ee5 Mon Sep 17 00:00:00 2001 From: dkraus Date: Thu, 26 Sep 2024 17:06:39 -0300 Subject: [PATCH 03/37] Add changelog --- CHANGELOG/current/7811.json | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 CHANGELOG/current/7811.json diff --git a/CHANGELOG/current/7811.json b/CHANGELOG/current/7811.json new file mode 100644 index 00000000000..66c93cc6ac9 --- /dev/null +++ b/CHANGELOG/current/7811.json @@ -0,0 +1,4 @@ +{ + "level": "community", + "md": "[ADD] Added the `description` field to evidence attachments in the `VulnerabilitySchema`. #7811" +} From 596e138558674bc15d93e42544d16ad5f4e3fcca Mon Sep 17 00:00:00 2001 From: dkraus Date: Thu, 26 Sep 2024 17:07:16 -0300 Subject: [PATCH 04/37] Add description to FileSchema --- faraday/server/api/modules/vulns.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/faraday/server/api/modules/vulns.py b/faraday/server/api/modules/vulns.py index 18a66c9c8ce..6aae8e16294 100644 --- a/faraday/server/api/modules/vulns.py +++ b/faraday/server/api/modules/vulns.py @@ -93,12 +93,14 @@ class EvidenceSchema(AutoSchema): content_type = fields.Method('get_content_type') data = fields.Method('get_data') + description = fields.String() class Meta: model = File fields = ( 'content_type', - 'data' + 'data', + 'description', ) @staticmethod From f31dd03bbc4d3d70859b2d2320912f7191ddcc0b Mon Sep 17 00:00:00 2001 From: dkraus Date: Fri, 27 Sep 2024 15:45:39 -0300 Subject: [PATCH 05/37] Add description getter from request form --- faraday/server/api/modules/vulns.py | 68 +++++++++++---------- faraday/server/api/modules/vulns_context.py | 10 ++- 2 files changed, 45 insertions(+), 33 deletions(-) diff --git a/faraday/server/api/modules/vulns.py b/faraday/server/api/modules/vulns.py index 6aae8e16294..5a948457ab5 100644 --- a/faraday/server/api/modules/vulns.py +++ b/faraday/server/api/modules/vulns.py @@ -994,39 +994,45 @@ def post_attachment(self, workspace_name, vuln_id): Workspace).filter(VulnerabilityGeneric.id == vuln_id, Workspace.name == workspace_name).first() - if vuln_workspace_check: - if 'file' not in request.files: - flask.abort(400) - vuln = VulnerabilitySchema().dump(vuln_workspace_check[0]) - filename = request.files['file'].filename - _attachments = vuln['_attachments'] - if filename in _attachments: - message = 'Evidence already exists in vuln' - return make_response(flask.jsonify(message=message, success=False, code=400), 400) - else: - partial = request.files['file'].read(32) - image_format = imghdr.what(None, h=partial) - if image_format and image_format.lower() == "webp": - logger.info("Evidence can't be webp") - flask.abort(400, "Evidence can't be webp") - faraday_file = FaradayUploadedFile(partial + request.files['file'].read()) - instance, created = get_or_create( - db.session, - File, - object_id=vuln_id, - object_type='vulnerability', - name=filename, - filename=filename, - content=faraday_file - ) - db.session.commit() - debounce_workspace_update(workspace_name) - message = 'Evidence upload was successful' - logger.info(message) - return flask.jsonify({'message': message}) - else: + if not vuln_workspace_check: flask.abort(404, "Vulnerability not found") + if 'file' not in request.files: + flask.abort(400) + + vuln = VulnerabilitySchema().dump(vuln_workspace_check[0]) + filename = request.files['file'].filename + _attachments = vuln['_attachments'] + + if filename in _attachments: + message = 'Evidence already exists in vuln' + return make_response(flask.jsonify(message=message, success=False, code=400), 400) + + description = request.form.get('description') + partial = request.files['file'].read(32) + image_format = imghdr.what(None, h=partial) + + if image_format and image_format.lower() == "webp": + logger.info("Evidence can't be webp") + flask.abort(400, "Evidence can't be webp") + + faraday_file = FaradayUploadedFile(partial + request.files['file'].read()) + get_or_create( + db.session, + File, + object_id=vuln_id, + object_type='vulnerability', + name=filename, + filename=filename, + content=faraday_file, + description=description, + ) + db.session.commit() + debounce_workspace_update(workspace_name) + message = 'Evidence upload was successful' + logger.info(message) + return flask.jsonify({'message': message}) + @route('/filter') def filter(self, workspace_name): """ diff --git a/faraday/server/api/modules/vulns_context.py b/faraday/server/api/modules/vulns_context.py index 18cb20e0143..5c5726af316 100644 --- a/faraday/server/api/modules/vulns_context.py +++ b/faraday/server/api/modules/vulns_context.py @@ -311,25 +311,31 @@ def post_attachment(self, vuln_id): if not vuln_permission_check: flask.abort(404, "Vulnerability not found") + if 'file' not in request.files: flask.abort(400) + vuln = VulnerabilitySchema().dump(vuln_permission_check) filename = request.files['file'].filename _attachments = vuln['_attachments'] + if filename in _attachments: message = 'Evidence already exists in vuln' return make_response(flask.jsonify(message=message, success=False, code=400), 400) + description = request.form.get('description') faraday_file = FaradayUploadedFile(request.files['file'].read()) - instance, created = get_or_create( + get_or_create( db.session, File, object_id=vuln_id, object_type='vulnerability', name=filename, filename=filename, - content=faraday_file + content=faraday_file, + description=description, ) + db.session.commit() message = 'Evidence upload was successful' logger.info(message) From d6d495c69a8cbbbfbc3794e6980826bf997f6f84 Mon Sep 17 00:00:00 2001 From: dkraus Date: Fri, 27 Sep 2024 16:58:57 -0300 Subject: [PATCH 06/37] Add tests --- tests/test_api_vulnerability.py | 28 +++++++++++++++++++++++++ tests/test_api_vulnerability_context.py | 28 +++++++++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/tests/test_api_vulnerability.py b/tests/test_api_vulnerability.py index 2e911d86e91..892ca6d7116 100644 --- a/tests/test_api_vulnerability.py +++ b/tests/test_api_vulnerability.py @@ -5037,6 +5037,34 @@ def test_filter_by_creator_command_id(self, assert res.status_code == 200 assert res.json['count'] == 100 + def test_add_evidence_with_description(self, test_client, session, workspace, csrf_token): + vuln = VulnerabilityFactory.create(workspace=workspace) + session.add(vuln) + session.commit() + + file_contents = b'Testing attachment with description' + data = { + 'file': (BytesIO(file_contents), 'testing_description.txt'), + 'csrf_token': csrf_token, + 'description': 'Attachment description' + } + + res = test_client.post( + f'/v3/ws/{workspace.name}/vulns/{vuln.id}/attachment', + data=data, + use_json_data=False + ) + assert res.status_code == 200 + + # Get vulnerability created + res = test_client.get(f'/v3/ws/{workspace.name}/vulns/{vuln.id}/attachment') + assert res.status_code == 200 + attachments_json = res.json + + attachment = attachments_json['testing_description.txt'] + + assert attachment['description'] == 'Attachment description' + def test_type_filter(workspace, session, vulnerability_factory, diff --git a/tests/test_api_vulnerability_context.py b/tests/test_api_vulnerability_context.py index 7ad61c67e86..1eb1bf66762 100644 --- a/tests/test_api_vulnerability_context.py +++ b/tests/test_api_vulnerability_context.py @@ -3699,6 +3699,34 @@ def test_filter_by_creator_command_id(self, assert res.status_code == 200 assert res.json['count'] == 100 + def test_add_evidence_with_description(self, test_client, session, csrf_token): + vuln = VulnerabilityFactory.create() + session.add(vuln) + session.commit() + + file_contents = b'Testing attachment with description' + data = { + 'file': (BytesIO(file_contents), 'testing_description.txt'), + 'csrf_token': csrf_token, + 'description': 'Attachment description' + } + + res = test_client.post( + f'/v3/vulns/{vuln.id}/attachment', + data=data, + use_json_data=False + ) + assert res.status_code == 200 + + # Get vulnerability created + res = test_client.get(f'/v3/vulns/{vuln.id}/attachment') + assert res.status_code == 200 + attachments_json = res.json + + attachment = attachments_json['testing_description.txt'] + + assert attachment['description'] == 'Attachment description' + def test_type_filter(workspace, session, vulnerability_factory, From 49fe8d748ad3e29cc703b2dac807202e1439732f Mon Sep 17 00:00:00 2001 From: Nahuel Alonso Date: Fri, 25 Oct 2024 16:12:31 -0300 Subject: [PATCH 07/37] added default pagination --- faraday/server/api/base.py | 6 +++++- faraday/server/api/modules/vulns.py | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/faraday/server/api/base.py b/faraday/server/api/base.py index 78fb507b8cd..f1fb0dcf5ba 100644 --- a/faraday/server/api/base.py +++ b/faraday/server/api/base.py @@ -646,7 +646,7 @@ class PaginatedMixin: per_page_parameter_name = 'page_size' page_number_parameter_name = 'page' - def _paginate(self, query): + def _paginate(self, query, hard_limit=0): page, per_page = None, None if self.per_page_parameter_name in flask.request.args: @@ -664,6 +664,10 @@ def _paginate(self, query): pagination_metadata = query.paginate(page=page, per_page=per_page, error_out=False) return pagination_metadata.items, pagination_metadata + elif hard_limit != 0: + pagination_metadata = query.paginate(page=1, per_page=hard_limit, error_out=False) + return pagination_metadata.items, pagination_metadata + return super()._paginate(query) diff --git a/faraday/server/api/modules/vulns.py b/faraday/server/api/modules/vulns.py index 0ab0c941894..8279d37944e 100644 --- a/faraday/server/api/modules/vulns.py +++ b/faraday/server/api/modules/vulns.py @@ -1613,5 +1613,8 @@ def _perform_bulk_delete(self, values, **kwargs): update_host_stats(host_id_list, service_id_list) return response + def _paginate(self, query, hard_limit=0): + return super()._paginate(query, hard_limit=3) + VulnerabilityView.register(vulns_api) From ed7bba39ee7bdcbdfdc5180502a43e51dc3fad05 Mon Sep 17 00:00:00 2001 From: Nahuel Alonso Date: Fri, 25 Oct 2024 16:16:09 -0300 Subject: [PATCH 08/37] added to config --- faraday/server/config.py | 1 + 1 file changed, 1 insertion(+) diff --git a/faraday/server/config.py b/faraday/server/config.py index 6a50426314f..f6532cf8f72 100644 --- a/faraday/server/config.py +++ b/faraday/server/config.py @@ -154,6 +154,7 @@ def __init__(self): self.socketio_ping_interval = 60 self.socketio_ping_timeout = 220 self.socketio_logger = False + self.vulnerabilities_max_get_limit = 1000 class StorageConfigObject(ConfigSection): From 6d8c3e5676f47005eb323632b339bf82e7782130 Mon Sep 17 00:00:00 2001 From: Nahuel Alonso Date: Fri, 25 Oct 2024 16:23:33 -0300 Subject: [PATCH 09/37] implemented default pagination --- faraday/server/api/modules/vulns.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/faraday/server/api/modules/vulns.py b/faraday/server/api/modules/vulns.py index 8279d37944e..47bf533f6ee 100644 --- a/faraday/server/api/modules/vulns.py +++ b/faraday/server/api/modules/vulns.py @@ -1614,7 +1614,8 @@ def _perform_bulk_delete(self, values, **kwargs): return response def _paginate(self, query, hard_limit=0): - return super()._paginate(query, hard_limit=3) + limit = faraday_server.vulnerabilities_max_get_limit + return super()._paginate(query, hard_limit=limit) VulnerabilityView.register(vulns_api) From f5ed5f0cda797c49cce7fcb4b54f09cc39c71a96 Mon Sep 17 00:00:00 2001 From: Nahuel Alonso Date: Mon, 28 Oct 2024 15:13:44 -0300 Subject: [PATCH 10/37] Implement limit to filters & context --- faraday/server/api/modules/vulns.py | 6 ++++-- faraday/server/api/modules/vulns_context.py | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/faraday/server/api/modules/vulns.py b/faraday/server/api/modules/vulns.py index 47bf533f6ee..68d08a0f459 100644 --- a/faraday/server/api/modules/vulns.py +++ b/faraday/server/api/modules/vulns.py @@ -1236,11 +1236,13 @@ def _filter(self, filters, workspace_name, exclude_list=None): ) if not exclude_list else exclude_list} if 'group_by' not in filters: offset = None - limit = None + limit = faraday_server.vulnerabilities_max_get_limit if 'offset' in filters: offset = filters.pop('offset') if 'limit' in filters: - limit = filters.pop('limit') # we need to remove pagination, since + filter_limit = filters.pop('limit') + if filter_limit < limit: + limit = filter_limit try: vulns = self._generate_filter_query( VulnerabilityGeneric, diff --git a/faraday/server/api/modules/vulns_context.py b/faraday/server/api/modules/vulns_context.py index a519cb580e1..de9398f14b3 100644 --- a/faraday/server/api/modules/vulns_context.py +++ b/faraday/server/api/modules/vulns_context.py @@ -495,11 +495,13 @@ def _filter(self, filters, exclude_list=None): )if not exclude_list else exclude_list} if 'group_by' not in filters: offset = None - limit = None + limit = faraday_server.vulnerabilities_max_get_limit if 'offset' in filters: offset = filters.pop('offset') if 'limit' in filters: - limit = filters.pop('limit') # we need to remove pagination, since + filter_limit = filters.pop('limit') + if filter_limit < limit: + limit = filter_limit try: vulns = self._generate_filter_query( From 4cb3c10062490088eab97f5de695acf63caa069d Mon Sep 17 00:00:00 2001 From: Nahuel Alonso Date: Mon, 28 Oct 2024 15:22:53 -0300 Subject: [PATCH 11/37] Fix imports order --- faraday/server/api/modules/vulns_context.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/faraday/server/api/modules/vulns_context.py b/faraday/server/api/modules/vulns_context.py index de9398f14b3..5d2eee41792 100644 --- a/faraday/server/api/modules/vulns_context.py +++ b/faraday/server/api/modules/vulns_context.py @@ -32,16 +32,16 @@ from faraday.server.utils.reference import create_reference from faraday.server.utils.search import search from faraday.server.api.base import ( + BulkDeleteMixin, + BulkUpdateMixin, + ContextMixin, + CountMultiWorkspacedMixin, FilterAlchemyMixin, FilterSetMeta, - PaginatedMixin, InvalidUsage, - CountMultiWorkspacedMixin, - get_filtered_data, - BulkUpdateMixin, - BulkDeleteMixin, + PaginatedMixin, ReadOnlyView, - ContextMixin + get_filtered_data, ) from faraday.server.fields import FaradayUploadedFile from faraday.server.models import ( From 0dd9206a463397f65314cd2b33ffaf2de451d722 Mon Sep 17 00:00:00 2001 From: Nahuel Alonso Date: Mon, 28 Oct 2024 16:03:58 -0300 Subject: [PATCH 12/37] Add tests to get, filter and context --- tests/test_api_vulnerability.py | 51 +++++++++++++++++++++++++ tests/test_api_vulnerability_context.py | 33 ++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/tests/test_api_vulnerability.py b/tests/test_api_vulnerability.py index cea2f10598a..38a86be9831 100644 --- a/tests/test_api_vulnerability.py +++ b/tests/test_api_vulnerability.py @@ -12,6 +12,7 @@ from base64 import b64encode from io import BytesIO, StringIO from posixpath import join +from unittest import mock from sqlalchemy.orm.util import was_deleted @@ -4763,6 +4764,56 @@ def test_search_filter_offset_and_limit(self, test_client, session): assert expected_vulns == paginated_vulns + @mock.patch("faraday.server.config.faraday_server.vulnerabilities_max_get_limit", 25) + def test_vuln_get_limit(self, test_client, session): + workspace = WorkspaceFactory.create() + host = HostFactory.create(workspace=workspace) + vulns = VulnerabilityWebFactory.create_batch(50, + workspace=workspace, + severity='high' + ) + session.add_all(vulns) + session.add(host) + session.commit() + + res = test_client.get(f'/v3/ws/{workspace.name}/vulns') + + assert res.status_code == 200 + assert res.json['count'] == 50 + assert len(res.json['vulnerabilities']) == 25 + + @mock.patch("faraday.server.config.faraday_server.vulnerabilities_max_get_limit", 25) + @pytest.mark.parametrize("limit", [ + ["5", 5], + [None, 25], + ["100", 25] + ]) + def test_vuln_filter_limit(self, test_client, session, limit): + workspace = WorkspaceFactory.create() + host = HostFactory.create(workspace=workspace) + vulns = VulnerabilityWebFactory.create_batch(50, + workspace=workspace, + severity='high' + ) + session.add_all(vulns) + session.add(host) + session.commit() + + if limit[0] is None: + query_filter = {} + else: + query_filter = { + "filters": [], + "limit": limit[0], + "offset": "1", + } + res = test_client.get( + f'/v3/ws/{workspace.name}/vulns/filter?q={json.dumps(query_filter)}' + ) + assert res.status_code == 200 + assert res.json['count'] == 50 + assert len(res.json['vulnerabilities']) == limit[1] + @pytest.mark.skip_sql_dialect('sqlite') @pytest.mark.usefixtures('ignore_nplusone') @pytest.mark.skip(reason="We need a better solution for searching in the model.") diff --git a/tests/test_api_vulnerability_context.py b/tests/test_api_vulnerability_context.py index 7ad61c67e86..30a51123199 100644 --- a/tests/test_api_vulnerability_context.py +++ b/tests/test_api_vulnerability_context.py @@ -12,6 +12,7 @@ from base64 import b64encode from io import BytesIO, StringIO from posixpath import join +from unittest import mock from sqlalchemy.orm.util import was_deleted @@ -3227,6 +3228,38 @@ def test_search_filter_offset_and_limit(self, test_client, session): assert expected_vulns == paginated_vulns + @mock.patch("faraday.server.config.faraday_server.vulnerabilities_max_get_limit", 25) + @pytest.mark.parametrize("limit", [ + ["5", 5], + [None, 25], + ["100", 25] + ]) + def test_vuln_filter_limit_context(self, test_client, session, limit): + workspace = WorkspaceFactory.create() + host = HostFactory.create(workspace=workspace) + vulns = VulnerabilityWebFactory.create_batch(50, + workspace=workspace, + severity='high' + ) + session.add_all(vulns) + session.add(host) + session.commit() + + if limit[0] is None: + query_filter = {} + else: + query_filter = { + "filters": [], + "limit": limit[0], + "offset": "1", + } + res = test_client.get( + f'/v3/vulns/filter?q={json.dumps(query_filter)}' + ) + assert res.status_code == 200 + assert res.json['count'] == 50 + assert len(res.json['vulnerabilities']) == limit[1] + @pytest.mark.skip_sql_dialect('sqlite') @pytest.mark.usefixtures('ignore_nplusone') @pytest.mark.skip(reason="We need a better solution for searching in the model.") From 41e5f820745eade07ace9e81c49534ec1e186ae3 Mon Sep 17 00:00:00 2001 From: Nahuel Alonso Date: Mon, 28 Oct 2024 16:17:26 -0300 Subject: [PATCH 13/37] Changelog --- CHANGELOG/current/7841 | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 CHANGELOG/current/7841 diff --git a/CHANGELOG/current/7841 b/CHANGELOG/current/7841 new file mode 100644 index 00000000000..8536eea4e4f --- /dev/null +++ b/CHANGELOG/current/7841 @@ -0,0 +1,4 @@ +{ + "level": "community", + "md": "[ADD] Added a configurable limit to the retrieval of vulnerabilities. #7841" +} From 35df94f26395672e8157bf3628ab6cb27fd287da Mon Sep 17 00:00:00 2001 From: Nahuel Alonso Date: Mon, 28 Oct 2024 17:10:01 -0300 Subject: [PATCH 14/37] Prevent limit 0 --- faraday/server/api/modules/vulns.py | 2 +- faraday/server/api/modules/vulns_context.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/faraday/server/api/modules/vulns.py b/faraday/server/api/modules/vulns.py index 68d08a0f459..31272fac6e5 100644 --- a/faraday/server/api/modules/vulns.py +++ b/faraday/server/api/modules/vulns.py @@ -1241,7 +1241,7 @@ def _filter(self, filters, workspace_name, exclude_list=None): offset = filters.pop('offset') if 'limit' in filters: filter_limit = filters.pop('limit') - if filter_limit < limit: + if limit > filter_limit > 0: limit = filter_limit try: vulns = self._generate_filter_query( diff --git a/faraday/server/api/modules/vulns_context.py b/faraday/server/api/modules/vulns_context.py index 5d2eee41792..03ea72057e7 100644 --- a/faraday/server/api/modules/vulns_context.py +++ b/faraday/server/api/modules/vulns_context.py @@ -500,7 +500,7 @@ def _filter(self, filters, exclude_list=None): offset = filters.pop('offset') if 'limit' in filters: filter_limit = filters.pop('limit') - if filter_limit < limit: + if limit > filter_limit > 0: limit = filter_limit try: From 3e3ce0639039176aaf11d642c0be61b22e5a12bf Mon Sep 17 00:00:00 2001 From: Nahuel Alonso Date: Mon, 28 Oct 2024 17:22:09 -0300 Subject: [PATCH 15/37] Mod new default of vuln limit and paginate context no filter --- faraday/server/api/modules/vulns_context.py | 4 ++++ faraday/server/config.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/faraday/server/api/modules/vulns_context.py b/faraday/server/api/modules/vulns_context.py index 03ea72057e7..eb5c11d64ff 100644 --- a/faraday/server/api/modules/vulns_context.py +++ b/faraday/server/api/modules/vulns_context.py @@ -864,5 +864,9 @@ def _perform_bulk_delete(self, values, **kwargs): update_host_stats(host_id_list, service_id_list) return response + def _paginate(self, query, hard_limit=0): + limit = faraday_server.vulnerabilities_max_get_limit + return super()._paginate(query, hard_limit=limit) + VulnerabilityContextView.register(vulns_context_api) diff --git a/faraday/server/config.py b/faraday/server/config.py index f6532cf8f72..9e1dda8ce72 100644 --- a/faraday/server/config.py +++ b/faraday/server/config.py @@ -154,7 +154,7 @@ def __init__(self): self.socketio_ping_interval = 60 self.socketio_ping_timeout = 220 self.socketio_logger = False - self.vulnerabilities_max_get_limit = 1000 + self.vulnerabilities_max_get_limit = 4000 class StorageConfigObject(ConfigSection): From a1dca14cc4aaf01e0f464ae7e3db0701e12aed0b Mon Sep 17 00:00:00 2001 From: Nahuel Alonso Date: Mon, 28 Oct 2024 17:26:13 -0300 Subject: [PATCH 16/37] Add test for get context --- tests/test_api_vulnerability_context.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/test_api_vulnerability_context.py b/tests/test_api_vulnerability_context.py index 30a51123199..610014b534e 100644 --- a/tests/test_api_vulnerability_context.py +++ b/tests/test_api_vulnerability_context.py @@ -3228,6 +3228,24 @@ def test_search_filter_offset_and_limit(self, test_client, session): assert expected_vulns == paginated_vulns + @mock.patch("faraday.server.config.faraday_server.vulnerabilities_max_get_limit", 25) + def test_vuln_get_limit_context(self, test_client, session): + workspace = WorkspaceFactory.create() + host = HostFactory.create(workspace=workspace) + vulns = VulnerabilityWebFactory.create_batch(50, + workspace=workspace, + severity='high' + ) + session.add_all(vulns) + session.add(host) + session.commit() + + res = test_client.get('/v3/vulns') + + assert res.status_code == 200 + assert res.json['count'] == 50 + assert len(res.json['vulnerabilities']) == 25 + @mock.patch("faraday.server.config.faraday_server.vulnerabilities_max_get_limit", 25) @pytest.mark.parametrize("limit", [ ["5", 5], From a7d8a9073a546d01ecc4fcdebd3b334e711a82a0 Mon Sep 17 00:00:00 2001 From: Nahuel Alonso Date: Mon, 28 Oct 2024 18:56:49 -0300 Subject: [PATCH 17/37] Improve logic and limit 0 --- faraday/server/api/modules/vulns.py | 13 +++++++++---- faraday/server/api/modules/vulns_context.py | 12 ++++++++---- faraday/server/config.py | 2 +- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/faraday/server/api/modules/vulns.py b/faraday/server/api/modules/vulns.py index 31272fac6e5..7e5ab2f3a67 100644 --- a/faraday/server/api/modules/vulns.py +++ b/faraday/server/api/modules/vulns.py @@ -1236,13 +1236,18 @@ def _filter(self, filters, workspace_name, exclude_list=None): ) if not exclude_list else exclude_list} if 'group_by' not in filters: offset = None - limit = faraday_server.vulnerabilities_max_get_limit if 'offset' in filters: offset = filters.pop('offset') + + limit = faraday_server.vulnerabilities_max_get_limit if 'limit' in filters: - filter_limit = filters.pop('limit') - if limit > filter_limit > 0: - limit = filter_limit + if limit: + filter_limit = filters.pop('limit') + if limit > filter_limit > 0: + limit = filter_limit + else: + limit = filters.pop('limit') + try: vulns = self._generate_filter_query( VulnerabilityGeneric, diff --git a/faraday/server/api/modules/vulns_context.py b/faraday/server/api/modules/vulns_context.py index eb5c11d64ff..745a30d2b3a 100644 --- a/faraday/server/api/modules/vulns_context.py +++ b/faraday/server/api/modules/vulns_context.py @@ -495,13 +495,17 @@ def _filter(self, filters, exclude_list=None): )if not exclude_list else exclude_list} if 'group_by' not in filters: offset = None - limit = faraday_server.vulnerabilities_max_get_limit if 'offset' in filters: offset = filters.pop('offset') + + limit = faraday_server.vulnerabilities_max_get_limit if 'limit' in filters: - filter_limit = filters.pop('limit') - if limit > filter_limit > 0: - limit = filter_limit + if limit: + filter_limit = filters.pop('limit') + if limit > filter_limit > 0: + limit = filter_limit + else: + limit = filters.pop('limit') try: vulns = self._generate_filter_query( diff --git a/faraday/server/config.py b/faraday/server/config.py index 9e1dda8ce72..80a676b0a90 100644 --- a/faraday/server/config.py +++ b/faraday/server/config.py @@ -154,7 +154,7 @@ def __init__(self): self.socketio_ping_interval = 60 self.socketio_ping_timeout = 220 self.socketio_logger = False - self.vulnerabilities_max_get_limit = 4000 + self.vulnerabilities_max_get_limit = 0 # No limit class StorageConfigObject(ConfigSection): From b318a29ffc28ff7ad9eab98fd00b358d3056ae61 Mon Sep 17 00:00:00 2001 From: Nahuel Alonso Date: Tue, 29 Oct 2024 13:30:38 -0300 Subject: [PATCH 18/37] Move to settings --- faraday/server/api/modules/vulns.py | 5 ++-- faraday/server/api/modules/vulns_context.py | 5 ++-- faraday/server/config.py | 1 - faraday/settings/__init__.py | 2 ++ faraday/settings/query_limits.py | 31 +++++++++++++++++++++ 5 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 faraday/settings/query_limits.py diff --git a/faraday/server/api/modules/vulns.py b/faraday/server/api/modules/vulns.py index 7e5ab2f3a67..a204f536ed1 100644 --- a/faraday/server/api/modules/vulns.py +++ b/faraday/server/api/modules/vulns.py @@ -90,6 +90,7 @@ ) from faraday.server.utils.vulns import parse_cve_references_and_policyviolations, update_one_host_severity_stat, bulk_update_custom_attributes from faraday.server.debouncer import debounce_workspace_update +from settings import get_settings vulns_api = Blueprint('vulns_api', __name__) logger = logging.getLogger(__name__) @@ -1239,7 +1240,7 @@ def _filter(self, filters, workspace_name, exclude_list=None): if 'offset' in filters: offset = filters.pop('offset') - limit = faraday_server.vulnerabilities_max_get_limit + limit = get_settings("query_limits").vuln_query_limit if 'limit' in filters: if limit: filter_limit = filters.pop('limit') @@ -1621,7 +1622,7 @@ def _perform_bulk_delete(self, values, **kwargs): return response def _paginate(self, query, hard_limit=0): - limit = faraday_server.vulnerabilities_max_get_limit + limit = get_settings("query_limits").vuln_query_limit return super()._paginate(query, hard_limit=limit) diff --git a/faraday/server/api/modules/vulns_context.py b/faraday/server/api/modules/vulns_context.py index 745a30d2b3a..ac19099c537 100644 --- a/faraday/server/api/modules/vulns_context.py +++ b/faraday/server/api/modules/vulns_context.py @@ -72,6 +72,7 @@ CustomILike, VulnerabilityFilterSet ) +from settings import get_settings vulns_context_api = Blueprint('vulns_context_api', __name__) logger = logging.getLogger(__name__) @@ -498,7 +499,7 @@ def _filter(self, filters, exclude_list=None): if 'offset' in filters: offset = filters.pop('offset') - limit = faraday_server.vulnerabilities_max_get_limit + limit = get_settings("query_limits").vuln_query_limit if 'limit' in filters: if limit: filter_limit = filters.pop('limit') @@ -869,7 +870,7 @@ def _perform_bulk_delete(self, values, **kwargs): return response def _paginate(self, query, hard_limit=0): - limit = faraday_server.vulnerabilities_max_get_limit + limit = get_settings("query_limits").vuln_query_limit return super()._paginate(query, hard_limit=limit) diff --git a/faraday/server/config.py b/faraday/server/config.py index 80a676b0a90..6a50426314f 100644 --- a/faraday/server/config.py +++ b/faraday/server/config.py @@ -154,7 +154,6 @@ def __init__(self): self.socketio_ping_interval = 60 self.socketio_ping_timeout = 220 self.socketio_logger = False - self.vulnerabilities_max_get_limit = 0 # No limit class StorageConfigObject(ConfigSection): diff --git a/faraday/settings/__init__.py b/faraday/settings/__init__.py index 437fca293e1..71589bb5d4a 100644 --- a/faraday/settings/__init__.py +++ b/faraday/settings/__init__.py @@ -28,3 +28,5 @@ def load_settings(): reports_init() from faraday.settings.elk import init_setting as elk_init # pylint: disable=import-outside-toplevel elk_init() + from faraday.settings.query_limits import init_setting as qlimits_init # pylint: disable=import-outside-toplevel + qlimits_init() diff --git a/faraday/settings/query_limits.py b/faraday/settings/query_limits.py new file mode 100644 index 00000000000..5ba443cfba1 --- /dev/null +++ b/faraday/settings/query_limits.py @@ -0,0 +1,31 @@ +""" +Faraday Penetration Test IDE +Copyright (C) 2021 Infobyte LLC (https://faradaysec.com/) +See the file 'doc/LICENSE' for the license information +""" + +# Related third party imports +from marshmallow import fields + +# Local application imports +from faraday.server.api.base import AutoSchema +from faraday.settings.base import Settings + +DEFAULT_VULN_LIMIT = 0 + + +class QueryLimitsSchema(AutoSchema): + vuln_query_limit = fields.Int(default=DEFAULT_VULN_LIMIT, required=True) + + +class QueryLimitsSettings(Settings): + settings_id = "query_limits" + settings_key = f'{settings_id}_settings' + schema = QueryLimitsSchema() + + def get_default_config(self): + return {'vuln_query_limit': DEFAULT_VULN_LIMIT} + + +def init_setting(): + QueryLimitsSettings() From 96815837d4a450a85184f9c3474266043b1c9f0d Mon Sep 17 00:00:00 2001 From: Nahuel Alonso Date: Tue, 29 Oct 2024 15:07:53 -0300 Subject: [PATCH 19/37] Add endpoint and tests --- .../api/modules/settings_query_limits.py | 28 +++++++++++++++++++ faraday/server/app.py | 3 ++ faraday/settings/query_limits.py | 2 +- tests/test_api_settings.py | 14 ++++++++++ tests/test_api_vulnerability.py | 11 ++++++-- tests/test_api_vulnerability_context.py | 11 ++++++-- 6 files changed, 62 insertions(+), 7 deletions(-) create mode 100644 faraday/server/api/modules/settings_query_limits.py diff --git a/faraday/server/api/modules/settings_query_limits.py b/faraday/server/api/modules/settings_query_limits.py new file mode 100644 index 00000000000..c939c78b10b --- /dev/null +++ b/faraday/server/api/modules/settings_query_limits.py @@ -0,0 +1,28 @@ +""" +Faraday Penetration Test IDE +Copyright (C) 2021 Infobyte LLC (https://faradaysec.com/) +See the file 'doc/LICENSE' for the license information +""" + +# Standard library imports +import logging + +# Related third party imports +from flask import Blueprint + +# Local application imports +from faraday.settings.query_limits import QueryLimitsSchema, QueryLimitsSettings +from faraday.server.api.modules.settings import SettingsAPIView + +logger = logging.getLogger(__name__) +query_limits_settings_api = Blueprint('query_limits_settings_api', __name__) + +QueryLimitsSchema + + +class QueryLimitsSettingsAPI(SettingsAPIView): + route_base = QueryLimitsSettings.settings_id + schema_class = QueryLimitsSchema + + +QueryLimitsSettingsAPI.register(query_limits_settings_api) diff --git a/faraday/server/app.py b/faraday/server/app.py index a2c7df525b8..e9fb9783caa 100644 --- a/faraday/server/app.py +++ b/faraday/server/app.py @@ -141,6 +141,8 @@ def register_blueprints(app): dashboard_settings_api # pylint:disable=import-outside-toplevel from faraday.server.api.modules.settings_elk import \ elk_settings_api # pylint:disable=import-outside-toplevel + from server.api.modules.settings_query_limits import \ + query_limits_settings_api # pylint:disable=import-outside-toplevel app.register_blueprint(ui) app.register_blueprint(commandsrun_api, url_prefix=app.config['APPLICATION_PREFIX']) @@ -177,6 +179,7 @@ def register_blueprints(app): app.register_blueprint(dashboard_settings_api, url_prefix=app.config['APPLICATION_PREFIX']) app.register_blueprint(elk_settings_api, url_prefix=app.config['APPLICATION_PREFIX']) app.register_blueprint(swagger_api, url_prefix=app.config['APPLICATION_PREFIX']) + app.register_blueprint(query_limits_settings_api, url_prefix=app.config['APPLICATION_PREFIX']) def check_testing_configuration(testing, app): diff --git a/faraday/settings/query_limits.py b/faraday/settings/query_limits.py index 5ba443cfba1..af1cb4d4b3d 100644 --- a/faraday/settings/query_limits.py +++ b/faraday/settings/query_limits.py @@ -15,7 +15,7 @@ class QueryLimitsSchema(AutoSchema): - vuln_query_limit = fields.Int(default=DEFAULT_VULN_LIMIT, required=True) + vuln_query_limit = fields.Int(default=DEFAULT_VULN_LIMIT, required=True, validate=lambda x: x >= 0) class QueryLimitsSettings(Settings): diff --git a/tests/test_api_settings.py b/tests/test_api_settings.py index 736cce73a20..ab98b9d9954 100644 --- a/tests/test_api_settings.py +++ b/tests/test_api_settings.py @@ -143,3 +143,17 @@ def test_update_settings_with_valid_value(self, test_client): data = {'custom_plugins_folder': response.json['custom_plugins_folder']} response = test_client.patch("/v3/settings/reports", json=data) assert response.status_code == 200 + + def test_update_query_limits_success(self, test_client): + data = { + "vuln_query_limit": 25, + } + response = test_client.patch("/v3/settings/query_limits", json=data) + assert response.status_code == 200 + + def test_update_query_limits_fails_negative(self, test_client): + data = { + "vuln_query_limit": -25, + } + response = test_client.patch("/v3/settings/query_limits", json=data) + assert response.status_code == 400 diff --git a/tests/test_api_vulnerability.py b/tests/test_api_vulnerability.py index 38a86be9831..a83e6dc36f7 100644 --- a/tests/test_api_vulnerability.py +++ b/tests/test_api_vulnerability.py @@ -12,7 +12,6 @@ from base64 import b64encode from io import BytesIO, StringIO from posixpath import join -from unittest import mock from sqlalchemy.orm.util import was_deleted @@ -4764,8 +4763,11 @@ def test_search_filter_offset_and_limit(self, test_client, session): assert expected_vulns == paginated_vulns - @mock.patch("faraday.server.config.faraday_server.vulnerabilities_max_get_limit", 25) def test_vuln_get_limit(self, test_client, session): + + # Change setting + test_client.patch('/v3/settings/query_limits', data={"vuln_query_limit": 25}) + workspace = WorkspaceFactory.create() host = HostFactory.create(workspace=workspace) vulns = VulnerabilityWebFactory.create_batch(50, @@ -4782,13 +4784,16 @@ def test_vuln_get_limit(self, test_client, session): assert res.json['count'] == 50 assert len(res.json['vulnerabilities']) == 25 - @mock.patch("faraday.server.config.faraday_server.vulnerabilities_max_get_limit", 25) @pytest.mark.parametrize("limit", [ ["5", 5], [None, 25], ["100", 25] ]) def test_vuln_filter_limit(self, test_client, session, limit): + + # Change setting + test_client.patch('/v3/settings/query_limits', data={"vuln_query_limit": 25}) + workspace = WorkspaceFactory.create() host = HostFactory.create(workspace=workspace) vulns = VulnerabilityWebFactory.create_batch(50, diff --git a/tests/test_api_vulnerability_context.py b/tests/test_api_vulnerability_context.py index 610014b534e..9eb62b7af19 100644 --- a/tests/test_api_vulnerability_context.py +++ b/tests/test_api_vulnerability_context.py @@ -12,7 +12,6 @@ from base64 import b64encode from io import BytesIO, StringIO from posixpath import join -from unittest import mock from sqlalchemy.orm.util import was_deleted @@ -3228,8 +3227,11 @@ def test_search_filter_offset_and_limit(self, test_client, session): assert expected_vulns == paginated_vulns - @mock.patch("faraday.server.config.faraday_server.vulnerabilities_max_get_limit", 25) def test_vuln_get_limit_context(self, test_client, session): + + # Change setting + test_client.patch('/v3/settings/query_limits', data={"vuln_query_limit": 25}) + workspace = WorkspaceFactory.create() host = HostFactory.create(workspace=workspace) vulns = VulnerabilityWebFactory.create_batch(50, @@ -3246,13 +3248,16 @@ def test_vuln_get_limit_context(self, test_client, session): assert res.json['count'] == 50 assert len(res.json['vulnerabilities']) == 25 - @mock.patch("faraday.server.config.faraday_server.vulnerabilities_max_get_limit", 25) @pytest.mark.parametrize("limit", [ ["5", 5], [None, 25], ["100", 25] ]) def test_vuln_filter_limit_context(self, test_client, session, limit): + + # Change setting + test_client.patch('/v3/settings/query_limits', data={"vuln_query_limit": 25}) + workspace = WorkspaceFactory.create() host = HostFactory.create(workspace=workspace) vulns = VulnerabilityWebFactory.create_batch(50, From 994c009473009e992e7970a59d466bdbf4a388d2 Mon Sep 17 00:00:00 2001 From: Nahuel Alonso Date: Tue, 29 Oct 2024 15:27:28 -0300 Subject: [PATCH 20/37] Fix import errors --- faraday/server/api/modules/vulns.py | 2 +- faraday/server/api/modules/vulns_context.py | 2 +- faraday/server/app.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/faraday/server/api/modules/vulns.py b/faraday/server/api/modules/vulns.py index a204f536ed1..247e388e428 100644 --- a/faraday/server/api/modules/vulns.py +++ b/faraday/server/api/modules/vulns.py @@ -90,7 +90,7 @@ ) from faraday.server.utils.vulns import parse_cve_references_and_policyviolations, update_one_host_severity_stat, bulk_update_custom_attributes from faraday.server.debouncer import debounce_workspace_update -from settings import get_settings +from faraday.settings import get_settings vulns_api = Blueprint('vulns_api', __name__) logger = logging.getLogger(__name__) diff --git a/faraday/server/api/modules/vulns_context.py b/faraday/server/api/modules/vulns_context.py index ac19099c537..7d1c17c6b5d 100644 --- a/faraday/server/api/modules/vulns_context.py +++ b/faraday/server/api/modules/vulns_context.py @@ -72,7 +72,7 @@ CustomILike, VulnerabilityFilterSet ) -from settings import get_settings +from faraday.settings import get_settings vulns_context_api = Blueprint('vulns_context_api', __name__) logger = logging.getLogger(__name__) diff --git a/faraday/server/app.py b/faraday/server/app.py index e9fb9783caa..a296fbf6591 100644 --- a/faraday/server/app.py +++ b/faraday/server/app.py @@ -141,7 +141,7 @@ def register_blueprints(app): dashboard_settings_api # pylint:disable=import-outside-toplevel from faraday.server.api.modules.settings_elk import \ elk_settings_api # pylint:disable=import-outside-toplevel - from server.api.modules.settings_query_limits import \ + from faraday.server.api.modules.settings_query_limits import \ query_limits_settings_api # pylint:disable=import-outside-toplevel app.register_blueprint(ui) From d221b77627865e4f39d1766538fbad413f5dcf2e Mon Sep 17 00:00:00 2001 From: Nahuel Alonso Date: Wed, 30 Oct 2024 12:34:17 -0300 Subject: [PATCH 21/37] Fix changelog --- CHANGELOG/current/{7841 => 7841.json} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename CHANGELOG/current/{7841 => 7841.json} (100%) diff --git a/CHANGELOG/current/7841 b/CHANGELOG/current/7841.json similarity index 100% rename from CHANGELOG/current/7841 rename to CHANGELOG/current/7841.json From 0214c611a8050f96a3daca64ef3d887d85a04c4d Mon Sep 17 00:00:00 2001 From: Nahuel Alonso Date: Wed, 30 Oct 2024 12:46:37 -0300 Subject: [PATCH 22/37] Try fix test --- tests/test_api_vulnerability.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/test_api_vulnerability.py b/tests/test_api_vulnerability.py index a83e6dc36f7..1333b6679bf 100644 --- a/tests/test_api_vulnerability.py +++ b/tests/test_api_vulnerability.py @@ -1295,6 +1295,10 @@ def test_filter_by_website(self, test_client, session, def test_filter_by_target(self, test_client, session, host_factory, service_factory, vulnerability_factory, vulnerability_web_factory): + + # Change setting + test_client.patch('/v3/settings/query_limits', data={"vuln_query_limit": 0}) + host = host_factory.create(workspace=self.workspace, ip='9.9.9.9') expected_ids = set() From 27cf8c06f9b63314e642d222bcdf80214ec7e669 Mon Sep 17 00:00:00 2001 From: Nahuel Alonso Date: Wed, 30 Oct 2024 13:09:40 -0300 Subject: [PATCH 23/37] Fix test context --- tests/test_api_vulnerability_context.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/test_api_vulnerability_context.py b/tests/test_api_vulnerability_context.py index 9eb62b7af19..7ce589fe002 100644 --- a/tests/test_api_vulnerability_context.py +++ b/tests/test_api_vulnerability_context.py @@ -1066,6 +1066,10 @@ def test_filter_by_website(self, test_client, session, def test_filter_by_target(self, test_client, session, host_factory, service_factory, vulnerability_factory, vulnerability_web_factory): + + # Change setting + test_client.patch('/v3/settings/query_limits', data={"vuln_query_limit": 0}) + host = host_factory.create(workspace=self.workspace, ip='9.9.9.9') expected_ids = set() From 8ee0015a412ea5e82cdf8bde69692ed3617c4489 Mon Sep 17 00:00:00 2001 From: Nahuel Alonso Date: Wed, 30 Oct 2024 19:52:24 -0300 Subject: [PATCH 24/37] Improve test --- tests/test_api_settings.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_api_settings.py b/tests/test_api_settings.py index ab98b9d9954..c2541ca8c8e 100644 --- a/tests/test_api_settings.py +++ b/tests/test_api_settings.py @@ -144,9 +144,10 @@ def test_update_settings_with_valid_value(self, test_client): response = test_client.patch("/v3/settings/reports", json=data) assert response.status_code == 200 - def test_update_query_limits_success(self, test_client): + @pytest.mark.parametrize("limit", [0, 25, 99999]) + def test_update_query_limits_success(self, test_client, limit): data = { - "vuln_query_limit": 25, + "vuln_query_limit": limit, } response = test_client.patch("/v3/settings/query_limits", json=data) assert response.status_code == 200 From 9f38dc8e5a5e88cccd8c262bf23f89974e813a03 Mon Sep 17 00:00:00 2001 From: Diego Nadares Date: Wed, 6 Nov 2024 15:03:17 +0000 Subject: [PATCH 25/37] Modify query limit init name --- faraday/settings/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/faraday/settings/__init__.py b/faraday/settings/__init__.py index 71589bb5d4a..8f46208ada5 100644 --- a/faraday/settings/__init__.py +++ b/faraday/settings/__init__.py @@ -28,5 +28,5 @@ def load_settings(): reports_init() from faraday.settings.elk import init_setting as elk_init # pylint: disable=import-outside-toplevel elk_init() - from faraday.settings.query_limits import init_setting as qlimits_init # pylint: disable=import-outside-toplevel - qlimits_init() + from faraday.settings.query_limits import init_setting as query_limits_init # pylint: disable=import-outside-toplevel + query_limits_init() From 11362e05a6f301bed0f589b3aea645ea7e96cffd Mon Sep 17 00:00:00 2001 From: Adriano Canavero Date: Fri, 8 Nov 2024 10:33:39 -0300 Subject: [PATCH 26/37] add csrf validation on post_attachment --- faraday/server/api/modules/vulns.py | 11 ++++++++--- faraday/server/utils/csrf.py | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 faraday/server/utils/csrf.py diff --git a/faraday/server/api/modules/vulns.py b/faraday/server/api/modules/vulns.py index 5230fff9149..a9aeff99ef2 100644 --- a/faraday/server/api/modules/vulns.py +++ b/faraday/server/api/modules/vulns.py @@ -38,6 +38,7 @@ from werkzeug.datastructures import ImmutableMultiDict from depot.manager import DepotManager +from faraday.server.utils.csrf import validate_file # Local application imports from faraday.server.utils.cwe import create_cwe from faraday.server.utils.reference import create_reference @@ -1042,6 +1043,13 @@ def post_attachment(self, workspace_name, vuln_id): description: Ok """ + try: + validate_file(request) + except FileNotFoundError: + flask.abort(400, "File not found in request") + except ValidationError as e: + flask.abort(403, str(e)) + vuln_workspace_check = db.session.query(VulnerabilityGeneric, Workspace.id).join( Workspace).filter(VulnerabilityGeneric.id == vuln_id, Workspace.name == workspace_name).first() @@ -1049,9 +1057,6 @@ def post_attachment(self, workspace_name, vuln_id): if not vuln_workspace_check: flask.abort(404, "Vulnerability not found") - if 'file' not in request.files: - flask.abort(400) - vuln = VulnerabilitySchema().dump(vuln_workspace_check[0]) filename = request.files['file'].filename _attachments = vuln['_attachments'] diff --git a/faraday/server/utils/csrf.py b/faraday/server/utils/csrf.py new file mode 100644 index 00000000000..5d6c0016b24 --- /dev/null +++ b/faraday/server/utils/csrf.py @@ -0,0 +1,14 @@ +from flask_wtf.csrf import validate_csrf +from wtforms import ValidationError + + +def validate_file(request): + if 'file' not in request.files: + raise FileNotFoundError() + + try: + validate_csrf(request.form.get('csrf_token')) + except ValidationError as e: + raise ValidationError(str(e)) from e + + return request.files['file'] From 34e0441d4cf8ff62510e182707172693d9592875 Mon Sep 17 00:00:00 2001 From: Adriano Canavero Date: Fri, 8 Nov 2024 13:00:21 -0300 Subject: [PATCH 27/37] fix attachment test with csrf token --- tests/test_api_vulnerability.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_api_vulnerability.py b/tests/test_api_vulnerability.py index db08a108e89..5aa3378bf77 100644 --- a/tests/test_api_vulnerability.py +++ b/tests/test_api_vulnerability.py @@ -3216,7 +3216,8 @@ def test_add_attachment_to_vuln(self, test_client, session, csrf_token, session.commit() file_contents = b'my file contents' data = { - 'file': (BytesIO(file_contents), 'borrar.txt') + 'file': (BytesIO(file_contents), 'borrar.txt'), + 'csrf_token': csrf_token } headers = {'Content-type': 'multipart/form-data'} From 9432e94400b566ac412c729d25e4eceb0622fb83 Mon Sep 17 00:00:00 2001 From: Adriano Canavero Date: Mon, 11 Nov 2024 13:58:43 -0300 Subject: [PATCH 28/37] add changelog --- CHANGELOG/current/7851.json | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 CHANGELOG/current/7851.json diff --git a/CHANGELOG/current/7851.json b/CHANGELOG/current/7851.json new file mode 100644 index 00000000000..262df8cb1d6 --- /dev/null +++ b/CHANGELOG/current/7851.json @@ -0,0 +1,4 @@ +{ + "level": "community", + "md": "[ADD] Added more validations to attachments. #7851" +} From 3ade67132e6ec1517104b94e970e259ba0553ab9 Mon Sep 17 00:00:00 2001 From: Adriano Canavero Date: Thu, 14 Nov 2024 12:00:01 -0300 Subject: [PATCH 29/37] fix validation error bad usage --- faraday/server/api/modules/vulns.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/faraday/server/api/modules/vulns.py b/faraday/server/api/modules/vulns.py index a9aeff99ef2..07e98afd3f7 100644 --- a/faraday/server/api/modules/vulns.py +++ b/faraday/server/api/modules/vulns.py @@ -17,6 +17,7 @@ import flask import sqlalchemy +from wtforms import ValidationError as WTFormsValidationError from flask import request, send_file from flask import Blueprint, make_response from flask_classful import route @@ -1047,7 +1048,7 @@ def post_attachment(self, workspace_name, vuln_id): validate_file(request) except FileNotFoundError: flask.abort(400, "File not found in request") - except ValidationError as e: + except WTFormsValidationError as e: flask.abort(403, str(e)) vuln_workspace_check = db.session.query(VulnerabilityGeneric, Workspace.id).join( From a1183d089d4cfc950a591309923b76cefca05996 Mon Sep 17 00:00:00 2001 From: Adriano Canavero Date: Thu, 14 Nov 2024 12:05:54 -0300 Subject: [PATCH 30/37] add csrf validation on context --- faraday/server/api/modules/vulns.py | 2 +- faraday/server/api/modules/vulns_context.py | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/faraday/server/api/modules/vulns.py b/faraday/server/api/modules/vulns.py index 07e98afd3f7..cc051a1f980 100644 --- a/faraday/server/api/modules/vulns.py +++ b/faraday/server/api/modules/vulns.py @@ -39,8 +39,8 @@ from werkzeug.datastructures import ImmutableMultiDict from depot.manager import DepotManager -from faraday.server.utils.csrf import validate_file # Local application imports +from faraday.server.utils.csrf import validate_file from faraday.server.utils.cwe import create_cwe from faraday.server.utils.reference import create_reference from faraday.server.utils.search import search diff --git a/faraday/server/api/modules/vulns_context.py b/faraday/server/api/modules/vulns_context.py index ea00d7ddc6c..4e67c0f2c2b 100644 --- a/faraday/server/api/modules/vulns_context.py +++ b/faraday/server/api/modules/vulns_context.py @@ -14,6 +14,7 @@ # Related third party imports import flask import sqlalchemy +from wtforms import ValidationError as WTFormsValidationError from flask import request, send_file from flask import Blueprint, make_response from flask_classful import route @@ -28,6 +29,7 @@ from faraday.server.config import faraday_server from faraday.server.debouncer import debounce_workspace_update # Local application imports +from faraday.server.utils.csrf import validate_file from faraday.server.utils.cwe import create_cwe from faraday.server.utils.reference import create_reference from faraday.server.utils.search import search @@ -310,6 +312,13 @@ def post_attachment(self, vuln_id): 200: description: Ok """ + try: + validate_file(request) + except FileNotFoundError: + flask.abort(400, "File not found in request") + except WTFormsValidationError as e: + flask.abort(403, str(e)) + vuln_permission_check = self._apply_filter_context( db.session.query(VulnerabilityGeneric).filter(VulnerabilityGeneric.id == vuln_id), operation="write" @@ -318,9 +327,6 @@ def post_attachment(self, vuln_id): if not vuln_permission_check: flask.abort(404, "Vulnerability not found") - if 'file' not in request.files: - flask.abort(400) - vuln = VulnerabilitySchema().dump(vuln_permission_check) filename = request.files['file'].filename _attachments = vuln['_attachments'] From de5dc9f793d206170b22e934d37426949e5a5e13 Mon Sep 17 00:00:00 2001 From: Adriano Canavero Date: Thu, 14 Nov 2024 14:05:17 -0300 Subject: [PATCH 31/37] fix tests --- tests/test_api_vulnerability_context.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_api_vulnerability_context.py b/tests/test_api_vulnerability_context.py index 99f170a0a25..4f36513e1d2 100644 --- a/tests/test_api_vulnerability_context.py +++ b/tests/test_api_vulnerability_context.py @@ -1825,7 +1825,8 @@ def test_add_attachment_to_vuln(self, test_client, session, csrf_token, session.commit() file_contents = b'my file contents' data = { - 'file': (BytesIO(file_contents), 'borrar.txt') + 'file': (BytesIO(file_contents), 'borrar.txt'), + 'csrf_token': csrf_token } headers = {'Content-type': 'multipart/form-data'} res = test_client.post( From 74a248ff2e4829cc29362198297252abb19a8101 Mon Sep 17 00:00:00 2001 From: Adriano Canavero Date: Thu, 14 Nov 2024 15:47:35 -0300 Subject: [PATCH 32/37] fix tests --- tests/test_api_vulnerability_context.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_api_vulnerability_context.py b/tests/test_api_vulnerability_context.py index 4f36513e1d2..b86becb6ca2 100644 --- a/tests/test_api_vulnerability_context.py +++ b/tests/test_api_vulnerability_context.py @@ -1839,7 +1839,7 @@ def test_add_attachment_to_vuln(self, test_client, session, csrf_token, depot = DepotManager.get() assert file_contents == depot.get(file_id).read() - def test_add_attachment_to_vuln_fails_readonly(self, test_client, session, host_with_hostnames): + def test_add_attachment_to_vuln_fails_readonly(self, test_client, session, host_with_hostnames, csrf_token): ws = WorkspaceFactory.create(name='abc') session.add(ws) vuln = VulnerabilityFactory.create(workspace=ws) @@ -1847,7 +1847,8 @@ def test_add_attachment_to_vuln_fails_readonly(self, test_client, session, host_ session.commit() file_contents = b'my file contents' data = { - 'file': (BytesIO(file_contents), 'borrar.txt') + 'file': (BytesIO(file_contents), 'borrar.txt'), + 'csrf_token': csrf_token } headers = {'Content-type': 'multipart/form-data'} From c0f3f590fe88aad665628bb1b86ecf6a0c4d0de2 Mon Sep 17 00:00:00 2001 From: dkraus Date: Thu, 14 Nov 2024 17:40:50 -0300 Subject: [PATCH 33/37] Fix migration --- faraday/migrations/versions/4423dd3f90be_clear_preferences.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/faraday/migrations/versions/4423dd3f90be_clear_preferences.py b/faraday/migrations/versions/4423dd3f90be_clear_preferences.py index 665cac89abe..8a93f3c4047 100644 --- a/faraday/migrations/versions/4423dd3f90be_clear_preferences.py +++ b/faraday/migrations/versions/4423dd3f90be_clear_preferences.py @@ -16,7 +16,7 @@ def upgrade(): - op.execute("UPDATE faraday_user SET preferences = NULL;") + op.execute("UPDATE faraday_user SET preferences = '{}';") def downgrade(): From 8a3d4ae80b232c7b8da760eaab8f6273ec487368 Mon Sep 17 00:00:00 2001 From: dkraus Date: Wed, 20 Nov 2024 16:16:54 -0300 Subject: [PATCH 34/37] Fix vulns delete for command_object references --- faraday/server/models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/faraday/server/models.py b/faraday/server/models.py index e60c631b7cb..79a630c6bbf 100644 --- a/faraday/server/models.py +++ b/faraday/server/models.py @@ -1465,6 +1465,7 @@ class VulnerabilityGeneric(VulnerabilityABC): secondary='command_object', primaryjoin='and_(VulnerabilityGeneric.id == CommandObject.object_id, CommandObject.object_type == "vulnerability")', collection_class=set, + passive_deletes=True, ) _cvss2_vector_string = Column(Text, nullable=True) From 8d022e829bcadd13ceb1aa6982158e267c049623 Mon Sep 17 00:00:00 2001 From: dkraus Date: Wed, 20 Nov 2024 16:18:19 -0300 Subject: [PATCH 35/37] Add changelog --- CHANGELOG/current/7859.json | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 CHANGELOG/current/7859.json diff --git a/CHANGELOG/current/7859.json b/CHANGELOG/current/7859.json new file mode 100644 index 00000000000..6fe321bd443 --- /dev/null +++ b/CHANGELOG/current/7859.json @@ -0,0 +1,4 @@ +{ + "level": "community", + "md": "[FIX] Fixed vulnerability deletion when it has more than one command associated. #7859" +} From 1be8eca1c698cc256911e22eac03fbcd70ddfad9 Mon Sep 17 00:00:00 2001 From: Diego Nadares Date: Thu, 21 Nov 2024 18:54:14 -0300 Subject: [PATCH 36/37] Run pynixify and update swagger --- faraday/__init__.py | 2 +- faraday/openapi/faraday_swagger.json | 200 ++++++++++++------ pynixify/packages/cvss/default.nix | 4 +- pynixify/packages/faraday-plugins/default.nix | 4 +- pynixify/packages/faradaysec/default.nix | 2 +- requirements.txt | 2 +- 6 files changed, 141 insertions(+), 73 deletions(-) diff --git a/faraday/__init__.py b/faraday/__init__.py index 4b19ee73ac7..4eb5982a862 100644 --- a/faraday/__init__.py +++ b/faraday/__init__.py @@ -4,4 +4,4 @@ See the file 'doc/LICENSE' for the license information """ -__version__ = '5.8.0' +__version__ = '5.9.0' diff --git a/faraday/openapi/faraday_swagger.json b/faraday/openapi/faraday_swagger.json index 20873c63ff0..0087cb49a9a 100644 --- a/faraday/openapi/faraday_swagger.json +++ b/faraday/openapi/faraday_swagger.json @@ -1,7 +1,7 @@ { "info": { "description": "The Faraday REST API enables you to interact with [our server](https://github.com/infobyte/faraday).\nUse this API to interact or integrate with Faraday server. This page documents the REST API, with HTTP response codes and example requests and responses.", - "title": "Faraday 5.8.0 API", + "title": "Faraday 5.9.0 API", "version": "v3" }, "security": [ @@ -6750,6 +6750,60 @@ } } } + }, + "/_api/v3/settings/query_limits": { + "get": { + "tags": [ + "settings" + ], + "summary": "Retrieves settings of {route_base}", + "responses": { + "200": { + "description": "Ok", + "content": { + "application/json": { + "schema": { + "schema_class": null + } + } + } + }, + "403": { + "description": "Admin user required" + } + } + }, + "patch": { + "tags": [ + "settings" + ], + "summary": "Creates/Updates settings of {route_base}", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "schema_class": null + } + } + } + }, + "responses": { + "200": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "schema_class": null + } + } + } + }, + "403": { + "description": "Admin user required" + } + } + } } }, "openapi": "3.0.2", @@ -6764,8 +6818,8 @@ }, "command": { "type": "string", - "nullable": true, - "minLength": 1 + "minLength": 1, + "nullable": true }, "duration": { "nullable": true @@ -6773,13 +6827,13 @@ "itime": {}, "ip": { "type": "string", - "nullable": true, - "maxLength": 250 + "maxLength": 250, + "nullable": true }, "hostname": { "type": "string", - "nullable": true, - "maxLength": 250 + "maxLength": 250, + "nullable": true }, "params": { "type": "string", @@ -6787,8 +6841,8 @@ }, "user": { "type": "string", - "nullable": true, - "maxLength": 250 + "maxLength": 250, + "nullable": true }, "creator": { "readOnly": true @@ -6798,18 +6852,19 @@ }, "tool": { "type": "string", - "nullable": true, - "minLength": 1 + "minLength": 1, + "nullable": true }, "import_source": { "enum": [ "report", "shell", "agent", - "cloud_agent" + "cloud_agent", + null ], - "nullable": true, - "maxLength": 11 + "maxLength": 11, + "nullable": true }, "metadata": {} }, @@ -6828,18 +6883,18 @@ }, "command": { "type": "string", - "nullable": true, - "minLength": 1 + "minLength": 1, + "nullable": true }, "ip": { "type": "string", - "nullable": true, - "maxLength": 250 + "maxLength": 250, + "nullable": true }, "hostname": { "type": "string", - "nullable": true, - "maxLength": 250 + "maxLength": 250, + "nullable": true }, "params": { "type": "string", @@ -6847,26 +6902,27 @@ }, "user": { "type": "string", - "nullable": true, - "maxLength": 250 + "maxLength": 250, + "nullable": true }, "workspace": { "readOnly": true }, "tool": { "type": "string", - "nullable": true, - "minLength": 1 + "minLength": 1, + "nullable": true }, "import_source": { "enum": [ "report", "shell", "agent", - "cloud_agent" + "cloud_agent", + null ], - "nullable": true, - "maxLength": 11 + "maxLength": 11, + "nullable": true }, "itime": {}, "sum_created_vulnerabilities": { @@ -7125,8 +7181,8 @@ }, "protocol": { "type": "string", - "nullable": true, - "minLength": 1 + "minLength": 1, + "nullable": true }, "description": { "type": "string", @@ -7204,8 +7260,8 @@ }, "product": { "type": "string", - "nullable": true, - "minLength": 1 + "minLength": 1, + "nullable": true }, "start": { "type": "string", @@ -7247,8 +7303,8 @@ }, "protocol": { "type": "string", - "nullable": true, - "minLength": 1 + "minLength": 1, + "nullable": true }, "name": { "type": "string", @@ -7324,7 +7380,8 @@ "simple", "moderate", "difficult", - "infeasible" + "infeasible", + null ], "nullable": true }, @@ -7368,8 +7425,8 @@ }, "name": { "type": "string", - "nullable": true, - "minLength": 1 + "minLength": 1, + "nullable": true }, "service": { "readOnly": true, @@ -7481,6 +7538,9 @@ }, "data": { "readOnly": true + }, + "description": { + "type": "string" } } }, @@ -7516,8 +7576,8 @@ }, "name": { "type": "string", - "nullable": true, - "minLength": 1 + "minLength": 1, + "nullable": true }, "references": {}, "refs": { @@ -7539,7 +7599,8 @@ "simple", "moderate", "difficult", - "infeasible" + "infeasible", + null ], "nullable": true }, @@ -7622,8 +7683,8 @@ }, "customer": { "type": "string", - "nullable": true, - "maxLength": 250 + "maxLength": 250, + "nullable": true }, "description": { "type": "string", @@ -7773,7 +7834,8 @@ }, "parameters_metadata": { "type": "object", - "readOnly": true + "readOnly": true, + "additionalProperties": {} }, "schedules": { "readOnly": true, @@ -7793,8 +7855,8 @@ }, "name": { "type": "string", - "nullable": true, - "minLength": 1 + "minLength": 1, + "nullable": true }, "status": { "type": "string", @@ -7903,8 +7965,8 @@ }, "protocol": { "type": "string", - "nullable": true, - "minLength": 1 + "minLength": 1, + "nullable": true }, "description": { "type": "string", @@ -8013,7 +8075,8 @@ "simple", "moderate", "difficult", - "infeasible" + "infeasible", + null ], "nullable": true }, @@ -8045,8 +8108,8 @@ }, "name": { "type": "string", - "nullable": true, - "minLength": 1 + "minLength": 1, + "nullable": true }, "service": { "readOnly": true, @@ -8237,8 +8300,8 @@ "properties": { "command": { "type": "string", - "nullable": true, - "minLength": 1 + "minLength": 1, + "nullable": true }, "duration": { "type": "integer", @@ -8250,13 +8313,13 @@ }, "ip": { "type": "string", - "nullable": true, - "maxLength": 250 + "maxLength": 250, + "nullable": true }, "hostname": { "type": "string", - "nullable": true, - "maxLength": 250 + "maxLength": 250, + "nullable": true }, "params": { "type": "string", @@ -8264,24 +8327,25 @@ }, "user": { "type": "string", - "nullable": true, - "maxLength": 250 + "maxLength": 250, + "nullable": true }, "creator": {}, "tool": { "type": "string", - "nullable": true, - "minLength": 1 + "minLength": 1, + "nullable": true }, "import_source": { "enum": [ "report", "shell", "agent", - "cloud_agent" + "cloud_agent", + null ], - "nullable": true, - "maxLength": 11 + "maxLength": 11, + "nullable": true } }, "required": [ @@ -8377,7 +8441,8 @@ "not_in", "any_in", "contains", - "inverted_in" + "inverted_in", + null ], "nullable": true }, @@ -8452,7 +8517,8 @@ "type": "string", "enum": [ "asset", - "" + "", + null ], "nullable": true }, @@ -8553,7 +8619,8 @@ "type": "array", "writeOnly": true, "items": { - "type": "object" + "type": "object", + "additionalProperties": {} } }, "tasks": { @@ -8664,7 +8731,8 @@ "type": "array", "writeOnly": true, "items": { - "type": "object" + "type": "object", + "additionalProperties": {} } }, "tasks": { diff --git a/pynixify/packages/cvss/default.nix b/pynixify/packages/cvss/default.nix index eb0f2759253..9100c6cb729 100644 --- a/pynixify/packages/cvss/default.nix +++ b/pynixify/packages/cvss/default.nix @@ -6,11 +6,11 @@ buildPythonPackage rec { pname = "cvss"; - version = "3.2"; + version = "3.3"; src = fetchPypi { inherit pname version; - sha256 = "12zs22hq1nnpb9dygmigrp7ikh5jad0z2f7gqb0dxjg6x6ahz3jy"; + sha256 = "1h7v75i7wlxzqrvb1fa289y0lgfaaxwd5492mdi25c2qxs1p22df"; }; # TODO FIXME diff --git a/pynixify/packages/faraday-plugins/default.nix b/pynixify/packages/faraday-plugins/default.nix index 3f61866e1c5..506f2c8452e 100644 --- a/pynixify/packages/faraday-plugins/default.nix +++ b/pynixify/packages/faraday-plugins/default.nix @@ -8,11 +8,11 @@ buildPythonPackage rec { pname = "faraday-plugins"; - version = "1.19.1"; + version = "1.20.0"; src = fetchPypi { inherit pname version; - sha256 = "0gvw21p67fqpjb7f4ljj0hisn6k320im0wbzrqlygr5zv97cfl3j"; + sha256 = "1ghlikg4j5bzff9qiq0skbbpj8r9lyqx5bka35ybwh7qwsv7y90p"; }; propagatedBuildInputs = [ diff --git a/pynixify/packages/faradaysec/default.nix b/pynixify/packages/faradaysec/default.nix index 264c470e4c0..e22c7714558 100644 --- a/pynixify/packages/faradaysec/default.nix +++ b/pynixify/packages/faradaysec/default.nix @@ -18,7 +18,7 @@ buildPythonPackage rec { pname = "faradaysec"; - version = "5.8.0"; + version = "5.9.0"; src = lib.cleanSource ../../..; diff --git a/requirements.txt b/requirements.txt index 6aa00df0414..d5becf6d01c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -36,7 +36,7 @@ syslog-rfc5424-formatter>=1.1.1 simplekv>=0.13.0 Flask-KVSession-fork>=0.6.4 distro>=1.4.0 -faraday-plugins>=1.19.1,<2.0.0 +faraday-plugins>=1.20.0,<2.0.0 apispec>=6.3.0 apispec-webframeworks<=0.5.2 pyyaml From a74b5822f72e5d6929abcce9ba9fce99fa74bd47 Mon Sep 17 00:00:00 2001 From: dkraus Date: Thu, 21 Nov 2024 18:58:33 -0300 Subject: [PATCH 37/37] Ready for realease 5.9.0 --- CHANGELOG/5.9.0/community.md | 5 +++++ CHANGELOG/5.9.0/date.md | 1 + CHANGELOG/current/7763.json | 4 ---- CHANGELOG/current/7811.json | 4 ---- CHANGELOG/current/7841.json | 4 ---- CHANGELOG/current/7851.json | 4 ---- CHANGELOG/current/7859.json | 4 ---- RELEASE.md | 8 ++++++++ 8 files changed, 14 insertions(+), 20 deletions(-) create mode 100644 CHANGELOG/5.9.0/community.md create mode 100644 CHANGELOG/5.9.0/date.md delete mode 100644 CHANGELOG/current/7763.json delete mode 100644 CHANGELOG/current/7811.json delete mode 100644 CHANGELOG/current/7841.json delete mode 100644 CHANGELOG/current/7851.json delete mode 100644 CHANGELOG/current/7859.json diff --git a/CHANGELOG/5.9.0/community.md b/CHANGELOG/5.9.0/community.md new file mode 100644 index 00000000000..73c943d6324 --- /dev/null +++ b/CHANGELOG/5.9.0/community.md @@ -0,0 +1,5 @@ + * [ADD] Added more validations to attachments. #7851 + * [MOD] Removed __license_version__ from init.py. #7763 + * [ADD] Added a configurable limit to the retrieval of vulnerabilities. #7841 + * [ADD] Added the `description` field to evidence attachments in the `VulnerabilitySchema`. #7811 + * [FIX] Fixed vulnerability deletion when it has more than one command associated. #7859 diff --git a/CHANGELOG/5.9.0/date.md b/CHANGELOG/5.9.0/date.md new file mode 100644 index 00000000000..b2c2f71889d --- /dev/null +++ b/CHANGELOG/5.9.0/date.md @@ -0,0 +1 @@ +Nov 21st, 2024 diff --git a/CHANGELOG/current/7763.json b/CHANGELOG/current/7763.json deleted file mode 100644 index f91242c5ba0..00000000000 --- a/CHANGELOG/current/7763.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "level": "community", - "md": "[MOD] Removed __license_version__ from init.py. #7763" -} diff --git a/CHANGELOG/current/7811.json b/CHANGELOG/current/7811.json deleted file mode 100644 index 66c93cc6ac9..00000000000 --- a/CHANGELOG/current/7811.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "level": "community", - "md": "[ADD] Added the `description` field to evidence attachments in the `VulnerabilitySchema`. #7811" -} diff --git a/CHANGELOG/current/7841.json b/CHANGELOG/current/7841.json deleted file mode 100644 index 8536eea4e4f..00000000000 --- a/CHANGELOG/current/7841.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "level": "community", - "md": "[ADD] Added a configurable limit to the retrieval of vulnerabilities. #7841" -} diff --git a/CHANGELOG/current/7851.json b/CHANGELOG/current/7851.json deleted file mode 100644 index 262df8cb1d6..00000000000 --- a/CHANGELOG/current/7851.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "level": "community", - "md": "[ADD] Added more validations to attachments. #7851" -} diff --git a/CHANGELOG/current/7859.json b/CHANGELOG/current/7859.json deleted file mode 100644 index 6fe321bd443..00000000000 --- a/CHANGELOG/current/7859.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "level": "community", - "md": "[FIX] Fixed vulnerability deletion when it has more than one command associated. #7859" -} diff --git a/RELEASE.md b/RELEASE.md index cc3e0bf4aa1..9c04899ae5b 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,6 +1,14 @@ New features in the latest update ===================================== +5.9.0 [Nov 21st, 2024]: +--- + * [ADD] Added more validations to attachments. #7851 + * [MOD] Removed __license_version__ from init.py. #7763 + * [ADD] Added a configurable limit to the retrieval of vulnerabilities. #7841 + * [ADD] Added the `description` field to evidence attachments in the `VulnerabilitySchema`. #7811 + * [FIX] Fixed vulnerability deletion when it has more than one command associated. #7859 + 5.8.0 [Oct 24th, 2024]: --- * [ADD] Added support for CVSS 4.0. #7753