fix(launcher): require executable Linux hosts

This commit is contained in:
Erik 2026-08-14 19:12:32 +02:00
parent 10a712d66b
commit ae2cbbee8c
5 changed files with 134 additions and 10 deletions

View file

@ -27,6 +27,8 @@ public sealed class LauncherExecutableSetTests : IDisposable
string headless = Path.Combine(_root, "acdream-headless" + suffix);
File.WriteAllText(graphical, string.Empty);
File.WriteAllText(headless, string.Empty);
MakeExecutableOnLinux(graphical);
MakeExecutableOnLinux(headless);
LauncherExecutableSet set = LauncherExecutableSet.FromDirectory(_root);
@ -64,4 +66,78 @@ public sealed class LauncherExecutableSetTests : IDisposable
Assert.Throws<LauncherOperationException>(() =>
set.CreateProbeSpec("session.json"));
}
[Fact]
public void LinuxRequiresExecutePermissionForBothCoDeployedHosts()
{
if (!OperatingSystem.IsLinux())
{
return;
}
Directory.CreateDirectory(_root);
string graphical = Path.Combine(_root, "AcDream.App");
string headless = Path.Combine(_root, "acdream-headless");
File.WriteAllText(graphical, string.Empty);
File.WriteAllText(headless, string.Empty);
UnixFileMode notExecutable = UnixFileMode.UserRead | UnixFileMode.UserWrite
| UnixFileMode.GroupRead | UnixFileMode.OtherRead;
File.SetUnixFileMode(graphical, notExecutable);
File.SetUnixFileMode(headless, notExecutable);
LauncherExecutableSet set = LauncherExecutableSet.FromDirectory(_root);
LauncherCapability gui = set.GetAvailability(LaunchMode.Gui);
LauncherCapability headlessCapability =
set.GetAvailability(LaunchMode.Headless);
Assert.False(gui.IsAvailable);
Assert.Contains("not executable", gui.Reason, StringComparison.Ordinal);
Assert.Contains("chmod +x", gui.Reason, StringComparison.Ordinal);
Assert.False(headlessCapability.IsAvailable);
Assert.Contains("not executable", headlessCapability.Reason, StringComparison.Ordinal);
Assert.Throws<LauncherOperationException>(() =>
set.CreatePlaySpec(LaunchMode.GuiSelect, "session.json"));
Assert.Throws<LauncherOperationException>(() =>
set.CreateProbeSpec("session.json"));
MakeExecutableOnLinux(graphical);
MakeExecutableOnLinux(headless);
Assert.True(set.GetAvailability(LaunchMode.GuiSelect).IsAvailable);
Assert.True(set.GetAvailability(LaunchMode.Headless).IsAvailable);
}
[Fact]
public void WindowsPreservesExistenceOnlyAvailability()
{
if (!OperatingSystem.IsWindows())
{
return;
}
var set = new LauncherExecutableSet(
"graphical.exe",
"headless.exe",
fileExists: _ => true,
hasUnixExecutePermission: _ => false);
Assert.True(set.GetAvailability(LaunchMode.Gui).IsAvailable);
Assert.True(set.GetAvailability(LaunchMode.Headless).IsAvailable);
}
private static void MakeExecutableOnLinux(string path)
{
if (OperatingSystem.IsLinux())
{
File.SetUnixFileMode(
path,
UnixFileMode.UserRead
| UnixFileMode.UserWrite
| UnixFileMode.UserExecute
| UnixFileMode.GroupRead
| UnixFileMode.GroupExecute
| UnixFileMode.OtherRead
| UnixFileMode.OtherExecute);
}
}
}

View file

@ -518,7 +518,8 @@ public sealed class LauncherOrchestratorTests : IDisposable
executables ?? new LauncherExecutableSet(
"gui-host",
"headless-host",
fileExists: _ => true),
fileExists: _ => true,
hasUnixExecutePermission: _ => true),
new LauncherInstallRecord("dats", "pak"),
platform ?? WindowsCapabilities(),
configService,