Files
Termind/FrameworkTests/TailscaleSSHWireTests.swift
T

73 lines
3.0 KiB
Swift

import Foundation
import TermindApplication
import TermindDomain
import Testing
@testable import TermindRemoteInfrastructure
/// Transport behavior shared by macOS and iOS, exercised against a real SSH/SFTP fixture.
@Suite(
.enabled(
if: ProcessInfo.processInfo.environment["TERMIND_SSH_FIXTURE"] != nil
|| ProcessInfo.processInfo.environment["TERMIND_SSH_FIXTURE_JSON"] != nil), .serialized
)
nonisolated struct TailscaleSSHWireTests {
@Test func noneAuthenticationSupportsSFTPAndAdditionalConnections() async throws {
let fixture = try Fixture.load()
let network = LoopbackTailnet(port: fixture.port, fingerprint: fixture.hostFingerprint)
for _ in 0..<2 {
var configuration = SSHConnectionConfiguration(
hostID: UUID(), host: "fixture.test.ts.net", port: 22,
username: "none", credentials: [], expectedHostKeys: [])
configuration.network = network
configuration.tailscaleNodeID = "fixture-node"
let connection = SSHConnection()
do {
try await connection.connect(
using: SSHConnectionRequest(
configuration: configuration,
interactionPolicy: .forbidden))
let files = try await connection.openSFTPChannel()
let contents = try await files.readFile(at: "/fixture.txt", maximumBytes: 1024)
#expect(contents == Data("fixture\n".utf8))
#expect(try await files.listDirectory(at: "/").count == 1)
await files.disconnect()
await connection.disconnect()
} catch {
await connection.disconnect()
throw error
}
}
}
private struct Fixture: Decodable {
var port: Int
var hostFingerprint: String
static func load() throws -> Self {
let environment = ProcessInfo.processInfo.environment
// Passing public endpoint metadata through the test runner also works in the app sandbox.
let data: Data
if let json = environment["TERMIND_SSH_FIXTURE_JSON"] {
data = Data(json.utf8)
} else {
let path = try #require(environment["TERMIND_SSH_FIXTURE"])
data = try Data(contentsOf: URL(fileURLWithPath: path))
}
return try JSONDecoder().decode(Self.self, from: data)
}
}
private struct LoopbackTailnet: SSHNetworkDialing {
var port: Int
var fingerprint: String
func open(host: String, port: Int, timeout: TimeInterval) async throws -> Int32 {
#expect(host == "fixture.test.ts.net")
return try SSHSocketConnector.open(host: "127.0.0.1", port: self.port)
}
func hostKeys(stableNodeID: String) async throws -> Set<SSHHostKeyIdentity> {
#expect(stableNodeID == "fixture-node")
return [SSHHostKeyIdentity(algorithm: .rsa, fingerprint: fingerprint)]
}
}
}