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

Make the number of request/response pairs returned by the API configurable #9967

Merged
merged 10 commits into from
Apr 22, 2024
5 changes: 4 additions & 1 deletion dojo/api_v2/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1802,8 +1802,11 @@ def build_relational_field(self, field_name, relation_info):

@extend_schema_field(BurpRawRequestResponseSerializer)
def get_request_response(self, obj):
# burp_req_resp = BurpRawRequestResponse.objects.filter(finding=obj)
# Not necessarily Burp scan specific - these are just any request/response pairs
burp_req_resp = obj.burprawrequestresponse_set.all()
var = settings.MAX_REQRESP_FROM_API
if var > -1:
burp_req_resp = burp_req_resp[:var]
burp_list = []
for burp in burp_req_resp:
request = burp.get_request()
Expand Down
6 changes: 5 additions & 1 deletion dojo/api_v2/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1004,8 +1004,12 @@ def request_response(self, request, pk=None):
return Response(
burps.errors, status=status.HTTP_400_BAD_REQUEST
)

# Not necessarily Burp scan specific - these are just any request/response pairs
burp_req_resp = BurpRawRequestResponse.objects.filter(finding=finding)
var = settings.MAX_REQRESP_FROM_API
if var > -1:
burp_req_resp = burp_req_resp[:var]

burp_list = []
for burp in burp_req_resp:
request = burp.get_request()
Expand Down
376 changes: 376 additions & 0 deletions dojo/fixtures/unit_limit_reqresp.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion dojo/settings/settings.dist.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,8 @@
# maximum number of result in search as search can be an expensive operation
DD_SEARCH_MAX_RESULTS=(int, 100),
DD_SIMILAR_FINDINGS_MAX_RESULTS=(int, 25),
# The maximum number of request/response pairs to return from the API. Values <0 return all pairs.
DD_MAX_REQRESP_FROM_API=(int, -1),
DD_MAX_AUTOCOMPLETE_WORDS=(int, 20000),
DD_JIRA_SSL_VERIFY=(bool, True),
# You can set extra Jira issue types via a simple env var that supports a csv format, like "Work Item,Vulnerability"
Expand Down Expand Up @@ -233,7 +235,6 @@
DD_FEATURE_FINDING_GROUPS=(bool, True),
DD_JIRA_TEMPLATE_ROOT=(str, 'dojo/templates/issue-trackers'),
DD_TEMPLATE_DIR_PREFIX=(str, 'dojo/templates/'),

# Initial behaviour in Defect Dojo was to delete all duplicates when an original was deleted
# New behaviour is to leave the duplicates in place, but set the oldest of duplicates as new original
# Set to True to revert to the old behaviour where all duplicates are deleted
Expand Down Expand Up @@ -600,6 +601,7 @@ def generate_url(scheme, double_slashes, user, password, host, port, path, param

SEARCH_MAX_RESULTS = env('DD_SEARCH_MAX_RESULTS')
SIMILAR_FINDINGS_MAX_RESULTS = env('DD_SIMILAR_FINDINGS_MAX_RESULTS')
MAX_REQRESP_FROM_API = env('DD_MAX_REQRESP_FROM_API')
MAX_AUTOCOMPLETE_WORDS = env('DD_MAX_AUTOCOMPLETE_WORDS')

LOGIN_EXEMPT_URLS = (
Expand Down
2 changes: 1 addition & 1 deletion dojo/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
v2_api.register(r'engagements', EngagementViewSet)
v2_api.register(r'development_environments', DevelopmentEnvironmentViewSet)
v2_api.register(r'finding_templates', FindingTemplatesViewSet)
v2_api.register(r'findings', FindingViewSet)
v2_api.register(r'findings', FindingViewSet, basename='finding')
v2_api.register(r'jira_configurations', JiraInstanceViewSet) # backwards compatibility
v2_api.register(r'jira_instances', JiraInstanceViewSet)
v2_api.register(r'jira_finding_mappings', JiraIssuesViewSet)
Expand Down
14 changes: 12 additions & 2 deletions readme-docs/DOCKER.md
Original file line number Diff line number Diff line change
Expand Up @@ -335,16 +335,26 @@ The integration-tests are under `tests`


## Running the unit tests

### All tests
This will run all unit-tests and leave the uwsgi container up:

```
docker/setEnv.sh unit_tests
./dc-up.sh
```
Enter the container to run more tests:

### Limited tests
If you want to enter the container to run more tests or a single test case, leave setEnv in normal or dev mode:
```
docker/setEnv.sh dev
./dc-up.sh
```
Then
```
docker-compose exec uwsgi bash
docker ps
#find the name of the uwsgi container from the above command
docker exec -ti [container-name] bash
```
Rerun all the tests:

Expand Down
734 changes: 734 additions & 0 deletions unittests/scans/burp_api/many_reqresp.json

Large diffs are not rendered by default.

42 changes: 42 additions & 0 deletions unittests/test_apiv2_limit_reqresp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from rest_framework.test import APITestCase, APIClient
from django.urls import reverse
from rest_framework.authtoken.models import Token
from django.conf import settings


class APILimitReqRespPairsTest(APITestCase):
"""
Test the MAX_REQRESP_FROM_API setting for /api/v2/findings/{id}/request_response/
"""

fixtures = ['unit_limit_reqresp.json']

def setUp(self: object):
token = Token.objects.get(user__username='admin')
self.client = APIClient()
self.client.credentials(HTTP_AUTHORIZATION='Token ' + token.key)

def assertReqrespValue(self: object, value: int, expect_notequal: bool = False) -> None:
settings.MAX_REQRESP_FROM_API = value
r = self.client.get(reverse('finding-list'), format='json')
results = r.json()['results']
# get finding with id 8
finding = self.getFinding(8, results)
if expect_notequal:
self.assertNotEqual(len(finding['request_response']['req_resp']), value)
else:
self.assertEqual(len(finding['request_response']['req_resp']), value)

def getFinding(self: object, idn: int, results: list) -> dict:
for result in results:
if result['id'] == idn:
return result
return None

def test_reqresp(self: object) -> None:
self.assertReqrespValue(5)
self.assertReqrespValue(10)
self.assertReqrespValue(18) # actual number of reqresp
self.assertReqrespValue(100, True) # more than the number in the request
self.assertReqrespValue(-1, True) # default value of MAX_REQRESP_FROM_API
self.assertReqrespValue(-100, True) # crazy negative value
Loading