Skip to content

fix(raw): escape path segments when building raw content URLs - #3615

Open
sarankumar1325 wants to merge 1 commit into
github:mainfrom
sarankumar1325:fix-raw-percent-filenames
Open

sarankumar1325 wants to merge 1 commit into
github:mainfrom
sarankumar1325:fix-raw-percent-filenames

Conversation

@sarankumar1325

Copy link
Copy Markdown

Summary

repo:// resource reads now percent-encode each path segment before building the raw.githubusercontent.com URL, so file names containing % are fetched exactly as named.

Why

Fixes #3614

raw.Client passed the decoded owner/repo/ref/path to url.URL.JoinPath, which treats its arguments as already escaped. %41.txt was fetched as A.txt, and 100%.txt (an invalid escape) made JoinPath quietly fall back to the base URL, so the resource returned GitHub's homepage HTML as the file content.

What changed

  • pkg/raw/raw.go: new escapePathSegments helper applies url.PathEscape to every /-separated segment of owner, repo, ref/sha and path before JoinPath in refURL and commitURL. The existing .. traversal rejection runs first and is unchanged.
  • pkg/raw/raw_test.go: cases for docs/100%.txt, %41.txt, % with a SHA, and space/#/?/unicode in a ref and path. The old benign percent-encoded filename allowed case expected %2ehidden to go out unescaped, which actually requested .hidden. It now expects %252ehidden.
  • pkg/github/repository_resource_test.go: handler-level test that repo://owner/repo/contents/docs/100%25.txt and .../%2541.txt request /owner/repo/HEAD/docs/100%.txt and /owner/repo/HEAD/%41.txt. Both fail on main (one errors, one requests A.txt).

MCP impact

  • No tool or API changes. Only the URL the repository resource handler fetches changes, and only for names containing characters that need escaping.
  • Tool schema or behavior changed
  • New tool added

Prompts tested (tool changes only)

  • N/A (no tool changes)

Security / limits

  • No security or limits impact
  • Auth / permissions considered. Path traversal checks (rejectPathTraversal) still run on the unescaped input before escaping, and escaping means an encoded .. can no longer be decoded by JoinPath.
  • Data exposure, filtering, or token/size limits considered

Tool renaming

  • I am renaming tools as part of this PR (e.g. a part of a consolidation effort)
    • I have added the new tool aliases in deprecated_tool_aliases.go
  • I am not renaming tools as part of this PR

Lint & tests

  • Linted locally with ./script/lint (gofmt -s and golangci-lint v2.14.0: 0 issues)
  • Tested locally with ./script/test (go test ./... passes)

Docs

  • Not needed
  • Updated (README / docs / examples)

I used an AI assistant to write this change. I reviewed the diff and ran the tests above.

repo:// resource reads pass the decoded file path to url.URL.JoinPath,
which treats its arguments as already escaped. A file named %41.txt was
fetched as A.txt, and an invalid escape such as 100%.txt made JoinPath
fall back to the bare base URL, so the resource returned GitHub's
homepage HTML. PathEscape each /-separated segment of owner, repo, ref
and path before joining.

Fixes github#3614
Copilot AI auto review requested due to automatic review settings October 29, 2026 12:28
@sarankumar1325
sarankumar1325 requested a review from a team as a code owner October 29, 2026 12:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Repository resources fetch the wrong content when a file name contains "%"

2 participants