import { accountDb, repoDb } from "../scoped-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 repoDb(repoId).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 db = repoDb(repo.id);
const [owner, repoRows, envRows] = await Promise.all([
accountDb(repo.owner_id).all<OwnerScoped & { name: string; value: string }>(
"SELECT name, value, visibility, selected_repos FROM owner_variables WHERE owner_id = ?",
repo.owner_id,
),
db.all<{ name: string; value: string }>("SELECT name, value FROM repo_variables WHERE repo_id = ?", repo.id),
environmentId
? db.all<{ name: string; value: string }>(
"SELECT name, value FROM environment_variables WHERE environment_id = ?",
environmentId,
)