Skip to content
Open
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

# Lab 8 cosign private key
labs/lab8/signing/cosign.key
1 change: 1 addition & 0 deletions labs/lab10/imports/engagement.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"id":1,"tags":[],"created":"2026-04-15T21:04:52.598568Z","updated":"2026-04-15T21:04:52.598579Z","name":"Labs Security Testing","description":"Created by lab10 importer","version":null,"first_contacted":null,"target_start":"2026-04-16","target_end":"2026-05-16","reason":null,"active":true,"tracker":null,"test_strategy":null,"threat_model":true,"api_test":true,"pen_test":true,"check_list":true,"status":"In Progress","progress":"threat_model","tmodel_path":"none","done_testing":false,"engagement_type":"CI/CD","build_id":null,"commit_hash":null,"branch_tag":null,"source_code_management_uri":null,"deduplication_on_engagement":false,"lead":null,"requester":null,"preset":null,"report_type":null,"product":1,"build_server":null,"source_code_management_server":null,"orchestration_engine":null,"notes":[],"files":[],"risk_acceptance":[]}
1 change: 1 addition & 0 deletions labs/lab10/imports/grype.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"minimum_severity":"Info","active":true,"verified":true,"endpoint_to_add":null,"auto_create_context":false,"deduplication_on_engagement":false,"lead":null,"push_to_jira":false,"api_scan_configuration":null,"create_finding_groups_for_all_findings":true,"test_id":5,"engagement_id":1,"product_id":1,"product_type_id":2,"statistics":{"after":{"info":{"active":14,"verified":14,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":14},"low":{"active":8,"verified":8,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":8},"medium":{"active":46,"verified":46,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":46},"high":{"active":88,"verified":88,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":88},"critical":{"active":11,"verified":11,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":11},"total":{"active":167,"verified":167,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":167}}},"apply_tags_to_findings":false,"apply_tags_to_endpoints":false,"scan_type":"Anchore Grype","engagement":1,"close_old_findings":false,"close_old_findings_product_scope":false,"test":5}
1 change: 1 addition & 0 deletions labs/lab10/imports/product-type.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"id":2,"created":"2026-04-15T21:04:52.108860Z","updated":"2026-04-15T21:04:52.108880Z","name":"Engineering","description":"Created by lab10 importer","critical_product":false,"key_product":false,"members":[],"authorization_groups":[]}
1 change: 1 addition & 0 deletions labs/lab10/imports/product.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"id":1,"findings_count":0,"findings_list":[],"business_criticality":null,"platform":null,"lifecycle":null,"origin":null,"tags":[],"product_meta":[],"created":"2026-04-15T21:04:52.366801Z","name":"Juice Shop","description":"Created by lab10 importer","prod_numeric_grade":null,"user_records":null,"revenue":null,"external_audience":false,"internet_accessible":false,"enable_product_tag_inheritance":false,"enable_simple_risk_acceptance":false,"enable_full_risk_acceptance":true,"disable_sla_breach_notifications":false,"product_manager":null,"technical_contact":null,"team_manager":null,"prod_type":2,"sla_configuration":1,"members":[],"authorization_groups":[],"regulations":[]}
204 changes: 92 additions & 112 deletions labs/lab10/imports/run-imports.sh
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,134 +1,114 @@
#!/usr/bin/env bash
set -euo pipefail

# Batch import helper for Lab 10
# - Auto-detects scan_type names from your Dojo instance
# - Imports whichever files exist among ZAP, Semgrep, Trivy, Nuclei (and optional Grype)
#
# Usage:
# export DD_API="http://localhost:8080/api/v2"
# export DD_TOKEN="<your_api_token>"
# # Optional overrides (defaults shown)
# export DD_PRODUCT_TYPE="${DD_PRODUCT_TYPE:-Engineering}"
# export DD_PRODUCT="${DD_PRODUCT:-Juice Shop}"
# export DD_ENGAGEMENT="${DD_ENGAGEMENT:-Labs Security Testing}"
# bash labs/lab10/imports/run-imports.sh

here_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
out_dir="$here_dir"

require_env() {
local name="$1"
if [[ -z "${!name:-}" ]]; then
echo "ERROR: env var $name is required" >&2
exit 1
fi
}

require_env DD_API
require_env DD_TOKEN

DD_API="${DD_API:-http://localhost:8080/api/v2}"
DD_TOKEN="${DD_TOKEN:?DD_TOKEN is not set}"
DD_PRODUCT_TYPE="${DD_PRODUCT_TYPE:-Engineering}"
DD_PRODUCT="${DD_PRODUCT:-Juice Shop}"
DD_ENGAGEMENT="${DD_ENGAGEMENT:-Labs Security Testing}"

