Merge pull request 'docs: this describes the prod deployment now, not beta' (#11) from fix/docs-prod-forge-bases into main

Docs-only. NOTE: merged WITHOUT a completed granthi-review. The gate's webhook rejection was fixed today (item 52eea395), but reviews still fail open — diff fetch timeout, and shre-router returning prose instead of JSON (item 6d4e8819). Merged on explicit human approval, not on a green check.
This commit is contained in:
Nirav Patel
2026-08-30 01:25:54 -04:00
2 changed files with 45 additions and 18 deletions
+38 -13
View File
@@ -1,8 +1,10 @@
# granthi-sync v1.2 # granthi-sync v1.2
The signup → download → link-folders → cloud product spine for the Granthi The signup → download → link-folders → cloud product spine for the Granthi
forge, tested against the BETA forge (granthi-beta.shre.ai). Python 3 stdlib + forge. Developed and live-E2E-tested against the BETA forge
git CLI only — same portability heritage as the estate's `gitea_sync.py` mesh. (granthi-beta.shre.ai); **the deployed service now runs against the PRODUCTION
forge** — see "Where this actually runs" below. Python 3 stdlib + git CLI only
— same portability heritage as the estate's `gitea_sync.py` mesh.
``` ```
┌──────────────┐ device flow ┌─────────────────┐ ┌──────────────┐ device flow ┌─────────────────┐
@@ -13,7 +15,8 @@ git CLI only — same portability heritage as the estate's `gitea_sync.py` mesh.
│ │ POST /v1/link {zitadel_access_token, device_name} │ │ POST /v1/link {zitadel_access_token, device_name}
│ │ ───────────────▶ ┌───────────────────────────────┐ │ │ ───────────────▶ ┌───────────────────────────────┐
│ │ ◀─────────────── │ granthi-link :3042 │ │ │ ◀─────────────── │ granthi-link :3042 │
│ │ {login, token} │ (granthi VPS, tailnet-only) │ │ {login, token} │ (granthi VPS; public via
│ │ │ https://granthi-link.shre.ai)│
│ │ │ · userinfo validation │ │ │ │ · userinfo validation │
│ │ POST /v1/repos │ · ensure Gitea user (admin) │ │ │ POST /v1/repos │ · ensure Gitea user (admin) │
│ │ ───────────────▶ │ · mint scoped user token │ │ │ ───────────────▶ │ · mint scoped user token │
@@ -21,11 +24,28 @@ git CLI only — same portability heritage as the estate's `gitea_sync.py` mesh.
│ │ git push/fetch (user token │ admin API │ │ git push/fetch (user token │ admin API
│ │ via credential helper) ▼ │ │ via credential helper) ▼
│ │ ───────────────▶ ┌───────────────────────────────┐ │ │ ───────────────▶ ┌───────────────────────────────┐
└──────────────┘ │ BETA forge :3041 └──────────────┘ │ PROD forge :3040
│ granthi-beta.shre.ai │ │ granthi.shre.ai
└───────────────────────────────┘ └───────────────────────────────┘
``` ```
## Where this actually runs
Verified on the granthi VPS (`[email protected]`) on 2026-08-30, because
this file previously described the beta tier long after the deployment moved:
| | value |
|---|---|
| service | `/opt/granthi-link/`, `granthi-link.service`, `systemctl is-active``active` |
| public entry | `https://granthi-link.shre.ai``/health` → 200. `/` → 404 is **no root route**, not an outage |
| `gitea_base` | `http://127.0.0.1:3040` (container `gitea-central-gitea-1`) |
| `public_gitea_base` | `https://granthi.shre.ai` |
| rate limiting | `trust_forwarded_for: true`, `trusted_proxies: ["100.107.37.98/32"]`, no `rules` key → falls back to `DEFAULT_RATE_RULES` |
| deployed version | `/health` reports **1.1.0** while this repo is **v1.2** — the running service lags `main` |
So a new computer that follows Quickstart lands on the **production** forge.
Beta remains where changes are proven before they reach it.
## Quickstart (invited user) ## Quickstart (invited user)
You need a shre-id account — an operator creates it; there is no open signup You need a shre-id account — an operator creates it; there is no open signup
@@ -194,13 +214,16 @@ So:
**64 KB** (413 beyond; missing `Content-Length` → 411, invalid → 400). **64 KB** (413 beyond; missing `Content-Length` → 411, invalid → 400).
* `POST /v1/repos {token, name, private}` → creates the user repo with the * `POST /v1/repos {token, name, private}` → creates the user repo with the
USER token; clone/html URLs are rebased onto `public_gitea_base` because the USER token; clone/html URLs are rebased onto `public_gitea_base` because the
container `ROOT_URL` (https://granthi-beta.shre.ai) does not resolve for container `ROOT_URL` does not necessarily resolve for the client that asked
tailnet-only clients. (it was a tailnet-only address on beta; on prod the rebase keeps clone URLs
on `https://granthi.shre.ai` rather than the container's own view).
Deployment: `/opt/granthi-link/{granthi_link.py,config.json,state.json}` + Deployment: `/opt/granthi-link/{granthi_link.py,config.json,state.json}` +
systemd unit `granthi-link.service`; binds `127.0.0.1:3042` **and** systemd unit `granthi-link.service`; binds `127.0.0.1:3042` **and**
`100.111.127.127:3042` (tailnet). **Not publicly exposed** — see promotion `100.111.127.127:3042` (tailnet), and is **publicly reachable** at
window. The service **refuses to start** (exit 2) unless `config.json` is `https://granthi-link.shre.ai` through the `pulse-granthi-edge` cloudflared
tunnel (done 2026-08-23; re-verified 2026-08-30). The service **refuses to
start** (exit 2) unless `config.json` is
mode 0600/0400 and owned by the user it runs as — the config carries the mode 0600/0400 and owned by the user it runs as — the config carries the
forge admin password, so permissive perms fail closed, not open. forge admin password, so permissive perms fail closed, not open.
@@ -620,10 +643,12 @@ Shape this should take, so the next session does not re-litigate it:
`https://granthi-link.shre.ai` (second-level, see above), origin stays `https://granthi-link.shre.ai` (second-level, see above), origin stays
tailnet-only, `trust_forwarded_for` on with the tunnel as the only tailnet-only, `trust_forwarded_for` on with the tunnel as the only
trusted proxy. trusted proxy.
2. **Swap forge base URLs** in `/opt/granthi-link/config.json`: 2. ~~**Swap forge base URLs** in `/opt/granthi-link/config.json`~~
`gitea_base` → prod forge, `public_gitea_base` **DONE — verified live 2026-08-30**: the deployed config reads
`https://granthi.shre.ai`; the client default server URL moves to the `gitea_base: http://127.0.0.1:3040` and
public endpoint. `public_gitea_base: https://granthi.shre.ai`, and the client default
server is already the public endpoint. Linking a new device therefore
creates the account on **prod**.
3. The `granthi-web` OIDC app already lists the prod callback; the device 3. The `granthi-web` OIDC app already lists the prod callback; the device
app is host-independent. Rotate the beta admin token/password out of the app is host-independent. Rotate the beta admin token/password out of the
config when pointing at prod (prod forge is READ-ONLY to this estate — config when pointing at prod (prod forge is READ-ONLY to this estate —
+7 -5
View File
@@ -1,15 +1,17 @@
{ {
"gitea_base": "http://127.0.0.1:3041", "_comment_forge": "Values below mirror the LIVE prod deployment (verified 2026-08-30). For the beta tier use gitea_base http://127.0.0.1:3041, public_gitea_base https://granthi-beta.shre.ai, container gitea-beta-gitea-1, creds /opt/gitea-beta/.admin-creds.",
"public_gitea_base": "http://100.111.127.127:3041", "gitea_base": "http://127.0.0.1:3040",
"public_gitea_base": "https://granthi.shre.ai",
"zitadel_userinfo": "https://id.shre.ai/oidc/v1/userinfo", "zitadel_userinfo": "https://id.shre.ai/oidc/v1/userinfo",
"admin_token": "MINT-VIA: docker exec -u git gitea-beta-gitea-1 gitea admin user generate-access-token --username nirpa --scopes write:admin,write:user,write:repository --raw", "admin_token": "MINT-VIA: docker exec -u git gitea-central-gitea-1 gitea admin user generate-access-token --username nirpa --scopes write:admin,write:user,write:repository --raw",
"admin_login": "nirpa", "admin_login": "nirpa",
"admin_password": "FROM /opt/gitea-beta/.admin-creds (required: Gitea 1.27 token minting only works via basic auth + Sudo header)", "admin_password": "FROM shre-cred: superadmin/granthi-link/granthi-prod-forge-admin (required: Gitea 1.27 token minting only works via basic auth + Sudo header). NEVER paste this into chat or a shell history.",
"binds": [["127.0.0.1", 3042], ["100.111.127.127", 3042]], "binds": [["127.0.0.1", 3042], ["100.111.127.127", 3042]],
"test_mode": false, "test_mode": false,
"rate_limit": { "rate_limit": {
"enabled": true, "enabled": true,
"trust_forwarded_for": false, "trust_forwarded_for": true,
"trusted_proxies": ["100.107.37.98/32"],
"rules": {"/v1/link": [5, 3600], "/v1/repos": [60, 3600]} "rules": {"/v1/link": [5, 3600], "/v1/repos": [60, 3600]}
} }
} }