skill
Adom UI Design System
Public Made by Adomby adom
How the AI builds and tests interfaces people love to use in Adom. Ships as one installable skill that bundles focused skills (tooltips, floating-windows, toasts, responsive-ui, app-shell, ai-driven-apps, clickable-paths).
master
John Lauer
2.10.0: ship proxy-fidelity.py - prove your control-API routes forward byte-for-byte without touching John's machine
0b8b38f
1mo ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
#!/usr/bin/env python3
"""proxy-fidelity — prove a dock dashboard forwards the control API FAITHFULLY.
The newbie-panel module calls two routes same-origin against your dashboard:
GET /updater/status (version gate)
POST /ai-threads/run-prompt (the send)
Your app forwards both to ah's control API. This checks that it forwards them
*unchanged*, which a "does it return 200" probe cannot see.
Three assertions, each against a real bug:
1. response bytes identical (sha256), awkward whitespace and nested
delivered_to included -> catches parse-then-re-emit
2. upstream's 207 comes back 207 -> catches a hand-built 200 {ok:true} wrapper
3. an unproxied path under the same prefix returns YOUR 404, not upstream's
418 -> catches blanket-proxying the control API
Why 1 matters even when the JSON "looks the same": the module splits
updater.current_version on dots and compares NUMERICALLY, and reads
delivered_to as an ARRAY. A re-serialisation that retypes either one changes
behaviour while every status probe stays green.
USAGE
# recommended: the script runs your app itself, in a throwaway HOME, so it
# never touches a real workspace
proxy-fidelity.py --app-cmd 'adom-project-manager --port $PORT'
# or point it at an already-running app (needs --home so the stub URL can be
# published where the app reads it; the file is backed up and restored)
proxy-fidelity.py --base http://127.0.0.1:8785 --home ~
# negative control: prove RED actually shows, using a deliberately
# re-serialising proxy. Run this once before you trust a green run.
proxy-fidelity.py --self-test
Exits non-zero if any assertion is RED, so it can sit in a build gate.
python3 stdlib only.
"""
import argparse, hashlib, json, os, random, shutil, signal, socket, subprocess, sys, time
import urllib.request, urllib.error
from http.server import BaseHTTPRequestHandler, HTTPServer
from threading import Thread
# Deliberately awkward: leading/trailing spaces that survive only if the bytes are
# untouched, a NUMERIC version, and delivered_to as an ARRAY.
STUB_BODY = (b'{"updater":{"current_version":"1.0.148","build":142},'
b'"delivered_to":["tab-7"],"spacing":" preserved "}')
TEAPOT = b'{"teapot":true}'
def free_port():
s = socket.socket()
s.bind(('127.0.0.1', 0))
p = s.getsockname()[1]
s.close()
return p
class Stub(BaseHTTPRequestHandler):
"""Stands in for ah's control API."""
def _send(self, code, body):
self.send_response(code)
self.send_header('Content-Type', 'application/json')
self.send_header('Content-Length', str(len(body)))
self.end_headers()
self.wfile.write(body)
def do_GET(self):
if self.path == '/updater/status':
self._send(200, STUB_BODY)
else:
# anything else is a teapot, so a blanket proxy is visible
self._send(418, TEAPOT)
def do_POST(self):
n = int(self.headers.get('Content-Length') or 0)
raw = self.rfile.read(n)
try:
echo = json.loads(raw or b'{}')
except Exception:
echo = {'unparsed': raw.decode('utf-8', 'replace')}
# 207 on purpose: a hand-built 200 wrapper cannot fake it
self._send(207, json.dumps({'echo': echo, 'delivered_to': ['tab-9']}).encode())
def log_message(self, *a):
pass
class BadProxy(BaseHTTPRequestHandler):
"""The NEGATIVE CONTROL: forwards correctly except it parses and re-emits,
which is exactly what most hand-written forwarding routes do."""
upstream = None
def do_GET(self):
if self.path == '/updater/status':
with urllib.request.urlopen(self.upstream + '/updater/status') as r:
data = json.loads(r.read())
out = json.dumps(data).encode() # <-- the bug, in one line
self.send_response(200)
self.send_header('Content-Type', 'application/json')
self.send_header('Content-Length', str(len(out)))
self.end_headers()
self.wfile.write(out)
else:
self.send_response(404); self.end_headers(); self.wfile.write(b'not found')
def do_POST(self):
n = int(self.headers.get('Content-Length') or 0)
raw = self.rfile.read(n)
req = urllib.request.Request(self.upstream + self.path, data=raw,
headers={'Content-Type': 'application/json'})
try:
with urllib.request.urlopen(req) as r:
body = r.read()
except urllib.error.HTTPError as e:
body = e.read()
out = json.dumps(json.loads(body)).encode()
self.send_response(200) # <-- collapses 207 to 200
self.send_header('Content-Type', 'application/json')
self.send_header('Content-Length', str(len(out)))
self.end_headers()
self.wfile.write(out)
def log_message(self, *a):
pass
def serve(handler, port):
srv = HTTPServer(('127.0.0.1', port), handler)
Thread(target=srv.serve_forever, daemon=True).start()
return srv
def http(method, url, body=None, timeout=20):
req = urllib.request.Request(url, method=method,
data=body.encode() if isinstance(body, str) else body,
headers={'Content-Type': 'application/json'} if body else {})
try:
with urllib.request.urlopen(req, timeout=timeout) as r:
return r.status, r.read()
except urllib.error.HTTPError as e:
return e.code, e.read()
except Exception as e:
return 0, str(e).encode()
def sha(b):
return hashlib.sha256(b).hexdigest()
def wait_ready(base, timeout=45):
end = time.time() + timeout
while time.time() < end:
code, _ = http('GET', base + '/', timeout=3)
if code:
return True
time.sleep(0.4)
return False
def run_checks(base, stub_port):
rows = []
code, body = http('GET', base + '/updater/status')
ok = (code == 200 and body == STUB_BODY)
rows.append(('GET /updater/status forwarded byte-for-byte', ok,
'status %s sha %s' % (code, sha(body)[:16]),
'status 200 sha %s' % sha(STUB_BODY)[:16],
None if ok else b'want: ' + STUB_BODY + b'\n got: ' + body))
sent = '{"new":true,"prompt":"proxy-fidelity probe","submit":false}'
code, body = http('POST', base + '/ai-threads/run-prompt', sent)
echoed = False
try:
echoed = json.loads(body).get('echo') == json.loads(sent)
except Exception:
pass
ok2 = (code == 207 and echoed)
rows.append(('POST /ai-threads/run-prompt: body intact, upstream 207 preserved', ok2,
'status %s, body echoed=%s' % (code, echoed), 'status 207, body echoed=True',
None if ok2 else b'got: ' + body))
code, body = http('GET', base + '/updater/definitely-not-a-real-path')
ok3 = (code != 418 and TEAPOT not in body)
rows.append(('unproxied path is NOT blanket-forwarded', ok3,
'status %s' % code, 'anything but upstream 418',
None if ok3 else b'upstream teapot leaked through: ' + body))
return rows
def report(rows):
print()
worst = 0
for what, ok, got, want, detail in rows:
print((' \033[32mPASS\033[0m ' if ok else ' \033[31mRED \033[0m ') + what)
print(' want %s' % want)
print(' got %s' % got)
if detail:
worst = 1
for line in detail.decode('utf-8', 'replace').splitlines():
print(' %s' % line)
print()
return worst
def main():
ap = argparse.ArgumentParser(description='Prove a dashboard forwards the control API unchanged.')
ap.add_argument('--base', help='base URL of an already-running dashboard, e.g. http://127.0.0.1:8785')
ap.add_argument('--home', help='the HOME that running app reads (its .adom/hydrogen-control-url is '
'briefly repointed at the stub, then restored)')
ap.add_argument('--app-cmd', help='command to start your app; $PORT and $HOME are set for you. '
'Safest: runs in a throwaway HOME.')
ap.add_argument('--self-test', action='store_true',
help='negative control: run a deliberately re-serialising proxy and show it go RED')
a = ap.parse_args()
stub_port = free_port()
serve(Stub, stub_port)
stub_url = 'http://127.0.0.1:%d' % stub_port
if a.self_test:
print('NEGATIVE CONTROL: a proxy that parses and re-emits, which should go RED.')
BadProxy.upstream = stub_url
bad_port = free_port()
serve(BadProxy, bad_port)
rows = run_checks('http://127.0.0.1:%d' % bad_port, stub_port)
rc = report(rows)
if all(r[1] for r in rows):
print('SELF-TEST FAILED: the negative control PASSED, so this harness proves nothing.')
return 2
print('Self-test OK: the harness detects a re-serialising proxy. A green run means something.')
return 0
proc = tmp_home = backup = ctrl = None
try:
if a.app_cmd:
tmp_home = os.path.join('/tmp', 'proxy-fidelity-%d' % random.randint(1000, 9999))
os.makedirs(os.path.join(tmp_home, '.adom'), exist_ok=True)
open(os.path.join(tmp_home, '.adom', 'hydrogen-control-url'), 'w').write(stub_url)
port = free_port()
env = dict(os.environ, HOME=tmp_home, PORT=str(port))
cmd = a.app_cmd.replace('$PORT', str(port)).replace('$HOME', tmp_home)
proc = subprocess.Popen(cmd, shell=True, env=env,
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
preexec_fn=os.setsid)
base = 'http://127.0.0.1:%d' % port
if not wait_ready(base):
print('RED: app did not answer on %s within 45s' % base)
return 1
elif a.base:
base = a.base.rstrip('/')
home = os.path.expanduser(a.home or os.environ.get('HOME', '~'))
ctrl = os.path.join(home, '.adom', 'hydrogen-control-url')
os.makedirs(os.path.dirname(ctrl), exist_ok=True)
if os.path.exists(ctrl):
backup = ctrl + '.proxy-fidelity.bak'
shutil.copy2(ctrl, backup)
open(ctrl, 'w').write(stub_url)
# Relies on the published rule that the control URL is read at REQUEST
# time. If your app caches it at startup, use --app-cmd instead.
else:
ap.error('give --app-cmd (recommended), --base, or --self-test')
print('stub control API on %s' % stub_url)
print('testing %s' % base)
rows = run_checks(base, stub_port)
rc = report(rows)
if rc:
print('One or more assertions are RED. Run --self-test once to confirm this harness')
print('can detect a known-bad proxy, then fix the route rather than the harness.')
return rc
finally:
if proc:
try:
os.killpg(os.getpgid(proc.pid), signal.SIGTERM)
except Exception:
pass
if backup:
shutil.move(backup, ctrl)
elif ctrl and os.path.exists(ctrl):
os.remove(ctrl)
if tmp_home:
shutil.rmtree(tmp_home, ignore_errors=True)
if __name__ == '__main__':
sys.exit(main())