╭──────────╮ │← previous│ ╰──────────╯ ╭ changed ────────╮ │src/serve_ssh.zig│ ╰─────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │13 pub const SessionHandler = struct { │ │14 admin_repo_path: []const u8, │ │15 repo_root_path: []const u8, │ │16 - // test mode serves repos directly by path instead of resolving them as │ │17 - // <owner>/<repo> through the event store │ │18 - is_test: bool, │ │16 err: *std.Io.Writer, │ │17 │ │18 pub fn handleSession(self: *const SessionHandler, sess: *ssh.SessionCtx, request: ssh.Request) !void {│ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │213 const any_repo_opts: rp.AnyRepoOpts(.xit) = .{}; │ │214 │ │215 // authenticate pushes: the authenticated key must be registered to the │ │219 - // repo's owner. skipped in test mode, which serves repos directly by path. │ │220 - if (create_if_missing and !handler.is_test) { │ │216 + // repo's owner. │ │217 + if (create_if_missing) { │ │218 const owner_repo = evt.parseOwnerRepoPath(parsed.dir) orelse return writeError(sess, "repo path must be <owner>/<repo>");│ │219 if (!try isKeyAuthorized(io, allocator, handler.admin_repo_path, owner_repo.owner, &sess.fingerprint)) │ │220 return writeError(sess, "unauthorized: this SSH key is not registered to the repo owner"); │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │221 } │ │222 │ │226 - const repo_path = switch (try serve_common.resolveRepoPath(io, allocator, handler.is_test, handler.repo_root_path, handler.admin_repo_path, parsed.dir, create_if_missing)) {│ │223 + const repo_path = switch (try serve_common.resolveRepoPath(io, allocator, handler.repo_root_path, handler.admin_repo_path, parsed.dir, create_if_missing)) { │ │224 .ok => |p| p, │ │225 .invalid => return writeError(sess, "repo path must be <owner>/<repo>"), │ │226 .not_found => return writeError(sess, "repo not found"), │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭ changed ───────╮ │src/test/net.zig│ ╰────────────────╯ ╭──────────────────────────────────────╮ │2 const builtin = @import("builtin");│ │3 const hx = @import("haxy"); │ │4 const xit = hx.xit; │ │5 +const evt = hx.event; │ │6 const rp = xit.repo; │ │7 const rf = xit.ref; │ │8 const work = xit.workdir; │ ╰──────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────╮ │24 test "push small" { │ │25 const io = std.testing.io; │ │26 const allocator = std.testing.allocator; │ │26 - try testPush(.xit, .{ .wire = .http }, io, allocator); │ │27 if (.windows != builtin.os.tag) { │ │28 try testPush(.xit, .{ .wire = .ssh }, io, allocator);│ │29 } │ ╰─────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────╮ │32 test "push creates missing repo under serve" { │ │33 const io = std.testing.io; │ │34 const allocator = std.testing.allocator; │ │35 - try testPushCreatesMissingRepo(.xit, .{ .wire = .http }, io, allocator); │ │35 if (.windows != builtin.os.tag) { │ │36 try testPushCreatesMissingRepo(.xit, .{ .wire = .ssh }, io, allocator);│ │37 } │ ╰───────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────╮ │67 test "push large subprocess" { │ │68 const io = std.testing.io; │ │69 const allocator = std.testing.allocator; │ │71 - try testPushLarge(.git, .{ .wire = .http }, true, io, allocator); │ │70 if (.windows != builtin.os.tag) { │ │71 try testPushLarge(.git, .{ .wire = .ssh }, true, io, allocator);│ │72 } │ ╰────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────╮ │ 94 try priv_key_file.setPermissions(io, @enumFromInt(0o600)); │ │ 95 } │ │ 96 } │ │ 97 + │ │ 98 + // seed the admin event store so the server can resolve <owner>/<repo> paths│ │ 99 + // and authenticate pushes from the dev key above │ │100 + try setupAdmin(io, allocator, temp_dir_name); │ │101 │ │102 const cwd_path = try std.process.currentPathAlloc(io, allocator); │ │103 defer allocator.free(cwd_path); │ ╰─────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │108 const ssh_listen_arg = std.fmt.comptimePrint("127.0.0.1:{}", .{ssh_port}); │ │109 │ │110 const process = try std.process.spawn(io, .{ │ │109 - .argv = &.{ haxy_path, "serve", "--http-listen", http_listen_arg, "--ssh-listen", ssh_listen_arg, "--data-dir", temp_dir_name, "--test" },│ │111 + .argv = &.{ haxy_path, "serve", "--http-listen", http_listen_arg, "--ssh-listen", ssh_listen_arg, "--data-dir", temp_dir_name }, │ │112 .stdin = .ignore, │ │113 .stdout = .ignore, │ │114 .stderr = .ignore, │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │150 var server_process = try runServer(io, allocator, temp_dir_name); │ │151 defer _ = server_process.kill(io); │ │152 │ │151 - const cwd_path = try std.process.currentPathAlloc(io, allocator); │ │152 - defer allocator.free(cwd_path); │ │153 - │ │154 - const server_path = try std.fs.path.join(allocator, &.{ cwd_path, temp_dir_name, "repos", "server" }); │ │153 + // register the repo under admin and locate its on-disk directory │ │154 + const server_path = (try repoOnDiskPath(io, allocator, temp_dir_name, "testrepo", true)).?; │ │155 defer allocator.free(server_path); │ │156 │ │157 var server_repo = try rp.Repo(.xit, .{ .is_test = true }).init(io, allocator, .{ .path = server_path });│ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────╮ │next →│ ╰──────╯