g1t/services/deployments/src/access.ts

43 lines1,661 bytesCodeBlame
1/**
2 * Who may do what with a project's deployments: each method's capability
3 * on the project's repository. Seeing deployments takes Read; deploying,
4 * redeploying and taking an app down spend compute and take Write (`run`);
5 * deployment settings and domains take Admin (`manage_integrations`).
6 * Types only, so the table is tested apart from the service.
7 */
8
9import type { Capability, Project, RepoRef, User } from "@g1t/contracts";
10
11export const NEEDS = {
12 settings: "read",
13 list: "read",
14 get: "read",
15 listDomains: "read",
16 redeploy: "run",
17 stack: "run",
18 takeDown: "run",
19 updateSettings: "manage_integrations",
20 addDomain: "manage_integrations",
21 removeDomain: "manage_integrations",
22 refreshDomain: "manage_integrations",
23} as const satisfies Record<string, Capability>;
24
25export type Method = keyof typeof NEEDS;
26
27/** The repository a project's permission comes from. A mirrored one has none: its workspace's base permission decides. */
28export function repoRef(project: Project): RepoRef {
29 if (project.source.kind === "hosted") {
30 return { id: project.source.repoId, namespace: project.source.repo.namespace, isPrivate: project.private };
31 }
32 return { id: "", namespace: project.workspace, isPrivate: project.private };
33}
34
35/**
36 * Whether whoever a pull request is for is trusted with a project's secrets
37 * without asking what they may do: only g1t itself, in work nobody asked it
38 * for. A change g1t made for someone is for them (`workOwner`), and they are
39 * asked about like anyone else.
40 */
41export function trustedOutright(owner: Pick<User, "kind">): boolean {
42 return owner.kind === "agent" || owner.kind === "system";
43}