pr_01m47d15m3e54sn21z27rpy5n9/apps/sudo/README.md

119 lines6,110 bytesCodeBlame

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Billing accounts, terms and enterprises; g1t is no longer free1# sudo
2
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace3g1t's staff console, at <https://sudo.g1t.sh>. It is organised the way
4customers know g1t: by **workspace**.
5
Stripe webhooks, enterprise invoices, and sudo for both6- **Workspaces** (the home page): every workspace, newest first, 50 to a
7 page, with its owners, members, who it is billed to, its terms, this
8 month's usage against its limit, what it was charged and what it cost
9 g1t. Search by workspace, owner, email or enterprise (across the whole
10 list); filter to stopped or warning, comped or custom, or on an
11 enterprise. Billing's figures are fetched for exactly the page shown, so
12 the filters, and the totals over the list, cover that page; the page
13 says so when there is more than one. A workspace's page shows its members, and under
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace14 **Billing** its terms, who it is billed to (move it onto or off an
15 enterprise), a credit form, a Stripe billing link, its ledger and its
16 audit log.
17- **Enterprises**: customers that pay for several workspaces with one
18 bill, one limit and one set of terms. Each has its workspaces (add or
Stripe webhooks, enterprise invoices, and sudo for both19 remove them), combined usage, terms, credits, ledger and audit log, and
20 **Invoices**: where they go (the billing email, which also makes its
21 Stripe customer), a "Send invoice now" button, and every invoice with
22 its status (open, paid, overdue, void), a line per workspace, and a link
23 to Stripe's hosted invoice page. An invoice also goes out on its own as
24 each month closes: one Stripe invoice, a line per workspace for what it
25 owes, net 30, emailed by Stripe.
26- **Stripe**: whether billing's key is in test or live mode (or off), the
27 webhook Stripe calls (URL, endpoint id, events, who registered it and
28 when), and the events Stripe sent lately with what billing did with
29 each. "Register webhook" (or "Replace") has billing delete the endpoint
30 it made before, create a new one and keep its signing secret, which no
31 one sees. Do it once per mode, and again after switching to live keys.
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace32
33Billing's internal account ids (`ws_<slug>` for a workspace's own,
34`ent_…` for an enterprise) are never shown as names; an enterprise's id
35appears only as small "Billing account id" text. Old `/accounts/…` links
36redirect to the workspace or enterprise they meant.
37
38**Cards stay on Stripe.** sudo never shows a card field. To help a customer
39update their card or see invoices, staff make a Stripe billing link on the
40workspace's page (it is recorded) and send it to the owner.
Billing accounts, terms and enterprises; g1t is no longer free41
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace42It holds no data. Workspaces, owners and members come from identity's
43staff methods (`admin_workspaces`, `admin_workspace`; `IdentityAdminApi` in
44`packages/contracts/src/identity.ts`); everything about money goes to the
45billing service's (`admin_*`, `BillingAdminApi` in
46`packages/contracts/src/billing.ts`), where each change is recorded with
47the staff member's email. Both are reached over service bindings only, and
48nothing but sudo binds to them.
Billing accounts, terms and enterprises; g1t is no longer free49
50## How it is locked
51
521. **Cloudflare Access** sits in front of `sudo.g1t.sh` and signs people in.
532. **The worker checks Access's work** on every request, the stylesheet
54 included (`run_worker_first`): it verifies the `Cf-Access-Jwt-Assertion`
55 JWT itself (RS256 against the team's published keys, audience, issuer,
56 expiry), then requires its email to be in `STAFF_EMAILS`. That email is
57 who every change is recorded as. See `app/lib/access.ts`.
583. **It fails closed.** Until `ACCESS_TEAM_DOMAIN`, `ACCESS_AUD` and
59 `STAFF_EMAILS` are all set, every request gets a 403 saying sudo is not
60 configured.
614. **Changes** are POSTs only, and only from sudo's own pages (`Origin`, or
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace62 `Referer`, must be `https://sudo.g1t.sh`). Terms, enterprise moves, new
Stripe webhooks, enterprise invoices, and sudo for both63 enterprises, Stripe billing links, invoice emails, invoices and the
64 webhook show a confirmation step first; a credit needs the workspace's
65 slug typed out.
Billing accounts, terms and enterprises; g1t is no longer free665. **The pages ship no JavaScript.** The content security policy forbids
67 every script and inline style; responses are `no-store`, `noindex` and
68 cannot be framed. The worker has no `workers.dev` address or preview URLs.
69
70## Setting up Access (once, in the Cloudflare dashboard)
71
721. **Zero Trust → Access → Applications → Add an application → Self-hosted.**
73 - Application name: `sudo`.
74 - Session duration: short, such as 8 hours.
75 - Public hostname: `sudo.g1t.sh` (path empty, so it covers everything).
sudo: Access is on, and everyone at g1t.sh is staff762. **Add a policy** (`g1t staff`): action *Allow*, include *Emails* → the
77 owner's address, and *Emails ending in* → `g1t.sh` for everyone with a
78 g1t address (the same entries as `STAFF_EMAILS`, where a domain is
79 written `@g1t.sh`). Add more staff here *and* in `STAFF_EMAILS`; either
80 one alone is not enough.
Billing accounts, terms and enterprises; g1t is no longer free813. Save, then open the application's **Overview** (or *Basic information*)
82 and copy the **Application Audience (AUD) tag**.
834. Find the **team domain** under **Zero Trust → Settings → Custom pages**
84 (or *Team name and domain*): it looks like `<team>.cloudflareaccess.com`.
855. Put both into `wrangler.jsonc`:
86
87 ```jsonc
88 "vars": {
89 "ACCESS_TEAM_DOMAIN": "<team>.cloudflareaccess.com",
90 "ACCESS_AUD": "<the AUD tag>",
sudo: Access is on, and everyone at g1t.sh is staff91 "STAFF_EMAILS": "syntaqx@gmail.com, @g1t.sh"
Billing accounts, terms and enterprises; g1t is no longer free92 }
93 ```
94
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace956. Deploy: `scripts/deploy.sh sudo` (after `billing` and `identity`, whose
96 `admin_*` methods it calls).
Billing accounts, terms and enterprises; g1t is no longer free97
Billing on Stripe's pages, month-end charges, warnings; sudo by workspace98Visit <https://sudo.g1t.sh>: Access asks you to sign in, then the workspaces
Billing accounts, terms and enterprises; g1t is no longer free99list opens. Anyone else gets Access's own refusal; anyone Access lets in who
100is not in `STAFF_EMAILS` gets a 403 from the worker.
101
sudo: WARP sign-in, and comped accounts say Comped102## Signing in through WARP
103
104Staff signed in to the Zero Trust org in the Cloudflare One agent (WARP)
105reach sudo without the login page: the org allows WARP sessions as Access
106sign-ins (8 hours), the sudo app accepts them, and the `g1t staff` policy
107is also on the WARP enrollment app, so staff can enroll their devices.
108The same two checks still apply: the Access policy, and `STAFF_EMAILS`.
109
Billing accounts, terms and enterprises; g1t is no longer free110## Working on it
111
112```sh
113npm run typecheck -w @g1t/sudo
Stripe webhooks, enterprise invoices, and sudo for both114npm test -w @g1t/sudo # JWT verification, forms, money, the workspace join, paging
Billing accounts, terms and enterprises; g1t is no longer free115npm run build -w @g1t/sudo
116```
117
118`npm run dev` serves the pages, but every request is refused without a real
119Access token, by design.