"""Run explicitly on a Linux Docker host; creates two disposable containers. No published ports, no production endpoints, fresh throwaway keys kept in memory. """ import hashlib import json import os from pathlib import Path import secrets import subprocess import tempfile import time IMAGE='athena-deck-network-test:20260928' DECK='athena-deck-test-runtime' PEER='athena-deck-test-peer' def run(*args, data=None, check=True): result=subprocess.run(args,input=data,text=True,capture_output=True,timeout=45) if check and result.returncode: raise RuntimeError('Test command failed: '+args[0]+' (output redacted)') return result.stdout.strip() def execute(container, script, value=None): payload=json.dumps(value) if value is not None else None result=run('docker','exec','-i',container,'python3','-c',script,data=payload) return json.loads(result) if result else None def rpc(action, **values): result=execute(DECK,"import json,sys;from network.rpc import request;print(json.dumps(request(json.load(sys.stdin))))",dict(action=action,**values)) return result HTTP = '''import http.client,json,sys v=json.load(sys.stdin) c=http.client.HTTPConnection(v['host'],8110,timeout=5) h={'Content-Type':'application/json','X-Athena-Deck':'1'} if v.get('cookie'):h['Cookie']=v['cookie'] if v.get('origin'):h['Origin']=v['origin'] c.request(v.get('method','GET'),v.get('path','/'),json.dumps(v['body']) if 'body' in v else None,h) r=c.getresponse();b=r.read().decode() print(json.dumps({'status':r.status,'body':b,'cookie':r.getheader('Set-Cookie')})) ''' def http(host,path='/',method='GET',body=None,cookie=None): value=dict(host=host,path=path,method=method,cookie=cookie) if body is not None:value['body']=body return execute(PEER,HTTP,value) def main(): for name in (DECK,PEER): if run('docker','ps','-aq','--filter','name=^/'+name+'$'): raise RuntimeError('Test container name already exists; refusing takeover') ids=run('docker','ps','-aq').splitlines() baseline=run('docker','inspect','--format','{{.Id}} {{.State.StartedAt}}',*ids) if ids else '' state=tempfile.TemporaryDirectory(prefix='athena-deck-test-') password=secrets.token_urlsafe(32) salt=secrets.token_bytes(16) auth=dict(salt=salt.hex(),hash=hashlib.pbkdf2_hmac('sha256',password.encode(),salt,600000).hex()) p=Path(state.name)/'auth.json';p.write_text(json.dumps(auth));p.chmod(0o600) try: run('docker','run','-d','--name',PEER,'--cap-drop','ALL','--cap-add','NET_ADMIN',IMAGE,'sleep','600') run('docker','run','-d','--name',DECK,'--read-only','--cap-drop','ALL','--cap-add','NET_ADMIN','--cap-add','NET_RAW','--cap-add','SETUID','--cap-add','SETGID','--cap-add','CHOWN','--security-opt','no-new-privileges:true','--tmpfs','/run:rw,nosuid,nodev,size=8m','--tmpfs','/tmp:rw,nosuid,nodev,size=8m','-v',state.name+':/data',IMAGE) for _ in range(20): try: assert rpc('status')['state']=='disabled' break except Exception:time.sleep(.5) else:raise RuntimeError('Helper did not become ready') print('PASS helper startup and unprivileged web child',flush=True) uid=execute(DECK,"import json;from pathlib import Path;print(json.dumps([p.read_text().split('Uid:')[1].splitlines()[0].split()[0] for p in Path('/proc').glob('[0-9]*/status') if 'Name:\\tpython' in p.read_text()]))") assert '65534' in uid deckip=run('docker','inspect','--format','{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}',DECK) peerip=run('docker','inspect','--format','{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}',PEER) assert http(deckip,'/api/v1/status')['status']==401 login=http(deckip,'/api/v1/login','POST',{'password':password}) assert login['status']==200 cookie=login['cookie'].split(';')[0] assert http(deckip,'/api/v1/status',cookie=cookie)['status']==200 print('PASS real LAN login and authenticated API',flush=True) # Keys stay in this Python process and stdin pipes; never printed. private_a=run('docker','exec',PEER,'wg','genkey') private_b=run('docker','exec',PEER,'wg','genkey') public_a=run('docker','exec','-i',PEER,'wg','pubkey',data=private_a+'\n') public_b=run('docker','exec','-i',PEER,'wg','pubkey',data=private_b+'\n') conf=f'[Interface]\nPrivateKey = {private_a}\nAddress = 10.240.77.1/32\nListenPort = 51822\n[Peer]\nPublicKey = {public_b}\nEndpoint = {peerip}:51823\nAllowedIPs = 10.240.77.2/32\nPersistentKeepalive = 1\n' status=rpc('import',config=conf) assert private_a not in json.dumps(status) and public_b not in json.dumps(status) peerconf=f'[Interface]\nPrivateKey = {private_b}\nListenPort = 51823\n[Peer]\nPublicKey = {public_a}\nEndpoint = {deckip}:51822\nAllowedIPs = 10.240.77.1/32\nPersistentKeepalive = 1\n' execute(PEER,'''import json,sys,subprocess,os v=json.load(sys.stdin) def cmd(*a):subprocess.run(a,check=True,stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL) cmd('ip','link','add','peerwg0','type','wireguard') fd=os.open('/tmp/peer.conf',os.O_WRONLY|os.O_CREAT,0o600) with os.fdopen(fd,'w') as f:f.write(v) cmd('wg','setconf','peerwg0','/tmp/peer.conf');os.unlink('/tmp/peer.conf') cmd('ip','addr','add','10.240.77.2/32','dev','peerwg0') cmd('ip','link','set','peerwg0','up') cmd('ip','route','add','10.240.77.1/32','dev','peerwg0') ''',peerconf) rpc('connect') for _ in range(20): if rpc('status')['connected']:break time.sleep(.5) else:raise RuntimeError('No real WireGuard handshake') assert http('10.240.77.1','/api/v1/status',cookie=cookie)['status']==403 print('PASS actual WireGuard handshake; LAN-only blocks tunnel ingress',flush=True) status=rpc('mode',mode='both');trial=status['pending']['id'] assert http('10.240.77.1','/api/v1/status',cookie=cookie)['status']==200 assert http(deckip,'/api/v1/network/confirm','POST',{'trial_id':trial},cookie)['status']==400 assert http('10.240.77.1','/api/v1/network/confirm','POST',{'trial_id':trial},cookie)['status']==200 print('PASS both paths; only actual tunnel ingress can confirm',flush=True) status=rpc('mode',mode='tunnel');trial=status['pending']['id'] assert http(deckip,'/api/v1/status',cookie=cookie)['status']==403 assert http('10.240.77.1','/api/v1/network/confirm','POST',{'trial_id':trial},cookie)['status']==200 rpc('disconnect') assert http(deckip,'/api/v1/status',cookie=cookie)['status']==403 assert rpc('status')['mode']=='tunnel' print('PASS tunnel-only closes LAN and stays closed after disconnect',flush=True) status=rpc('mode',mode='lan');trial=status['pending']['id'] assert http(deckip,'/api/v1/network/confirm','POST',{'trial_id':trial},cookie)['status']==200 rpc('connect') for _ in range(20): if rpc('status')['connected']:break time.sleep(.5) rpc('mode',mode='tunnel') run('docker','restart',DECK) for _ in range(20): try: status=rpc('status') break except Exception:time.sleep(.5) assert status['mode']=='lan' and not status['pending'] print('PASS restart discards unconfirmed trial and restores confirmed mode',flush=True) after=run('docker','inspect','--format','{{.Id}} {{.State.StartedAt}}',*ids) if ids else '' assert baseline==after print('PASS production container start times unchanged',flush=True) finally: for name in (DECK,PEER):run('docker','rm','-f',name,check=False) state.cleanup() if __name__=='__main__':main()