Skip to content

fix(html): reject unknown scene attributes instead of dropping them - #252

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

LeadcodeDev merged 1 commit into
chantier/audit-2026-09from
fix/html-unknown-attributes

Conversation

@LeadcodeDev

Copy link
Copy Markdown
Owner

Severity Medium, category coherence. Location: crates/rustmotion-html/src/scene.rs:20

Impact

Executed: <scene duration="2" freeze_at="1" world-position="0,0" animated-background="halo"> transpiles to a scene carrying only duration and layout — three documented scene features (CLAUDE.md documents all three) are discarded with no warning and validate exits 0. Same on the root: <rustmotion codec="prores" durationn="5"> drops both. Same on containers/text: <div gap="32" width="400" id="x"> keeps nothing but style/anim (element.rs:101-112 and :92-100 never iterate attrs). This is the exact failure mode check_component_attrs exists to prevent, but that check runs on the already-transpiled ResolvedScenario (validate_attrs.rs:79 check_component_attrs(scenario: &ResolvedScenario)) and only over scene.children — an attribute the transpiler never emitted is invisible to it, so the workspace's only unknown-attribute net has a blind spot precisely over the HTML front-end's own attribute surface. rm-* custom elements are the asymmetric exception: they forward everything and do get caught.

Fix

After reading the known keys in scene_to_value and html_to_scenario_value, diff against the consumed set and return a named error (with did-you-mean, mirroring validate_attrs) for the remainder — class/id/data-* can be allowlisted as deliberately inert. Do the same for TagKind::Container/TagKind::Text. Separately, extend <scene>'s allowlist to cover freeze_at, world-position and animated-background, which are otherwise unreachable from HTML.

Evidence the audit read

let attrs = element_attrs(handle);
    let get = |k: &str| attrs.iter().find(|(n, _)| n == k).map(|(_, v)| v.clone());

    let duration = get("duration").ok_or(HtmlError::MissingDuration)?;
// only duration/align/justify/direction/gap/padding/background/effects/
// transition{,-duration,-easing} are ever read; nothing iterates `attrs`
// to report the leftovers.

Based directly on the chantier branch.

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

@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-unknown-attributes branch 2 times, most recently from 122c9ec to 838dc53 Compare September 22, 2026 08:35
Executed: <scene duration="2" freeze_at="1" world-position="0,0" animated-
background="halo"> transpiles to a scene carrying only duration and layout —
three documented scene features (CLAUDE.md documents all three) are
discarded with no warning and validate exits 0. Same on the root:
<rustmotion codec="prores" durationn="5"> drops both. Same on
containers/text: <div gap="32" width="400" id="x"> keeps nothing but
style/anim (element.rs:101-112 and :92-100 never iterate attrs). This is the
exact failure mode check_component_attrs exists to prevent, but that check
runs on the already-transpiled ResolvedScenario (validate_attrs.rs:79
check_component_attrs(scenario: &ResolvedScenario)) and only over
scene.children — an attribute the transpiler never emitted is invisible to
it, so the workspace's only unknown-attribute net has a blind spot precisely
over the HTML front-end's own attribute surface. rm-* custom elements are
the asymmetric exception: they forward everything and do get caught.

Fix: After reading the known keys in scene_to_value and
html_to_scenario_value, diff against the consumed set and return a named
error (with did-you-mean, mirroring validate_attrs) for the remainder —
class/id/data-* can be allowlisted as deliberately inert. Do the same for
TagKind::Container/TagKind::Text. Separately, extend <scene>'s allowlist to
cover freeze_at, world-position and animated-background, which are otherwise
unreachable from HTML.

Refs #220
@LeadcodeDev
LeadcodeDev force-pushed the fix/html-unknown-attributes branch from 838dc53 to 6b6c8d9 Compare September 22, 2026 08:45
@LeadcodeDev
LeadcodeDev merged commit 1952295 into chantier/audit-2026-09 Sep 22, 2026
3 checks passed
@LeadcodeDev
LeadcodeDev deleted the fix/html-unknown-attributes branch September 22, 2026 08:53
LeadcodeDev added a commit that referenced this pull request Sep 22, 2026
…252)

Executed: <scene duration="2" freeze_at="1" world-position="0,0" animated-
background="halo"> transpiles to a scene carrying only duration and layout —
three documented scene features (CLAUDE.md documents all three) are
discarded with no warning and validate exits 0. Same on the root:
<rustmotion codec="prores" durationn="5"> drops both. Same on
containers/text: <div gap="32" width="400" id="x"> keeps nothing but
style/anim (element.rs:101-112 and :92-100 never iterate attrs). This is the
exact failure mode check_component_attrs exists to prevent, but that check
runs on the already-transpiled ResolvedScenario (validate_attrs.rs:79
check_component_attrs(scenario: &ResolvedScenario)) and only over
scene.children — an attribute the transpiler never emitted is invisible to
it, so the workspace's only unknown-attribute net has a blind spot precisely
over the HTML front-end's own attribute surface. rm-* custom elements are
the asymmetric exception: they forward everything and do get caught.

Fix: After reading the known keys in scene_to_value and
html_to_scenario_value, diff against the consumed set and return a named
error (with did-you-mean, mirroring validate_attrs) for the remainder —
class/id/data-* can be allowlisted as deliberately inert. Do the same for
TagKind::Container/TagKind::Text. Separately, extend <scene>'s allowlist to
cover freeze_at, world-position and animated-background, which are otherwise
unreachable from HTML.

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