65 lines · 3.1 KB
import { all, first } from "../db";
import type { RepoRow } from "~/lib/types";

export type OwnerVisibility = "all" | "private" | "selected";

type EncryptedRow = { name: string; ciphertext: string; iv: string };
type OwnerScoped = { visibility: OwnerVisibility; selected_repos: string };

/** Owner-level secrets and variables apply to all repos, only private repos, or an explicit allow-list. */
export function ownerScopeAllows(row: OwnerScoped, repo: Pick<RepoRow, "id" | "visibility">): boolean {
  if (row.visibility === "all") return true;
  if (row.visibility === "private") return repo.visibility === "private";
  const selected: unknown = JSON.parse(row.selected_repos);
  return Array.isArray(selected) && selected.includes(repo.id);
}

export async function environmentIdFor(repoId: string, name: string | null | undefined): Promise<string | null> {
  if (!name) return null;
  const row = await first<{ id: string }>("SELECT id FROM environments WHERE repo_id = ? AND name = ?", repoId, name);
  return row?.id ?? null;
}

/** The `vars` context: environment variables override repository variables, which override owner variables. */
export async function loadVariables(repo: RepoRow, environmentId: string | null): Promise<Record<string, string>> {
  const [owner, repoRows, envRows] = await Promise.all([
    all<OwnerScoped & { name: string; value: string }>(
      "SELECT name, value, visibility, selected_repos FROM owner_variables WHERE owner_id = ?",
      repo.owner_id,
    ),
    all<{ name: string; value: string }>("SELECT name, value FROM repo_variables WHERE repo_id = ?", repo.id),
    environmentId
      ? all<{ name: string; value: string }>(
          "SELECT name, value FROM environment_variables WHERE environment_id = ?",
          environmentId,
        )
      : Promise.resolve([]),
  ]);
  const values: Record<string, string> = {};
  for (const row of owner.filter((candidate) => ownerScopeAllows(candidate, repo))) values[row.name] = row.value;
  for (const row of repoRows) values[row.name] = row.value;