Skip to content

Commit 9378e49

Browse files
committed
Example Updates
1 parent e48f63b commit 9378e49

3 files changed

Lines changed: 160 additions & 11 deletions

File tree

defectdojo_api/defectdojo.py

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,11 @@ def get_user(self, user_id):
111111
return self._request('GET', 'users/' + str(user_id) + '/')
112112

113113
###### Engagements API #######
114-
def list_engagements(self, status=None, product_in=None,limit=20):
114+
def list_engagements(self, status=None, product_in=None, name_contains=None,limit=20):
115115
"""Retrieves all the engagements.
116116
117117
:param product_in: List of product ids (1,2).
118+
:param name_contains: Engagement name
118119
:param limit: Number of records to return.
119120
120121
"""
@@ -129,6 +130,9 @@ def list_engagements(self, status=None, product_in=None,limit=20):
129130
if status:
130131
params['status'] = status
131132

133+
if name_contains:
134+
params['name_contains'] = name_contains
135+
132136
return self._request('GET', 'engagements/', params)
133137

134138
def get_engagement(self, engagement_id):
@@ -404,7 +408,7 @@ def set_test(self, test_id, engagement_id=None, test_type=None, environment=None
404408
###### Findings API #######
405409
def list_findings(self, active=None, duplicate=None, mitigated=None, severity=None, verified=None, severity_lt=None,
406410
severity_gt=None, severity_contains=None, title_contains=None, url_contains=None, date_lt=None,
407-
date_gt=None, date=None, product_id_in=None, engagement_id_in=None, test_id_in=None, limit=20):
411+
date_gt=None, date=None, product_id_in=None, engagement_id_in=None, test_id_in=None, build=None, limit=20):
408412

409413
"""Returns filtered list of findings.
410414
@@ -424,6 +428,7 @@ def list_findings(self, active=None, duplicate=None, mitigated=None, severity=No
424428
:param product_id_in: Product id(s) associated with a finding. (1,2 or 1)
425429
:param engagement_id_in: Engagement id(s) associated with a finding. (1,2 or 1)
426430
:param test_in: Test id(s) associated with a finding. (1,2 or 1)
431+
:param build_id: User specified build id relating to the build number from the build server. (Jenkins, Travis etc.).
427432
:param limit: Number of records to return.
428433
429434
"""
@@ -480,6 +485,9 @@ def list_findings(self, active=None, duplicate=None, mitigated=None, severity=No
480485
if test_id_in:
481486
params['test__id__in'] = test_id_in
482487

488+
if build:
489+
params['build_id__contains'] = build
490+
483491
return self._request('GET', 'findings/', params)
484492

485493
def get_finding(self, finding_id):
@@ -490,7 +498,7 @@ def get_finding(self, finding_id):
490498
return self._request('GET', 'findings/' + str(finding_id) + '/')
491499

492500
def create_finding(self, title, description, severity, cwe, date, product_id, engagement_id, test_id, user_id,
493-
impact, active, verified, mitigation, references=None):
501+
impact, active, verified, mitigation, references=None, build=None):
494502

495503
"""Creates a finding with the given properties.
496504
@@ -508,7 +516,7 @@ def create_finding(self, title, description, severity, cwe, date, product_id, en
508516
:param verified: Finding has been verified.
509517
:param mitigation: Steps to mitigate the finding.
510518
:param references: Details on finding.
511-
519+
:param build: User specified build id relating to the build number from the build server. (Jenkins, Travis etc.).
512520
"""
513521

