Changelog

v2.1.15 — 2026/06/13

Fix runique (forms, admin)

TextField double-encoded & when storing plain-text input: sanitize_strict() used ammonia::Builder::new().tags(HashSet::new()).clean(input) to strip all HTML tags. This is correct, but ammonia always HTML-encodes & → & in its output even when no tags remain — a side effect of its HTML-entity serialiser. The raw output was then stored in the database. When Tera later rendered it with autoescaping active, the & in & was re-encoded to &, so the browser displayed the literal text & instead of &. Fixed: after ammonia strips the tags, the result is decoded back to plain text via html_escape::decode_html_entities() — removing the spurious entity encoding before storage. Dangerous protocol stripping (javascript:, vbscript:, data:, file:) runs on the decoded string, preserving security guarantees. New dependency: html-escape = "0.2".

Fix runique (forms, admin)

add_js() scripts blocked by CSP strict-dynamic in admin forms: render_js() built its own isolated Tera context containing only js_files, with no access to the request-scoped csp_nonce. Under strict-dynamic, any

Feature runique / derive_form (DSL model! / extend!)

Column rename via [renamed_from: "old"]: renaming a field previously produced a DROP COLUMN + ADD COLUMN — silent data loss. The new explicit hint makes makemigrations emit ALTER TABLE … RENAME COLUMN old TO new (portable across PostgreSQL, MySQL/MariaDB and SQLite), with no data loss. It is a migration-only directive (no effect on the generated entity/form) and is tolerated by both DSL field parsers (FormFieldDecl for v2/extend!, FieldDef for v1). Guard against a stale hint: if the old column still exists in the snapshot, no rename is emitted (falls back to add). ParsedColumn.renamed_from is transient and never written to snapshots.

← Newer 1 / 37 Older →