import hashlib,json,os,subprocess,urllib.request from pathlib import Path import client,prepare W=client.W;R=prepare.R;DATA=prepare.DATA assert (W/'acceptance-http.json').is_file() and (W/'acceptance-browser.json').is_file() assert Path('/tmp/project-member-runtime-independent-review.md').is_file() ADMIN=Path('/home/weichen/projects/Agent-System-RDM-wt-feature-project-member-access/bin/agent-system-admin') NAME='project-member-runtime-20261013' env=dict(os.environ);env.pop('AGENT_SYSTEM_DSN',None) results={} for owner in ['weichen','test']: with prepare.db(DATA/'agent-system.db') as c: row=c.execute('select revoked from api_keys where owner=? and name=?',(owner,NAME)).fetchone();assert row is not None if not row['revoked']: r=subprocess.run([str(ADMIN),'apikey','revoke','--owner',owner,'--name',NAME,'--data',str(DATA)],capture_output=True,text=True,env=env) assert r.returncode==0,'credential revocation failed; reconcile before retry' code,_=client.request(owner,'/api/me');assert code==401,'revoked credential still admitted' results[owner]=code with prepare.db(DATA/'agent-system.db') as c: assert c.execute('select count(*) from api_keys where name=? and revoked=0',(NAME,)).fetchone()[0]==0 with urllib.request.urlopen(client.BASE+'/',timeout=15) as res:assert res.status==200 before=json.loads((W/'baseline-private.json').read_text());now=prepare.logical(DATA) assert now['agent-system.db:users']==before['logical']['agent-system.db:users'],'existing account/password state changed' for a in before['artifacts']:assert prepare.sha(Path(a['content_path']))==a['sha256'] assert json.loads((R/'manifest.json').read_text())['instance_id']==prepare.INSTANCE pid=int((R/'svc.pid').read_text());exe=Path(f'/proc/{pid}/exe').resolve() assert exe==(R/'current/bin/agent-system').resolve() assert prepare.sha(exe)=='d5db3d0ac292d99582ec91938317af356c050ad61e61f42c097e7faf7a731765' (W/'credentials.json').unlink() result={'source':'SELF','operation':'succeeded','pid':pid,'release':os.readlink(R/'current'),'binary_sha256':prepare.sha(exe),'instance':prepare.INSTANCE,'root_http':200,'temporary_keys_revoked':results,'plaintext_credential_file_removed':True,'existing_accounts_and_passwords_unchanged':True,'original_artifact_bytes_preserved':len(before['artifacts']),'auth_route':'temporary API credentials; password login NOT_RUN','verification_data_retained':{'empty_conversations':5,'synthetic_private_files':2},'worktrees_retained':True} client.save('final-state.json',result);print(json.dumps(result,ensure_ascii=False))