feat(installer): pull in preflight check implementations as prerequisite for SystemCheckPage

Git/GitIdentity/Port/WriteAccess and Claude CLI/Version/Auth/PermissionModeAuto
checks plus the ExecutableResolver they depend on were built in two sibling
task branches that hadn't landed on main yet. Vendored the finished files in
from those branches (same content, verified building + tests green) so the
SystemCheckPage task has something to consume.
This commit is contained in:
mika kuns
2026-08-05 19:56:07 +02:00
parent bdee731376
commit 05be07b28c
30 changed files with 1683 additions and 3 deletions
@@ -0,0 +1,80 @@
using System.Security.AccessControl;
using System.Security.Principal;
using ClaudeDo.Installer.Checks;
using ClaudeDo.Installer.Core;
namespace ClaudeDo.Installer.Tests.Checks;
public sealed class WriteAccessCheckTests : IDisposable
{
private readonly List<string> _cleanupDirs = new();
private string TempDir()
{
var dir = Path.Combine(Path.GetTempPath(), $"cdwriteaccess_{Guid.NewGuid():N}");
Directory.CreateDirectory(dir);
_cleanupDirs.Add(dir);
return dir;
}
public void Dispose()
{
foreach (var dir in _cleanupDirs)
{
try { Directory.Delete(dir, recursive: true); } catch { }
}
}
[Fact]
public async Task Writable_directory_reports_ok()
{
var dir = TempDir();
var check = new WriteAccessCheck();
var result = await check.RunAsync(new InstallContext { InstallDirectory = dir }, CancellationToken.None);
Assert.Equal(CheckStatus.Ok, result.Status);
}
[Fact]
public async Task NonExistent_path_under_writable_parent_reports_ok()
{
var parent = TempDir();
var target = Path.Combine(parent, "does", "not", "exist");
var check = new WriteAccessCheck();
var result = await check.RunAsync(new InstallContext { InstallDirectory = target }, CancellationToken.None);
Assert.Equal(CheckStatus.Ok, result.Status);
}
[Fact]
public async Task Unwritable_directory_reports_failed_with_no_leftover_file()
{
var dir = TempDir();
var dirInfo = new DirectoryInfo(dir);
var identity = WindowsIdentity.GetCurrent().User!;
var denyRule = new FileSystemAccessRule(identity, FileSystemRights.CreateFiles | FileSystemRights.WriteData, AccessControlType.Deny);
var acl = dirInfo.GetAccessControl();
acl.AddAccessRule(denyRule);
dirInfo.SetAccessControl(acl);
try
{
var check = new WriteAccessCheck();
var result = await check.RunAsync(new InstallContext { InstallDirectory = dir }, CancellationToken.None);
Assert.Equal(CheckStatus.Failed, result.Status);
Assert.Equal(CheckSeverity.Error, result.Severity);
Assert.Contains(dir, result.Message);
Assert.Empty(Directory.GetFiles(dir));
}
finally
{
acl.RemoveAccessRule(denyRule);
dirInfo.SetAccessControl(acl);
}
}
}