Repository navigation
fix(includes): catch a file that includes itself through a symlink - #1339
Merged
Merged
Conversation
Merging this PR will not alter performance
Comparing Footnotes
|
IncludeReader::read and Storage::read_include return the file's canonical project path with its text, and the walker finds cycles by it, so `a.md` including `link.md -> a.md` warns on the first repeat instead of rendering a.md once more. Warnings and relative paths keep the written spelling. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
yumike
force-pushed
the
fix/include-cycle-identity
branch
from
October 29, 2026 03:55
7371a97 to
28a4eda
Compare
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
Spec PR 6 (case-sensitive paths, "Include cycles"). A file that includes itself through a symlink is now caught on its first repeat. Before,
a.mdincludinglink.md -> a.mdrendered a.md's body once more before the written-path check caught it. When the path differed at every level, only the 64-include cap stopped it.IncludeReader::readreturnsIncludedFile { text, canonical_path }, andStorage::read_includereturnsIncludeTextwith the same fields.FsStorage::confinenow returns the canonical file and its path relative to the canonical project. The samestrip_prefixis the inside-the-project check, so the relative path has no fallback. The mock storage, the S3 published map and the test readers return the path they were given.include `docs/link.md` is `docs/a.md`, which includes itself. Warnings,RenderResult::includesand relative-path resolution keep the written spelling.Source.rw-siteincluded_files) now collect only the includes the render kept (RenderResult::includes). Before, a file the walker read and then refused, as a cycle or past the byte cap, still had its links resolved from the refused path. Withdocs/sub/link.md -> ../a.md, a.md's[r](report.pdf)allowlisteddocs/sub/report.pdf, which no rendered page links.Validation
a_file_that_includes_itself_through_a_symlink_is_caught_on_its_first_repeat. An in-memory reader maps link paths to their targets (runs on every OS) and covers a page aliasing itself, a file aliasing itself directly and through another file, and an exact repeat reached through a link. It also asserts that each file is read once. With the canonical check disabled, this test fails.read_includethroughdocs/alias.md -> index.mdand a symlinked folderdocs/shared -> ../partialsreportsdocs/index.mdandpartials/note.md. Non-symlinked reads report their own path.a_page_that_includes_itself_through_a_symlink_renders_once. With a realdocs/link.md -> a.md, the page rendersOnce.once and warns as a cycle. With the canonical check disabled, it fails: the body renders twice and the exact-repeat warning comes one level deeper.an_include_refused_as_a_cycle_links_nothing.docs/report.pdfis served anddocs/sub/report.pdfis not. Without theRenderResult::includesfilter, this test fails.make test,make lintandmake formatpass. No e2e tests were run.🤖 Generated with Claude Code