This is a pre-release. djust 1.0.0 has shipped since: read the djust 1.0.0 release notes.
Before you upgrade, read the upgrade guide.
Security
- Bumped
idna3.11 → 3.15 — patches CVE-2026-45409 (GHSA-65pc-fj4g-8rjx, Dependabot alert #101). Specially crafted inputs toidna.encode()("٠" * Nor"・" * N + "漢") hit thevalid_contextofunction prior to length rejection, so high values of N consumed significant resources — a ReDoS-style denial-of-service. Same class as CVE-2024-3651; the 2024 remediation was incomplete. idna 3.14 rejects long inputs early; 3.15 extends the early-reject to lesser-used per-label conversion and codec paths.idnais a transitive runtime dep (pulled in byanyio/httpx/httpcore/requests); the bump is a lockfile-only change viauv lock --upgrade-package idna, no direct-dep change inpyproject.toml. CVSS v4 6.9 / medium. Verified via full Python regression (7301 passed, 0 failed). Domain names cannot exceed 253 characters in normal usage, so the practical exposure surface was thin, but the fix removes the ReDoS class entirely.
Fixed
LiveView.requestno longer triggers a "non-serializable ASGIRequest" warning on every mount/event (#1545).self.requestwas assigned by the HTTPpost()path (mixins/request.py:489) and the WebSocket path (websocket.py:1940) AFTER__init__, so it sat OUTSIDE_framework_attrsand the state-snapshot machinery treated theASGIRequestas user state — hitting the non-serializable fallback atserialization.py:557and logging "LiveView state contains non-serializable value: ASGIRequest …" on every mount AND every event for everyLiveView. The warning was cosmetic (the frameworkstr()-stringifies the value and re-setsself.requestto the live request on every request/event, so the stringified copy is never read back) but noisy enough to dilute the warning's signal for genuine app-author bugs. Fix: assignself.request: Any = NoneinLiveView.__init__BEFORE the_framework_attrs = frozenset(self.__dict__.keys())line atlive_view.py:526—requestis now captured as framework state and excluded from the user-state snapshot. Matches the_framework_attrssnapshot-order invariant (#1393). The fix also adds"request"to the_FRAMEWORK_INTERNAL_ATTRShard-coded frozenset used by_debug_state_sizesand the debug-toolbar observability path (discovered during regression-suite verification — 2test_debug_state_sizes_*tests started reportingrequestas user state until both filters were updated). Covered by 5 regression cases inpython/tests/test_liveview_request_framework_attr_1545.py, including a gate-off self-test (#254) confirming 4 of 5 tests fail without the fix.crates/djust_liveis nowcargo test-able —extension-modulegated behind a default-on Cargo feature (#1543).crates/djust_livecarried PyO3'sextension-modulefeature unconditionally, socargo test -p djust_livefailed at link time withld: symbol(s) not found ... Py_True— the crate that holdsdjust._rust's entry point, the actor system, theRustLiveViewbackend, and (since #1541 / PR #1546) thePatchResponseround-trip regression tests had no fast Rust-native test feedback loop.make testworked around it with--exclude djust_live. Surfaced twice in the v1.0.0rc4 Phase-2 drain (PRs #1530, #1535) — standing structural constraint. The fix gates the feature behind a default-on Cargo feature ([features] default = ["extension-module"]; extension-module = ["pyo3/extension-module"]), somaturin develop/cargo buildare unchanged butcargo test -p djust_live --no-default-featuresnow links against libpython and runs. 37 djust_live tests now execute (including the 4msgpack_round_trip_patch_response_*regression tests from PR #1546 / #1541 that previously compile-checked only). The Makefiletest-rusttarget, the paralleltesttarget, and the CI workflow (.github/workflows/test.yml) all gained a Phase 2 invocation that runs the djust_live tests with--no-default-featuresafter the existing workspace-minus-djust_live pass. Maturin build path verified end-to-end (wheel build → import).PatchResponsemsgpack round-trip is now positionally-stable for everyNone/Somecombination ofpatchesandhtml(#1541). Sibling audit of #1538.PatchResponseis a plain#[derive(Serialize, Deserialize)]struct incrates/djust_live/src/actors/messages.rs, so under msgpack it serializes as a positional array — and its first two fields,patches: Option<Vec<Patch>>andhtml: Option<String>, carried#[serde(skip_serializing_if = "Option::is_none")]without#[serde(default)]. The fix that worked for #1538 (VNode.djust_id— adddefault) does not generalize: that fix only works for STRICTLY TRAILING optionals. For leading optionals likePatchResponse's,skip_serializing_ifshifts later array elements into the wrong positional slot on deserialize — anddefaultcannot repair this because the deserializer isn't running out of elements; it's reading wrong-typed values at the wrong positions (empirically witnessed incrates/djust_vdom/tests/wire_protocol_snapshot.rs :: msgpack_skip_with_default_works_for_trailing_optional_only). The correct fix forPatchResponseis to removeskip_serializing_ifentirely —Noneis then serialized as msgpacknil(1 byte) and positional slots stay aligned. This is defense-in-depth:PatchResponseis not currentlyrmp_serde::to_vec'd on any production path (only the innerVec<Patch>is atlib.rs:679), but future cross-process actor transport would have hit the same #1538 class. The #1448 wire-protocol snapshot suite now also carries 3 structural witness tests pinning the bug class so any future plain wire struct hitting the same pattern fails fast. Wire-format note: the JSON encoding ofPatchResponsenow always includes thepatchesandhtmlkeys (nullrather than omitted); no current consumer parsesPatchResponseJSON, but the existing inlineserde_jsontest was updated to reflect the new always-present shape. Layer B regression tests forPatchResponseitself live inline inmessages.rsand currently compile-check only (cargo test -p djust_liveis blocked by #1543's unconditionalextension-modulefeature); they will execute automatically once #1543 lands. 3 newmsgpack_*cases incrates/djust_vdom/tests/wire_protocol_snapshot.rsand 4 newmsgpack_round_trip_patch_response_*cases incrates/djust_live/src/actors/messages.rs.
Added
- Audit:
sync_to_async→ native-async-ORM migration surface (#1434). A new audit,docs/audits/async-orm-2026-05.md, classifies everysync_to_async/async_to_synccall site in framework code — 126 sites across 14 files — and a companion benchmark,scripts/bench_sync_to_async_overhead.py, measures the per-crossing asgiref threadpool overhead empirically (~60 µs/crossing on the dev machine). The audit finds that issue #1434's premise does not hold: there are zerosync_to_async(Model.objects.X)call sites, only 3 ORM-category sites (all indirect auth/tenant helpers that fire once per connection at mount, never per event), and the ORM/cache-migratable fraction of per-event latency is 0% — below #1434's own 5% deprioritize gate. The audit recommends closing #1434. Internal/contributor documentation and tooling; no framework behavior change.