import { COUNTED } from "./issue-counters";
import { waitUntil } from "cloudflare:workers";
import { all, batch, stmt } from "./db";
import { loadUserById, toViewer } from "./auth";
import { pullHeadAccessible } from "./git/bridge-policy";
import { dropHiddenRefsForRepo, dropPullRefsForIssue, requestHiddenRefCleanup } from "./git/pull-bridge";
import { CAPS } from "./limits";
import { addIssueEvent } from "./pulls";
import type { PullRow } from "./pulls";
import { hasPermission, loadRepoById, repoPermission } from "./repos";
import type { RepoRow, Viewer } from "~/lib/types";
type GuardedPull = Pick<PullRow, "issue_id" | "repo_id" | "head_repo_id" | "author_id" | "state">;
/** Closes a pull request because its author can no longer read one of its repositories. */
async function closeForRevokedAccess(pull: GuardedPull): Promise<void> {
const now = Date.now();
await batch([
stmt(
"UPDATE issues SET state = 'closed', closed_at = ?, closed_by = NULL, updated_at = ? WHERE id = ? AND state = 'open'",
now,
now,
pull.issue_id,
),
stmt(
`UPDATE repos SET open_pulls_count = MAX(open_pulls_count - 1, 0) WHERE id = ? AND ${COUNTED}`,
pull.repo_id,
pull.issue_id,
),
]);
await addIssueEvent(pull.issue_id, null, "closed", { reason: "access_revoked" });
waitUntil(dropPullRefsForIssue(pull.issue_id));
}
/**
* Whether a fork pull request may still synchronize, bridge or run CI: the author must currently read
* both repositories and the head must be a live fork of the base. When that stopped being true the pull
* request is closed and its hidden refs dropped, so revoked readers stop receiving (and feeding) history.
*/
export async function ensurePullHeadAccessible(pull: GuardedPull): Promise<boolean> {