docs: this describes the prod deployment now, not beta

granthi-link has run against the PROD forge since the promotion, but every
document in this repo still described the beta tier. Someone following the
README would expect their device to land on granthi-beta.shre.ai; it lands on
granthi.shre.ai. Two of the statements were not merely stale but false:
"tailnet-only" and "Not publicly exposed" — the service has been public at
https://granthi-link.shre.ai since 2026-08-23, and that 404 at / (no root
route) has twice been misread as an outage.

Verified on [email protected], 2026-08-30:
  gitea_base         = http://127.0.0.1:3040   (gitea-central-gitea-1)
  public_gitea_base  = https://granthi.shre.ai
  systemctl is-active granthi-link -> active
  https://granthi-link.shre.ai/health -> 200 {"status":"ok","version":"1.1.0"}
  rate_limit: trust_forwarded_for true, trusted_proxies ["100.107.37.98/32"],
              no "rules" key -> falls back to DEFAULT_RATE_RULES

Docs only. No server, client or test code is touched, and the deployed
service is NOT redeployed by this change — it still reports 1.1.0 against a
v1.2 repo, which is recorded separately.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01L1b6BN9TZVxHkmignRq4p8
This commit is contained in:
Claude
2026-08-29 23:20:30 -04:00
co-authored by Claude Opus 5
parent 7eb57acdbe
commit ba107c1b53
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]}
} }
} }