Skip to content

Replace Path.Combine with Path.Join#2997

Merged
Mpdreamz merged 5 commits intomainfrom
feature/path-join
Mar 30, 2026
Merged

Replace Path.Combine with Path.Join#2997
Mpdreamz merged 5 commits intomainfrom
feature/path-join

Conversation

@Mpdreamz
Copy link
Copy Markdown
Member

Summary

  • Replaces all 157 usages of Path.Combine with Path.Join across 103 C# files (src, tests, integration tests)
  • Path.Join is preferred because it does not treat absolute path segments as rooted, avoiding potential path traversal issues (see Need Span based path join API dotnet/runtime#24263)
  • System.IO.Abstractions v22.1.0 in use supports IPath.Join

Test plan

  • Build passes with no compilation errors
  • Run unit tests

🤖 Generated with Claude Code

Path.Join is preferred over Path.Combine because it does not treat
absolute path segments as rooted, preventing potential path traversal
issues. See dotnet/runtime#24263

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@Mpdreamz Mpdreamz requested a review from a team as a code owner March 30, 2026 11:55
@Mpdreamz Mpdreamz requested a review from reakaleek March 30, 2026 11:55
@Mpdreamz Mpdreamz added the fix label Mar 30, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 30, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6ac34050-9903-4b2a-9014-0d6d4cb89f49

📥 Commits

Reviewing files that changed from the base of the PR and between 55b616d and 4dc0e12.

📒 Files selected for processing (1)
  • src/services/Elastic.Documentation.Assembler/Sourcing/RepositorySourcesFetcher.cs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/services/Elastic.Documentation.Assembler/Sourcing/RepositorySourcesFetcher.cs

📝 Walkthrough

Walkthrough

This PR replaces many uses of Path.Combine/fs.Path.Combine with Path.Join/fs.Path.Join across source and test files, altering path-segmentation behavior consistently. It adds Elastic.Documentation.Extensions.UrlPath with Join and JoinUrl helpers and introduces Paths.ValidateSinglePathSegment. Several places add or tighten path-containment and relative-path validation (e.g., GitLinkIndexReader, StaticWebHost, DocumentationWebHost). Control flow, public APIs, and error handling are otherwise preserved.

Sequence Diagram(s)

sequenceDiagram
  participant Client as Client (HTTP)
  participant Host as StaticWebHost
  participant FS as FileSystem
  participant Res as Result

  Client->>Host: GET /<slug>
  Host->>Host: normalize contentRoot (Path.GetFullPath)
  Host->>Host: build localPath = Path.Join(contentRoot, slug or slug/index.html)
  Host->>Host: resolve fullLocalPath = Path.GetFullPath(localPath)
  Host->>FS: FileExists(fullLocalPath)?
  alt not inside contentRoot (traversal)
    Host->>Res: Results.NotFound()
    Res-->>Client: 404 Not Found
  else file exists
    Host->>FS: OpenRead(fullLocalPath)
    FS-->>Host: Stream
    Host-->>Client: 200 OK with file stream
  end
Loading

Suggested labels

enhancement

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.30% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the primary change: replacing Path.Combine with Path.Join across the codebase.
Description check ✅ Passed The description is directly related to the changeset, explaining the rationale, scope (157 usages across 103 files), and the security motivation for preferring Path.Join.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feature/path-join

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/services/Elastic.Changelog/Rendering/BundleValidationService.cs (1)

243-247: ⚠️ Potential issue | 🟠 Major

Validate file path references against bundle directory boundary.

Line 243 joins untrusted entry.File.Name (sourced from bundle YAML) directly without containment checks. Path.Join preserves .. segments—an attacker can craft entry.File.Name: ../../../etc/passwd to escape bundleDirectory. No tests exist for this scenario, and no validation guards follow the join.

Suggested fix
-		var filePath = fileSystem.Path.Join(bundleDirectory, entry.File.Name);
+		var bundleRoot = fileSystem.Path.GetFullPath(bundleDirectory);
+		var filePath = fileSystem.Path.GetFullPath(fileSystem.Path.Join(bundleRoot, entry.File.Name));
+		var relativePath = fileSystem.Path.GetRelativePath(bundleRoot, filePath);
+		if (relativePath.StartsWith("..", StringComparison.Ordinal) || fileSystem.Path.IsPathRooted(relativePath))
+		{
+			collector.EmitError(bundleFile, $"Referenced changelog file '{entry.File.Name}' resolves outside bundle directory");
+			return false;
+		}
 		if (!fileSystem.File.Exists(filePath))
 		{
 			collector.EmitError(bundleFile, $"Referenced changelog file '{entry.File.Name}' does not exist at path: {filePath}");
 			return false;
 		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/services/Elastic.Changelog/Rendering/BundleValidationService.cs` around
lines 243 - 247, The code builds filePath by joining bundleDirectory and
untrusted entry.File.Name without containment checks, allowing path traversal;
update the validation in BundleValidationService (around filePath,
bundleDirectory, entry.File.Name usage) to compute canonical/absolute paths
(e.g., Path.GetFullPath on both bundleDirectory and the joined path), reject if
the resulting filePath is outside the bundleDirectory boundary or if
entry.File.Name is an absolute path, and call collector.EmitError with a clear
message and return false when the check fails; ensure the containment check is
robust to OS path-casing rules and trailing separators before proceeding to
File.Exists.
🧹 Nitpick comments (1)
src/services/Elastic.Documentation.Assembler/Configuration/ConfigurationCloneService.cs (1)

68-68: Use fs.Path.Join for consistency with the file system abstraction.

The rest of this file uses the injected FileSystem fs abstraction (fs.DirectoryInfo, fs.File, fs.Directory), but this line uses the static Path.Join. For testability and consistency, use the abstraction.

Suggested fix
-		var gitRefInformationFile = Path.Join(checkoutFolder.FullName, "config", "git-ref.txt");
+		var gitRefInformationFile = fs.Path.Join(checkoutFolder.FullName, "config", "git-ref.txt");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/services/Elastic.Documentation.Assembler/Configuration/ConfigurationCloneService.cs`
at line 68, Replace the static System.IO.Path.Join usage with the injected file
system abstraction to keep testability consistent: in ConfigurationCloneService,
change the creation of the gitRefInformationFile variable (named
gitRefInformationFile) to use the injected FileSystem (fs.Path.Join) instead of
Path.Join, keeping the same inputs (checkoutFolder.FullName and
"config/git-ref.txt") so the rest of the method continues to operate against the
FileSystem abstraction.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/Elastic.Documentation.LinkIndex/GitLinkIndexReader.cs`:
- Around line 52-54: The current check only blocks rooted paths but allows '..'
to traverse out of CloneDirectory; update the validation in GitLinkIndexReader
to compute the absolute path of the joined path (e.g.,
Path.GetFullPath(Path.Join(CloneDirectory, _environment, "link-index.json"))),
compute the absolute path of CloneDirectory, and ensure the file path starts
with the CloneDirectory full path (or otherwise rejects when the resolved path
is outside CloneDirectory); also apply the same fix to the other block that
constructs the path (lines referencing Path.Join and _environment around the
66–69 area). Ensure you still keep rejecting rooted inputs and fold both checks
into the same secure full-path containment validation.

In `@src/Elastic.Markdown/Extensions/DetectionRules/DetectionRuleFile.cs`:
- Around line 113-116: The relative path trimming only checks for "../" (using
Path.GetRelativePath result), which fails on Windows where the parent-separator
is "..\..."; update the logic that computes relative (the variable from
Path.GetRelativePath(rulePath.FullName, build.OutputDirectory.FullName) or
equivalent) to detect and remove a leading parent-directory segment using both
separators (e.g., check StartsWith("../") OR StartsWith("..\\") or normalize
separators via Path.DirectorySeparatorChar/Path.AltDirectorySeparatorChar)
before calling Path.Join to produce newPath; ensure the check references the
existing variables relative, rulePath and build.OutputDirectory and preserves
cross-platform behavior.

In `@src/Elastic.Markdown/HtmlWriter.cs`:
- Around line 83-90: The code uses Path.Join (filesystem paths) to build URLs
which yields backslashes on Windows; update the URL construction in the
HtmlWriter to use URL-safe forward‑slash concatenation instead of Path.Join:
build the editUrl by joining relativeSourcePath and markdown.RelativePath with
"/" (not Path.Join) before interpolating into editUrl, and when creating
reportLinkParameter/reportUrl join DocumentationSet.Context.UrlPathPrefix and
current.Url with "/" (or normalize to ensure a single leading/trailing slash) so
the Uri and GitHub link are valid across platforms; adjust any related helpers
in HtmlWriter.cs that produce these strings.

In
`@src/services/Elastic.Documentation.Assembler/Sourcing/RepositorySourcesFetcher.cs`:
- Line 38: The code builds filesystem paths using repo.Name (e.g., when creating
checkoutFolder via Path.Join) without validating or sanitizing it, which allows
path traversal like "../outside"; update the logic that uses repo.Name in
RepositorySourcesFetcher (the checkoutFolder and the other Path.Join usage) to
validate or sanitize the name before joining: reject or normalize names
containing path-separators or "..", or replace repo.Name with
Path.GetFileName(repo.Name) (or a safe-sanitization function) and throw/log an
error for invalid values so callers cannot escape the intended checkout
directory. Ensure the same validation is applied to both places where repo.Name
is joined into paths.

In `@src/tooling/docs-builder/Http/DocumentationWebHost.cs`:
- Around line 216-217: The code builds a file path from user-controlled slug and
then reads it; to prevent path traversal ensure the resolved path stays inside
holder.ApiPath.FullName: after joining holder.ApiPath.FullName and slug (and
"index.html"), call Path.GetFullPath on the resulting path and also
Path.GetFullPath on holder.ApiPath.FullName (append a trailing separator) and
verify the resolved path starts with the canonical base path; if it does not,
reject the request (return 404/forbidden) instead of calling
_writeFileSystem.FileInfo.New(path). Update the logic in DocumentationWebHost
where path is constructed (the block using holder.ApiPath.FullName,
slug.Trim('/'), and _writeFileSystem.FileInfo.New) to perform this
canonicalization and containment check before any file reads.

In `@src/tooling/docs-builder/Http/StaticWebHost.cs`:
- Around line 114-118: The code constructs localPath from user-controlled slug
and may allow path traversal; compute the canonical absolute paths using
Path.GetFullPath for both the joined slug path and _contentRoot, normalize
separators, then verify the slug-derived full path starts with the content-root
full path (use StringComparison.OrdinalIgnoreCase on Windows) before creating
FileInfo/DirectoryInfo or reading files; if the check fails, treat it as not
found or return a 403/404 instead of accessing the filesystem (also apply the
same check when resolving index.html).

In `@tests-integration/Elastic.Assembler.IntegrationTests/SiteNavigationTests.cs`:
- Line 54: The code uses redundant nested Path.Join calls in the expression
fs.DirectoryInfo.New(fs.Path.Join(Path.Join(CheckoutDirectory.FullName, name)));
— simplify by removing the inner Path.Join and pass both segments to
fs.Path.Join directly (e.g., change to
fs.DirectoryInfo.New(fs.Path.Join(CheckoutDirectory.FullName, name))); so the
path is built in one call; update the expression where it appears (the
fs.DirectoryInfo.New(...) invocation) accordingly.

---

Outside diff comments:
In `@src/services/Elastic.Changelog/Rendering/BundleValidationService.cs`:
- Around line 243-247: The code builds filePath by joining bundleDirectory and
untrusted entry.File.Name without containment checks, allowing path traversal;
update the validation in BundleValidationService (around filePath,
bundleDirectory, entry.File.Name usage) to compute canonical/absolute paths
(e.g., Path.GetFullPath on both bundleDirectory and the joined path), reject if
the resulting filePath is outside the bundleDirectory boundary or if
entry.File.Name is an absolute path, and call collector.EmitError with a clear
message and return false when the check fails; ensure the containment check is
robust to OS path-casing rules and trailing separators before proceeding to
File.Exists.

---

Nitpick comments:
In
`@src/services/Elastic.Documentation.Assembler/Configuration/ConfigurationCloneService.cs`:
- Line 68: Replace the static System.IO.Path.Join usage with the injected file
system abstraction to keep testability consistent: in ConfigurationCloneService,
change the creation of the gitRefInformationFile variable (named
gitRefInformationFile) to use the injected FileSystem (fs.Path.Join) instead of
Path.Join, keeping the same inputs (checkoutFolder.FullName and
"config/git-ref.txt") so the rest of the method continues to operate against the
FileSystem abstraction.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9c25fdfa-eb08-452e-9b5e-b65cbe2bbf29

📥 Commits

Reviewing files that changed from the base of the PR and between 61dd902 and 9e348b0.

📒 Files selected for processing (103)
  • src/Elastic.ApiExplorer/OpenApiGenerator.cs
  • src/Elastic.Codex/Building/CodexBuildService.cs
  • src/Elastic.Codex/CodexContext.cs
  • src/Elastic.Codex/CodexGenerator.cs
  • src/Elastic.Codex/Sourcing/CodexCloneService.cs
  • src/Elastic.Codex/Sourcing/CodexGitRepository.cs
  • src/Elastic.Documentation.Configuration/Assembler/AssemblyConfiguration.cs
  • src/Elastic.Documentation.Configuration/BuildContext.cs
  • src/Elastic.Documentation.Configuration/Builder/ConfigurationFile.cs
  • src/Elastic.Documentation.Configuration/Builder/RedirectFile.cs
  • src/Elastic.Documentation.Configuration/ConfigurationFileProvider.cs
  • src/Elastic.Documentation.Configuration/Paths.cs
  • src/Elastic.Documentation.Configuration/ReleaseNotes/BundleLoader.cs
  • src/Elastic.Documentation.Configuration/Toc/DocumentationSetFile.cs
  • src/Elastic.Documentation.LegacyDocs/LegacyPageService.cs
  • src/Elastic.Documentation.LegacyDocs/PagesProvider.cs
  • src/Elastic.Documentation.LinkIndex/GitLinkIndexReader.cs
  • src/Elastic.Documentation.Links/CrossLinks/CrossLinkFetcher.cs
  • src/Elastic.Documentation.Links/InboundLinks/LinkIndexLinkChecker.cs
  • src/Elastic.Documentation.Navigation/Isolated/Node/DocumentationSetNavigation.cs
  • src/Elastic.Documentation.Site/FileProviders/EmbeddedOrPhysicalFileProvider.cs
  • src/Elastic.Documentation/Extensions/IFileInfoExtensions.cs
  • src/Elastic.Documentation/GitCheckoutInformation.cs
  • src/Elastic.Markdown/DocumentationGenerator.cs
  • src/Elastic.Markdown/Exporters/ConfigurationExporter.cs
  • src/Elastic.Markdown/Exporters/LlmMarkdownExporter.cs
  • src/Elastic.Markdown/Extensions/DetectionRules/DetectionRule.cs
  • src/Elastic.Markdown/Extensions/DetectionRules/DetectionRuleFile.cs
  • src/Elastic.Markdown/HtmlWriter.cs
  • src/Elastic.Markdown/IO/DocumentationSet.cs
  • src/Elastic.Markdown/Myst/Directives/CsvInclude/CsvIncludeBlock.cs
  • src/Elastic.Markdown/Myst/Directives/Include/IncludeBlock.cs
  • src/Elastic.Markdown/Myst/Directives/Settings/SettingsBlock.cs
  • src/Elastic.Markdown/Myst/InlineParsers/DiagnosticLinkInlineParser.cs
  • src/authoring/Elastic.Documentation.Refactor/Move.cs
  • src/authoring/Elastic.Documentation.Refactor/Tracking/LocalChangesService.cs
  • src/services/Elastic.Changelog/Bundling/ChangelogBundleAmendService.cs
  • src/services/Elastic.Changelog/Bundling/ChangelogBundlingService.cs
  • src/services/Elastic.Changelog/Bundling/ChangelogRemoveService.cs
  • src/services/Elastic.Changelog/Configuration/ChangelogConfigurationLoader.cs
  • src/services/Elastic.Changelog/Creation/ChangelogFileWriter.cs
  • src/services/Elastic.Changelog/Evaluation/ChangelogPrEvaluationService.cs
  • src/services/Elastic.Changelog/GithubRelease/GitHubReleaseChangelogService.cs
  • src/services/Elastic.Changelog/Rendering/Asciidoc/ChangelogAsciidocRenderer.cs
  • src/services/Elastic.Changelog/Rendering/BundleDataResolver.cs
  • src/services/Elastic.Changelog/Rendering/BundleValidationService.cs
  • src/services/Elastic.Changelog/Rendering/FeatureHidingLoader.cs
  • src/services/Elastic.Changelog/Rendering/Markdown/MarkdownRendererBase.cs
  • src/services/Elastic.Documentation.Assembler/AssembleContext.cs
  • src/services/Elastic.Documentation.Assembler/Building/AssemblerBuildService.cs
  • src/services/Elastic.Documentation.Assembler/Building/AssemblerBuilder.cs
  • src/services/Elastic.Documentation.Assembler/Building/SitemapBuilder.cs
  • src/services/Elastic.Documentation.Assembler/Configuration/ConfigurationCloneService.cs
  • src/services/Elastic.Documentation.Assembler/Deploying/Synchronization/AwsS3SyncApplyStrategy.cs
  • src/services/Elastic.Documentation.Assembler/Deploying/Synchronization/AwsS3SyncPlanStrategy.cs
  • src/services/Elastic.Documentation.Assembler/Navigation/AssemblerDocumentationSet.cs
  • src/services/Elastic.Documentation.Assembler/Navigation/GlobalNavigationPathProvider.cs
  • src/services/Elastic.Documentation.Assembler/Navigation/NavigationPrefixChecker.cs
  • src/services/Elastic.Documentation.Assembler/Sourcing/GitFacade.cs
  • src/services/Elastic.Documentation.Assembler/Sourcing/RepositorySourcesFetcher.cs
  • src/services/Elastic.Documentation.Isolated/IsolatedBuildService.cs
  • src/tooling/docs-builder/Arguments/BundleInputParser.cs
  • src/tooling/docs-builder/Commands/ChangelogCommand.cs
  • src/tooling/docs-builder/Commands/Codex/CodexCommands.cs
  • src/tooling/docs-builder/Filters/CheckForUpdatesFilter.cs
  • src/tooling/docs-builder/Http/DocumentationWebHost.cs
  • src/tooling/docs-builder/Http/LiveReload.cs
  • src/tooling/docs-builder/Http/ParcelWatchService.cs
  • src/tooling/docs-builder/Http/ReloadableGeneratorState.cs
  • src/tooling/docs-builder/Http/StaticWebHost.cs
  • tests-integration/Elastic.Assembler.IntegrationTests/AssemblerConfigurationTests.cs
  • tests-integration/Elastic.Assembler.IntegrationTests/DocsSyncTests.cs
  • tests-integration/Elastic.Assembler.IntegrationTests/SiteNavigationTests.cs
  • tests/Elastic.Changelog.Tests/Changelogs/BundleAmendTests.cs
  • tests/Elastic.Changelog.Tests/Changelogs/BundleChangelogsTests.cs
  • tests/Elastic.Changelog.Tests/Changelogs/BundleProfileGitHubReleaseTests.cs
  • tests/Elastic.Changelog.Tests/Changelogs/BundleReleaseVersionTests.cs
  • tests/Elastic.Changelog.Tests/Changelogs/ChangelogConfigurationTests.cs
  • tests/Elastic.Changelog.Tests/Changelogs/ChangelogRemoveTests.cs
  • tests/Elastic.Changelog.Tests/Changelogs/Create/CreateChangelogTestBase.cs
  • tests/Elastic.Changelog.Tests/Changelogs/Create/PrIntegrationTests.cs
  • tests/Elastic.Changelog.Tests/Changelogs/Create/ReleaseVersionTests.cs
  • tests/Elastic.Changelog.Tests/Changelogs/RemoveReleaseVersionTests.cs
  • tests/Elastic.Changelog.Tests/Changelogs/Render/BasicRenderTests.cs
  • tests/Elastic.Changelog.Tests/Changelogs/Render/BundleValidationTests.cs
  • tests/Elastic.Changelog.Tests/Changelogs/Render/ChecksumValidationTests.cs
  • tests/Elastic.Changelog.Tests/Changelogs/Render/DuplicateHandlingTests.cs
  • tests/Elastic.Changelog.Tests/Changelogs/Render/ErrorHandlingTests.cs
  • tests/Elastic.Changelog.Tests/Changelogs/Render/HideFeaturesTests.cs
  • tests/Elastic.Changelog.Tests/Changelogs/Render/HighlightsRenderTests.cs
  • tests/Elastic.Changelog.Tests/Changelogs/Render/OutputFormatTests.cs
  • tests/Elastic.Changelog.Tests/Changelogs/Render/TitleTargetTests.cs
  • tests/Elastic.Documentation.Build.Tests/SitemapTests.cs
  • tests/Elastic.Documentation.Configuration.Tests/PhysicalDocsetTests.cs
  • tests/Elastic.Documentation.Configuration.Tests/VersionInferenceTests.cs
  • tests/Elastic.Markdown.Tests/Directives/DirectiveBaseTests.cs
  • tests/Elastic.Markdown.Tests/DocSet/BreadCrumbTests.cs
  • tests/Elastic.Markdown.Tests/DocSet/NestedTocTests.cs
  • tests/Elastic.Markdown.Tests/MockFileSystemExtensions.cs
  • tests/Elastic.Markdown.Tests/Mover/MoverTests.cs
  • tests/Elastic.Markdown.Tests/SettingsInclusion/IncludeTests.cs
  • tests/Navigation.Tests/Isolation/FileInfoValidationTests.cs
  • tests/Navigation.Tests/Isolation/PhysicalDocsetTests.cs

Comment thread src/Elastic.Documentation.LinkIndex/GitLinkIndexReader.cs Outdated
Comment thread src/Elastic.Markdown/Extensions/DetectionRules/DetectionRuleFile.cs
Comment thread src/Elastic.Markdown/HtmlWriter.cs Outdated
Comment thread src/tooling/docs-builder/Http/DocumentationWebHost.cs Outdated
Comment thread src/tooling/docs-builder/Http/StaticWebHost.cs Outdated
Comment thread tests-integration/Elastic.Assembler.IntegrationTests/SiteNavigationTests.cs Outdated
@reakaleek reakaleek self-requested a review March 30, 2026 12:48
…RemoveService

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai coderabbitai bot added chore and removed fix labels Mar 30, 2026
… fixes, and shared utilities

- Add UrlPath static class for URL-safe path joining (always '/', normalises backslashes)
- Add Paths.ValidateSinglePathSegment shared utility; remove duplicated copies
- GitLinkIndexReader: replace IsPathRooted check with full-path containment
  validation to block '..' traversal segments
- DetectionRuleFile: handle Windows path separator in relative path prefix trim
- HtmlWriter: use UrlPath.Join/JoinUrl instead of Path.Join for URL construction
- RepositorySourcesFetcher: use Paths.ValidateSinglePathSegment before joining
  repo.Name into filesystem paths
- DocumentationWebHost: verify slug-derived path stays under ApiPath
- StaticWebHost: verify slug-derived path stays under content root
- SiteNavigationTests: remove redundant nested Path.Join call

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai coderabbitai bot added enhancement and removed chore labels Mar 30, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/services/Elastic.Documentation.Assembler/Sourcing/RepositorySourcesFetcher.cs`:
- Around line 139-146: The CloneRef method in RepositorySourcesFetcher drops
non-default flags when it retries (appendRepositoryName and assumeCloned),
causing retries to use different checkoutFolder and behavior; update all retry
paths inside CloneRef (and any recursive/internal retry calls referenced around
CloneRef) to forward the original appendRepositoryName and assumeCloned
parameters (and pull/attempt as appropriate) so the same checkoutFolder
resolution is used on retry, and ensure any constructed checkoutFolder uses
those forwarded values rather than defaulting.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 7e71ace6-13b1-45b0-bb64-c639208579fe

📥 Commits

Reviewing files that changed from the base of the PR and between cfb912c and 428bb3e.

📒 Files selected for processing (9)
  • src/Elastic.Documentation.Configuration/Paths.cs
  • src/Elastic.Documentation.LinkIndex/GitLinkIndexReader.cs
  • src/Elastic.Documentation/Extensions/UrlPath.cs
  • src/Elastic.Markdown/Extensions/DetectionRules/DetectionRuleFile.cs
  • src/Elastic.Markdown/HtmlWriter.cs
  • src/services/Elastic.Documentation.Assembler/Sourcing/RepositorySourcesFetcher.cs
  • src/tooling/docs-builder/Http/DocumentationWebHost.cs
  • src/tooling/docs-builder/Http/StaticWebHost.cs
  • tests-integration/Elastic.Assembler.IntegrationTests/SiteNavigationTests.cs
✅ Files skipped from review due to trivial changes (3)
  • src/Elastic.Markdown/HtmlWriter.cs
  • src/Elastic.Markdown/Extensions/DetectionRules/DetectionRuleFile.cs
  • src/Elastic.Documentation/Extensions/UrlPath.cs
🚧 Files skipped from review as they are similar to previous changes (3)
  • tests-integration/Elastic.Assembler.IntegrationTests/SiteNavigationTests.cs
  • src/tooling/docs-builder/Http/StaticWebHost.cs
  • src/tooling/docs-builder/Http/DocumentationWebHost.cs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Retry calls were dropping non-default arguments, causing retries to
resolve a different checkout folder than the initial attempt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@Mpdreamz Mpdreamz enabled auto-merge (squash) March 30, 2026 14:04
@Mpdreamz Mpdreamz merged commit ce8705a into main Mar 30, 2026
30 checks passed
@Mpdreamz Mpdreamz deleted the feature/path-join branch March 30, 2026 14:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants