Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM python:3.7-slim AS builder
ADD . /app
RUN pip install --target=/app requests logging setuptools


FROM gcr.io/distroless/python3-debian10
COPY --from=builder /app /app
WORKDIR /app
ENV PYTHONPATH /app
CMD ["/app/defectdojo.py"]
50 changes: 50 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: "Defectdojo Upload"
author: "Adeniji Idris (Alvacoder)"
description: "A github action that sends scan reports to a DefectDojo instance with support for multiple authentication methods"
branding:
icon: 'code'
color: 'green'
inputs:
defectdojo_url:
description: the url of your defectdojo instance
required: true
defectdojo_username:
description: the username to login into your defectdojo instance if using basic authentication
required: false
defectdojo_password:
description: the password to login into your defectdojo instance if using basic authentication
required: false
defectdojo_api_key:
description: the API key to authenticate with your defectdojo instance if using API key authentication
required: false
defectdojo_product_type:
description: the defectdojo product type that the scan result relates to
required: true
defectdojo_product:
description: the defectdojo product that the scan result relates to
required: true
defectdojo_environment_type:
description: the defectdojo environment type that the scan result relates to
required: true
defectdojo_scan_type:
description: the defectdojo scan type that the scan result relates to
required: true
defectdojo_engagement_name:
description: the defectdojo engagement name that the scan result relates to
required: true
scan_results_file_name:
description: the file name of the scan result to be uploaded
required: true
client_certificate_file_path:
description: the file path for a client side certificate if required
required: false
client_key_file-path:
description: the file path for a client side private key if required
required: false
# outputs:
# defectdojo-report-id:
# description: the id of the defectdojo report that was created
# value: ${{ steps.import_scan_results.outputs.defectdojo-report-id }}
runs:
using: 'docker'
image: 'Dockerfile'
93 changes: 93 additions & 0 deletions defectdojo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
"""
* @author Idris Adeniji (alvacoder)
* @email [email protected]
* @create date 2025-03-18 22:01:56
"""

import requests
import os
import sys
import logging

class Defectdojo:

def __init__(self):
# Required Secrets for this awesome code to function.
self.defectdojo_api_key = os.environ["INPUT_DEFECTDOJO_API_KEY"]
self.defectdojo_username = os.environ["INPUT_DEFECTDOJO_USERNAME"]
self.defectdojo_password = os.environ["INPUT_DEFECTDOJO_PASSWORD"]
self.defectdojo_service_account = os.environ["INPUT_DEFECTDOJO_SERVICE_ACCOUNT"]

# Required Defectdojo Variables.
self.defectdojo_url = os.environ["INPUT_DEFECTDOJO_URL"]
self.defectdojo_product_type = os.environ["INPUT_DEFECTDOJO_PRODUCT_TYPE"]
self.defectdojo_product = os.environ["INPUT_DEFECTDOJO_PRODUCT"]
self.defectdojo_environment_type = os.environ["INPUT_DEFECTDOJO_ENVIRONMENT_TYPE"]
self.defectdojo_scan_type = os.environ["INPUT_DEFECTDOJO_SCAN_TYPE"]
self.defectdojo_engagement_name = os.environ["INPUT_DEFECTDOJO_ENGAGEMENT_NAME"]
self.scan_results_file_path = os.environ["INPUT_RESULTS_FILE_PATH"]

def import_scan_results_to_defectdojo(
self,
logger: logging.Logger,
client_certificate_file_path=None,
client_key_file_path=None
) -> int:

api_endpoint = f"{self.defectdojo_url}/api/v2/import-scan/"
headers = {"Authorization": f"Token {self.defectdojo_api_key}"}
data = {
"product_type_name": self.defectdojo_product_type,
"product_name": self.defectdojo_product,
"environment": self.defectdojo_environment_type,
"scan_type": self.defectdojo_scan_type,
"engagement_name": self.defectdojo_engagement_name,
"auto_create_context": True,
"close_old_findings": True,
"verified": False,
}

try:
with open(self.scan_results_file_path, "rb") as scan_file:
files = {"file": scan_file}

if client_certificate_file_path and client_key_file_path:
r = requests.post(
api_endpoint,
headers=headers,
files=files,
data=data,
verify=True,
cert=(client_certificate_file_path, client_key_file_path),
timeout=180
)
else:
r = requests.post(
api_endpoint,
headers=headers,
files=files,
data=data,
verify=True,
timeout=180
)

if r.status_code == 201:
return r.status_code
else:
logger.error(f"Upload of results failed with status code {r.status_code}")
sys.exit(1)
except requests.exceptions.RequestException as e:
logger.error(f"Network error during scan upload: {e}")
sys.exit(1)

def run(self):
try:
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
self.import_scan_results_to_defectdojo(logger)
except Exception as e:
print(f"Exception: {e}")
sys.exit(1)

if __name__ == "__main__":
Defectdojo().run()