╭ changed ────────╮ │src/serve_ssh.zig│ ╰─────────────────╯ ╭───────────╮ │← all files│ ╰───────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │380 const owner_repo = evt.parseOwnerRepoPath(repo_identity) orelse return writeError(sess, "repo path must be <owner>/<repo>"); │ │381 var author_arena = std.heap.ArenaAllocator.init(allocator); │ │382 defer author_arena.deinit(); │ │383 - const author = switch (try authorizeRepoKey(io, &author_arena, handler.admin_repo_path, owner_repo.owner, owner_repo.name, parsed.service, &sess.fingerprint)) { │ │383 + const author = switch (try authorizeRepoKey(io, &author_arena, handler.admin_repo_path, handler.repo_root_path, owner_repo.owner, owner_repo.name, parsed.service, &sess.fingerprint)) {│ │384 .allowed => |user| user, │ │385 .denied => return switch (parsed.service) { │ │386 .upload_pack => writeError(sess, "unauthorized: this SSH key cannot read this repo"), │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │420 const io = sess.conn.io; │ │421 │ │422 const route = fork.parseRoute(fork_path) orelse return writeError(sess, "invalid fork path"); │ │423 - const owner_repo = evt.parseOwnerRepoPath(route.identity) orelse return writeError(sess, "repo path must be <owner>/<repo>"); │ │423 + // the route names the forker and the target repo │ │424 + const forker_repo = evt.parseOwnerRepoPath(route.identity) orelse return writeError(sess, "repo path must be <forker>/<repo>");│ │425 │ │426 var admin = try rp.Repo(.xit, evt.admin_repo_opts).open(io, allocator, .{ .path = handler.admin_repo_path }); │ │427 defer admin.deinit(io, allocator); │ ╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │429 defer admin_arena.deinit(); │ │430 const admin_moment = try evt.currentMoment(evt.admin_repo_opts, &admin); │ │431 const fork_id = try evt.parseEventId(&route.id); │ │431 - const fork_record = (try evt.Fork.readById(evt.AdminDB, evt.admin_repo_opts.hash, admin_moment, &admin_arena, &fork_id)) orelse │ │432 + const forker_id = (try evt.User.readIdByName(evt.AdminDB, evt.admin_repo_opts.hash, admin_moment, forker_repo.owner)) orelse │ │433 + return writeError(sess, "patch draft not found"); │ │434 + const fork_record = (try evt.readForkById(io, allocator, &admin_arena, handler.repo_root_path, &forker_id, &fork_id)) orelse │ │435 return writeError(sess, "patch draft not found"); │ │436 if (fork_record.removed) return writeError(sess, "patch draft not found"); │ │434 - const user = (try evt.User.readById(evt.AdminDB, evt.admin_repo_opts.hash, admin_moment, &admin_arena, fork_record.event.user_id)) orelse│ │437 + const user = (try evt.User.readById(evt.AdminDB, evt.admin_repo_opts.hash, admin_moment, &admin_arena, &forker_id)) orelse │ │438 return writeError(sess, "invalid patch draft"); │ │439 if (user.removed) return writeError(sess, "invalid patch draft"); │ │440 if (service == .receive_pack and !isKeyInAuthorizedKeys(user.event.ssh_keys, &sess.fingerprint)) │ ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │451 inline else => |*repo| try repo.uploadPack(io, allocator, reader, writer, .{ .protocol_version = protocol_version }, &sideband), │ │452 } │ │453 } else { │ │451 - const target = (try evt.Repo.readByOwnerAndName(evt.AdminDB, evt.admin_repo_opts.hash, admin_moment, &admin_arena, owner_repo.owner, owner_repo.name)) orelse │ │454 + const target = (try evt.readRepoById(io, allocator, &admin_arena, handler.repo_root_path, fork_record.event.repo_user_id[0..evt.event_id_size], fork_record.event.repo_id)) orelse│ │455 return writeError(sess, "repo not found"); │ │453 - if (!std.mem.eql(u8, fork_record.event.repo_id, &target.event_id)) return writeError(sess, "patch draft belongs to another repo"); │ │454 - const target_id = std.fmt.bytesToHex(target.event_id, .lower); │ │456 + if (!std.mem.eql(u8, target.event.name, forker_repo.name)) return writeError(sess, "patch draft belongs to another repo"); │ │457 + const target_id = std.fmt.bytesToHex(fork_record.event.repo_id[0..evt.event_id_size].*, .lower); │ │458 const target_path = try std.fs.path.join(allocator, &.{ handler.repo_root_path, &target_id }); │ │459 defer allocator.free(target_path); │ │460 const author: evt.CommitAuthor = .{ .name = user.event.name, .email = user.event.email }; │ ╰───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ ╭─────────────────────────────────────────╮ │547 io: std.Io, │ │548 arena: *std.heap.ArenaAllocator,│ │549 admin_repo_path: []const u8, │ │550 + repo_root_path: []const u8, │ │551 owner_name: []const u8, │ │552 repo_name: []const u8, │ │553 service: GitService, │ ╰─────────────────────────────────────────╯ ╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮ │561 defer admin.deinit(io, allocator); │ │562 │ │563 const moment = try evt.currentMoment(evt.admin_repo_opts, &admin); │ │560 - const repo = (try evt.Repo.readByOwnerAndName(evt.AdminDB, evt.admin_repo_opts.hash, moment, arena, owner_name, repo_name)) orelse {│ │564 + const repo = (try evt.readRepoByOwnerAndName(io, allocator, arena, moment, repo_root_path, owner_name, repo_name)) orelse { │ │565 if (service == .upload_pack) return .not_found; │ │566 const owner = (try evt.User.readByName(io, allocator, admin_repo_path, arena, owner_name)) orelse return .not_found; │ │567 return if (isKeyInAuthorizedKeys(owner.event.ssh_keys, fingerprint)) │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