flagon-io/g1t

public

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

g1t/packages/contracts/src/guardrails.ts

89 lines3,338 bytesCodeBlame
1/**
2 * Guardrails: what a workspace lets its agents do in a sandbox, kept by the
3 * work service. Mirrors `g1t_contracts::guardrails`.
4 */
5import type { ServiceBinding } from "./clients";
6import type { User, Viewer } from "./identity";
7import type { RepoPath } from "./repos";
8import type { Result } from "./result";
9
10/** What one level, the workspace or a project, sets. Unset is inherited. */
11export type GuardrailSettings = {
12 restrictNetwork?: boolean | null;
13 /** The registries that are on, by id. Replaces the inherited list. */
14 registries?: string[] | null;
15 /** More hosts to allow; they add to the other level's. */
16 domains?: string[];
17 /** Built-in command rules turned on or off, by id. */
18 rules?: Record<string, boolean>;
19 /** Permission rules to refuse; they add to the other level's. */
20 deny?: string[];
21 /** The most a run may cost, in US dollars. Zero means no cap. */
22 budgetUsd?: number | null;
23 /** How long each kind of run may take, in minutes. */
24 minutes?: Record<string, number>;
25 updatedBy?: string | null;
26 updatedAt?: string | null;
27};
28
29/** What a run actually gets. */
30export type Guardrails = {
31 restrictNetwork: boolean;
32 registries: string[];
33 domains: string[];
34 /** Every host a sandbox may reach. `*.example.com` covers subdomains. */
35 hosts: string[];
36 rules: Record<string, boolean>;
37 deny: string[];
38 /** Null: no cap. */
39 budgetUsd: number | null;
40 minutes: Record<string, number>;
41};
42
43export type RegistryInfo = { id: string; name: string; hosts: string[] };
44export type RuleInfo = { id: string; title: string; about: string };
45
46export type GuardrailsView = {
47 workspace: GuardrailSettings;
48 project: GuardrailSettings | null;
49 defaults: Guardrails;
50 /** g1t's defaults with the workspace's: what a project inherits. */
51 inherited: Guardrails;
52 effective: Guardrails;
53 g1tHosts: string[];
54 registries: RegistryInfo[];
55 rules: RuleInfo[];
56};
57
58export interface GuardrailsApi {
59 /** Members only. With `repo`, that project's level too. */
60 getGuardrails(viewer: Viewer, workspace: string, repo?: RepoPath | null): Promise<Result<GuardrailsView>>;
61 /** The workspace's level (owners), or with `repo`, that project's (members). */
62 updateGuardrails(
63 actor: User,
64 workspace: string,
65 repo: RepoPath | null,
66 settings: GuardrailSettings,
67 ): Promise<Result<GuardrailsView>>;
68 /** For the runner: what a run in `repo` gets. */
69 runGuardrails(repo: RepoPath): Promise<Result<Guardrails>>;
70}
71
72/** The guardrails methods of the work service. */
73export function guardrailsClient(service: ServiceBinding): GuardrailsApi {
74 const call = async <T>(method: string, args: object): Promise<T> => {
75 const response = await service.fetch(`https://service/rpc/${method}`, {
76 method: "POST",
77 headers: { "content-type": "application/json" },
78 body: JSON.stringify(args),
79 });
80 if (!response.ok) throw new Error(`${method} failed with status ${response.status}`);
81 return (await response.json()) as T;
82 };
83 return {
84 getGuardrails: (viewer, workspace, repo) => call("get_guardrails", { viewer, workspace, repo: repo ?? null }),
85 updateGuardrails: (actor, workspace, repo, settings) =>
86 call("update_guardrails", { actor, workspace, repo, settings }),
87 runGuardrails: (repo) => call("run_guardrails", { repo }),
88 };
89}