From fcb859d0ff7813657260587a4f4336403f53a90b Mon Sep 17 00:00:00 2001 From: Sebastien Tardif Date: Tue, 22 Sep 2026 19:03:00 -0700 Subject: [PATCH] fix(setup): restore gateway reload mode through stdin Signed-off-by: Sebastien Tardif --- src/OpenClaw.SetupEngine/SetupWizardRunner.cs | 3 +- .../SetupWizardReloadModeRestoreTests.cs | 93 +++++++++++++++++++ 2 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 tests/OpenClaw.SetupEngine.Tests/SetupWizardReloadModeRestoreTests.cs diff --git a/src/OpenClaw.SetupEngine/SetupWizardRunner.cs b/src/OpenClaw.SetupEngine/SetupWizardRunner.cs index 6c70ec18e..cc66d93b3 100644 --- a/src/OpenClaw.SetupEngine/SetupWizardRunner.cs +++ b/src/OpenClaw.SetupEngine/SetupWizardRunner.cs @@ -657,7 +657,8 @@ private async Task RunReloadModeRestorationCommandAsync(string re _ctx.DistroName!, command, remaining, - ct: CancellationToken.None); + ct: CancellationToken.None, + inputViaStdin: true); lastResult = result; if (result.ExitCode == 0 || !IsStartupMigrationLeaseContention(result)) diff --git a/tests/OpenClaw.SetupEngine.Tests/SetupWizardReloadModeRestoreTests.cs b/tests/OpenClaw.SetupEngine.Tests/SetupWizardReloadModeRestoreTests.cs new file mode 100644 index 000000000..e11e02b1a --- /dev/null +++ b/tests/OpenClaw.SetupEngine.Tests/SetupWizardReloadModeRestoreTests.cs @@ -0,0 +1,93 @@ +using OpenClaw.Connection; + +namespace OpenClaw.SetupEngine.Tests; + +public class SetupWizardReloadModeRestoreTests +{ + [Fact] + public async Task RestoreReloadMode_PipesScriptAndKeepsUserAndModeOutOfWslArgv() + { + const string linuxUser = "reloaduser"; + const string reloadMode = "$PATH"; + var commands = new RecordingCommandRunner(); + var logger = new SetupLogger(filePath: null, LogLevel.Trace); + var ctx = new SetupContext( + new SetupConfig + { + Wsl = new WslConfig { User = linuxUser }, + Gateway = new GatewayConfig { ReloadMode = reloadMode }, + }, + logger, + new TransactionJournal(filePath: null), + commands, + CancellationToken.None); + ctx.DistroName = "test-distro"; + ctx.EndpointProvenanceProbe = (_, _) => Task.FromResult( + new GatewayEndpointProvenance( + GatewayEndpointProvenanceKind.ExpectedManagedGateway, + ctx.Config.GatewayPort)); + + var result = await new SetupWizardRunner(ctx).RestoreReloadModeAsync(); + + Assert.True(result.IsSuccess, result.Message); + var restore = Assert.Single( + commands.WslCalls, + call => call.Command.Contains("config set gateway.reload.mode", StringComparison.Ordinal)); + Assert.True(restore.InputViaStdin); + Assert.Contains("'$PATH'", restore.Command, StringComparison.Ordinal); + Assert.Contains($"/home/{linuxUser}/", restore.Command, StringComparison.Ordinal); + + var argv = string.Join('\n', BuildWslArguments(restore)); + Assert.DoesNotContain(reloadMode, argv, StringComparison.Ordinal); + Assert.DoesNotContain(linuxUser, argv, StringComparison.Ordinal); + Assert.DoesNotContain("bash\n-c", argv, StringComparison.Ordinal); + } + + private static string[] BuildWslArguments( + (string DistroName, string Command, string? User, bool InputViaStdin) call) + { + var command = call.Command.Replace("\r", ""); + var args = new List { "-d", call.DistroName }; + if (!string.IsNullOrWhiteSpace(call.User)) + { + args.Add("-u"); + args.Add(call.User); + } + + if (call.InputViaStdin) + args.AddRange(["--", "bash", "-s"]); + else + args.AddRange(["--", "bash", "-c", command]); + + return args.ToArray(); + } + + private sealed class RecordingCommandRunner : ICommandRunner + { + public List<(string DistroName, string Command, string? User, bool InputViaStdin)> WslCalls { get; } = []; + + public Task RunAsync( + string executable, + string[] arguments, + TimeSpan timeout, + IReadOnlyDictionary? environment = null, + string? workingDirectory = null, + string? stdinInput = null, + CancellationToken ct = default, + Stream? stdinStream = null) => + Task.FromResult(new CommandResult(0, "", "", TimeSpan.Zero, TimedOut: false)); + + public Task RunInWslAsync( + string distroName, + string command, + TimeSpan timeout, + IReadOnlyDictionary? environment = null, + CancellationToken ct = default, + string? user = null, + bool inputViaStdin = false) + { + WslCalls.Add((distroName, command, user, inputViaStdin)); + return Task.FromResult(new CommandResult(0, "200", "", TimeSpan.Zero, TimedOut: false)); + } + } +}