Skip to content

Commit 7cb8c02

Browse files
authored
Merge pull request #1 from alvacoder/feat/implement-defectdojo-scan-import
Feat/implement defectdojo scan import
2 parents 4fb25fc + bbf09c6 commit 7cb8c02

File tree

3 files changed

+153
-0
lines changed

3 files changed

+153
-0
lines changed

Dockerfile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
FROM python:3.7-slim AS builder
2+
ADD . /app
3+
RUN pip install --target=/app requests logging setuptools
4+
5+
6+
FROM gcr.io/distroless/python3-debian10
7+
COPY --from=builder /app /app
8+
WORKDIR /app
9+
ENV PYTHONPATH /app
10+
CMD ["/app/defectdojo.py"]

action.yml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
name: "Defectdojo Upload"
2+
author: "Adeniji Idris (Alvacoder)"
3+
description: "A github action that sends scan reports to a DefectDojo instance with support for multiple authentication methods"
4+
branding:
5+
icon: 'code'
6+
color: 'green'
7+
inputs:
8+
defectdojo_url:
9+
description: the url of your defectdojo instance
10+
required: true
11+
defectdojo_username:
12+
description: the username to login into your defectdojo instance if using basic authentication
13+
required: false
14+
defectdojo_password:
15+
description: the password to login into your defectdojo instance if using basic authentication
16+
required: false
17+
defectdojo_api_key:
18+
description: the API key to authenticate with your defectdojo instance if using API key authentication
19+
required: false
20+
defectdojo_product_type:
21+
description: the defectdojo product type that the scan result relates to
22+
required: true
23+
defectdojo_product:
24+
description: the defectdojo product that the scan result relates to
25+
required: true
26+
defectdojo_environment_type:
27+
description: the defectdojo environment type that the scan result relates to
28+
required: true
29+
defectdojo_scan_type:
30+
description: the defectdojo scan type that the scan result relates to
31+
required: true
32+
defectdojo_engagement_name:
33+
description: the defectdojo engagement name that the scan result relates to
34+
required: true
35+
scan_results_file_name:
36+
description: the file name of the scan result to be uploaded
37+
required: true
38+
client_certificate_file_path:
39+
description: the file path for a client side certificate if required
40+
required: false
41+
client_key_file-path:
42+
description: the file path for a client side private key if required
43+
required: false
44+
# outputs:
45+
# defectdojo-report-id:
46+
# description: the id of the defectdojo report that was created
47+
# value: ${{ steps.import_scan_results.outputs.defectdojo-report-id }}
48+
runs:
49+
using: 'docker'
50+
image: 'Dockerfile'

defectdojo.py

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
"""
2+
* @author Idris Adeniji (alvacoder)
3+
4+
* @create date 2025-03-18 22:01:56
5+
"""
6+
7+
import requests
8+
import os
9+
import sys
10+
import logging
11+
12+
class Defectdojo:
13+
14+
def __init__(self):
15+
# Required Secrets for this awesome code to function.
16+
self.defectdojo_api_key = os.environ["INPUT_DEFECTDOJO_API_KEY"]
17+
self.defectdojo_username = os.environ["INPUT_DEFECTDOJO_USERNAME"]
18+
self.defectdojo_password = os.environ["INPUT_DEFECTDOJO_PASSWORD"]
19+
self.defectdojo_service_account = os.environ["INPUT_DEFECTDOJO_SERVICE_ACCOUNT"]
20+
21+
# Required Defectdojo Variables.
22+
self.defectdojo_url = os.environ["INPUT_DEFECTDOJO_URL"]
23+
self.defectdojo_product_type = os.environ["INPUT_DEFECTDOJO_PRODUCT_TYPE"]
24+
self.defectdojo_product = os.environ["INPUT_DEFECTDOJO_PRODUCT"]
25+
self.defectdojo_environment_type = os.environ["INPUT_DEFECTDOJO_ENVIRONMENT_TYPE"]
26+
self.defectdojo_scan_type = os.environ["INPUT_DEFECTDOJO_SCAN_TYPE"]
27+
self.defectdojo_engagement_name = os.environ["INPUT_DEFECTDOJO_ENGAGEMENT_NAME"]
28+
self.scan_results_file_path = os.environ["INPUT_RESULTS_FILE_PATH"]
29+
30+
def import_scan_results_to_defectdojo(
31+
self,
32+
logger: logging.Logger,
33+
client_certificate_file_path=None,
34+
client_key_file_path=None
35+
) -> int:
36+
37+
api_endpoint = f"{self.defectdojo_url}/api/v2/import-scan/"
38+
headers = {"Authorization": f"Token {self.defectdojo_api_key}"}
39+
data = {
40+
"product_type_name": self.defectdojo_product_type,
41+
"product_name": self.defectdojo_product,
42+
"environment": self.defectdojo_environment_type,
43+
"scan_type": self.defectdojo_scan_type,
44+
"engagement_name": self.defectdojo_engagement_name,
45+
"auto_create_context": True,
46+
"close_old_findings": True,
47+
"verified": False,
48+
}
49+
50+
try:
51+
with open(self.scan_results_file_path, "rb") as scan_file:
52+
files = {"file": scan_file}
53+
54+
if client_certificate_file_path and client_key_file_path:
55+
r = requests.post(
56+
api_endpoint,
57+
headers=headers,
58+
files=files,
59+
data=data,
60+
verify=True,
61+
cert=(client_certificate_file_path, client_key_file_path),
62+
timeout=180
63+
)
64+
else:
65+
r = requests.post(
66+
api_endpoint,
67+
headers=headers,
68+
files=files,
69+
data=data,
70+
verify=True,
71+
timeout=180
72+
)
73+
74+
if r.status_code == 201:
75+
return r.status_code
76+
else:
77+
logger.error(f"Upload of results failed with status code {r.status_code}")
78+
sys.exit(1)
79+
except requests.exceptions.RequestException as e:
80+
logger.error(f"Network error during scan upload: {e}")
81+
sys.exit(1)
82+
83+
def run(self):
84+
try:
85+
logger = logging.getLogger(__name__)
86+
logger.setLevel(logging.INFO)
87+
self.import_scan_results_to_defectdojo(logger)
88+
except Exception as e:
89+
print(f"Exception: {e}")
90+
sys.exit(1)
91+
92+
if __name__ == "__main__":
93+
Defectdojo().run()

0 commit comments

Comments
 (0)