Skip to content

fix(html): preserve the document around the rustmotion element - #255

Merged
LeadcodeDev merged 1 commit into
chantier/audit-2026-09from
fix/html-writeback-preserve
Sep 22, 2026
Merged

LeadcodeDev merged 1 commit into
chantier/audit-2026-09from
fix/html-writeback-preserve

Conversation

@LeadcodeDev

Copy link
Copy Markdown
Owner

Severity Medium, category correctness. Location: crates/rustmotion-html/src/lib.rs:289

Impact

All four write-back entry points (set_inline_style, set_text_content, set_attribute, remove_inline_style) re-serialize only the <rustmotion> element, and rustmotion-studio writes that string straight over the source file (editor/inspector.rs:2168 -> write_and_note(path, &updated)). Executed: a 281-byte document with <!DOCTYPE html>, <html><head><meta charset="utf-8"></head><body>, a leading <!-- authored by hand --> comment and a trailing comment becomes 150 bytes — doctype, head, meta, body and both outer comments gone — after one font-size tweak in the inspector. The transpiler happily accepts such documents (find_element is a document-wide DFS), so this is a supported authoring form being destroyed. The docstring's "formatting is normalized" does not cover deleting the surrounding document. Secondarily, serialize_element (lib.rs:488-497) does let _ = serialize(...) and String::from_utf8(buf).unwrap_or_default(), so a serializer failure would write an empty file rather than surface an error.

Fix

Preserve the prologue/epilogue: record the byte span of the <rustmotion> element in the original source and splice the re-serialized subtree back into it, or serialize the whole dom.document including the doctype. Make serialize_element return Result and propagate failures so a write is never performed on a partial buffer. Add a round-trip test on a full document with doctype/head/body/comments.

Evidence the audit read

pub fn set_inline_style(html: &str, pointer: &str, prop: &str, value: &str) -> Option<String> {
    let dom = parse_fragment_dom(html);
    let root = find_element(&dom.document, "rustmotion")?;
    let target = resolve_pointer(&root, pointer)?;
    set_style_attr(&target, prop, value)?;
    Some(serialize_element(&root))   // serializes ONLY the <rustmotion> subtree
}

Stacked on fix/html-text-children, which carries the previous finding of this workstream. GitHub shows only this finding's diff; merge in order.

Part of the September 2026 audit remediation chantier. Refs #220 (RM-12).

@LeadcodeDev LeadcodeDev added the bug Something isn't working label Sep 21, 2026
@LeadcodeDev LeadcodeDev self-assigned this Sep 21, 2026
@LeadcodeDev
LeadcodeDev force-pushed the fix/html-text-children branch from 8eb5453 to 7fced5c Compare September 22, 2026 06:11
@LeadcodeDev
LeadcodeDev force-pushed the fix/html-writeback-preserve branch from 4216009 to 4ad7a5f Compare September 22, 2026 06:11
@LeadcodeDev
LeadcodeDev force-pushed the fix/html-text-children branch from 7fced5c to 5b45306 Compare September 22, 2026 08:35
@LeadcodeDev
LeadcodeDev force-pushed the fix/html-writeback-preserve branch from 4ad7a5f to ce389f3 Compare September 22, 2026 08:35
@LeadcodeDev
LeadcodeDev force-pushed the fix/html-text-children branch from 5b45306 to 6717eb1 Compare September 22, 2026 08:45
@LeadcodeDev
LeadcodeDev force-pushed the fix/html-writeback-preserve branch from ce389f3 to 964b340 Compare September 22, 2026 08:45
@LeadcodeDev
LeadcodeDev changed the base branch from fix/html-text-children to chantier/audit-2026-09 September 22, 2026 08:53
@LeadcodeDev
LeadcodeDev force-pushed the fix/html-writeback-preserve branch from 964b340 to e23b14f Compare September 22, 2026 09:01
All four write-back entry points (`set_inline_style`, `set_text_content`, `set_attribute`, `remove_inline_style`) re-serialize only the `<rustmotion>` element, and rustmotion-studio writes that string straight over the source file (editor/inspector.rs:2168 -> `write_and_note(path, &updated)`). Executed: a 281-byte document with `<!DOCTYPE html>`, `<html><head><meta charset="utf-8"></head><body>`, a leading `<!-- authored by hand -->` comment and a trailing comment becomes 150 bytes — doctype, head, meta, body and both outer comments gone — after one font-size tweak in the inspector. The transpiler happily accepts such documents (`find_element` is a document-wide DFS), so this is a supported authoring form being destroyed. The docstring's "formatting is normalized" does not cover deleting the surrounding document. Secondarily, `serialize_element` (lib.rs:488-497) does `let _ = serialize(...)` and `String::from_utf8(buf).unwrap_or_default()`, so a serializer failure would write an empty file rather than surface an error.

Refs #220
@LeadcodeDev
LeadcodeDev force-pushed the fix/html-writeback-preserve branch from e23b14f to 92117e9 Compare September 22, 2026 09:06
@LeadcodeDev
LeadcodeDev merged commit fbf64bb into chantier/audit-2026-09 Sep 22, 2026
LeadcodeDev added a commit that referenced this pull request Sep 22, 2026
All four write-back entry points (`set_inline_style`, `set_text_content`, `set_attribute`, `remove_inline_style`) re-serialize only the `<rustmotion>` element, and rustmotion-studio writes that string straight over the source file (editor/inspector.rs:2168 -> `write_and_note(path, &updated)`). Executed: a 281-byte document with `<!DOCTYPE html>`, `<html><head><meta charset="utf-8"></head><body>`, a leading `<!-- authored by hand -->` comment and a trailing comment becomes 150 bytes — doctype, head, meta, body and both outer comments gone — after one font-size tweak in the inspector. The transpiler happily accepts such documents (`find_element` is a document-wide DFS), so this is a supported authoring form being destroyed. The docstring's "formatting is normalized" does not cover deleting the surrounding document. Secondarily, `serialize_element` (lib.rs:488-497) does `let _ = serialize(...)` and `String::from_utf8(buf).unwrap_or_default()`, so a serializer failure would write an empty file rather than surface an error.

Refs #220
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant