Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix limit parameter in GET sca check endpoint and Fix odd offset issue when paginating wdb queries #6464

Merged
merged 14 commits into from
Oct 30, 2020
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ All notable changes to this project will be documented in this file.

- **API:**
- Added missing agent:group resource to RBAC's catalog. ([6427](https://github.com/wazuh/wazuh/issues/6427))
- Changed `limit` parameter behaviour in `GET sca/{agent_id}/checks/{policy_id}` endpoint and fixed some loss of information when paginating `wdb`. ([#6464](https://github.com/wazuh/wazuh/pull/6464))

### Removed

Expand Down
125 changes: 83 additions & 42 deletions api/api/controllers/sca_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
import logging

from aiohttp import web

import wazuh.sca as sca
from api.encoder import dumps, prettify
from api.util import remove_nones_to_dict, parse_api_param, raise_if_exc
from wazuh.core.common import database_limit

import wazuh.sca as sca
from wazuh.core.cluster.dapi.dapi import DistributedAPI
from wazuh.core.common import database_limit

logger = logging.getLogger('wazuh')

Expand All @@ -20,20 +20,34 @@ async def get_sca_agent(request, agent_id=None, pretty=False, wait_for_complete=
references=None, offset=0, limit=database_limit, sort=None, search=None, q=None):
"""Get security configuration assessment (SCA) database of an agent

:param agent_id: Agent ID. All possible values since 000 onwards.
:param pretty: Show results in human-readable format
:param wait_for_complete: Disable timeout response
:param name: Filters by policy name
:param description: Filters by policy description
:param references: Filters by references
:param offset:First element to return in the collection
:param limit: Maximum number of elements to return
:param sort: Sorts the collection by a field or fields (separated by comma). Use +/- at the beginning to list in
ascending or descending order
:param search: Looks for elements with the specified string
:param q: Query to filter results by. This is specially useful to filter by total checks passed, failed or total
score (fields pass, fail, score)
:return: AllItemsResponseSCADatabase
Parameters
----------
agent_id : str
Agent ID. All possible values since 000 onwards.
pretty : bool
Show results in human-readable format
wait_for_complete : bool
Disable timeout response
name : str
Filters by policy name
description : str
Filters by policy description
references : str
Filters by references
offset : int
First element to return in the collection
limit : int
Maximum number of elements to return
sort : str
Sorts the collection by a field or fields (separated by comma). Use +/- at the beginning to list in ascending or descending order
search : str
Looks for elements with the specified string
q : str
Query to filter results by. This is specially useful to filter by total checks passed, failed or total score (fields pass, fail, score)

Returns
-------
AllItemsResponseSCADatabase
"""
filters = {'name': name,
'description': description,
Expand Down Expand Up @@ -65,31 +79,58 @@ async def get_sca_checks(request, agent_id=None, pretty=False, wait_for_complete
condition=None, offset=0, limit=database_limit, sort=None, search=None, q=None):
"""Get policy monitoring alerts for a given policy

:param agent_id: Agent ID. All possible values since 000 onwards
:param pretty: Show results in human-readable format
:param wait_for_complete: Disable timeout response
:param policy_id: Filters by policy id
:param title: Filters by title
:param description: Filters by policy description
:param rationale: Filters by rationale
:param remediation: Filters by remediation
:param command: Filters by command
:param status: Filters by status
:param reason: Filters by reason
:param file: Filters by file
:param process: Filters by process
:param directory: Filters by directory
:param registry: Filters by registry
:param references: Filters by references
:param result: Filters by result
:param condition: Filters by condition
:param offset:First element to return in the collection
:param limit: Maximum number of elements to return
:param sort: Sorts the collection by a field or fields (separated by comma). Use +/- at the beginning to list in
ascending or descending order
:param search: Looks for elements with the specified string
:param q: Query to filter results by. This is specially useful to filter by total checks passed, failed or total
score (fields pass, fail, score)
Parameters
----------
agent_id : str
Agent ID. All possible values since 000 onwards
pretty : bool
Show results in human-readable format
wait_for_complete : bool
Disable timeout response
policy_id : str
Filters by policy id
title : str
Filters by title
description : str
Filters by policy description
rationale : str
Filters by rationale
remediation : str
Filters by remediation
command : str
Filters by command
status : str
Filters by status
reason : str
Filters by reason
file : str
Filters by file
process : str
Filters by process
directory : str
Filters by directory
registry : str
Filters by registry
references : str
Filters by references
result : str
Filters by result
condition : str
Filters by condition
offset : int
First element to return in the collection
limit : int
Maximum number of elements to return
sort : str
Sorts the collection by a field or fields (separated by comma). Use +/- at the beginning to list in ascending or descending order
search : str
Looks for elements with the specified string
q : str
Query to filter results by. This is specially useful to filter by total checks passed, failed or total score (fields pass, fail, score)

Returns
-------
AllItemsResponseSCADatabase
"""
filters = {'title': title,
'description': description,
Expand Down
12 changes: 9 additions & 3 deletions api/test/integration/test_sca_endpoints.tavern.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,6 @@ stages:
rationale: !anystr
title: !anystr
policy_id: !anystr
file: !anystr
description: !anystr
id: !anyint
result: !anystr
Expand Down Expand Up @@ -302,6 +301,8 @@ stages:
affected_items:
- <<: *sca_check_result_001
- <<: *sca_check_result_001
- <<: *sca_check_result_001
- <<: *sca_check_result_001
failed_items: []
total_failed_items: 0

Expand All @@ -323,6 +324,7 @@ stages:
total_affected_items: !anyint
affected_items:
- <<: *sca_check_result_001
- <<: *sca_check_result_001
failed_items: []
total_failed_items: 0

Expand Down Expand Up @@ -944,7 +946,6 @@ stages:
rationale: !anystr
title: !anystr
policy_id: !anystr
file: !anystr
description: !anystr
id: !anyint
result: !anystr
Expand Down Expand Up @@ -972,6 +973,8 @@ stages:
affected_items:
- <<: *sca_check_result_002
- <<: *sca_check_result_002
- <<: *sca_check_result_002
- <<: *sca_check_result_002
failed_items: []
total_failed_items: 0

Expand All @@ -993,6 +996,7 @@ stages:
total_affected_items: !anyint
affected_items:
- <<: *sca_check_result_002
- <<: *sca_check_result_002
failed_items: []
total_failed_items: 0

Expand Down Expand Up @@ -1516,7 +1520,6 @@ stages:
rationale: !anystr
title: !anystr
policy_id: !anystr
file: !anystr
description: !anystr
id: !anyint
result: !anystr
Expand Down Expand Up @@ -1544,6 +1547,8 @@ stages:
affected_items:
- <<: *sca_check_result_003
- <<: *sca_check_result_003
- <<: *sca_check_result_003
- <<: *sca_check_result_003
failed_items: []
total_failed_items: 0

Expand All @@ -1565,6 +1570,7 @@ stages:
total_affected_items: !anyint
affected_items:
- <<: *sca_check_result_003
- <<: *sca_check_result_003
failed_items: []
total_failed_items: 0

Expand Down
59 changes: 57 additions & 2 deletions framework/wazuh/core/sca.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
# Created by Wazuh, Inc. <[email protected]>.
# This program is free software; you can redistribute it and/or modify it under the terms of GP

import re
from datetime import datetime

from wazuh.core.agent import Agent
from wazuh.core.common import database_limit
from wazuh.core.exception import WazuhError
from wazuh.core.utils import WazuhDBQuery, WazuhDBBackend

# API field -> DB field
Expand Down Expand Up @@ -43,7 +46,7 @@

default_query_sca = 'SELECT {0} FROM sca_policy sca INNER JOIN sca_scan_info si ON sca.id=si.policy_id'
default_query_sca_check = 'SELECT {0} FROM sca_check a LEFT JOIN sca_check_compliance b ON a.id=b.id_check ' \
'LEFT JOIN sca_check_rules c ON a.id=c.id_check'
'LEFT JOIN sca_check_rules c ON a.id=c.id_check WHERE id IN (SELECT id FROM sca_check)'


class WazuhDBQuerySCA(WazuhDBQuery):
Expand Down Expand Up @@ -95,6 +98,58 @@ def format_fields(field_name, value):
return value

self._data = [{key: format_fields(key, value)
for key, value in item.items() if key in self.select} for item in self._data]
for key, value in item.items() if key in self.select} for item in self._data]

return super()._format_data_into_dictionary()


class WazuhDBQuerySCACheck(WazuhDBQuerySCA):

def _parse_filters(self):
if self.legacy_filters:
self._parse_legacy_filters()
if self.q:
self._parse_query()
if self.search or self.query_filters:
self.query += " WHERE " if self.query.count('WHERE') == 1 else ' AND '

def _add_limit_to_query(self):
if self.limit:
if self.limit > database_limit:
raise WazuhError(1405, str(self.limit))

# We add offset and limit only to the inner SELECT (subquery)
self.query += ' LIMIT :inner_limit OFFSET :inner_offset'
self.request['inner_offset'] = self.offset
self.request['inner_limit'] = self.limit
self.request['offset'] = 0
self.request['limit'] = 0
elif self.limit == 0: # 0 is not a valid limit
raise WazuhError(1406)

def run(self):
"""Builds the query and runs it on the database"""
# Remove the last )
self.query = self.query[:-1]

self._add_select_to_query()
self._add_filters_to_query()
self._add_search_to_query()

# Add the last )
self.query += ")"
if self.count:
self._get_total_items()
if not self.data:
return {'totalItems': self.total_items}

# Remove the last )
self.query = self.query[:-1]
self._add_limit_to_query()

# Add the last )
self.query += ")"
self._add_sort_to_query()
if self.data:
self._execute_data_query()
return self._format_data_into_dictionary()
2 changes: 1 addition & 1 deletion framework/wazuh/core/tests/test_wdb.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ def test_execute(send_mock, socket_send_mock, connect_mock):
mywdb = WazuhDBConnection()
mywdb.execute('agent 000 sql delete from test', delete=True)
mywdb.execute("agent 000 sql update test set value = 'test' where key = 'test'", update=True)
with patch("wazuh.core.wdb.WazuhDBConnection._send", return_value=[{'total':5}]):
with patch("wazuh.core.wdb.WazuhDBConnection._send", return_value=[{'total': 5}]):
mywdb.execute("agent 000 sql select test from test offset 1 limit 1")
mywdb.execute("agent 000 sql select test from test offset 1 limit 1", count=True)
mywdb.execute("agent 000 sql select test from test offset 1 count")
Expand Down
Loading