Skip to content

Release: Merge release into master from: release/3.3.300 - #16106

Merged
Maffooch merged 55 commits into
masterfrom
release/3.3.300
Sep 28, 2026
Merged

Maffooch merged 55 commits into
masterfrom
release/3.3.300

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

Release triggered by Maffooch

DefectDojo release bot and others added 30 commits September 21, 2026 16:57
…200-3.4.0-dev (#16024)

* Update versions in application files

* Update versions in application files

---------

Co-authored-by: DefectDojo release bot <dojo-release-bot@users.noreply.github.com>
Co-authored-by: Ross E Esposito <rossespo@gmail.com>
Summarize the user-facing features, enhancements, bug fixes, behavior
changes, and upgrade notes for the 3.3.200 release, grouped by type.
Dependency bumps, dormant Go writer delegations, internal refactors,
and chores are omitted.


Claude-Session: https://claude.ai/code/session_01XD7LmxiJbZvMRQUqDd3tiB

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…#16035)

Two corrections and one promotion, all of them things the page already implied
but did not deliver.

The date note said comparisons order ISO-8601 strings "correctly as text". That
was the design, and it was wrong for the three fields that carry a time of day:
compared as text, "mitigated lte 2026-08-27" excluded every Finding mitigated
on the 27th. Dates now compare as dates, by calendar day whenever the value you
write is a calendar day, so the page says that instead and spells out how to
ask for finer than a day when you need it.

"The field's data type decides which operators the editor offers" was true of
custom fields only, and sat in the custom-fields section. It is now true of
every field, so it moves up under Conditions as a table, gains the list-valued
row (vulnerability_ids and tags, where eq could never match), and names the two
ordered code vocabularies that keep their comparison operators.

Also documents the "unsupported" label a reader may meet on an existing rule,
and adds risk_acceptance_expiration_date to the date field lists.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…6044)

A new Tabular or Detail block no longer shows its filter table up front. The
table opens when the user clicks Add Filters, is shown right away when editing
a block that already has filter entries, and closes when the Model changes.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…#16042)

find_candidates_for_deduplication_uid_or_hash evaluated its candidate
queryset in one go. The whole result set was buffered by the database
client and cached on the queryset, each prefetch_related lookup spanned
every candidate id, and select_related built a separate Test, Engagement
and Test_Type instance for every candidate row. On a product where many
existing findings share the batch's hash codes or unique ids, that pushed
the post-processing task past a worker memory limit.

- Walk the candidates with iterator(chunk_size=DEDUPE_CANDIDATE_CHUNK_SIZE):
  a server-side cursor, no queryset result cache, and prefetches issued
  per chunk.
- Point each candidate at one shared Test / Engagement / Test_Type
  instance per id, as prefetch_related already does for its relations.
  Values are unchanged; only duplicate copies of identical rows are
  dropped.

