Skip to content

Commit fc13c47

Browse files
committed
Closing engagements now supported.
1 parent c7c64f6 commit fc13c47

2 files changed

Lines changed: 40 additions & 14 deletions

File tree

defectdojo_api/defectdojo.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def __init__(self, host, api_key, user, api_version='v1', verify_ssl=True, timeo
1818
:param api_version: API version to call, the default is v1.
1919
:param verify_ssl: Specify if API requests will verify the host's SSL certificate, defaults to true.
2020
:param timeout: HTTP timeout in seconds, default is 30.
21-
:param proxies: Proxy for API requests.
21+
:param proxis: Proxy for API requests.
2222
:param user_agent: HTTP user agent string, default is "DefectDojo_api/[version]".
2323
:param cert: You can also specify a local cert to use as client side certificate, as a single file (containing
2424
the private key and the certificate) or as a tuple of both file's path
@@ -193,7 +193,23 @@ def create_engagement(self, name, product_id, lead_id, status, target_start, tar
193193

194194
return self._request('POST', 'engagements/', data=data)
195195

196-
def set_engagement(self, id, name=None, product_id=None, lead_id=None, status=None, target_start=None,
196+
def close_engagement(self, id, user_id=None):
197+
198+
"""Closes an engagement with the given properties.
199+
:param id: Engagement id.
200+
:param user_id: User from the user table.
201+
"""
202+
engagement = self.get_engagement(id).data
203+
204+
#if user isn't provided then close with the lead ID
205+
if user_id is None:
206+
user_id = self.get_id_from_url(engagement["lead"])
207+
208+
product_id = engagement["product_id"]
209+
210+
self.set_engagement(id, name=engagement["name"], lead_id=user_id, product_id=product_id, status="Completed", active=False)
211+
212+
def set_engagement(self, id, product_id=None, lead_id=None, name=None, status=None, target_start=None,
197213
target_end=None, active=None, pen_test=None, check_list=None, threat_model=None, risk_path=None,
198214
test_strategy=None, progress=None, done_testing=None):
199215

@@ -225,7 +241,7 @@ def set_engagement(self, id, name=None, product_id=None, lead_id=None, status=No
225241
data['product'] = self.get_product_uri(product_id)
226242

227243
if lead_id:
228-
data['lead'] = self.get_user_uri(user_id)
244+
data['lead'] = self.get_user_uri(lead_id)
229245

230246
if status:
231247
data['status'] = status
@@ -236,7 +252,7 @@ def set_engagement(self, id, name=None, product_id=None, lead_id=None, status=No
236252
if target_end:
237253
data['target_end'] = target_end
238254

239-
if active:
255+
if active is not None:
240256
data['active'] = active
241257

242258
if pen_test:

examples/dojo_ci_cd.py

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,12 @@ def dojo_connection(host, api_key, user, proxy):
3838
# 3. Call this script to load scan data, specifying scanner type
3939
# 4. Script returns along with a pass or fail results: Example: 2 new critical vulns, 1 low out of 10 vulnerabilities
4040

41-
def return_engagement(dd, product_id, user):
41+
def return_engagement(dd, product_id, user, build_id=None):
4242
#Specify the product id
4343
product_id = product_id
4444
engagement_id = None
4545

46+
"""
4647
# Check for a CI/CD engagement_id
4748
engagements = dd.list_engagements(product_in=product_id, status="In Progress")
4849
@@ -52,16 +53,21 @@ def return_engagement(dd, product_id, user):
5253
engagement_id = engagement['id']
5354
5455
if engagement_id == None:
55-
start_date = datetime.now()
56-
end_date = start_date+timedelta(days=180)
57-
users = dd.list_users(user)
58-
user_id = None
56+
"""
57+
start_date = datetime.now()
58+
end_date = start_date+timedelta(days=1)
59+
users = dd.list_users(user)
60+
user_id = None
5961

60-
if users.success:
61-
user_id = users.data["objects"][0]["id"]
62+
if users.success:
63+
user_id = users.data["objects"][0]["id"]
6264

63-
engagement_id = dd.create_engagement("Recurring CI/CD Integration", product_id, str(user_id),
64-
"In Progress", start_date.strftime("%Y-%m-%d"), end_date.strftime("%Y-%m-%d"))
65+
engagementText = "CI/CD Integration"
66+
if build_id is not None:
67+
engagementText = engagementText + " - Build #" + build_id
68+
69+
engagement_id = dd.create_engagement(engagementText, product_id, str(user_id),
70+
"In Progress", start_date.strftime("%Y-%m-%d"), end_date.strftime("%Y-%m-%d"))
6571
return engagement_id
6672

6773
def process_findings(dd, engagement_id, dir, build=None):
@@ -238,6 +244,7 @@ class Main:
238244
parser.add_argument('--host', help="DefectDojo Hostname", required=True)
239245
parser.add_argument('--proxy', help="Proxy ex:localhost:8080", required=False, default=None)
240246
parser.add_argument('--api_key', help="API Key", required=True)
247+
parser.add_argument('--build_id', help="Reference to external build id", required=False)
241248
parser.add_argument('--user', help="User", required=True)
242249
parser.add_argument('--product', help="DefectDojo Product ID", required=True)
243250
parser.add_argument('--file', help="Scanner file", required=False)
@@ -264,10 +271,11 @@ class Main:
264271
max_medium = args["medium"]
265272
build = args["build"]
266273
proxy = args["proxy"]
274+
build_id = args["build_id"]
267275

268276
if dir is not None or file is not None:
269277
dd = dojo_connection(host, api_key, user, proxy=proxy)
270-
engagement_id = return_engagement(dd, product_id, user)
278+
engagement_id = return_engagement(dd, product_id, user, build_id=build_id)
271279
test_ids = None
272280
if file is not None:
273281
if scanner is not None:
@@ -277,6 +285,8 @@ class Main:
277285
else:
278286
test_ids = process_findings(dd, engagement_id, dir, build)
279287

288+
#Close the engagement_id
289+
dd.close_engagement(engagement_id)
280290
summary(dd, engagement_id, test_ids, max_critical, max_high, max_medium)
281291
else:
282292
print "No file or directory to scan specified."

0 commit comments

Comments
 (0)