import { loadUserById, toViewer } from "../auth";
import { hasPermission, repoPermission } from "../repos";
import type { RepoRow } from "~/lib/types";
/** Copying must never widen visibility: private objects may only land in a private repository. */
export function canBridge(from: RepoRow, to: RepoRow): boolean {
return from.visibility === "public" || to.visibility === "private";
}
/**
* Base commits copied into the head repo become readable by everyone who can read the head repo, which
* is not a subset of base readers (not even with the same owner: collaborators differ). Only public
* bases may flow there; private bases use the git container, which never stores objects in the fork.
*/
export function canBridgeBase(baseRepo: RepoRow): boolean {
return baseRepo.visibility === "public";
}
/** A pull request head must be the base itself or a live (not detached) direct fork of the base. */
export function isPullHeadRepo(
baseRepo: Pick<RepoRow, "id">,
headRepo: Pick<RepoRow, "id" | "fork_of_id" | "detached">,
): boolean {
return headRepo.id === baseRepo.id || (headRepo.fork_of_id === baseRepo.id && headRepo.detached !== 1);
}
export type PullAccessSubject = { author_id: string };
/**
* Whether a fork pull request may still move objects from its head into its base: the head must be a
* fork of the base, the copy must not widen visibility, and the author must currently be able to read
* both repositories. A reader who was removed from the base therefore stops receiving its history
* (and stops feeding theirs) the moment access is revoked, not when someone notices.
*/
export async function pullHeadAccessible(
pull: PullAccessSubject,
baseRepo: RepoRow,
headRepo: RepoRow,
): Promise<boolean> {
if (baseRepo.id === headRepo.id) return true;