修复登录自启的权限问题:低完整性目录、日志兜底与数据目录自检
登录任务本身没问题(InteractiveToken + HighestAvailable + --minimized), ICACLS 也没有拒绝 ACE;真因是 exe 所在的 D:\dsh workspace 带 Low 强制标签, Windows 用低完整性令牌运行这里的 exe,它写不了中完整性的 %LOCALAPPDATA%, 于是第一步写日志就 UnauthorizedAccessException,托盘起不来。 - FileLog 改为 fail-safe:首选目录失败依次回退 LocalLow / TEMP / ProgramData, 缓存待写行,永不抛异常,暴露 ActiveDirectory 与 LastFailure; - 启动自检增加数据目录可写性探测,致命对话框写出真实日志目录与低完整性判断; - 新增 --logcheck 只读自检:输出程序路径、数据目录可写性、实际日志目录与结论; - README 增加放置目录说明,validation.md 记录第八轮; - 新增两条 FileLog 回归测试(本地 49/49,探测 16/16,Release 0 警告 0 错误)。
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
using GatewayKeepalive.Core;
|
||||
|
||||
namespace GatewayKeepalive.Tests;
|
||||
|
||||
internal static class LogFallbackTests
|
||||
{
|
||||
public static Task WritablePrimaryDirectoryIsUsedAsync()
|
||||
{
|
||||
using var temp = new TempDirectory();
|
||||
var target = Path.Combine(temp.DirectoryPath, "logs");
|
||||
var log = new FileLog(target);
|
||||
|
||||
log.Write("测试:首选目录可写");
|
||||
|
||||
Check.Equal(Path.GetFullPath(target), Path.GetFullPath(log.ActiveDirectory), "A writable primary directory must stay active");
|
||||
Check.True(log.LastFailure is null, "No failure should be recorded when the primary directory works");
|
||||
var file = Path.Combine(target, $"gateway-{DateTime.Now:yyyy-MM-dd}.log");
|
||||
Check.True(File.Exists(file), "The log file should exist in the primary directory");
|
||||
Check.Contains("测试:首选目录可写", File.ReadAllText(file), "The line should land in the primary log");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public static Task UnusablePrimaryDirectoryFallsBackAsync()
|
||||
{
|
||||
using var temp = new TempDirectory();
|
||||
var blocked = Path.Combine(temp.DirectoryPath, "blocked");
|
||||
File.WriteAllText(blocked, "a file, so no directory can be created here");
|
||||
var log = new FileLog(blocked);
|
||||
|
||||
log.Write("测试:日志回退");
|
||||
|
||||
Check.True(
|
||||
!string.Equals(Path.GetFullPath(blocked), Path.GetFullPath(log.ActiveDirectory), StringComparison.OrdinalIgnoreCase),
|
||||
"An unusable primary directory must be replaced by a fallback");
|
||||
Check.True(log.LastFailure is not null, "The unusable primary directory should be reported as a failure");
|
||||
Check.Contains("blocked", log.LastFailure!, "The failure text should name the unusable directory");
|
||||
|
||||
var fallback = Path.Combine(log.ActiveDirectory, $"gateway-{DateTime.Now:yyyy-MM-dd}.log");
|
||||
Check.True(File.Exists(fallback), "The line should be written to the fallback directory");
|
||||
Check.Contains("测试:日志回退", File.ReadAllText(fallback), "The line should be present in the fallback log");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
@@ -50,6 +50,8 @@ internal static class Program
|
||||
("NetworkComparison: every owned route, DNS, and network field participates", NetworkComparisonTests.EachOwnedFieldParticipatesAsync),
|
||||
("NetworkComparison: transaction recovery accepts only exact before/intended rows", NetworkComparisonTests.RecoveryRejectsForeignRowsAsync),
|
||||
("JsonStore: round trip, backup, and failed serialization preserve the last complete file", JsonStoreTests.AtomicReplacementAsync),
|
||||
("FileLog: a writable primary directory is used and reports no failure", LogFallbackTests.WritablePrimaryDirectoryIsUsedAsync),
|
||||
("FileLog: an unusable primary directory falls back instead of throwing", LogFallbackTests.UnusablePrimaryDirectoryFallsBackAsync),
|
||||
("Windows NativeLayout: x64 structure sizes and metric offsets", NativeLayoutTests.X64LayoutAsync),
|
||||
("LoginStartup: logon task XML starts minimized with highest privileges", LoginStartupTests.LogonTaskXmlAsync),
|
||||
("LoginStartup: missing-task detection follows HRESULT, not exception type", LoginStartupTests.TaskMissingDetectionAsync),
|
||||
|
||||
Reference in New Issue
Block a user