Skip to content

fix: gate Schannel/gitconfig probe to Windows only - #31

Merged
liviu-uba merged 1 commit into
developfrom
fix/macos-schannel-probe-gate
Jul 16, 2026
Merged

fix: gate Schannel/gitconfig probe to Windows only#31
liviu-uba merged 1 commit into
developfrom
fix/macos-schannel-probe-gate

Conversation

@liviu-uba

Copy link
Copy Markdown

Problem

On macOS and Linux, Studio logs fill with [ERROR] bursts during startup / first git access:

[ERROR] [UiPath.Studio] Error when reading /Users/<user>/.gitconfig System.EntryPointNotFoundException:
  Unable to find an entry point named 'GetPrivateProfileString' in shared library 'kernel32'.
   at ConfigurationFileReader.GetPrivateProfileString(...)
   at ConfigurationFileReader.Read(String section, String key) in /_/LibGit2Sharp/Core/ConfigurationFileReader.cs:line 20
   at LibGit2Sharp.Core.NativeMethods.IsSchannelSelectedInGitConfig() in /_/LibGit2Sharp/Core/NativeMethods.cs:line 167

Git functionality is not affected — the exception is caught, forces useSchannel = false (the only correct answer on non-Windows), and the plain liblibgit2.dylib is loaded as intended. The problem is pure log noise that masks real errors.

Root cause

IsSchannelSelectedInGitConfig() P/Invokes GetPrivateProfileString from kernel32 to read ~/.gitconfig as an INI file. On macOS, the kernel32 shim dylib is found and loaded (it is registered via XpfBootstrap.OnResolvingUnmanagedDll), but the shim does not export GetPrivateProfileStringEntryPointNotFoundException on every call.

The function's sole purpose is to decide whether to load the libgit2_schannel variant. Schannel is a Windows-only TLS stack (SSPI); no schannel binaries ship for osx-* or linux-* RIDs. The probe is therefore meaningless on non-Windows and has no valid non-false result.

Why gating is the correct fix (not implementing the P/Invoke)

Implementing GetPrivateProfileString in the shim would make the read succeed, but a true result (sslBackend = schannel in .gitconfig, plausible via dotfiles synced from Windows) would set libraryName = "libgit2_schannel" and call SetHttpBackend(Schannel) — then the loader would hunt for liblibgit2_schannel.dylib, which does not exist, breaking git entirely for those users. The unconditionally-false answer produced today by the exception is the only correct mac/Linux answer; gating the probe makes that explicit.

Fix

One-line guard in NativeMethods.cs:95:

// Before
bool useSchannel = HasEnvironmentVariable("UIPATH_STUDIO_GIT_USE_SCHANNEL") || IsSchannelSelectedInGitConfig();

// After
bool useSchannel = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
    && (HasEnvironmentVariable("UIPATH_STUDIO_GIT_USE_SCHANNEL") || IsSchannelSelectedInGitConfig());
  • Windows: && short-circuits into the original expression — byte-for-byte identical behaviour.
  • macOS / Linux: useSchannel is false immediately — no gitconfig probe, no kernel32 P/Invoke, no error, no risk of the broken schannel-load path. Also neutralises the UIPATH_STUDIO_GIT_USE_SCHANNEL footgun on non-Windows (setting that env var would previously trigger a schannel load attempt for a dylib that doesn't exist).

IsOSPlatform(Windows) is intentionally used here (not !IsWindows()): both GetPrivateProfileString and Schannel are genuinely Windows-specific, not merely non-Linux concerns. There is no equivalent backend to gate on for macOS separately.

Test plan

  • macOS: launch Studio, open a project with a git repo, verify zero GetPrivateProfileString / EntryPointNotFoundException lines in _dotnet.log
  • macOS: git clone / push / pull still works (native lib loads correctly)
  • Windows: no behaviour change — Schannel selection and ~/.gitconfig probe work as before
  • Linux: same as macOS (no exception, git works)

Follow-up

After this package is published, bump LibGit2Sharp.UiPath in Studio/Directory.Build.targets from 1.9.1-v6 to the new version. A plain v6→v7 bump does not fix this — the gate must be in the package.

🤖 Generated with Claude Code

On macOS and Linux, `IsSchannelSelectedInGitConfig()` P/Invokes
`GetPrivateProfileString` from `kernel32`. That symbol is not exported
by the kernel32 shim dylib, so every startup that finds `~/.gitconfig`
throws an `EntryPointNotFoundException` which is caught, logged via
`Trace.TraceError`, and surfaced in Studio logs as an [ERROR] burst.
Git functionality is unaffected (the exception forces `useSchannel =
false`, which is the only correct value on non-Windows anyway — no
schannel binaries ship for osx/linux RIDs), but the log noise is
confusing and masks real errors.

`GetPrivateProfileString` and Schannel are Windows-only concepts.
Guard the entire probe with `RuntimeInformation.IsOSPlatform(Windows)`
so the gitconfig read and the env-var env-var footgun (`UIPATH_STUDIO_GIT_USE_SCHANNEL`
forcing a missing dylib) are both inert on mac/Linux. Windows behavior
is byte-for-byte unchanged: the `&&` short-circuits into the original
expression on Windows.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@liviu-uba
liviu-uba requested a review from andrei-balint July 16, 2026 11:18
@liviu-uba
liviu-uba merged commit c350c88 into develop Jul 16, 2026
11 of 12 checks passed
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