╭ changed ─────────────────╮ │src/serve_ssh_protocol.zig│ ╰──────────────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │140 const keypair = Ed25519.KeyPair.generate(io); │ │141 // owner-only from the start — never a window where the key is readable │ │142 const permissions: std.Io.File.Permissions = if (builtin.os.tag == .windows) .default_file else @enumFromInt(0o600);│ │143 - const file = try cwd.createFile(io, path, .{ .permissions = permissions }); │ │144 - defer file.close(io); │ │145 - try file.writeStreamingAll(io, &keypair.secret_key.bytes); │ │143 + // linked into place only once complete, and never over an existing key │ │144 + var atomic_file = try cwd.createFileAtomic(io, path, .{ .permissions = permissions }); │ │145 + defer atomic_file.deinit(io); │ │146 + try atomic_file.file.writeStreamingAll(io, &keypair.secret_key.bytes); │ │147 + try atomic_file.link(io); │ │148 return .{ .keypair = keypair }; │ │149 + } │ │150 + │ │151 + /// what `ssh` shows a user on first connect │ │152 + pub fn fingerprint(self: HostKey, allocator: std.mem.Allocator) ![fingerprint_len]u8 { │ │153 + var blob: std.ArrayList(u8) = .empty; │ │154 + defer blob.deinit(allocator); │ │155 + try self.appendPublicBlob(&blob, allocator); │ │156 + return formatFingerprint(blob.items); │ │157 } │ │158 │ │159 /// SSH wire-format ed25519 public key blob (used as K_S in the hash and │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────╮ │2136 try buf.appendSlice(allocator, &bytes); │ │2137 } │ │2138 │ │2129 -test "pty dimensions have bounded axes and area, preserving normal and zero sizes" { │ │2139 +test "pty dimensions have bounded axes, preserving normal and zero sizes" { │ │2140 for ([_]struct { width: u32, height: u32, expected: PtySize }{ │ │2141 .{ .width = 80, .height = 24, .expected = .{ .width_cells = 80, .height_cells = 24 } },│ │2142 .{ .width = 0, .height = 0, .expected = .{ .width_cells = 0, .height_cells = 0 } }, │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────╯