Skip to content

Commit 98de506

Browse files
Copilotwaldekmastykarzgarrytrinder
authored
Add TTY detection for interactive prompts to prevent agent hangs (#1547)
* Initial plan * Add TTY detection for interactive prompts to prevent agent hangs - CertCommand: detect non-interactive stdin before prompting, fail with clear error directing users to --force flag - ProxyEngine: skip first-run cert trust prompt in non-interactive mode, default to trusting the certificate - Update --force option help text to note it's required for non-interactive use Co-authored-by: waldekmastykarz <11164679+waldekmastykarz@users.noreply.github.com> * Address review feedback: add CI env var check and return non-zero exit code - CertCommand and ProxyEngine: check both Console.IsInputRedirected and CI env var for non-interactive detection, matching ExecuteAsync pattern - RemoveCert returns int: exit code 1 for non-interactive failure or exceptions, 0 for success Co-authored-by: waldekmastykarz <11164679+waldekmastykarz@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: waldekmastykarz <11164679+waldekmastykarz@users.noreply.github.com> Co-authored-by: Waldek Mastykarz <waldek@mastykarz.nl> Co-authored-by: Garry Trinder <garry@trinder365.co.uk>
1 parent 9635ab1 commit 98de506

2 files changed

Lines changed: 26 additions & 5 deletions

File tree

DevProxy/Commands/CertCommand.cs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ sealed class CertCommand : Command
1515
private readonly ILoggerFactory _loggerFactory;
1616
private readonly Option<bool> _forceOption = new("--force", "-f")
1717
{
18-
Description = "Don't prompt for confirmation when removing the certificate"
18+
Description = "Don't prompt for confirmation when removing the certificate. Required for non-interactive use (CI, piped stdin, automation)."
1919
};
2020

2121
public CertCommand(ILogger<CertCommand> logger, ILoggerFactory loggerFactory) :
@@ -74,7 +74,7 @@ private async Task EnsureCertAsync()
7474
_logger.LogTrace("EnsureCertAsync() finished");
7575
}
7676

77-
public void RemoveCert(ParseResult parseResult)
77+
public int RemoveCert(ParseResult parseResult)
7878
{
7979
_logger.LogTrace("RemoveCert() called");
8080

@@ -83,10 +83,17 @@ public void RemoveCert(ParseResult parseResult)
8383
var isForced = parseResult.GetValue(_forceOption);
8484
if (!isForced)
8585
{
86+
if (Console.IsInputRedirected ||
87+
Environment.GetEnvironmentVariable("CI") is not null)
88+
{
89+
_logger.LogError("Confirmation required but running in non-interactive mode. Use --force to skip confirmation.");
90+
return 1;
91+
}
92+
8693
var isConfirmed = PromptConfirmation("Do you want to remove the root certificate", acceptByDefault: false);
8794
if (!isConfirmed)
8895
{
89-
return;
96+
return 0;
9097
}
9198
}
9299

@@ -111,10 +118,12 @@ public void RemoveCert(ParseResult parseResult)
111118
}
112119

113120
_logger.LogInformation("DONE");
121+
return 0;
114122
}
115123
catch (Exception ex)
116124
{
117125
_logger.LogError(ex, "Error removing certificate");
126+
return 1;
118127
}
119128
finally
120129
{

DevProxy/Proxy/ProxyEngine.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,8 +231,20 @@ private void FirstRunSetup()
231231

232232
Console.WriteLine();
233233
Console.WriteLine("Dev Proxy uses a self-signed certificate to intercept and inspect HTTPS traffic.");
234-
Console.Write("Update the certificate in your Keychain so that it's trusted by your browser? (Y/n): ");
235-
var answer = Console.ReadLine()?.Trim();
234+
235+
string? answer;
236+
if (Console.IsInputRedirected ||
237+
Environment.GetEnvironmentVariable("CI") is not null)
238+
{
239+
// Non-interactive mode, default to trusting the certificate
240+
_logger.LogInformation("Non-interactive mode detected. Defaulting to trusting the certificate.");
241+
answer = "y";
242+
}
243+
else
244+
{
245+
Console.Write("Update the certificate in your Keychain so that it's trusted by your browser? (Y/n): ");
246+
answer = Console.ReadLine()?.Trim();
247+
}
236248

237249
if (string.Equals(answer, "n", StringComparison.OrdinalIgnoreCase))
238250
{

0 commit comments

Comments
 (0)