fix: preserve same-space page links in Markdown#217
Merged
Conversation
Resolve page links using the containing page's space when Confluence storage omits `ri:space-key`. Preserve custom link body formatting and add regression coverage. Fixes #215
Pass the containing page base through same-space title lookups so scoped API clients produce browser URLs on the tenant origin while preserving a result's own base URL when supplied.
|
🎉 This PR is included in version 2.16.2 🎉 The release is available on: Your semantic-release bot 📦🚀 |
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.
What Changed
Risk Assessment
✅ Low: The change is well-bounded, preserves fallback behavior, limits lookups, and includes focused regression coverage.
Testing
Reviewed the issue intent and diff, ran focused and full regression tests, then verified an actual CLI read→update round-trip against a Confluence-compatible HTTP fixture; the internal link remained intact and the worktree stayed clean. As this is CLI behavior, the transcript and captured API payload provide the reviewer-visible evidence rather than a screenshot.
Evidence: CLI read/update round-trip
Read emitted a tenant-qualified Markdown link; update persisted the same linked URL.Evidence: Captured update payload
Evidence: CLI read output
Start here: [Target page](https://tenant.atlassian.net/wiki/spaces/ENG/pages/456/Target-page).Pipeline
Updates from git push no-mistakes
⏭️ **intent** - skipped
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
🔧 **Review** - 3 issues found → auto-fixed (7) ✅
lib/confluence-client.js:668- The resolver replaces every page link, including references inside include/shared-block macro parameters. This destroys the structure required by StorageWalker, causing macro output to disappear or lose semantics. Skip semantic macro-parameter links.lib/confluence-client.js:715- Fallback titles and custom bodies enter a Markdown link label without Markdown escaping. A crafted title such asevil](https://attacker) [xcan inject another link, regressing the converter’s existing escaping invariant.lib/confluence-client.js:697- All unique link lookups run concurrently. Pages with many same-space links can create a large request burst, trigger rate limits, and silently leave links unresolved because lookup errors are swallowed. Apply bounded concurrency.🔧 Fix: fix: harden same-space page link resolution
2 warnings still open:
lib/confluence-client.js:706- Recursive DOM traversal bypasses StorageWalker’s depth guard. Pathologically nested storage can throw a native stack overflow before the controlled StorageDepthExceededError. Use iterative traversal or enforce the same depth limit.lib/storage-walker.js:136- Link-label escaping is context-blind and incomplete: plain*text*becomes unintended emphasis, while[x]inside<code>gains visible backslashes. Escape literal Markdown syntax outside code spans while preserving markup emitted by inline element handlers.🔧 Fix: fix: harden deep page-link rendering
1 warning still open:
lib/storage-walker.js:183- Code text bypasses escaping, but code spans always use one backtick. A label containing a backtick plus](can leave the span unmatched and inject a sibling Markdown link. Use a delimiter longer than the longest backtick run.🔧 Fix: Harden inline code spans against Markdown link injection
1 warning still open:
lib/confluence-client.js:747- Lenient parsing assigns EOF asendIndexfor an unclosed<ac:link>, so replacement can delete the remainder of malformed storage and bypass StorageWalker’s warning path. Only replace explicitly closed link nodes.🔧 Fix: Preserve malformed page links without dropping trailing content
1 warning still open:
lib/storage-walker.js:136- Link-label escaping only covers text nodes. Attribute-derived inline content such as<time datetime="x](https://attacker) [y">bypasses escaping and can terminate a resolved page-link label. Escape every attribute-derived fragment emitted while_markdownLinkLabelDepthis active.🔧 Fix: Escape datetime content in Markdown link labels
1 warning still open:
lib/confluence-client.js:451- Only the space key reaches the resolver. Title-search result items omit_links.base, so scoped clients fall back tohttps://api.atlassian.com/wiki/...instead of the tenant URL. Pass the containing page’s_links.basethrough the lookup. See the Atlassian response examples.🔧 Fix: Preserve tenant origins for scoped page links
1 warning still open:
lib/confluence-client.js:770- Resolved links copy rich bodies into<a>unchanged. An embeddedac:imagecan emit an unescaped filename or URL that closes the Markdown label and injects another link. Make image rendering honor link-label escaping.🔧 Fix: Escape images in resolved Markdown link labels
✅ Re-checked - no issues remain.
✅ **Test** - passed
✅ No issues found.
gh-axi issue view 215 --fullnpm test -- --runInBand tests/confluence-client.test.jsnode /var/folders/mm/mzvsb9xn40vd3pqkp4y8n_sm0000gn/T/no-mistakes-evidence/01KXJVGBVYCC6BB1P3KV9A7Y6T/cli-roundtrip-e2e.jsnpm test -- --runInBandgit status --short --untracked-files=all✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.