275 lines · 11.4 KB
import { advertisement, artifactsSource, relayPack } from "./relay";
import { isHiddenRef, pullBaseRef, pullHeadRef } from "./hidden-refs";
import { isPrivateRef } from "./advertise-filter";
import { branchSha, listRefs } from "./refs";
import { pushToArtifacts } from "./writer";
import { withStore, ZERO_SHA } from "./store";
import { enforceRateLimit } from "../limits";
import { all, first, run } from "../db";
import { loadRepoById } from "../repos";
import type { RepoRow } from "~/lib/types";

const MAX_BRIDGE_BYTES = 64 * 1024 * 1024;
const DROP_ATTEMPTS = 3;

/** 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.
 */
function canBridgeBase(baseRepo: RepoRow): boolean {
  return baseRepo.visibility === "public";
}

async function hasCommit(repo: RepoRow, sha: string): Promise<boolean> {
  return withStore(repo.artifacts_name, async (store) => (await store.commit(sha)) !== null);
}

/**
 * Ensures `sha` and its history exist in `to`, pinned by the hidden `ref` so Artifacts keeps them.
 * Objects are relayed Artifacts-to-Artifacts, never from user-supplied URLs; the hidden ref is filtered
 * out of push processing, so no CI, webhooks or indexing run for it. Returns false when refused.
 */
/**
 * Re-reads both repos right before writing, so a bridge that started before a visibility change cannot
 * pin objects under the old visibility after the change's cleanup ran.