fix: validate safe.directory path before writing to global git config#165
Merged
jmaxdev merged 1 commit intoTrixtyAI:mainfrom Apr 21, 2026
Merged
Conversation
|
Thanks for the contribution! I'll review it as soon as possible. If you have still changes, please mark this PR as draft and all reviews will be cancelled. Tests reviews will be re-run only when the PR is marked as ready for review. |
There was a problem hiding this comment.
Pull request overview
This PR hardens the Tauri backend command that adds safe.directory entries to the user’s global git config by validating and normalizing the provided path before invoking git config --global --add.
Changes:
- Rejects unsafe
safe.directoryvalues (empty,*, and leading-). - Canonicalizes the path and requires it to be an existing directory.
- Attempts to normalize Windows verbatim (
\\?\) paths before writing to git config.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
git_add_safe_directory forwarded the caller-supplied path straight to `git config --global --add safe.directory`. Because the target config is global and persistent, any junk that made it through — most dangerously the `*` wildcard — auto-whitelisted every repository on disk, meaning any repo opened afterwards could run its pre/post hooks without the usual dubious-ownership prompt. Validation added before shelling out: - Reject empty input, `*`, and any value starting with `-` (so it can't be reparsed as a git flag like `--global --get`). - `Path::canonicalize` the path and require it to be an existing directory. The frontend only ever calls this with the current workspace root, which is a real directory on disk, so legitimate usage is unchanged. - Strip the `\\?\` verbatim prefix on Windows before handing the value to `git config`, since git stores entries in plain form and doesn't recognize the UNC-verbatim variant. The user-facing confirmation dialog in GitExplorerComponent already shows the path being added; canonicalization now makes that dialog match what actually lands in the global config.
a515475 to
974a71a
Compare
matiaspalmac
added a commit
to matiaspalmac/ide
that referenced
this pull request
Apr 21, 2026
Addresses review feedback on TrixtyAI#165: on Windows, canonicalize() returns \\?\UNC\server\share\... for network shares. The previous strip of just \\?\ turned that into UNC\server\share\..., which is not a valid Windows path and would land in the user's global git config as garbage — git would then read "safe.directory = UNC\server\share\..." and never match the real repo. Map \\?\UNC\... back to \\server\share\... and keep the simple strip for drive-letter paths.
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.
[Fix]: Validate
safe.directorypath before writing to the global git configDescription
git_add_safe_directoryforwarded the caller-supplied path straight togit config --global --add safe.directory. Because the target config isglobal and persistent, any junk that made it through ended up in
the user's
~/.gitconfig. The worst shape is*, whichauto-whitelists every repository on disk — from that point on any
untrusted repo opened by the user can run pre/post hooks without the
usual dubious-ownership prompt.
Change
apps/desktop/src-tauri/src/lib.rs—git_add_safe_directorynowvalidates before shelling out:
*, and any value starting with-so itcannot be reparsed as a git flag (e.g.
--global --get).Path::canonicalizethe input and require the result to be anexisting directory. The only in-tree caller
(
GitExplorerComponent.tsx→ "fix dubious ownership" confirmation)always passes the current workspace root, which is a real directory
on disk, so legitimate usage is unchanged.
\\?\verbatim prefix on Windows before handing the valueto
git config. Git writes entries in plain form and does notrecognize the UNC-verbatim variant, so this keeps the config entry
readable and matches what the user saw in the UI confirmation.
The user-facing confirmation dialog in
GitExplorerComponentalreadyshows the exact path being added; canonicalization now makes that
dialog match what actually lands in the global config instead of
whatever string the frontend happened to send.
Trade-offs
canonical == workspace_rootas suggested in the issuewould require threading the workspace root through an extra Tauri
command argument, and the frontend can trivially fake it anyway.
The real defense — "the value must be a real directory, not a
wildcard or flag" — is applied here. A deeper workspace-scoping
check is out of scope for this security fix.
written to global config. The one legitimate caller always passes
an existing directory, so no behavior changes for the happy path.
Verification
cargo checkandcargo clippy -- -D warningsonsrc-tauri→ clean.""→safe.directory path is empty."*"→ refused with the wildcard-specific message."--global"→ refused for leading-."/path/that/does/not/exist"→ canonicalize error."C:\\path\\to\\a\\file.txt"→must be a directory.stripped, written to global config (matches previous behavior).
Related Issue
Fixes #57
Checklist