wardrobegod/depot/README.md
type-two db47546c2b Absorb the 3GOD depot; retire the name, keep the service
3GOD was "three.js god" — a quick way to eyeball a GLB and drop it into a game. wardrobegod's
stage, grid and publish flow cover that far better now, so the bench is retired. What survives is
the half that quietly became infrastructure.

Absorbed into depot/: server.py (271 lines, verbatim), its hardening tests, and viewer.html kept
as superseded reference only.

Retiring the REPO is safe; retiring the SERVICE is not. The live instance on the dealgod VPS
holds 773 assets and two shipping games fetch from it at runtime — thriftgod web/index.html:1176
and procity loaders.js:7 both hardcode https://digalot.fyi/3god. So the /3god URL stays even
though the name is gone: changing it means editing two shipping codebases for no benefit, and the
name now survives only as a URL path nobody looks at. The VPS service is deployed, not sourced
live from the Gitea checkout, so archiving that repo changes nothing at runtime.

Checked before discarding the UI: the depot's /api/meta tag store had 0 tags and 0 notes across
all 773 assets, so there was nothing to migrate. Tagging lives in library/index.json now.

depot/README.md records the two things that are easy to get wrong and expensive to rediscover:
publishing must go direct over the tailnet (the Cloudflare front 403s because auth trusts the raw
socket peer — thriftgod's own prop_campaign.py --publish is broken for exactly this), and
clean_name DELETES illegal characters so 'shop!-cat.glb' silently resolves to an existing
different mesh.

Verified after the change: both the public and tailnet endpoints still answer 200.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-24 22:16:05 +10:00

60 lines
2.9 KiB
Markdown

# depot — the asset CDN (formerly "3GOD")
3GOD was "three.js god": an easy way to eyeball a GLB and drop it into a game. **wardrobegod's
stage covers the viewing half far better now**, so the *bench* is retired. What survives is the
part that quietly became infrastructure: a small HTTP asset server that two shipping games fetch
from at runtime.
- `server.py` (271 lines) — the depot itself. Absorbed verbatim from `3GOD/server.py`.
- `viewer.html` — the old browse/upload UI. Kept for reference only; **superseded** by
wardrobegod's stage, grid and publish flow. Not deployed by us.
- `test_hardening.py` — its security tests (SSRF allowlist, tag XSS escape, meta race).
## Why this is not just deletable
The live instance runs on the dealgod VPS (container `3god`, assets bind-mounted at
`/opt/3god/assets`, published on `100.94.195.115:8788`, fronted at `https://digalot.fyi/3god`)
and holds **773 assets**. Two shipping games read it *at runtime*:
| consumer | line |
|---|---|
| thriftgod | `web/index.html:1176``const DEPOT = 'https://digalot.fyi/3god';` |
| procity | `web/js/.../loaders.js:7` — same URL; `LOCAL_DEPOT` is null unless `?localdepot=1` |
**Keep the `/3god` URL even though the name is retired.** It is hardcoded in both games; changing
it means editing two shipping codebases for no benefit. The name now survives only as a URL path
nobody looks at.
## Publishing (what wardrobegod does)
```
POST http://100.94.195.115:8788/api/upload?name=<file>.glb # raw body, direct over tailnet
```
**Not** via `https://digalot.fyi/3god`. Auth trusts the raw socket peer against a tailnet
allow-list, so through the Cloudflare front the peer is CF and every write 403s. Measured:
`/api/list` reports `authed=false` via CF, `authed=true` direct. (thriftgod's own shipped
`tools/prop_campaign.py --publish` defaults to the CF URL and is broken for this reason.)
## The filename hazard
`clean_name` **deletes** illegal characters rather than substituting them, and matching is
case-sensitive. So `shop!-cat.glb` becomes `shop-cat.glb` — an existing, *different* mesh — and
is then served with no error at all. `[A-Za-z0-9._ -]` survive verbatim; the first character must
be alphanumeric; a missing extension gets `.glb` appended.
wardrobegod reproduces this rule in `god3_name()` and refuses to publish over an existing name
unless `overwrite:true` is passed. Do not bypass that check.
## Migration note
The depot's `/api/meta` tag/note store was checked before retiring the UI: **0 of 773 assets had
any tags or notes**, so nothing needed migrating into wardrobegod's manifest. Tagging now lives in
`library/index.json`.
## Retiring the repo
`ssh://git@100.71.119.27:222/monster/3GOD.git` (Gitea on the old box) can be archived once this
copy is committed. The running VPS service is unaffected — it is deployed, not sourced live from
that checkout. ultra's `~/Documents/3GOD` is a dev copy holding 4 files and its `:8788` is closed.