server-monitor-manager/tests/ServerMonitorManager.Desktop.Security.Tests/SshConnectionArgumentsTests.cs
ochenstarik-ui ba14d29211
fix(security): close desktop and helper debts (#10)
Co-authored-by: Ochenstarik <ochenstarik@inbox.ru>
2026-07-31 13:22:00 +07:00

89 lines
No EOL
3.4 KiB
C#

using ServerMonitorManager_Desktop;
using Xunit;
namespace ServerMonitorManager.Desktop.Security.Tests;
public sealed class SshConnectionArgumentsTests : IDisposable
{
private readonly string _directory = Path.Combine(
Path.GetTempPath(),
$"smm-ssh-arguments-{Guid.NewGuid():N}");
[Fact]
public async Task InteractiveTerminalUsesOnlyTheConfirmedEndpointPin()
{
var candidate = SshHostKeyTrust.ParseCandidate(
"server.example",
2222,
"[server.example]:2222 ssh-ed25519 AQIDBA==\n");
var path = SshHostKeyTrust.GetPinPath(_directory, candidate.Host, candidate.Port);
await SshHostKeyTrust.WriteAsync(path, candidate, TestContext.Current.CancellationToken);
var arguments = SshConnectionArguments.BuildInteractive(
"server.example",
2222,
"operator",
path,
candidate.Fingerprint);
Assert.Equal("none", ValueAfter(arguments, "-F"));
Assert.Contains("StrictHostKeyChecking=yes", arguments);
Assert.Contains($"UserKnownHostsFile={path}", arguments);
Assert.Contains("GlobalKnownHostsFile=none", arguments);
Assert.Contains("KnownHostsCommand=none", arguments);
Assert.Contains("UpdateHostKeys=no", arguments);
Assert.Contains("CheckHostIP=no", arguments);
Assert.Equal("operator@server.example", arguments[^1]);
}
[Fact]
public void InteractiveTerminalRejectsProfileWithoutConfirmedFingerprint()
{
var path = SshHostKeyTrust.GetPinPath(_directory, "server.example", 22);
var exception = Assert.Throws<InvalidOperationException>(() =>
SshConnectionArguments.BuildInteractive(
"server.example", 22, "operator", path, expectedFingerprint: null));
Assert.Contains("Подтвердить host key", exception.Message, StringComparison.Ordinal);
}
[Fact]
public async Task UnchangedEndpointCanReuseItsPersistedPin()
{
var candidate = SshHostKeyTrust.ParseCandidate(
"server.example",
22,
"server.example ssh-ed25519 AQIDBA==\n");
var path = SshHostKeyTrust.GetPinPath(_directory, candidate.Host, candidate.Port);
await SshHostKeyTrust.WriteAsync(path, candidate, TestContext.Current.CancellationToken);
var current = new ServerProfileData(
"id", "Old name", candidate.Host, candidate.Port, "monitor", false, candidate.Fingerprint);
var renamed = current with { Name = "New name", User = "other" };
var moved = renamed with { Host = "other.example" };
Assert.True(SshHostKeyTrust.CanReusePin(_directory, current, renamed));
Assert.False(SshHostKeyTrust.CanReusePin(_directory, current, moved));
}
[Fact]
public void LegacyProfileHasDedicatedPendingConfirmationState()
{
var server = new ServerViewModel(
new ServerProfileData("id", "Legacy", "server.example", 22, "monitor"));
Assert.True(server.HostKeyPendingConfirmation);
Assert.Equal("Требуется подтверждение host key", server.Status);
}
private static string ValueAfter(IReadOnlyList<string> arguments, string option)
=> arguments[arguments.ToList().IndexOf(option) + 1];
public void Dispose()
{
if (Directory.Exists(_directory))
{
Directory.Delete(_directory, recursive: true);
}
}
}