Skip to content

Commit f89b1a2

Browse files
committed
fix: Robuste Lösung für Credential-Prompts bei öffentlichen Repositories
Umfassende Lösung implementiert, die mehrere Ansätze kombiniert: 1. SkipCredentials Flag zu Command-Klasse hinzugefügt 2. Automatische Erkennung von öffentlichen Repos (GitHub, GitLab, Bitbucket, Gitee) 3. Mehrfache Deaktivierung von Credential Helpers: - credential.helper= (leer setzen) - credential.helper='' (explizit leer) - credential.helper=! (deaktivieren) - core.askpass= (leer setzen) - core.askPass='' (explizit leer) 4. Environment-Variablen zur Unterdrückung von Prompts: - GIT_TERMINAL_PROMPT=0 - GIT_ASKPASS=echo - GCM_INTERACTIVE=never - GIT_CREDENTIAL_HELPER='' 5. Fetch und Pull Commands angepasst: - Prüfen Remote-URL auf öffentliche Hosts - Setzen SkipCredentials=true für öffentliche HTTPS-Repos - Überspringen von SSH-Keys für öffentliche Repos Diese Lösung sollte zuverlässig verhindern, dass SourceGit nach Credentials fragt, wenn mit öffentlichen Repositories gearbeitet wird.
1 parent 9ef1fe0 commit f89b1a2

File tree

3 files changed

+100
-14
lines changed

3 files changed

+100
-14
lines changed

src/Commands/Command.cs

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public enum EditorType
3131
public EditorType Editor { get; set; } = EditorType.CoreEditor;
3232
public string SSHKey { get; set; } = string.Empty;
3333
public string Args { get; set; } = string.Empty;
34+
public bool SkipCredentials { get; set; } = false;
3435

3536
// Only used in `ExecAsync` mode.
3637
public CancellationToken CancellationToken { get; set; } = CancellationToken.None;
@@ -180,6 +181,16 @@ protected ProcessStartInfo CreateGitStartInfo(bool redirect)
180181
start.Environment.Add("SOURCEGIT_LAUNCH_AS_ASKPASS", "TRUE");
181182
if (!OperatingSystem.IsLinux())
182183
start.Environment.Add("DISPLAY", "required");
184+
185+
// For public repositories, disable credential prompts via environment
186+
if (SkipCredentials || (Args != null && (Args.Contains("github.com") || Args.Contains("gitlab.com"))))
187+
{
188+
// These environment variables tell Git not to prompt for credentials
189+
start.Environment["GIT_TERMINAL_PROMPT"] = "0";
190+
start.Environment["GIT_ASKPASS"] = "echo";
191+
start.Environment["GCM_INTERACTIVE"] = "never";
192+
start.Environment["GIT_CREDENTIAL_HELPER"] = "";
193+
}
183194

184195
// If an SSH private key was provided, sets the environment.
185196
if (!start.Environment.ContainsKey("GIT_SSH_COMMAND") && !string.IsNullOrEmpty(SSHKey))
@@ -197,23 +208,47 @@ protected ProcessStartInfo CreateGitStartInfo(bool redirect)
197208

198209
// Check if we're working with a public repository (no credentials needed)
199210
var isPublicRepo = false;
200-
if (!string.IsNullOrEmpty(WorkingDirectory))
211+
var needsCredentials = true;
212+
213+
// Check for operations that typically don't need credentials on public repos
214+
if (Args != null)
201215
{
202-
// Check if this appears to be a public GitHub/GitLab URL in the arguments
203-
if (Args != null && (Args.Contains("github.com") || Args.Contains("gitlab.com")))
216+
// Check if this is a read-only operation on GitHub/GitLab
217+
var isReadOperation = Args.Contains("fetch") || Args.Contains("pull") ||
218+
Args.Contains("ls-remote") || Args.Contains("clone") ||
219+
Args.Contains("remote -v") || Args.Contains("remote get-url");
220+
221+
// Check if URL contains public Git hosts
222+
var hasPublicHost = Args.Contains("github.com") || Args.Contains("gitlab.com") ||
223+
Args.Contains("bitbucket.org") || Args.Contains("gitee.com");
224+
225+
// If it's a read operation on a public host, disable credentials
226+
if (isReadOperation && hasPublicHost)
204227
{
205-
// For fetch, pull, clone operations on public repos, skip credentials
206-
if (Args.Contains("fetch") || Args.Contains("pull") || Args.Contains("ls-remote") || Args.Contains("clone"))
207-
{
208-
isPublicRepo = true;
209-
// Explicitly disable credential helpers for public repos
210-
builder.Append(" -c credential.helper=");
211-
}
228+
isPublicRepo = true;
229+
needsCredentials = false;
230+
}
231+
232+
// Also check for HTTPS URLs which are typically public
233+
if (Args.Contains("https://github.com") || Args.Contains("https://gitlab.com"))
234+
{
235+
isPublicRepo = true;
236+
needsCredentials = false;
212237
}
213238
}
214239

