108 lines
4.6 KiB
C#
108 lines
4.6 KiB
C#
using Moq;
|
|
using SilverOS.Welcome.Core.Apply;
|
|
using SilverOS.Welcome.Core.Apps;
|
|
|
|
public class BootstrapServiceRevertKioskTests
|
|
{
|
|
private static Mock<IProcessRunner> Ok()
|
|
{
|
|
var m = new Mock<IProcessRunner>();
|
|
m.Setup(r => r.RunAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(new ProcessResult(0, "", ""));
|
|
return m;
|
|
}
|
|
|
|
private static Mock<IProcessRunner> Fail()
|
|
{
|
|
var m = new Mock<IProcessRunner>();
|
|
m.Setup(r => r.RunAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(new ProcessResult(1, "", "the operation failed"));
|
|
return m;
|
|
}
|
|
|
|
[Fact]
|
|
public async Task RevertKioskAsync_is_best_effort_and_does_not_throw_on_nonzero_exit()
|
|
{
|
|
// Kiosk revert is best-effort (like TearDownAsync): a non-zero exit must NOT
|
|
// fail the apply — the real user still gets Explorer regardless of WESL state.
|
|
var ex = await Record.ExceptionAsync(() =>
|
|
new BootstrapService(Fail().Object).RevertKioskAsync());
|
|
Assert.Null(ex);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task RevertKioskAsync_disables_keyboard_filter_rules()
|
|
{
|
|
var run = Ok();
|
|
await new BootstrapService(run.Object).RevertKioskAsync();
|
|
// First call: disable the Keyboard Filter predefined-key blocks for the real user.
|
|
run.Verify(r => r.RunAsync("powershell.exe", It.Is<string>(s =>
|
|
s.Contains("WEKF_PredefinedKey") &&
|
|
s.Contains("Enabled=$false")),
|
|
It.IsAny<CancellationToken>()), Times.Once);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task RevertKioskAsync_reverts_escape_policies()
|
|
{
|
|
var run = Ok();
|
|
await new BootstrapService(run.Object).RevertKioskAsync();
|
|
// Second call: policy revert — must remove the three escape policy values.
|
|
run.Verify(r => r.RunAsync("powershell.exe", It.Is<string>(s =>
|
|
s.Contains("Remove-ItemProperty") &&
|
|
s.Contains("DisableTaskMgr") &&
|
|
s.Contains("DisableLockWorkstation") &&
|
|
s.Contains("HideFastUserSwitching")),
|
|
It.IsAny<CancellationToken>()), Times.Once);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task ApplyService_calls_revert_kiosk_before_teardown()
|
|
{
|
|
var order = new List<string>();
|
|
var run = new Mock<IProcessRunner>();
|
|
run.Setup(r => r.RunAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
|
.Callback<string, string, CancellationToken>((_, a, _) =>
|
|
{
|
|
if (a.Contains("Invoke-Hardening")) order.Add("modules");
|
|
})
|
|
.ReturnsAsync(new ProcessResult(0, "", ""));
|
|
|
|
var acct = new Mock<IAccountService>();
|
|
acct.Setup(a => a.CreateAccountsAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
|
.Callback(() => order.Add("accounts"))
|
|
.Returns(Task.CompletedTask);
|
|
|
|
var bl = new Mock<IBitLockerService>();
|
|
bl.Setup(b => b.EnableAsync(It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
|
.Callback(() => order.Add("bitlocker"))
|
|
.Returns(Task.CompletedTask);
|
|
|
|
var boot = new Mock<IBootstrapService>();
|
|
boot.Setup(b => b.RevertKioskAsync(It.IsAny<CancellationToken>()))
|
|
.Callback(() => order.Add("revert-kiosk"))
|
|
.Returns(Task.CompletedTask);
|
|
boot.Setup(b => b.TearDownAsync(It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
|
.Callback(() => order.Add("teardown"))
|
|
.Returns(Task.CompletedTask);
|
|
|
|
var installer = new Mock<IAppInstaller>();
|
|
installer.Setup(i => i.InstallAsync(It.IsAny<IReadOnlyList<AppCatalogEntry>>(),
|
|
It.IsAny<IProgress<ApplyProgress>>(), It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(System.Array.Empty<AppInstallResult>());
|
|
|
|
var sut = new ApplyService(run.Object, acct.Object, bl.Object, boot.Object, installer.Object, "C:\\hard");
|
|
var flavour = new SilverOS.Welcome.Core.Flavours.FlavourManifest
|
|
{
|
|
Id = "daily-driver",
|
|
Hardening = new SilverOS.Welcome.Core.Flavours.HardeningSpec { Modules = new[] { "00" } }
|
|
};
|
|
var req = new ApplyRequest(flavour, "alice", "pw", "adminpw", "123456", "sm-bootstrap", System.Array.Empty<AppCatalogEntry>());
|
|
|
|
await sut.RunAsync(req, new Progress<ApplyProgress>(_ => { }));
|
|
|
|
// revert-kiosk must precede teardown so the sm-bootstrap SID still resolves.
|
|
Assert.Equal(new[] { "modules", "accounts", "bitlocker", "revert-kiosk", "teardown" }, order);
|
|
}
|
|
}
|