echo "Using context:"
echo " DD_API=$DD_API"
echo " DD_PRODUCT_TYPE=$DD_PRODUCT_TYPE"
echo " DD_PRODUCT=$DD_PRODUCT"
echo " DD_ENGAGEMENT=$DD_ENGAGEMENT"
OUT_DIR="labs/lab10/imports"
SRC_DIR="labs/lab10/imports/source-reports"
mkdir -p "$OUT_DIR"

have_jq=true
command -v jq >/dev/null 2>&1 || have_jq=false
if ! $have_jq; then
echo "WARN: jq not found; falling back to defaults for scan_type names." >&2
fi
auth_header="Authorization: Token $DD_TOKEN"

# Discover scan type names from your instance if jq is available
SCAN_ZAP="${SCAN_ZAP:-}"
SCAN_SEMGREP="${SCAN_SEMGREP:-}"
SCAN_TRIVY="${SCAN_TRIVY:-}"
SCAN_NUCLEI="${SCAN_NUCLEI:-}"

if $have_jq; then
echo "Discovering importer names from /test_types/ ..."
mapfile -t types < <(curl -sS -H "Authorization: Token $DD_TOKEN" "$DD_API/test_types/?limit=2000" | jq -r '.results[].name')
choose_type() {
local pat="$1"
local fallback="$2"
local val=""
for t in "${types[@]}"; do
if [[ "$t" =~ $pat ]]; then val="$t"; break; fi
done
if [[ -z "$val" ]]; then val="$fallback"; fi
echo "$val"
}
SCAN_ZAP="${SCAN_ZAP:-$(choose_type '^ZAP' 'ZAP Scan')}"
SCAN_SEMGREP="${SCAN_SEMGREP:-$(choose_type '^Semgrep' 'Semgrep JSON Report')}"
SCAN_TRIVY="${SCAN_TRIVY:-$(choose_type '^Trivy' 'Trivy Scan')}"
SCAN_NUCLEI="${SCAN_NUCLEI:-$(choose_type '^Nuclei' 'Nuclei Scan')}"
# Grype importer (commonly named "Anchore Grype")
if [[ -z "${SCAN_GRYPE:-}" ]]; then
SCAN_GRYPE=$(printf '%s\n' "${types[@]}" | grep -i '^Anchore Grype' | head -n1)
if [[ -z "$SCAN_GRYPE" ]]; then
SCAN_GRYPE=$(printf '%s\n' "${types[@]}" | grep -i 'Grype' | head -n1)
fi
fi
else
SCAN_ZAP="${SCAN_ZAP:-ZAP Scan}"
SCAN_SEMGREP="${SCAN_SEMGREP:-Semgrep JSON Report}"
SCAN_TRIVY="${SCAN_TRIVY:-Trivy Scan}"
SCAN_NUCLEI="${SCAN_NUCLEI:-Nuclei Scan}"
fi
SCAN_GRYPE="${SCAN_GRYPE:-Anchore Grype}"
urlencode() {
python3 -c 'import urllib.parse,sys; print(urllib.parse.quote(sys.argv[1]))' "$1"
}

get_first_id() {
local endpoint="$1"
local query_name="$2"
curl -s -H "$auth_header" "$DD_API/$endpoint/?name=$(urlencode "$query_name")" | jq -r '.results[0].id // empty'
}

echo "Importer names:"
echo " ZAP = $SCAN_ZAP"
echo " Semgrep = $SCAN_SEMGREP"
echo " Trivy = $SCAN_TRIVY"
echo " Nuclei = $SCAN_NUCLEI"
echo " Grype = $SCAN_GRYPE"
create_product_type() {
curl -s -X POST "$DD_API/product_types/" \
-H "$auth_header" \
-H "Content-Type: application/json" \
-d "{\"name\":\"$DD_PRODUCT_TYPE\",\"description\":\"Created by lab10 importer\"}" \
| tee "$OUT_DIR/product-type.json" | jq -r '.id'
}

create_product() {
local pt_id="$1"
curl -s -X POST "$DD_API/products/" \
-H "$auth_header" \
-H "Content-Type: application/json" \
-d "{\"name\":\"$DD_PRODUCT\",\"description\":\"Created by lab10 importer\",\"prod_type\":$pt_id}" \
| tee "$OUT_DIR/product.json" | jq -r '.id'
}

create_engagement() {
local product_id="$1"
local today enddate
today=$(date +%F)
enddate=$(python3 - <<'PY'
from datetime import date, timedelta
print((date.today()+timedelta(days=30)).isoformat())
PY
)
curl -s -X POST "$DD_API/engagements/" \
-H "$auth_header" \
-H "Content-Type: application/json" \
-d "{
\"name\":\"$DD_ENGAGEMENT\",
\"description\":\"Created by lab10 importer\",
\"product\":$product_id,
\"target_start\":\"$today\",
\"target_end\":\"$enddate\",
\"status\":\"In Progress\",
\"engagement_type\":\"CI/CD\"
}" | tee "$OUT_DIR/engagement.json" | jq -r '.id'
}