The returned maps are unchanged: the same Finding instances, in the same
id order, with the same prefetches. For 20,000 colliding candidates, peak
RSS growth of the call drops from 345 MB to 256 MB.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…mpty cells; document every field (#16043)

* docs(generic): document data types, accepted values and gaps for Generic Findings Import

Audit the Generic Findings Import parser guide against dojo/tools/generic
and the importer, and rewrite it as per-field reference tables with a data
type, example values and behavior notes for every CSV column and JSON key.

Gaps closed:
- CSV: required columns, case-sensitive headers, BOM breakage, row merging
  on severity+title+description, CweIds / CVE / Vulnerability Id columns,
  empty-cell failures for numeric/date columns, the Active empty-cell
  behavior, and that known_exploited / ransomware_used / fix_available
  read any non-empty value (including FALSE) as true.
- CSV: remove CVSSV3_score, which the parser never reads.
- JSON: cwes key, endpoints/files/tags schemas, report-level keys
  (version, description, static_tool, dynamic_tool, Pro-only soc; name is
  unused), unknown-key rejection, severity normalization, numeric
  coercion, YYYY-MM-DD-only date fields, thread_id is an integer,
  numerical_severity is ignored, repeated unique_id_from_tool handling.
- Fix the example JSON, which had a trailing comma and did not parse.
- Test Type naming: CSV always uses Generic Findings Import; reimport
  type-mismatch rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(generic): read CSV KEV/fix booleans correctly, parse CVSSV3_score, skip empty cells

The Generic Findings Import CSV parser:
- converted known_exploited, ransomware_used and fix_available with
  bool(str), so any non-empty value, including "FALSE", became True. They
  now use the same rule as the other CSV booleans (_convert_bool), and an
  empty cell leaves the model default in place.
- never read the CVSSV3_score column. It is now parsed like CVSSV4_score;
  Finding.save() still recalculates it from a valid CVSSV3 vector.
- aborted the whole import on an empty CweId, epss_score, epss_percentile,
  CVSSV4_score, MitigatedDate or kev_date cell (int('') / float('') /
  dateutil ParserError). Empty cells are now skipped, matching JSON, where
  an omitted field stays unset.

Docs: update the CSV column table and boolean rules to match, and add a
Test Type metadata section explaining that static_tool, dynamic_tool and
soc are written to the shared Test Type (last import wins, omitted keeps
the current value, a report without "type" changes the built-in Generic
Findings Import Test Type, quoted "false" rejects the import).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(generic): add CSV fixture for filled, FALSE and empty KEV/fix and numeric cells

Gives the Generic Findings Import CSV fix a scan fixture (true, false,
empty and whitespace-only rows), exercised by a unit test here and usable
by downstream parser parity harnesses that walk unittests/scans.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(generic): merge data type and example columns so notes stay readable

The CSV column, JSON report-level and JSON finding-field tables now use
three columns (name, type and examples, notes), with the type above its
examples. At narrower content widths the four-column layout squeezed the
notes into a thin strip. Also shortens two unbreakable examples that
pushed the finding-field table past the content width.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(generic): give every JSON finding field a note

Fills the 15 JSON finding-field rows that had no note: what the field
holds, plus the non-obvious behavior where it exists (an import-request
service overrides the report's and scopes close-old-findings; tags must
be a list; component and SAST source fields feed Locations; thread_id
defaults to 0; blank component values are stored as empty).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(generic): rewrite the Using Generic Findings Import overview

Makes the overview page accurate and a hub into the rest of the docs:
- CSV vs JSON, with links to each format section and example in the
  Parser Guide.
- How to import (Import Scan form, /api/v2/import-scan/) and reimport,
  including the Test type mismatch rule.
- What makes an import fail for CSV and JSON, and that an unrecognized
  CSV severity becomes Info.
- Test Type naming with examples that no longer imply the report-level
  name field does anything (it is ignored), plus the shared Test Type
  metadata caveat.
- Deduplication: the default hash fields and how to tune a generic tool
  by its Test Type name in open source (settings) and Pro (Deduplication
  Tuning).
- Links the canonical Universal Parser page and the sample reports.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
#16034)

The agent_redteam feature flag was removed; AI Agent Red Teaming is now
available on any instance whose license includes Sensei. Update the
requirements, the intro note, and the troubleshooting entry to stop
telling readers to enable a feature flag.
…ats (#16036)

* docs(reporting): document the Report Builder CSV, Excel and JSON formats

A Generated Report can now be produced as CSV, Excel or JSON alongside PDF
and HTML. The data formats carry the rows a report is built from rather than
the document built around them, which is what makes a report automatable: a
script, a spreadsheet or a downstream system can consume one directly.

Documents what a reader needs to know before choosing one:

- The five formats, split into the Document and Data groups.
- That a data format includes only Tabular and Detail blocks, because a cover
  page, a chart or a widget has nothing to put in a cell, and that the generate
  dialog names the included and left-out blocks before you generate.
- The per-format shape: CSV sections for a multi-block template, one Excel
  worksheet per block, and the JSON envelope (with a worked example), including
  why JSON rows are keyed by field path rather than by label.
- How truncation is reported in each format.
- The `file_format` values on the API, and the Triage Engine report node's
  Format setting.

English only; translated pages are regenerated on the quarterly refresh.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs(triage-engine): say where a failed data-format report surfaces

A rule whose template has no Tabular or Detail block cannot produce a CSV,
Excel or JSON file. The engine records that on the delivery and rolls the
report row back, so nothing appears in Generated Reports and a rule author
looking there finds nothing at all. Point them at the deliveries instead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: blakeaowens <agent-blake-2@defectdojo.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: blakeaowens <agent-blake@defectdojo.com>
* docs: describe the two ways to start DefectDojo Cloud

The Contact Sales page described a free two-week trial requested through
the old wizard (firewall step, monthly or annual billing, Stripe checkout
for every tier). Rewrite it around the current wizard: pay as you go as
the self-serve plan, and annual tiers through the sales team, with the
Pricing Plans tabs, the spend limit, and Location only on the annual
path. Drop the stale screenshots of the old wizard.

Also point the two cloud-manager pages at the wizard's current URL and
remove the trial wording from the support page.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* docs: Pricing Plans shows two tiles; the sales tile names no tier or price

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* docs: the annual plan tile is named Pre-pay

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* docs: the annual plan tile is named Pre-pay & save

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* docs: Location step is always shown; pay as you go only reads its fixed region there

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* docs: plan names in title case (Pay As You Go, Pre-Pay & Save)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* docs: describe the pre-pay estimator and the minimum plan size

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs: either checkout action agrees to the terms

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…n bar (#16061)

* docs(dashboards): Command Center dot grid, softer beams, risk colors, automation bar

Describe the dot grid behind the scene and its ripples, the gray beam on the
plain source lines in light mode, the actionable ring in the risk colors,
and the automation card's sectioned bar with its breakdown on hover. Refresh
the scene screenshot (sample data).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(dashboards): drop the Command Center dot grid from the page

The dot grid is background decoration and carries no data, so the page does
not describe it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…hing list filters (#16068)

Document the column picker's new Select All / Deselect All actions (they act
on the columns the picker's search shows) and the searchable list filters'
"Select all N matching", which filters a table to every option whose name
contains the search text rather than only the options loaded on screen.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…ports (#16069)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…16070)

Describe the filter on every Vulnerability Explorer column (multi-value Type
and Severity, EPSS, KEV, count and date filters), that blanks sort last in
both directions, and Ctrl/Cmd-click multi-column sorting.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
… live drill (#16074)

Add "Restoring a Self-Hosted Deployment" for Docker Compose (containerized-db
and separate-db) and Kubernetes. Every command on it was run end to end in a
backup, destroy, and restore drill on DefectDojo Pro 3.3.200 (dojo-compose-cli
2.1.3, chart 3.3.200).

Backing Up now covers the orchestrator's -ddorch database, names the Compose
files (/etc/defectdojo/compose.config, the systemd unit holding DOJO_CLI_KEY),
gives Kubernetes commands for values, Secrets, and media, and adds the s3
storage backend.

Also correct which key encrypts what in the Kubernetes migration runbook,
replace a nonexistent databaseUrl Helm value and a missing Compose command in
the open source migration page, fix a Products-to-Assets replace slip there,
and link backup and restore from the upgrade pages. On-prem page weights are
renumbered in every locale to fit the new page.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…ey (#16067)

The prerequisite said a User Key of any role works. The Cloud Integrations
API rejects keys whose owner is not a platform administrator with a 401
("The supplied key does not have permission to perform this action."),
because a User Key inherits its owner's permissions. State the real
requirement and the error a scoped key produces, in all translations.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…yles (#16066)

The OS message bucket serves text/markdown with no charset, so requests
decoded it as ISO-8859-1 and non-ASCII characters were garbled on every
instance ("→" rendered as "â" plus two invisible control characters).
Force UTF-8, which is what the publisher writes.

The base CSS reset also zeroed list markers and block margins inside the
expanded banner, so markdown bullets had no markers and paragraphs ran
together. Restore them, scoped to .banner-expanded.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
… bulk delete (#16064)

The duplicate_finding self-FK is ON DELETE DO_NOTHING and DEFERRABLE
INITIALLY DEFERRED, and both code paths that guard it read without a
lock and wrote afterwards:

- _drop_links_to_deleted_originals checked the matched originals with a
  plain SELECT. A delete still uncommitted at that moment was invisible
  to it, so the flush wrote its links and then failed at COMMIT with
  "Key (duplicate_finding_id)=(N) is not present", rolling back the
  whole batch's deduplication.
- resolve_inbound_duplicate_references read the findings pointing into
  a chunk, then the chunk was deleted. A dedup flush committing a new
  link into the chunk in between failed the chunk at COMMIT with
  "Key (id)=(N) is still referenced" (the excess-duplicate delete task).

The flush now takes FOR KEY SHARE (the lock Postgres itself takes for an
FK check) on the originals and the rows it writes, in one ascending-id
statement inside its transaction. Each bulk-delete chunk takes FOR
UPDATE on its findings, also in one ascending-id statement, right before
resolving inbound references; the resolver moved after the child-row
cascade so finding rows remain the last rows a chunk locks. A flush
that locks first commits first and the resolver sees its links; a flush
that comes later waits, finds the original gone, and drops the link.

Tests reproduce both interleavings with two real connections and real
commits, plus a lock-order case that deadlocks if the flush locked only
the originals.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The message named the stored Product Type of the resolved product. That
value reaches callers who hold no grant on it, because the import
permission classes resolve the product before any authorization call
runs. Report only the value the caller supplied.

Refs H1 #4032888, story 15579.
…#16027)

One branch of the merge view acted on a stricter intent than the check in
front of it, so it accepted callers the sibling routes for the same action
already refuse. The check runs before the merge writes anything, so a
refusal cannot leave work half applied. Behaviour for correctly
permissioned callers is unchanged, including the other branch of the same
selector.

Adds regression tests for the refusal, for the unaffected branch, and for
the permitted caller.
…16013)

Tenable's description field carries per-scan data - timestamps and affected
hosts - that differs between two scans of the very same vulnerability. Because
it is part of HASHCODE_FIELDS_PER_SCANNER, the hash_code changes on every
reimport and the finding never deduplicates against its own earlier occurrence.

The remaining fields (title, severity, vulnerability_ids, cwe) are stable
properties of the vulnerability and already match the Nexpose Scan entry.

Fixes #11994

Signed-off-by: Elaria <3.14hell@gmail.com>
…aces (#16075)

DefectDojo Pro no longer serves Classic UI pages, so the Relabeling and
Locations sections no longer list them among the surfaces that pick up
a toggle only after a restart. Server-side URL routing, generated
reports and the /api/v2 route wiring are still fixed at startup, so the
Restart Recommended tag and its explanation are unchanged otherwise.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
#16065)

Auto grouping looked up the group with get_or_create keyed on
(test, creator, name). A reimport by a different user than the group's
creator therefore made a second same-name group in the same test, and
once a test held two same-name groups for the importing user (for
example after two imports raced), get_or_create raised
Finding_Group.MultipleObjectsReturned and reimport-scan returned a 500.
The lone-finding path hit the same duplicates through a get() inside a
bare except, which swallowed the error and left the finding ungrouped.

Look the group up by (test, name) only and reuse the oldest one by id,
creating a group (owned by the importing user) only when none exists.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
#16029)

A Location row is deduplicated across every product that records the same URL, so
a predicate that joins out of the row can be satisfied by a reference the caller
is not authorized for. Authorizing the result set afterwards is a separate
filter() call, which Django compiles to a second join, so the row still qualifies
through the caller's own reference while the match through another product's data
stays observable.

The existing rewrite that bounds those predicates was a method on one filterset
class. Move it to a mixin and apply it to the REST Location list filterset, then
bound the two remaining predicates that are applied outside a filterset: the
endpoint_status compatibility filter and the vulnerable-endpoint view body.

The subquery now applies the predicate and the product bound as two filter()
calls. As one kwargs dict they can spell the same lookup and silently drop one
of them, which is reachable from the list-valued product filters.

No query parameter, response field or schema change. For a non-privileged caller
the only behaviour that changes is that a predicate stops matching through
references they cannot see.

Co-authored-by: Cody Maffucci <46459665+Maffooch@users.noreply.github.com>
The FIPS page told readers to email for access, and its Docker Compose
steps used a DD_IMAGE_TAG variable and an x-psirt-vars block that the
deployment files do not have.

- New "Getting the FIPS images" section: <version>-fips tags from 3.3.200,
  pulled with the license's registry credentials, linux/amd64 only, signed.
- Compose tab rewritten around DD_FIPS_MODE (3.3.300+), set with
  dojo-compose-cli so it survives upgrades, with a note for 3.3.200.
- Coverage: drop the PSIRT advisory engine, add the OSCAL validator.
- ECS page: where the images come from and how to copy them into ECR;
  drop the removed PSIRT sidecar references.
- Translations: the same corrections, with explicit heading IDs so the
  new anchor and #guard-rails resolve in every language.

Co-authored-by: devGregA <greg-agent-2@defectdojo.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…ering (#16071)

Numeric, score and date columns now sort highest or newest first on the
first click, text columns sort A to Z, and rows with no value always sort
last. Adds a Sorting columns section to the table customization page,
covering multi-column sort and the sort being part of the page URL.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
#16082)

The GitLab asset connector gains an opt-in "Exclude Archived Projects"
setting that leaves archived projects out of Discover and Sync. Documents
where the toggle lives, what happens to already-mapped projects (flagged
MISSING, imported data kept), and what turning it back off does.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Superusers can now reset another user's MFA from the user menu or with
POST /api/v2/users/{id}/reset_mfa/, behind the Administrator MFA Reset
feature flag, which is on by default. Update the lost-device recovery
steps to lead with that, keep remove_mfa as the shell fallback, and say
how to turn the action off.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Maffooch and others added 14 commits September 25, 2026 20:39
…M2M rows (#16091)

The chunked bulk delete cleared a chunk's M2M through rows and cascaded its
child rows before it row-locked the chunk's findings. A concurrent writer that
committed a row referencing one of those findings in between (for example an
import adding a found_by row) left a reference the chunk's COMMIT then
rejected: "update or delete on table dojo_finding violates foreign key
constraint dojo_finding_found_by_finding_id_..._fk_dojo_finding_id ... is still
referenced from table dojo_finding_found_by".

lock_findings_for_delete is now the first statement of each chunk transaction.
Postgres takes FOR KEY SHARE on the finding when it checks a referencing row's
deferred foreign key, and that conflicts with the chunk's FOR UPDATE, so a
writer either committed before the lock (and the clear sees its row) or queues
behind the chunk and then finds the finding gone.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
These are images under docs/ that nothing in the repository references --
roughly 28 MB, accumulated as docs pages were rewritten or deleted without
pruning their screenshots.

The list was built by searching every tracked image basename across the whole
repository, not just docs/, matching literal basenames with a boundary check
rather than a regex describing what a filename may contain. That kept eight
files that a narrower check would have deleted: three whose names contain "&"
and are referenced from the notification docs, and five social icons the root
README hotlinks out of docs/assets/images/ through github.com/ghraw.

Every image referenced from docs/content still resolves after this change.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
… Pools (#16041)

The cross-tool estimate now compares findings within each Asset's cross-tool
pool and keeps engagement-scoped deduplication on its own. Say so on the Sensei
Advisor page, and that the model sees pool counts, never pool names.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…ation (#16021)

* Fix crash bugs in Aqua and Snyk parsers caused by None field concatenation

The Aqua parser crashes with TypeError when scan reports contain null
or missing resource objects, or when fields like cpe, file, or name
are absent. This affects all three report format variants (apiv1,
apiv2, and CICD).

The Snyk parser crashes with TypeError when the identifiers field
is present in the JSON report but set to null instead of a dict.

Guard all affected code paths with inline fallbacks so that missing
or null fields produce empty strings instead of raising exceptions.

* Fix test assertions and handle None score in severity_of

* Handle a missing resource name, version, file and CVE in the Aqua parser

The new missing-fields tests still errored. A null resource or one with
neither name nor path left resource_name as None, which crashed the title
concatenation in get_item, and get_item_v2 indexed item["file"] and
item["name"] directly.

get_item now falls back to the path and then to "No resource name", and a
null version reads as "No version". get_item_v2 reads file and name with
.get() and only records a vulnerability id when there is one. Output for
every existing Aqua sample report is unchanged; only inputs that used to
raise now parse. The new tests also assert the resulting titles.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Cody Maffucci <46459665+Maffooch@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Harden authorization on the audit history page

Tighten how the action history page scopes the pghistory events it
aggregates, so it only serves rows the caller is already authorized for.
Adds regression tests. No functional change for correctly-permissioned
users.

* Skip the Location history scope tests when V3_FEATURE_LOCATIONS is off

The Location views and their URL names are only registered when
V3_FEATURE_LOCATIONS is on at startup, so override_settings on the class
cannot turn them on. With the feature off, reverse("add_endpoint_to_product")
raised NoReverseMatch and all three tests errored in the Locations-off rest
framework job. Gate the class with skip_unless_v3, like the other
Location-only test classes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Cody Maffucci <46459665+Maffooch@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The registered jira_link.get_authorized_jira_projects filter returned an
unordered queryset (JIRA_Project has no Meta.ordering), while the fallback
it replaces orders by id. The list endpoint's first row was therefore
whatever Postgres returned first. When that was the engagement-scoped
project from the test fixture, JiraProjectTest.test_update_object_not_authorized
and test_delete_object_not_authorized saw the permission check run against
the Engagement instead of the Product and failed. That has kicked docs-only
PRs out of the merge queue more than once.

Restore the id ordering on both branches of the filter, matching the
fallback and giving the API stable pagination.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…lor customizer (#16087)

* docs(appearance): document the Appearance page, theme presets, and color customizer

Adds an Appearance section under Admin covering the theme preset choice
(DefectDojo and Legacy), the primary color, the interface colors set
separately for light and dark mode (neutral palette, surfaces, text,
components, operational status), the Legibility checks that stop an
unreadable change from saving, the metric colors, and the ui_color_theme
field on /api/v2/system_settings/ for automation.

Pairs with the Pro change that ships the customizer on the same release line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(appearance): reports follow the Appearance theme; new report themes start from it

- Appearance: a Reports and exports section (metrics and dashboard PDF exports,
  Report Builder charts including scheduled reports, reports with no theme,
  and new report themes all use the instance's light-mode colors).
- Report Builder: the theme defaults table now describes the instance-derived
  starting colors instead of fixed hex values.
- Retake the Appearance screenshot with the current logo.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs(appearance): retake the Appearance screenshot with the current logo and type

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…amework job stalls (#16099)

The Locations-on rest framework job intermittently stops printing near the
end of its parallel phase and sits there until the 25 minute step timeout.
It has happened at least a dozen times since August on both amd64 and arm64.
When a --parallel worker never returns its subsuite, the main process blocks
in multiprocessing's pool iterator with no output, so the log cannot say
whether a test was stuck, and on what, or a worker died.

Run a watchdog on the runner beside `docker compose up`. It only reads from
the containers and changes nothing about how the tests run. After 5 minutes
with no uwsgi output, and again at 20 minutes, it records the container's
processes and memory, a py-spy dump of every python process (taken from the
host by host pid, so the container needs no ptrace capability; py-spy is
installed only when a dump is needed), and pg_stat_activity with blocking
pids plus pg_locks. A new always() step prints the result, so it survives
the step being killed by its timeout.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…g writer race (#16100)

test_tag_writer_holding_a_tag_row_does_not_fail_the_chunk assumed Postgres
always aborts the bulk-delete chunk when it deadlocks with
bulk_add_tags_to_instances. Postgres does not promise that. A waiting
backend runs the deadlock check once, deadlock_timeout after it started
waiting. The chunk starts waiting first, so it is the victim only when the
writer reaches its COMMIT within deadlock_timeout. On a slow or loaded
machine the chunk's one check runs before the cycle exists, and the writer
is aborted instead. That failed the test about 1 run in 17 locally
(3 of 50).

Both orders satisfy what #16091 guarantees: the chunk deletes, no tag
through row survives, and the tag count stays consistent. The test now
asserts exactly that, plus that exactly one side was the deadlock victim
(the chunk's attempts are counted through lock_findings_for_delete). A new
test forces the writer-victim order deterministically by holding the
writer's COMMIT past the chunk's deadlock check, so both orders stay
covered.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* build(nginx): collect only runtime files into the static tree

Once the Tailwind CSS is built, reinstall components with --production so
the CSS toolchain (tailwind cli, lightningcss and their prebuilt native
binaries) is not collected, and have collectstatic skip source maps,
TypeScript sources and declarations, and the npm lockfiles some packages
ship in their tarballs. None of these are loaded by any page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore(components): update nanoid 3.x to 3.3.19

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore(api_v3): turn off Scalar's hosted AI assistant on the reference page

Scalar enables its "Ask AI" assistant by default, which is a third-party
hosted service. Disable it through data-configuration so the page stays
self-contained, the same reason the bundle is served from our own static
files instead of a CDN.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: devGregA <greg-agent-2@defectdojo.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Add docs on MCP Report Generation

* Update MCP docs for Multi-MCP Report Builder

* Update docs for MCP Dashboard addition
…anaged (#16103)

The 0268 backfill translates global roles into is_superuser / is_staff
for installs that move to the authorized_users model. When an installed
app still manages the role tables, the roles keep applying there, so the
translation is skipped and the flags stay as they were. Open source
only installs are unaffected: nothing else manages those tables, and the
backfill runs as before.

Co-authored-by: devGregA <greg-agent-2@defectdojo.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The Jira downstream connector now reads a field's type from Jira and
wraps a plain option name for a select list into the option object Jira
expects. Document that under Custom Fields on the Jira connector page,
in English and in its German, Spanish, French and Japanese translations.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added the release-management Automated release-train PR label Sep 28, 2026
@Maffooch Maffooch closed this Sep 28, 2026
@Maffooch Maffooch reopened this Sep 28, 2026
@github-actions github-actions Bot added docker New Migration Adding a new migration file. Take care when merging. settings_changes Needs changes to settings.py based on changes in settings.dist.py included in this PR docs unittests ui parser helm labels Sep 28, 2026
@dryrunsecurity

dryrunsecurity Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

DryRun Security

This pull request modifies a sensitive codepath in dojo/importers/auto_create_context.py by an author not included in the allowed list. The issue is classified as low severity and is not blocking.

Configured Sensitive Codepath Modified by Non-Allowed Author in dojo/importers/auto_create_context.py (drs_d1deafe5)
Vulnerability Configured Sensitive Codepath Modified by Non-Allowed Author
Description File 'dojo/importers/auto_create_context.py' matches configured sensitive codepath pattern 'dojo/importers/*.py' and was modified by 'svader0' (commit f723093) who is not in the allowed authors list.

Comment to provide feedback on these findings.

Report false positive: @dryrunsecurity fp [FINDING ID] [FEEDBACK]
Report low-impact: @dryrunsecurity nit [FINDING ID] [FEEDBACK]

Example: @dryrunsecurity fp drs_90eda195 This code is not user-facing

All finding details can be found in the DryRun Security Dashboard.

@Maffooch
Maffooch merged commit 8b12d80 into master Sep 28, 2026
47 checks passed
@Maffooch
Maffooch deleted the release/3.3.300 branch September 28, 2026 11:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docker docs helm New Migration Adding a new migration file. Take care when merging. parser release-management Automated release-train PR settings_changes Needs changes to settings.py based on changes in settings.dist.py included in this PR ui unittests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants