Skip to content

feature: confirm before trusting a repository refused by git - #2746

Open
a2580vb wants to merge 1 commit into
sourcegit-scm:developfrom
a2580vb:develop
Open

a2580vb wants to merge 1 commit into
sourcegit-scm:developfrom
a2580vb:develop

Conversation

@a2580vb

@a2580vb a2580vb commented Sep 27, 2026 •

Copy link
Copy Markdown

PR Description

Target branch: develop
Screenshots: before.png (old behavior) / pr-session.png (session-only trust) / pr-permanent.png (permanent trust) / pr-old-git.png (git older than 2.38)

Problem

Starting with Git 2.35.2, if the repository's top-level directory is owned by another user (the fix for CVE-2022-24765), Git will refuse to use the repository.
Repositories on network shares / UNC paths inevitably trigger this check, because the file owner SID of an SMB share cannot be resolved on the client:

$ git -C '\\service\share\test_repo' rev-parse --show-toplevel
fatal: detected dubious ownership in repository at '//service/share/test_repo'
'//service/share/test_repo' is owned by:
        (inconvertible) (S-1-5-21-...)
but the current user is:
        DESKTOP-XXX/user (S-1-5-21-...)
To add an exception for this directory, call:

        git config --global --add safe.directory '%(prefix)///service/share/test_repo'

Currently SourceGit treats such paths as "not a valid Git repository" (it pops up Initialize Repository, or silently ignores them on drag and drop). This is misleading—the path is indeed a valid repository; Git is simply refusing to access it.

Approach

Detect this specific error and let the user decide how to trust the repository; do not write anything before the user explicitly confirms:

  • Trust for this session only (default): does not modify any configuration. The exception is kept only in memory, and all subsequent Git commands executed under that path automatically append -c safe.directory=<value> until the application exits. When the detected Git is older than 2.38 this option is disabled with an explanation, because those versions do not respect -c safe.directory (see Notes);
  • Permanent trust: the only option that writes configuration; it runs git config --global --add safe.directory "<value>". The option text uses a warning color, and when selected, the exact command to be executed is displayed below it.

The value to be allowed is taken directly from Git's own suggested value, so platform-specific forms are handled correctly, and Git's shell quoting is decoded back to the plain path (' and ! are escaped by Git). When Git does not provide a hint, it falls back to constructing the value from the path.

Implementation

File Purpose
Models/SafeDirectories.cs Detects the error, parses and decodes the safe.directory value suggested by Git, maintains in-memory session trust and builds the -c safe.directory=... arguments
Models/GitVersions.cs New SAFE_DIRECTORY_COMMAND_LINE = 2.38.0 (the first Git version that respects the command-line option)
Commands/AddSafeDirectory.cs git config --global --add safe.directory ...
Commands/Command.cs Appends -c safe.directory=... to working directories trusted for the session (also used by the few commands that spawn Git directly: QueryFileContent, SaveRevisionFile, UpdateIndexInfo, SaveChangesAsPatch)
ViewModels/TrustRepository.cs + Views/TrustRepository.axaml Confirmation dialog
ViewModels/Launcher.cs, ViewModels/OpenLocalRepository.cs, ViewModels/Welcome.cs, Views/Welcome.axaml.cs Integrates into all open entry points: command line / file association / IPC, open local repository, drag and drop, workspace restore, worktree / submodule
ViewModels/ScanRepositories.cs Counts and notifies about repositories skipped by the trust check during scanning
App.axaml.cs --history / --blame outputs Git's real stderr instead of a generic message
Resources/Themes.axaml Adds Color.Warn / Brush.Warn for the permanent trust option
Resources/Locales/{en_US,zh_CN,zh_TW}.axaml Adds new strings

Screenshots

Trust for this session only Permanent trust Git older than 2.38 Old behaviour
pr-session pr-permanent pr-old-git before

Testing

  • dotnet build -c Debug: 0 warnings / 0 errors;
  • dotnet format --verify-no-changes src/SourceGit.csproj: passes;
  • Manually verified on a real SMB repository (\\service\share\...):
    • Trust for this session only: after confirmation, the repository opens and git rev-parse --show-toplevel succeeds;
    • Permanent trust: verified using an isolated GIT_CONFIG_GLOBAL;
    • a repository path containing ' and ! is parsed correctly: the dialog shows safe.directory "%(prefix)///.../service'test!ok" without any '\'' / '\!' leftovers;
    • the "Git older than 2.38" state was simulated by temporarily raising the version threshold: the session option is disabled and explained, permanent trust is preselected;
  • Both radio states were verified in the UI, including Chinese line wrapping and line spacing.

Notes

  • Session trust relies on -c safe.directory, which Git only respects since 2.38 (2.35.2 - 2.37.x intentionally ignored the command-line option). On older Git the session option is disabled in the dialog, so the user is never sent into a dead end; permanent trust works on every version;
  • Session trust remains valid until the process exits; there is currently no revoke entry point; canceling will prompt again next time;
  • The new strings currently exist only for en_US, zh_CN, and zh_TW; other languages will be marked as missing in TRANSLATION.md according to the existing process;
  • Git is now forced to use the C locale on macOS as well (Linux already did this), so the English fatal message can always be recognized.

@love-linger love-linger self-assigned this Sep 28, 2026
@love-linger

Copy link
Copy Markdown
Collaborator

An excellent and complete implementation!

However, I prefer to only provide just one CheckBox - Trust for this repository, which the Permanent trust does in your PR.

This branch has not been deployed

No deployments
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.

2 participants