Files
Termind/TFMTests/AuthorizedKeyExportTests.swift

143 lines
4.6 KiB
Swift

// SPDX-FileCopyrightText: 2026 Kaede Akino
// SPDX-License-Identifier: GPL-3.0-only
import Foundation
import TermindApplication
import TermindDomain
import Testing
@testable import Termind
@testable import TermindRemoteInfrastructure
struct AuthorizedKeyExportTests {
@Test(arguments: [
(
"ssh-ed25519 AAAAC3Nza test@example.com", "Production",
"# Production Key by Termind\nssh-ed25519 AAAAC3Nza test@example.com\n"
),
(
"ssh-ed25519 AAAAC3Nza", " Production\n\tServer ",
"# Production Server Key by Termind\nssh-ed25519 AAAAC3Nza\n"
),
])
func exportPlacesTheKeyNameCommentAboveThePublicKeyOnOneLine(
publicKey: String, keyName: String, expected: String
) throws {
let input = try SSHConnectionOpener.authorizedKeyInstallInput(publicKey: publicKey, keyName: keyName)
#expect(String(decoding: input, as: UTF8.self) == expected)
}
@Test
func privateKeyEnvelopeRequiresACompleteJSONObject() throws {
var encoded = try JSONEncoder().encode(
SSHPrivateKeySecret(privateKey: "-----BEGIN TEST-----\nsecret\n-----END TEST-----")
)
let secret = try KeychainSecretStore.decodePrivateKeySecret(from: &encoded)
#expect(encoded.isEmpty)
#expect(secret.matches("-----BEGIN TEST-----\nsecret\n-----END TEST-----"))
#expect(throws: KeychainSecretError.self) {
var data = Data(#"{"privateKey":"secret""#.utf8)
_ = try KeychainSecretStore.decodePrivateKeySecret(
from: &data
)
}
#expect(throws: KeychainSecretError.self) {
var data = Data(#"{"privateKey":"secret"} trailing"#.utf8)
_ = try KeychainSecretStore.decodePrivateKeySecret(
from: &data
)
}
}
@Test
func multipleKeysReuseOneAuthenticatedConnection() async throws {
let password = SSHSecret("one-use")
let request = SSHConnectionRequest(
configuration: SSHConnectionConfiguration(
hostID: UUID(), host: "server.invalid", port: 22,
username: "deploy", credentials: [.password(password)],
expectedHostKeys: []
)
)
let connection = AuthorizedKeyConnection()
try await SSHPTYChannelWorker.installAuthorizedKeys(
[
SSHAuthorizedKeyInstall(publicKey: "ssh-ed25519 first", name: "First"),
SSHAuthorizedKeyInstall(publicKey: "ssh-ed25519 second", name: "Second"),
],
using: request, connection: connection
)
let snapshot = await connection.snapshot()
#expect(snapshot.connects == 1)
#expect(snapshot.executions == 2)
#expect(snapshot.disconnects == 1)
#expect(
snapshot.inputs == [
"# First Key by Termind\nssh-ed25519 first\n",
"# Second Key by Termind\nssh-ed25519 second\n",
])
#expect(password.isConsumed)
}
}
private actor AuthorizedKeyConnection: SSHConnectionProtocol {
struct Snapshot: Sendable {
var connects: Int
var executions: Int
var disconnects: Int
var inputs: [String]
}
private var connects = 0
private var executions = 0
private var disconnects = 0
private var inputs: [String] = []
func connect(using configuration: SSHConnectionConfiguration) async throws {
connects += 1
}
func execute(
_ command: String, workingDirectory: String?, stdin: SSHCommandInput?,
timeout: TimeInterval, outputLimit: Int, onOutput: SSHExecOutputHandler?
) async throws -> SSHExecResult {
executions += 1
let input: String
switch stdin {
case .plain(let bytes):
input = String(decoding: bytes, as: UTF8.self)
case .text(let value):
input = value
case .secret(let secret):
defer { secret.clear() }
input = try secret.withUnsafeBytes { String(decoding: $0, as: UTF8.self) }
case nil:
input = ""
}
inputs.append(input)
return SSHExecResult(
stdout: "", stderr: "", exitCode: 0,
stdoutTruncated: false, stderrTruncated: false
)
}
func openSFTPChannel() async throws -> any SFTPChannelProtocol {
throw TermindSSHError.disconnected
}
func disconnect() async {
disconnects += 1
}
func snapshot() -> Snapshot {
Snapshot(
connects: connects, executions: executions,
disconnects: disconnects, inputs: inputs
)
}
}