93 lines · 4.8 KB
import { waitUntil } from "cloudflare:workers";
import { chunks, placeholders, stmt } from "../db";
import { accountDb, repoDb } from "../scoped-db";
import { deleteRunnerRow } from "../ci/runner-registration";
import { cancelActiveJob } from "../ci/jobs";
import { forgetLocator } from "../scoped-db/locators";
import { dropRepoRunners } from "../repo-account-cleanup";
import { dropMcpAccess, purgeInaccessibleFollowers } from "../access-revocation";
import { publishScopeGauges } from "../metering/scope-gauges";

/**
 * Integrations and legacy webhooks are configured by a repository's admins, so they do not survive a change
 * of ownership: the new owner must knowingly re-enable them. Pull mirrors would otherwise keep writing refs as
 * the old admin and push mirrors would keep exporting the new owner's pushes to the old admin's GitHub repo.
 * Deploy tokens were minted by the old admins, so they are revoked too. These are the D1 statements (batch them
 * with the transfer); the repository's own webhooks and deploy tokens are handled by `disableRepoConfigOnTransfer`.
 */
export function repoOwnershipChangeStatements(repoId: string, actorId: string | null): D1PreparedStatement[] {
  const now = Date.now();
  return [
    stmt(
      `INSERT INTO integration_audit (id, integration_id, actor_id, action, detail, created_at)
       SELECT lower(hex(randomblob(16))), id, ?, 'repo.transferred', ?, ? FROM integrations
       WHERE scope_type = 'repo' AND scope_id = ? AND active = 1`,
      actorId,
      JSON.stringify({ reason: "Repository transferred; integration disabled until the new owner re-enables it" }),
      now,
      repoId,
    ),
    stmt(
      `UPDATE integrations SET active = 0, updated_at = ?,
         config = json_remove(json_set(config, '$.githubMirror', 'none'), '$.githubRepo')
       WHERE scope_type = 'repo' AND scope_id = ?`,
      now,
      repoId,
    ),
  ];
}

/**