215-
// Only add credential helper if it's configured and not a public repo
216-
if (!isPublicRepo && !string.IsNullOrEmpty(Native.OS.CredentialHelper))
240+
// ALWAYS explicitly set credential helper to avoid system defaults
241+
if (SkipCredentials || !needsCredentials || isPublicRepo)
242+
{
243+
// Explicitly disable ALL credential helpers including system ones
244+
// Use multiple methods to ensure no credentials are requested
245+
builder.Append(" -c credential.helper=");
246+
builder.Append(" -c credential.helper=''");
247+
builder.Append(" -c credential.helper=!");
248+
builder.Append(" -c core.askpass=");
249+
builder.Append(" -c core.askPass=''");
250+
}
251+
else if (!string.IsNullOrEmpty(Native.OS.CredentialHelper))
217252
{
218253
// For the cache helper with timeout, we need special handling
219254
if (Native.OS.CredentialHelper == "cache")

src/Commands/Fetch.cs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ public class Fetch : Command
77
public Fetch(string repo, string remote, bool noTags, bool force)
88
{
99
_remoteKey = $"remote.{remote}.sshkey";
10+
_remote = remote;
1011

1112
WorkingDirectory = repo;
1213
Context = repo;
@@ -26,6 +27,7 @@ public Fetch(string repo, string remote, bool noTags, bool force)
2627
public Fetch(string repo, Models.Branch local, Models.Branch remote)
2728
{
2829
_remoteKey = $"remote.{remote.Remote}.sshkey";
30+
_remote = remote.Remote;
2931

3032
WorkingDirectory = repo;
3133
Context = repo;
@@ -34,10 +36,39 @@ public Fetch(string repo, Models.Branch local, Models.Branch remote)
3436

3537
public async Task<bool> RunAsync()
3638
{
37-
SSHKey = await new Config(WorkingDirectory).GetAsync(_remoteKey).ConfigureAwait(false);
39+
// Check if remote URL is a public repository
40+
if (!string.IsNullOrEmpty(_remote))
41+
{
42+
var remoteUrl = await new Config(WorkingDirectory).GetAsync($"remote.{_remote}.url").ConfigureAwait(false);
43+
if (!string.IsNullOrEmpty(remoteUrl) && remoteUrl.StartsWith("https://"))
44+
{
45+
// For public HTTPS repos, we don't need SSH keys or credentials
46+
if (remoteUrl.Contains("github.com") || remoteUrl.Contains("gitlab.com") ||
47+
remoteUrl.Contains("bitbucket.org") || remoteUrl.Contains("gitee.com"))
48+
{
49+
// Skip SSH key and credentials for public repos
50+
SSHKey = string.Empty;
51+
SkipCredentials = true;
52+
}
53+
else
54+
{
55+
SSHKey = await new Config(WorkingDirectory).GetAsync(_remoteKey).ConfigureAwait(false);
56+
}
57+
}
58+
else
59+
{
60+
SSHKey = await new Config(WorkingDirectory).GetAsync(_remoteKey).ConfigureAwait(false);
61+
}
62+
}
63+
else
64+
{
65+
SSHKey = await new Config(WorkingDirectory).GetAsync(_remoteKey).ConfigureAwait(false);
66+
}
67+
3868
return await ExecAsync().ConfigureAwait(false);
3969
}
4070

4171
private readonly string _remoteKey;
72+
private readonly string _remote = string.Empty;
4273
}
4374
}

src/Commands/Pull.cs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,27 @@ public Pull(string repo, string remote, string branch, bool useRebase)
2020

2121
public async Task<bool> RunAsync()
2222
{
23-
SSHKey = await new Config(WorkingDirectory).GetAsync($"remote.{_remote}.sshkey").ConfigureAwait(false);
23+
// Check if remote URL is a public repository
24+
var remoteUrl = await new Config(WorkingDirectory).GetAsync($"remote.{_remote}.url").ConfigureAwait(false);
25+
if (!string.IsNullOrEmpty(remoteUrl) && remoteUrl.StartsWith("https://"))
26+
{
27+
// For public HTTPS repos, we don't need SSH keys or credentials
28+
if (remoteUrl.Contains("github.com") || remoteUrl.Contains("gitlab.com") ||
29+
remoteUrl.Contains("bitbucket.org") || remoteUrl.Contains("gitee.com"))
30+
{
31+
SSHKey = string.Empty;
32+
SkipCredentials = true;
33+
}
34+
else
35+
{
36+
SSHKey = await new Config(WorkingDirectory).GetAsync($"remote.{_remote}.sshkey").ConfigureAwait(false);
37+
}
38+
}
39+
else
40+
{
41+
SSHKey = await new Config(WorkingDirectory).GetAsync($"remote.{_remote}.sshkey").ConfigureAwait(false);
42+
}
43+
2444
return await ExecAsync().ConfigureAwait(false);
2545
}
2646

0 commit comments

Comments
 (0)