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/apps/sudo/README.md

71 lines3,213 bytesCodeBlame
1# sudo
2
3g1t's staff console, at <https://sudo.g1t.sh>. Staff use it to manage how
4accounts pay: comp a workspace, set custom terms (a discount, a ceiling on
5unpaid usage, an end date), create Enterprise accounts that pay for several
6workspaces, move workspaces on and off them, issue credits, and see where
7every account stands this month with its ledger and audit log.
8
9It holds no data. Everything goes to the billing service's staff methods
10(`admin_*`, see `BillingAdminApi` in `packages/contracts/src/billing.ts`),
11and each change is recorded there with the staff member's email.
12
13## How it is locked
14
151. **Cloudflare Access** sits in front of `sudo.g1t.sh` and signs people in.
162. **The worker checks Access's work** on every request, the stylesheet
17 included (`run_worker_first`): it verifies the `Cf-Access-Jwt-Assertion`
18 JWT itself (RS256 against the team's published keys, audience, issuer,
19 expiry), then requires its email to be in `STAFF_EMAILS`. That email is
20 who every change is recorded as. See `app/lib/access.ts`.
213. **It fails closed.** Until `ACCESS_TEAM_DOMAIN`, `ACCESS_AUD` and
22 `STAFF_EMAILS` are all set, every request gets a 403 saying sudo is not
23 configured.
244. **Changes** are POSTs only, and only from sudo's own pages (`Origin`, or
25 `Referer`, must be `https://sudo.g1t.sh`). Terms, enterprise moves and new
26 enterprises show a confirmation step first; a credit needs the workspace's
27 slug typed out.
285. **The pages ship no JavaScript.** The content security policy forbids
29 every script and inline style; responses are `no-store`, `noindex` and
30 cannot be framed. The worker has no `workers.dev` address or preview URLs.
31
32## Setting up Access (once, in the Cloudflare dashboard)
33
341. **Zero Trust → Access → Applications → Add an application → Self-hosted.**
35 - Application name: `sudo`.
36 - Session duration: short, such as 8 hours.
37 - Public hostname: `sudo.g1t.sh` (path empty, so it covers everything).
382. **Add a policy:** action *Allow*, include *Emails* → the owner's address
39 (the same addresses as `STAFF_EMAILS`). Add more staff here *and* in
40 `STAFF_EMAILS`; either one alone is not enough.
413. Save, then open the application's **Overview** (or *Basic information*)
42 and copy the **Application Audience (AUD) tag**.
434. Find the **team domain** under **Zero Trust → Settings → Custom pages**
44 (or *Team name and domain*): it looks like `<team>.cloudflareaccess.com`.
455. Put both into `wrangler.jsonc`:
46
47 ```jsonc
48 "vars": {
49 "ACCESS_TEAM_DOMAIN": "<team>.cloudflareaccess.com",
50 "ACCESS_AUD": "<the AUD tag>",
51 "STAFF_EMAILS": "syntaqx@gmail.com"
52 }
53 ```
54
556. Deploy: `scripts/deploy.sh sudo` (after `billing`, whose `admin_*`
56 methods it calls).
57
58Visit <https://sudo.g1t.sh>: Access asks you to sign in, then the accounts
59list opens. Anyone else gets Access's own refusal; anyone Access lets in who
60is not in `STAFF_EMAILS` gets a 403 from the worker.
61
62## Working on it
63
64```sh
65npm run typecheck -w @g1t/sudo
66npm test -w @g1t/sudo # JWT verification, forms, money
67npm run build -w @g1t/sudo
68```
69
70`npm run dev` serves the pages, but every request is refused without a real
71Access token, by design.