Conversation
7 of 8 tasks
tommy230
force-pushed
the
fix/anchor-rel-single-attribute
branch
from
September 28, 2026 23:58
3395e38 to
2bde07a
Compare
base.link and base.button emitted the author's rel from the htmlAttributes bag and their own security rel as two separate attributes. Browsers keep the first, so a nofollow new-tab link published without noopener noreferrer, and the canvas showed a different rel than the page. The HTML importer also dropped every source rel on anchors as if the module regenerated it. The two anchor modules now merge the authored tokens with the security rel through one shared helper on both render paths, and the importer keeps rel. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tommy230
force-pushed
the
fix/anchor-rel-single-attribute
branch
from
September 29, 2026 04:45
2bde07a to
b67f1a9
Compare
tommy230
marked this pull request as ready for review
September 29, 2026 04:47
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A link or button anchor that carries its own
rel(typed into the Attributes view, or brought in by the HTML importer) is published with tworelattributes: the author's from thehtmlAttributesbag, then the module'snoopener noreferrerfortarget="_blank". A duplicate attribute is a parse error and the browser keeps the first one, so the new-tab guard is silently gone. The canvas does not show this: React lets the module'srelwin there, so the editor and the published page disagree.Modern browsers imply
noopenerfortarget="_blank", so in practice the loss isnoreferrerplus the editor/page mismatch. This is a hardening fix, not a vulnerability report.On import the opposite happens:
walkAndMap.tslistsrelas module-generated forbase.linkandbase.button, so every sourcerel(nofollow,sponsored,next/prev,me) is dropped, even though the module only ever regenerates the_blankguard. A theme that styles its pagination witha[rel="next"]loses that styling after import.The cause is that
render()and the*Editor.tsxof both modules serialiseanchorRel(target)next to the untouched bag instead of combining them.The fix:
mergeAnchorRel(authoredRel, target)insrc/modules/base/shared/anchorTarget.tsreturns one token list: the author's tokens, then the security rel, each once.anchorHtmlAttributes(bag, target)splitsrelout of the bag and merges it; both anchor modules use it on the publisher and canvas paths, so exactly onerelis emitted and it is the same in both._blankanchor always carriesnoopener noreferrer, whatever the author wrote.relon links and button anchors inhtmlAttributes.relvalue is HTML-escaped on the publisher path like every other bag attribute.Rich text and markdown links already emit a single
rel(sanitize.tsreplaces it,renderMarkdown.tswrites a fixed one), so only these two modules had the duplicate.Anchors without an authored
relpublish byte-identical markup (the render goldens are unchanged). Existing stored nodes with arelin the bag start publishing the merged value on their next publish.Overlaps with #575 on
shared/anchorTarget.tsanddocs/features/modules.md; whichever lands second gets a small rebase.Verification
bun run buildbun run lintbun test: 7060 pass, 0 failNew and updated tests, all failing on
mainand passing with this change:src/__tests__/base-modules-shared-render.test.ts: 4 render tests. They cannot load onmainbecausemergeAnchorReldoes not exist there.src/__tests__/base-modules-shared-render.editor.test.tsx: 2 editor tests.src/__tests__/htmlImport/mapping.test.ts: 2 importer tests, one of them the existing attribute-preservation test, which now keepsrel="nofollow".Checklist
docs/features/modules.mdanddocs/features/html-import.md.)🤖 Generated with Claude Code