#!/usr/bin/env python3 """Read-only GET checks of the author's public service migration; never follows redirects.""" import argparse,hashlib,json,platform,subprocess,tempfile from datetime import datetime,timezone from pathlib import Path def inspect(): checks=[] for host,prefix in [('gamepunch.org','/public/'),('punchblog.com','/')]: for slug in ['gamepunch','coinpunch','punch-livescore','punch-re']: url='https://'+host+prefix+slug with tempfile.TemporaryDirectory(prefix='service-retirement-check-') as name: root=Path(name) result=subprocess.run(['curl','-q','--noproxy','*','-sS','--connect-timeout','4','--max-time','20','-D',str(root/'headers'),'-o',str(root/'body'),'-w','%{http_code}\n%{ssl_verify_result}',url],capture_output=True,text=True,timeout=25) metrics=result.stdout.strip().splitlines() headers={} if (root/'headers').exists(): for line in (root/'headers').read_text().splitlines(): key,sep,value=line.partition(':') if sep and key.lower() in ('location','x-robots-tag','cache-control','content-type'):headers[key.lower()]=value.strip() body=(root/'body').read_bytes() if (root/'body').exists() else b'' checks.append({'label':('기존 주소 ' if host=='gamepunch.org' else '새 주소 ')+slug,'url':url,'method':'GET','status':int(metrics[0]) if metrics and metrics[0].isdigit() else None,'curl_exit':result.returncode,'ssl_verify_result':metrics[-1] if len(metrics)>1 else None,'headers':headers,'response_bytes':len(body),'body_sha256':hashlib.sha256(body).hexdigest()}) return {'observed_at':datetime.now(timezone.utc).isoformat(),'environment':{'os':platform.system(),'python':platform.python_version()},'method':'Eight public HTTPS GET requests without following Location; TLS verification enabled. Response bodies are hashed, never published. No cookies or credentials are collected.','limits':'A post-deployment snapshot, not an archived before-state, uptime measurement or proof that search engines have recrawled a URL. Later responses may change.','checks':checks} if __name__=='__main__': p=argparse.ArgumentParser();p.add_argument('--output',required=True,type=Path);a=p.parse_args() if a.output.exists():raise SystemExit('Choose a new evidence filename.') r=inspect() with a.output.open('x') as f:json.dump(r,f,ensure_ascii=False,indent=2);f.write('\n') print(json.dumps({'checks':len(r['checks']),'statuses':[c['status'] for c in r['checks']]}))