Skip to content

fix(sanitizer): merge sanitize rules for the same tag instead of overwriting them - #3041

Open
playlikeboy wants to merge 2 commits into
codex-team:nextfrom
playlikeboy:fix/2501-merge-sanitize-config
Open

playlikeboy wants to merge 2 commits into
codex-team:nextfrom
playlikeboy:fix/2501-merge-sanitize-config

Conversation

@playlikeboy

Copy link
Copy Markdown
Contributor

Resolves #2501

Problem

When several Inline Tools declare a sanitize rule for the same tag, the rules were combined with Object.assign, so the last tool to register silently overwrote the others. Example from the issue: one tool allows <span class> and another allows <span style>; only one of the two attributes survives, and content from the other tool is stripped on paste / save.

This happened in two places:

  • src/components/tools/block.ts (baseSanitizeConfig)
  • src/components/modules/tools.ts (getAllInlineToolsSanitizeConfig)

Change

  • New helper mergeSanitizerConfigs(...configs) in src/components/utils/sanitizer.ts that merges rules per tag and per attribute instead of replacing them. Semantics (documented in the JSDoc):
    • true on either side keeps the tag with all attributes;
    • false / undefined yields to the other side;
    • object + object = union of allowed attributes; when both declare the same attribute, two trues stay true, a function and anything else become one combined function, and two different attribute-string constraints become an OR check;
    • inputs are never mutated.
  • Both call sites use the helper. The block tool's own field rule in block.ts still takes precedence over the merged inline config (unchanged), as discussed on the issue.
  • package.json bumped to 2.32.0-rc.4 and a Fix line added to docs/CHANGELOG.md, following the pattern from fix(inline-toolbar): do not show "Convert to" when there is nothing to convert to #3040.

Tests

  • test/cypress/tests/sanitisation.cy.ts: two inline tools declaring different span attributes; both attributes survive.
  • test/cypress/tests/utils/sanitizer.cy.ts (new): 11 unit cases for the merge semantics above.

Locally: yarn lint (0 errors, same warning count as next), yarn build and yarn build:test pass. Cypress could not run on my machine (no Xvfb), so the Cypress specs were validated through a headless-Chrome harness against the built UMD bundle (reproduces the bug on next, passes with this change); CI will be the first full Cypress run and I will fix anything it reports.

Notes

  • types/configs/sanitizer-config.d.ts declares attribute values as boolean | string, while html-janitor also accepts functions; the helper handles that internally and I left the public type unchanged to keep the diff small. Happy to widen the type in this PR if you prefer.
  • Parts of this change were drafted with AI assistance (Claude Code); I reviewed and tested every line.

🤖 Generated with Claude Code

playlikeboy and others added 2 commits November 2, 2026 13:10
When several Inline Tools (or Block Tunes) declare sanitize rules for the
same tag, the configs were combined with Object.assign, so the last tool's
rule replaced the previous ones. Two tools that both wrap text in <span>
with different allowed attributes lost one set of attributes on save.

Add mergeSanitizerConfigs() which combines rules per tag: boolean, attribute
object and function rules are merged so that an attribute allowed by any
contributor stays allowed. Use it in BlockToolAdapter.baseSanitizeConfig and
Tools.getAllInlineToolsSanitizeConfig.

Closes codex-team#2501

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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The strict comparison in sanitizer.ts rejects truthy non-boolean predicate results, potentially stripping previously allowed attributes when rules are merged; boolean coercion and a regression test are needed.

1 open issue
What changed in this PR

This PR addresses #2501 by merging sanitizer rules from tools that share an HTML tag, preventing one tool’s allowed attributes from overwriting another’s.

Changes:

  • Adds per-tag and per-attribute merging and applies it to both sanitizer configuration collectors.
  • Adds unit and save-path regression tests for shared-tag rules.
  • Updates the release version and changelog.
File Description
test/​cypress/​tests/​utils/​sanitizer.cy.ts Adds 11 cases covering merge semantics.
test/​cypress/​tests/​sanitisation.cy.ts Tests saving attributes allowed by multiple inline tools.
src/​components/​utils/​sanitizer.ts Adds the shared sanitizer configuration merge helper.
src/​components/​tools/​block.ts Merges inline-tool and tune sanitizer rules.
src/​components/​modules/​tools.ts Merges sanitizer rules across all inline tools.
package.json Bumps the version to 2.32.0-rc.4.
docs/​CHANGELOG.md Documents the shared-tag sanitizer fix.

Review effort: Balanced

*/
function checkAttributeRule(rule: AttributeRule, value: string, node: Element): boolean {
if (_.isFunction(rule)) {
return rule(value, node) === true;

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Sanitize settings are corrupted if multiple inline tools specify the same tag

2 participants