64 lines
4.5 KiB
Python
64 lines
4.5 KiB
Python
from pathlib import Path
|
|
import hashlib,json,subprocess,urllib.request,re
|
|
p=Path(__file__).resolve().parent;r=Path('/home/worsch/ops-warden')
|
|
cfg=json.loads((p/'integration.json').read_text());head=cfg['head']
|
|
def git(*a):return subprocess.check_output(['git','-C',str(r),*a],stderr=subprocess.PIPE,text=True,timeout=90).strip()
|
|
assert git('rev-parse','HEAD')==head
|
|
assert git('ls-remote','origin','refs/heads/main').split()[0] in {cfg['base'],head}
|
|
backup=p/'consistency-backup';assert not backup.exists();backup.mkdir()
|
|
files=[r/'.custodian-brief.md',r/'WORK-RECORDS.md',*sorted((r/'workplans').rglob('*.md'))]
|
|
rows=[]
|
|
for f in files:
|
|
if not f.exists():continue
|
|
n=str(f.relative_to(r));dst=backup/n;dst.parent.mkdir(parents=True,exist_ok=True);dst.write_bytes(f.read_bytes())
|
|
rows.append({'path':n,'sha256':hashlib.sha256(f.read_bytes()).hexdigest(),'index':git('ls-files','--stage','--',n)})
|
|
(p/'consistency-preimage.json').write_text(json.dumps(rows,indent=2)+'\n')
|
|
try:
|
|
result=subprocess.run(['statehub','fix-consistency','--repo','ops-warden','--no-writeback','--json'],cwd=r,capture_output=True,text=True,timeout=300)
|
|
(p/'consistency.json').write_text(result.stdout);(p/'consistency.stderr.txt').write_text(result.stderr)
|
|
assert result.returncode==0,'required consistency failed'
|
|
data=json.loads(result.stdout);assert data.get('fail',data.get('summary',{}).get('fail',0))==0
|
|
finally:
|
|
for row in rows:
|
|
n=row['path'];f=r/n;old=(backup/n).read_bytes()
|
|
if f.read_bytes()!=old:
|
|
(p/('changed-'+n.replace('/','-'))).write_bytes(f.read_bytes());f.write_bytes(old)
|
|
if git('ls-files','--stage','--',n)!=row['index']:
|
|
mode,oid,stage,name=row['index'].split();assert stage=='0';git('update-index','--cacheinfo',mode,oid,name)
|
|
assert hashlib.sha256(f.read_bytes()).hexdigest()==row['sha256']
|
|
assert git('rev-parse','HEAD')==head
|
|
result=subprocess.run(['/home/worsch/repo-manager/.venv/bin/rmgr','sync','--path',str(r),'--push'],capture_output=True,text=True,timeout=180)
|
|
(p/'normal-sync.json').write_text(result.stdout);(p/'normal-sync.stderr.txt').write_text(result.stderr)
|
|
if result.returncode:
|
|
text=result.stdout+result.stderr
|
|
assert 'WARDEN-WP-0038-T01' in text and ('UUID' in text or 'uuid' in text),'unexpected sync refusal; stop'
|
|
assert git('ls-remote','origin','refs/heads/main').split()[0] in {cfg['base'],head}
|
|
push=subprocess.run(['git','-C',str(r),'push','origin','main'],capture_output=True,text=True,timeout=120)
|
|
(p/'source-push.json').write_text(json.dumps({'exit_code':push.returncode,'stdout':push.stdout,'stderr':push.stderr},indent=2)+'\n')
|
|
assert push.returncode==0,'normal source push refused'
|
|
else:
|
|
data=json.loads(result.stdout);assert data.get('status') in {'applied','noop'}
|
|
assert git('ls-remote','origin','refs/heads/main').split()[0]==head
|
|
body={'expected_commit':head,'acknowledge_retirements':False}
|
|
request=urllib.request.Request('http://127.0.0.1:8000/repos/ops-warden/work-record-projection/reconcile',data=json.dumps(body).encode(),headers={'Content-Type':'application/json','X-StateHub-Component':'ops-warden'},method='POST')
|
|
with urllib.request.urlopen(request,timeout=120) as response: receipt=json.load(response)
|
|
(p/'receiver-receipt.json').write_text(json.dumps(receipt,indent=2)+'\n')
|
|
assert receipt['ok'] and receipt['status'] in {'applied','noop'}
|
|
rp=receipt['receipt'];assert rp['expected_commit']==rp['derived_commit']==head
|
|
assert (rp['instance_role'],rp['instance_label'])==('primary','railiance01')
|
|
assert rp['outcome']['counts']['retired']==0
|
|
name='workplans/WARDEN-WP-0044-security-case-follow-through.md';text=(r/name).read_text()
|
|
blocks=re.findall(r'```task\n.*?```',text,re.S)
|
|
assert len(blocks)==4
|
|
bindings=[]
|
|
for b in blocks:
|
|
tid=re.search(r'state_hub_task_id: "(.*?)"',b).group(1);status=re.search(r'^status: (.+)$',b,re.M).group(1)
|
|
with urllib.request.urlopen('http://127.0.0.1:8000/tasks/'+tid,timeout=15) as response:task=json.load(response)
|
|
assert task['status']==status
|
|
bindings.append({'record_id':task.get('record_id'),'id':tid,'status':status})
|
|
for row in rows:
|
|
assert hashlib.sha256((r/row['path']).read_bytes()).hexdigest()==row['sha256']
|
|
assert git('ls-files','--stage','--',row['path'])==row['index']
|
|
verification={'status':'published-and-projected','head':head,'primary_task_bindings':bindings,'preserved_files_and_index':len(rows),'normal_allocator_refusal_preserved':result.returncode!=0,'catalog_promotion':False,'PARAMETER_PINS_changed':False,'native_actions':False}
|
|
(p/'verification.json').write_text(json.dumps(verification,indent=2)+'\n')
|
|
print(json.dumps(verification))
|