From 4ca11034aad5dc8db095ea424b156b86b9d2b0ab Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Thu, 23 Apr 2026 13:35:47 +0200 Subject: [PATCH 1/2] [BUG] filesystem: skip symbolic links instead of aborting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `FlySystemAdapter::createForPath()` instantiates the Local/Flysystem adapter with the default link-handling mode, which is `DISALLOW_LINKS` in both `league/flysystem` v1 (`Adapter\Local`) and v3 (`Local\LocalFilesystemAdapter`). When the adapter's `listContents()` encounters any symbolic link during directory traversal it throws — v1: `League\Flysystem\NotSupportedException`, v3: `League\Flysystem\SymbolicLinkEncountered` — aborting the whole render. Concrete consumer impact ------------------------ `phpDocumentor\Guides\Handlers\ParseDirectoryHandler` calls `FlySystemAdapter::listContents()` to find the entrypoint of an input directory. A single symlink anywhere in the input tree kills the run, even for symlinks that point to files the parser would ignore anyway (e.g. `CLAUDE.md -> AGENTS.md` for AI tooling, vendored references, build artefacts). Downstream report in the TYPO3 render-guides wrapper: https://github.com/TYPO3-Documentation/render-guides/issues/1234 Fix --- Pass `SKIP_LINKS` as the link-handling constructor argument to both the v1 and v3 Local adapters. This preserves the current "do not follow links" posture but turns an abort into a silent skip — aligning with how most documentation builders treat filesystem entries they can't or shouldn't parse. - v1: `new Local($path, LOCK_EX, Local::SKIP_LINKS)` (positional, since v1's constructor predates named args; `LOCK_EX` is the library's own default for `$writeFlags`). - v3: `new LocalFilesystemAdapter($path, linkHandling: SKIP_LINKS)` (named arg, skipping the unchanged `$visibility` and `$writeFlags`). Verification ------------ The project has `FlySystemAdapter::createForPath` as its one code path for building filesystem instances from a local path, so this covers every entry point. Downstream reproducer (now green once shipped): ln -s AGENTS.md Documentation/CLAUDE.md docker run --rm -v "$PWD:/project" -w /project \ ghcr.io/typo3-documentation/render-guides:latest \ render --config=Documentation --output=out Documentation Signed-off-by: Sebastian Mendel --- packages/filesystem/src/FlySystemAdapter.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/filesystem/src/FlySystemAdapter.php b/packages/filesystem/src/FlySystemAdapter.php index 8b14497da..b3046dfc5 100644 --- a/packages/filesystem/src/FlySystemAdapter.php +++ b/packages/filesystem/src/FlySystemAdapter.php @@ -34,11 +34,11 @@ public static function createForPath(string $path): self { if (class_exists(Local::class)) { /** @phpstan-ignore-next-line */ - $filesystem = new FlysystemV1(new LeagueFilesystem(new Local($path))); + $filesystem = new FlysystemV1(new LeagueFilesystem(new Local($path, LOCK_EX, Local::SKIP_LINKS))); } else { $filesystem = new FlysystemV3( new LeagueFilesystem( - new LocalFilesystemAdapter($path), + new LocalFilesystemAdapter($path, linkHandling: LocalFilesystemAdapter::SKIP_LINKS), ), ); } From 30453afd15261924cded6a15d07b3a68006bbec5 Mon Sep 17 00:00:00 2001 From: Sebastian Mendel Date: Thu, 23 Apr 2026 13:46:36 +0200 Subject: [PATCH 2/2] fix(cs): import LOCK_EX via `use const` instead of fallback lookup PHPCS flagged the bare `LOCK_EX` reference in the v1 Local adapter constructor call as a fallback global name. Add `use const LOCK_EX` to match the repo's coding standard. Signed-off-by: Sebastian Mendel --- packages/filesystem/src/FlySystemAdapter.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/filesystem/src/FlySystemAdapter.php b/packages/filesystem/src/FlySystemAdapter.php index b3046dfc5..a0c9d13a0 100644 --- a/packages/filesystem/src/FlySystemAdapter.php +++ b/packages/filesystem/src/FlySystemAdapter.php @@ -23,6 +23,8 @@ use function class_exists; +use const LOCK_EX; + class FlySystemAdapter implements FileSystem { public function __construct(