import_scan() {
local scan_type="$1"; shift
local file="$1"; shift
if [[ ! -f "$file" ]]; then
echo "SKIP: $scan_type file not found: $file"
local scan_type="$1"
local file_path="$2"
local label="$3"

if [[ ! -f "$file_path" ]]; then
echo "[!] Skipping $label: missing $file_path"
return 0
fi
local base out
base="$(basename "$file")"
out="$out_dir/import-${base//[^A-Za-z0-9_.-]/_}.json"
echo "Importing $scan_type from $file"
curl -sS -X POST "$DD_API/import-scan/" \
-H "Authorization: Token $DD_TOKEN" \

echo "[*] Importing $label with scan_type='$scan_type' from $file_path"
curl -s -X POST "$DD_API/import-scan/" \
-H "$auth_header" \
-F "engagement=$ENGAGEMENT_ID" \
-F "scan_type=$scan_type" \
-F "file=@$file" \
-F "product_type_name=$DD_PRODUCT_TYPE" \
-F "product_name=$DD_PRODUCT" \
-F "engagement_name=$DD_ENGAGEMENT" \
-F "auto_create_context=true" \
-F "minimum_severity=Info" \
-F "active=true" \
-F "verified=true" \
-F "close_old_findings=false" \
-F "push_to_jira=false" \
| tee "$out"
-F "file=@$file_path" \
| tee "$OUT_DIR/$label.json"
echo
}

# Candidate paths per tool
zap_file="labs/lab5/zap/zap-report-noauth.json"
semgrep_file="labs/lab5/semgrep/semgrep-results.json"
trivy_file="labs/lab4/trivy/trivy-vuln-detailed.json"
nuclei_file="labs/lab5/nuclei/nuclei-results.json"
echo "[*] Ensuring Product Type exists..."
PT_ID="$(get_first_id product_types "$DD_PRODUCT_TYPE")"
if [[ -z "$PT_ID" ]]; then
PT_ID="$(create_product_type)"
fi
echo "[+] Product Type ID: $PT_ID"

# Grype
grype_file="labs/lab4/syft/grype-vuln-results.json"
echo "[*] Ensuring Product exists..."
PRODUCT_ID="$(get_first_id products "$DD_PRODUCT")"
if [[ -z "$PRODUCT_ID" ]]; then
PRODUCT_ID="$(create_product "$PT_ID")"
fi
echo "[+] Product ID: $PRODUCT_ID"

import_scan "$SCAN_ZAP" "$zap_file"
import_scan "$SCAN_SEMGREP" "$semgrep_file"
import_scan "$SCAN_TRIVY" "$trivy_file"
import_scan "$SCAN_NUCLEI" "$nuclei_file"
echo "[*] Ensuring Engagement exists..."
ENGAGEMENT_ID="$(get_first_id engagements "$DD_ENGAGEMENT")"
if [[ -z "$ENGAGEMENT_ID" ]]; then
ENGAGEMENT_ID="$(create_engagement "$PRODUCT_ID")"
fi
echo "[+] Engagement ID: $ENGAGEMENT_ID"

# Grype
import_scan "$SCAN_GRYPE" "$grype_file"
import_scan "Semgrep JSON Report" "$SRC_DIR/semgrep-results.json" "semgrep"
import_scan "Trivy Scan" "$SRC_DIR/trivy-results.json" "trivy"
import_scan "Anchore Grype" "$SRC_DIR/grype-results.json" "grype"

echo "Done. Import responses saved under $out_dir"
echo "[+] Imports completed."
1 change: 1 addition & 0 deletions labs/lab10/imports/semgrep.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"minimum_severity":"Info","active":true,"verified":true,"endpoint_to_add":null,"auto_create_context":false,"deduplication_on_engagement":false,"lead":null,"push_to_jira":false,"api_scan_configuration":null,"create_finding_groups_for_all_findings":true,"test_id":3,"engagement_id":1,"product_id":1,"product_type_id":2,"statistics":{"after":{"info":{"active":0,"verified":0,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":0},"low":{"active":0,"verified":0,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":0},"medium":{"active":5,"verified":5,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":5},"high":{"active":0,"verified":0,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":0},"critical":{"active":0,"verified":0,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":0},"total":{"active":5,"verified":5,"duplicate":0,"false_p":0,"out_of_scope":0,"is_mitigated":0,"risk_accepted":0,"total":5}}},"pro":["Did you know, Pro has an automated no-code connector for Semgrep JSON Report? Try today for free or email us at hello@defectdojo.com"],"apply_tags_to_findings":false,"apply_tags_to_endpoints":false,"scan_type":"Semgrep JSON Report","engagement":1,"close_old_findings":false,"close_old_findings_product_scope":false,"test":3}
1 change: 1 addition & 0 deletions labs/lab10/imports/source-reports/grype-results.json

Large diffs are not rendered by default.

Loading