wardrobegod/depot/test_hardening.py
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

31 lines
1.6 KiB
Python

#!/usr/bin/env python3
"""Self-check for the SSRF guard added to server.py. No framework, no network:
literal-IP URLs resolve via getaddrinfo without a DNS lookup, so this is hermetic.
GOD3_OPEN=1 python3 test_hardening.py # OPEN so import doesn't sys.exit on missing GOD3_PW
"""
import os
os.environ.setdefault('GOD3_OPEN', '1') # let server.py import without a real GOD3_PW
import server
# --- blocked: non-http schemes (file://, ftp://) — the /etc/passwd + FileHandler vector ---
assert server.public_host('file:///etc/passwd') is False
assert server.public_host('ftp://ftp.example.com/x') is False
assert server.public_host('gopher://x/') is False
assert server.public_host('') is False
# --- blocked: internal / metadata / loopback targets (literal IPs, no DNS) ---
assert server.public_host('http://127.0.0.1/') is False # loopback
assert server.public_host('http://[::1]/') is False # loopback v6
assert server.public_host('http://169.254.169.254/latest/meta-data/') is False # cloud metadata
assert server.public_host('http://10.0.0.5/') is False # private
assert server.public_host('http://192.168.1.1/') is False # private
assert server.public_host('http://172.16.0.9/') is False # private
assert server.public_host('http://0.0.0.0/') is False # unspecified
# --- allowed: public literal IPs (hermetic — no DNS) ---
assert server.public_host('http://8.8.8.8/model.glb') is True
assert server.public_host('https://1.1.1.1/x.glb') is True
print('ok — SSRF guard blocks file/ftp + loopback/private/metadata, allows public http(s)')