| name | defectdojo-dev |
| description | Develop, test, and validate DefectDojo changes end to end against a local Docker stack — bring the app up on localhost:8080, reproduce a bug on the target branch before fixing it, write behavioral unit tests that fail without the fix, drive the UI with the Playwright MCP, and fetch an API token to exercise the REST API. The same review lenses (scalability, performance, memory, DB resourcing, query design, security, DRF serializer exposure) let it double as an inbound PR reviewer, with a dedicated checklist for infra/Helm/deployment PRs. Use when developing or testing a change, reproducing or fixing a bug, writing a regression test, validating a fix, or reviewing any DefectDojo PR/branch (app, API, or Helm chart). |
Develop, test, and review DefectDojo changes
This is the primary workflow for building and verifying a change in this repo, and
secondarily for reviewing someone else's PR. DefectDojo is a Django app (server-rendered
templates, not a SPA) run via Docker Compose, with a Postgres DB and a Valkey broker. Work
the loop below against a running local stack — do not reason about behavior from the
code alone when you can exercise it.
Read AGENTS.md first for the branch/release-line policy: bug fixes target bugfix,
features target dev, and master is off-limits without explicit confirmation (the
.claude/hooks/branch-guard.sh hook enforces this). Put the work on the right branch
before editing.
Inputs
- What you're working on (one of): a change/feature you're building, a bug or issue to
reproduce and fix, or a PR number / branch / URL to review.
- Focus area (optional): a specific concern lens to emphasize (e.g. "just the query
performance", "security only").
Helper scripts
Both live in this skill directory. chmod +x them once if needed.
get-api-token.sh — fetches a REST API token so you can test API endpoints.
POSTs to /api/v2/api-token-auth/ with a username/password and prints the raw token.
Defaults: user admin, password admin, base URL http://localhost:8080 (override with
DD_USER / DD_PASSWORD / DD_BASE_URL). Use the token as Authorization: Token <t>.
If token auth is disabled, get one from the UI at /api/key-v2 instead.
run-tests.sh — thin wrapper over the repo's sanctioned ./run-unittest.sh that tees
output to a log. Pass a fully-qualified test target:
./run-tests.sh unittests.tools.test_acunetix_parser.TestAcunetixParser. Requires the dev
stack to be up. Do not call pytest or manage.py test directly — the wrapper is the
supported path (runs --keepdb -v2, checks compose first).
Steps
-
Bring the stack up (dev mode). Dev mode is what gives you admin/admin and
hot-reload:
./docker/setEnv.sh dev
docker compose up -d
The UI is at http://localhost:8080 (login /login). Creds are admin/admin in dev
mode only. If someone ran a plain docker compose up instead, the admin password is
random — read it with docker compose logs initializer | grep "Admin password:", or
reset via docker compose exec uwsgi ./manage.py changepassword admin.
-
Reproduce first (bugs). Before changing anything, prove the bug exists on the
target/base branch (the one the fix will land on). Capture the concrete failure — a
screenshot, a stack trace, a wrong value, a 500. Reproduce through the real surface:
- UI: drive it with the Playwright MCP — navigate to
http://localhost:8080/login,
log in, and walk the exact flow. Expect full-page navigations and CSRF-protected forms
(hidden csrfmiddlewaretoken inputs); auth is a session cookie, so there's no
client-side router to wait on.
- API: grab a token with
get-api-token.sh and hit /api/v2/... with
Authorization: Token <t>.
A bug you cannot reproduce is not yet understood — say so rather than guessing at a fix.
-
Develop / apply the change. Make the fix or feature on the correct branch. The dev
stack bind-mounts the source with autoreload, so edits to Python are picked up live —
re-exercise the same UI/API path from step 2 to confirm the behavior actually changed.
-
Write behavioral unit tests. Every fix gets a test that fails without the change and
passes with it — that's what stops the regression from coming back. Prefer asserting on
observable behavior (returned values, DB state, response codes, finding counts/attributes)
over implementation details or line coverage. Tests live under unittests/
(unittests/tools/ for parsers). Run them the sanctioned way:
./run-tests.sh unittests.<module>.<TestClass>
Confirm the test is real by checking it fails on the pre-fix code (stash the fix, run,
see red), then passes with the fix.
Reviewing infra / Helm / deployment PRs
A recurring PR category touches the Helm chart (helm/defectdojo/), nginx config
(nginx/), or Docker entrypoints (docker/) rather than Django code. The concern lenses
still apply (security defaults, backward compatibility), but the checks are different:
- The branch/release-line policy applies to chart and docker PRs too — they are not
exempt. A fix still targets
bugfix, a feature dev, never master. Defer to AGENTS.md.
- Know the three Helm CI jobs (
.github/workflows/test-helm-chart.yml) — each is an
automatic blocker when it fails:
Lint chart (version) includes an artifacthub.io/changes annotation check: it
fails on any chart change whose helm/defectdojo/Chart.yaml annotation wasn't updated
versus the target branch. A chart PR with no new changelog annotation entry is red until
fixed (this is the single most common chart-PR CI failure).
Update schema regenerates values.schema.json and fails on diff — the schema must be
generator-produced, not hand-edited. A hand-edited schema is an automatic request-change.
Update documentation runs helm-docs — README.md must be regenerated from
values.yaml, not written by hand.
- New features must be opt-in and default-off. Gate every new resource behind
{{- if .Values.X.enabled }} with enabled: false by default, so helm template on defaults
renders nothing new and existing installs are untouched. A new env/config default that applies
to all installs (e.g. forcing LC_ALL) is a behavior change — flag it and make it overridable.
- Template-correctness spot checks: confirm
backendRefs/service references point at real
service names and ports; watch list-vs-map YAML rendering from a conditional - in the wrong
place; guard required secret fields so an enabled-but-unconfigured block fails with a clear
message instead of rendering empty strings.
- Validate locally without the Django stack:
helm lint helm/defectdojo, then
helm template helm/defectdojo with and without --set X.enabled=true to diff what the new
block renders; run the schema/docs generators before pushing.
Notes
- Creds caveat:
admin/admin is a dev-mode convenience only. A production-style
docker compose up generates a random admin password (see step 1).
- Playwright expectations: server-rendered Django, so drive full-page loads and real form
submits; the CSRF token is a hidden input on each form and auth is a session cookie.
- Never publish without approval: posting review comments, opening/editing PRs, or any
outward action waits for an explicit yes from the user (see the global action policy).
- Branch & milestones:
AGENTS.md is the source of truth for which release line a change
belongs on and the milestone rules for new PRs — defer to it.
- Test runner: always go through
./run-unittest.sh / run-tests.sh; raw pytest and
manage.py test are not the supported invocation here.