514522
data = {
@@ -525,7 +533,8 @@ def create_finding(self, title, description, severity, cwe, date, product_id, en
525533
'active': active,
526534
'verified': verified,
527535
'mitigation': mitigation,
528-
'references': references
536+
'references': references,
537+
'build_id' : build
529538
}
530539

531540
return self._request('POST', 'findings/', data=data)
@@ -550,6 +559,7 @@ def set_finding(self, finding_id, product_id, engagement_id, test_id, title=None
550559
:param verified: Finding has been verified.
551560
:param mitigation: Steps to mitigate the finding.
552561
:param references: Details on finding.
562+
:param build: User specified build id relating to the build number from the build server. (Jenkins, Travis etc.).
553563
554564
"""
555565

@@ -597,25 +607,34 @@ def set_finding(self, finding_id, product_id, engagement_id, test_id, title=None
597607
if references:
598608
data['references'] = references
599609

610+
if build:
611+
data['build_id'] = build
612+
600613
return self._request('PUT', 'findings/' + str(finding_id) + '/', data=data)
601614

602615
##### Upload API #####
603616

604-
def upload_scan(self, engagement_id, scan_type, file, active, scan_date, tags=None):
617+
def upload_scan(self, engagement_id, scan_type, file, active, scan_date, tags=None, build=None):
605618
"""Uploads and processes a scan file.
606619
607620
:param application_id: Application identifier.
608621
:param file_path: Path to the scan file to be uploaded.
609622
610623
"""
624+
if tags is None:
625+
tags = ''
626+
627+
if build is None:
628+
build = ''
611629

612630
data = {
613631
'file': open(file, 'rb'),
614632
'engagement': ('', self.get_engagement_uri(engagement_id)),
615633
'scan_type': ('', scan_type),
616634
'active': ('', active),
617635
'scan_date': ('', scan_date),
618-
'tags': ('', tags)
636+
'tags': ('', tags),
637+
'build_id': ('', build)
619638
}
620639

621640
return self._request(
@@ -725,6 +744,9 @@ def id(self):
725744
raise ValueError('Object not created:' + json.dumps(self.data, sort_keys=True, indent=4, separators=(',', ': ')))
726745
return int(self.data)
727746

747+
def count(self):
748+
return self.data["meta"]["total_count"]
749+
728750
def data_json(self, pretty=False):
729751
"""Returns the data as a valid JSON string."""
730752
if pretty:

examples/dojo_ci_cd.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def print_findings(findings):
3232
print "Low: " + str(findings[1])
3333
print "Info: " + str(findings[0])
3434

35-
def create_findings(host, api_key, user, product_id, file, scanner, engagement_id=None, max_critical=0, max_high=0, max_medium=0):
35+
def create_findings(host, api_key, user, product_id, file, scanner, engagement_id=None, max_critical=0, max_high=0, max_medium=0, build=None):
3636

3737
#Optionally, specify a proxy
3838
proxies = {
@@ -75,11 +75,11 @@ def create_findings(host, api_key, user, product_id, file, scanner, engagement_i
7575
"In Progress", start_date.strftime("%Y-%m-%d"), end_date.strftime("%Y-%m-%d"))
7676

7777
# Upload the scanner export
78-
dir_path = os.path.dirname(os.path.realpath(__file__))
78+
#dir_path = os.path.dirname(os.path.realpath(__file__))
7979

8080
print "Uploading scanner data."
8181
date = datetime.now()
82-
upload_scan = dd.upload_scan(engagement_id, scanner, dir_path + file, "true", date.strftime("%Y/%m/%d"), "API")
82+
upload_scan = dd.upload_scan(engagement_id, scanner, file, "true", date.strftime("%Y-%m-%d"), build=build)
8383

8484
if upload_scan.success:
8585
test_id = upload_scan.id()
@@ -132,6 +132,7 @@ class Main:
132132
parser.add_argument('--product', help="Dojo Product ID", required=True)
133133
parser.add_argument('--file', help="Scanner file", required=True)
134134
parser.add_argument('--scanner', help="Type of scanner", required=True)
135+
parser.add_argument('--build', help="Build ID", required=False)
135136
parser.add_argument('--engagement', help="Engagement ID (optional)", required=False)
136137
parser.add_argument('--critical', help="Maximum new critical vulns to pass the build.", required=False)
137138
parser.add_argument('--high', help="Maximum new high vulns to pass the build.", required=False)
@@ -149,5 +150,6 @@ class Main:
149150
max_critical = args["critical"]
150151
max_high = args["high"]
151152
max_medium = args["medium"]
153+
build = args["build"]
152154

153-
create_findings(host, api_key, user, product_id, file, scanner, engagement_id, max_critical, max_high, max_medium)
155+
create_findings(host, api_key, user, product_id, file, scanner, engagement_id, max_critical, max_high, max_medium, build)

examples/dojo_finding.py

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
"""
2+
Example written by Aaron Weaver <aaron.weaver@owasp.org>
3+
as part of the OWASP DefectDojo and OWASP AppSec Pipeline Security projects
4+
5+
Description: Creates a manual finding in DefectDojo and returns information about the newly created finding
6+
"""
7+
from defectdojo_api import defectdojo
8+
from datetime import datetime, timedelta
9+
from random import randint
10+
import os
11+
12+
# Setup DefectDojo connection information
13+
host = 'http://localhost:8000'
14+
api_key = os.environ['DOJO_API_KEY']
15+
user = 'admin'
16+
user_id = 1 #Default user
17+
18+
19+
#Optionally, specify a proxy
20+
proxies = {
21+
'http': 'http://localhost:8080',
22+
'https': 'http://localhost:8080',
23+
}
24+
"""
25+
proxies=proxies
26+
"""
27+
28+
def create_finding_data(product_id, engagement_id, test_id, build):
29+
cwe = [352, 22, 676, 863, 134, 759, 798]
30+
cwe_desc = ['Cross-Site Request Forgery (CSRF)', 'Improper Limitation of a Pathname to a Restricted Directory (\'Path Traversal\')',
31+
'Use of Potentially Dangerous Function', 'Incorrect Authorization', 'Uncontrolled Format String',
32+
'Use of a One-Way Hash without a Salt', 'Use of Hard-coded Credentials']
33+
severity=['Low','Medium','High', 'Critical']
34+
user_id = 1
35+
finding_date = datetime.now()
36+
finding_date = finding_date+timedelta(days=randint(-30,0))
37+
finding_cwe = randint(0,6)
38+
39+
finding = dd.create_finding(cwe_desc[finding_cwe], cwe_desc[finding_cwe], severity[randint(0,3)],
40+
cwe[finding_cwe], finding_date.strftime("%Y-%m-%d"), product_id, engagement_id, test_id, user_id,
41+
"None", "true", "true", "References", build=build)
42+
43+
# Instantiate the DefectDojo api wrapper
44+
dd = defectdojo.DefectDojoAPI(host, api_key, user, debug=False, proxies=proxies)
45+
46+
# Search and see if product exists so that we don't create multiple product entries
47+
product_name = "Acme API Finding Demo"
48+
products = dd.list_products(name_contains=product_name)
49+
product_id = None
50+
51+
if products.count() > 0:
52+
for product in products.data["objects"]:
53+
product_id = product['id']
54+
else:
55+
# Create a product
56+
prod_type = 1 #1 - Research and Development, product type
57+
product = dd.create_product(product_name, "This is a detailed product description.", prod_type)
58+
59+
# Get the product id
60+
product_id = product.id()
61+
print "Product successfully created with an id: " + str(product_id)
62+
63+
# Retrieve the newly created product
64+
product = dd.get_product(product_id)
65+
66+
product_name = "Acme API Finding Demo"
67+
engagement = dd.list_engagements(product_in=product_id, name_contains="Intial " + product_name + " Engagement")
68+
engagement_id = None
69+
70+
start_date = datetime.now()
71+
end_date = start_date+timedelta(days=randint(2,8))
72+
73+
if engagement.count() > 0:
74+
for engagement in engagement.data["objects"]:
75+
engagement_id = engagement['id']
76+
else:
77+
# Create an engagement
78+
print "Creating engagement: " + "Intial " + product_name + " Engagement"
79+
engagement = dd.create_engagement("Intial " + product_name + " Engagement", product_id, user_id,
80+
"In Progress", start_date.strftime("%Y-%m-%d"), end_date.strftime("%Y-%m-%d"))
81+
engagement_id = engagement.id()
82+
83+
print "Creating the test"
84+
# Create Test
85+
test_type = 5 #Web Test
86+
environment = 3 #Production environment
87+
test = dd.create_test(engagement_id, test_type, environment,
88+
start_date.strftime("%Y-%m-%d"), start_date.strftime("%Y-%m-%d"))
89+
test_id = test.id()
90+
91+
print "Creating the finding"
92+
build = "Jenkins-" + str(randint(100,999))
93+
# Create Finding
94+
create_finding_data(product_id, engagement_id, test_id, build=build)
95+
96+
print "Listing the new findings for this build"
97+
98+
i = 0
99+
#Creating four tests
100+
while i < 4:
101+
test_type = i+1 #Select some random tests
102+
environment = randint(1,6) #Select random environments
103+
test = dd.create_test(engagement_id, test_type, environment,
104+
start_date.strftime("%Y-%m-%d"), start_date.strftime("%Y-%m-%d"))
105+
test_id = test.id()
106+
107+
f = 0
108+
f_max = randint(2,4)
109+
while f < f_max:
110+
# Load findings
111+
create_finding_data(product_id, engagement_id, test_id, build=build)
112+
f = f + 1
113+
114+
i = i + 1
115+
116+
#Summarize the findings loaded
117+
print "***************************************"
118+
findings = dd.list_findings(build=build)
119+
print "Build ID: " + build
120+
print "Total Created: " + str(findings.count())
121+
print "***************************************"
122+
print
123+
if findings.count() > 0:
124+
for finding in findings.data["objects"]:
125+
print finding["title"] + ", Severity: " + finding["severity"]

0 commit comments

Comments
 (0)