141 lines · 5.5 KB
import { all, first, MAX_IN_LIST, placeholders } from "../db";
import { accountDb, repoDb, type ScopedDb } from "../scoped-db";
import { encryptRepoSecret } from "../secrets";
import { assertBelowCap, CAPS } from "../limits";
import { canAdministerAccount } from "../repos";
import { notFoundError, forbidden } from "../errors";
import type { OwnerVisibility } from "./config-values";
import type { Viewer } from "~/lib/types";

export type ConfigScope =
  | { kind: "repo"; id: string }
  | { kind: "environment"; id: string; repoId: string }
  | { kind: "owner"; id: string; visibility: OwnerVisibility; selectedRepos: string[] };

const TABLES = {
  variable: {
    repo: ["repo_variables", "repo_id"],
    environment: ["environment_variables", "environment_id"],
    owner: ["owner_variables", "owner_id"],
  },
  secret: {
    repo: ["secrets", "repo_id"],
    environment: ["environment_secrets", "environment_id"],
    owner: ["owner_secrets", "owner_id"],
  },
} as const;

type Kind = keyof typeof TABLES;

/** Repository and environment values live in the repository's RepoState, owner values in the owner's AccountState. */
function scopeDb(scope: ConfigScope): ScopedDb {
  if (scope.kind === "owner") return accountDb(scope.id);
  return repoDb(scope.kind === "repo" ? scope.id : scope.repoId);
}

function table(kind: Kind, scope: ConfigScope): readonly [string, string] {
  return TABLES[kind][scope.kind];
}

async function assertRoom(kind: Kind, scope: ConfigScope, name: string): Promise<void> {