Spaces:
Running
Running
Download test_browser.py from Hugdrigo/reprochain-ai: direct link, hf CLI and curl.
- Browser
- Download file 8.54 kB
-
https://huggingface.co/spaces/Hugdrigo/reprochain-ai/resolve/main/test_browser.py
- Command line
-
hf download hf://spaces/Hugdrigo/reprochain-ai/test_browser.py
-
curl -L -o test_browser.py https://huggingface.co/spaces/Hugdrigo/reprochain-ai/resolve/main/test_browser.py
8.54 kB
| import asyncio, pathlib, json | |
| from playwright.async_api import async_playwright | |
| ROOT=pathlib.Path(__file__).resolve().parent | |
| OUT=pathlib.Path('/mnt/data') | |
| async def main(): | |
| async with async_playwright() as p: | |
| browser=await p.chromium.launch(headless=True, executable_path='/usr/bin/chromium', args=['--no-sandbox','--disable-dev-shm-usage']) | |
| ctx=await browser.new_context(viewport={'width':1512,'height':980}, accept_downloads=True) | |
| page=await ctx.new_page();errors=[];page.on('pageerror', lambda e:errors.append(str(e))) | |
| import base64,hashlib | |
| await page.set_content((ROOT/'index.html').read_text(),wait_until='domcontentloaded') | |
| await page.add_style_tag(content=(ROOT/'styles.css').read_text()) | |
| await page.expose_function('__shahex',lambda b64:hashlib.sha256(base64.b64decode(b64)).hexdigest()) | |
| await page.evaluate('''() => { | |
| Object.defineProperty(window.crypto,'subtle',{configurable:true,value:{digest:async (_alg,buffer)=>{ | |
| let arr=new Uint8Array(buffer), bin=''; | |
| for(let i=0;i<arr.length;i+=8192)bin+=String.fromCharCode(...arr.subarray(i,i+8192)); | |
| const hex=await window.__shahex(btoa(bin)); | |
| return Uint8Array.from(hex.match(/../g),x=>parseInt(x,16)).buffer; | |
| }}}); | |
| }''') | |
| assets={f.name:base64.b64encode(f.read_bytes()).decode() for f in ROOT.iterdir() if f.is_file() and f.suffix in ('.json','.js','.css','.html','.md')} | |
| await page.evaluate('''(assets)=>{ | |
| window.__ASSETS=assets; | |
| window.fetch=async uri=>{ | |
| const id=String(uri).split('/').pop().split('?')[0],base=window.__ASSETS[id]; | |
| if(!base)return {ok:false,status:404}; | |
| const bin=atob(base),arr=Uint8Array.from(bin,c=>c.charCodeAt(0)); | |
| return {ok:true,status:200,arrayBuffer:async()=>arr.buffer,json:async()=>JSON.parse(new TextDecoder().decode(arr))}; | |
| }; | |
| }''',assets) | |
| await page.add_script_tag(content=(ROOT/'evalflow_engine.js').read_text()) | |
| await page.add_script_tag(content=(ROOT/'reprochain_engine.js').read_text()) | |
| await page.add_script_tag(content=(ROOT/'app.js').read_text()) | |
| await page.wait_for_function("document.querySelector('#statusBadge').textContent.includes('PASS')",timeout=45000) | |
| checks=[] | |
| def ck(name,condition): | |
| if not condition: raise AssertionError(name+' errors='+repr(errors)) | |
| checks.append(name);print('PASS',name) | |
| ck('hero ReproChain AI', 'ReproChain' in await page.locator('h1').inner_text()) | |
| ck('22 hashed artifact nodes',await page.locator('#kArtifact').inner_text()=='22') | |
| ck('4416 prediction records',await page.locator('#kRecords').inner_text()=='4,416') | |
| ck('manifest root verified',await page.locator('#kRoot').inner_text()=='VALID') | |
| ck('default research gate PASS',await page.locator('#statusBadge').inner_text()=='RESEARCH GATES PASS') | |
| ck('candidate 77.8% Accuracy', '77.8%' in await page.locator('#content').inner_text()) | |
| ck('nine navigation modules',await page.locator('.nav-btn').count()==9) | |
| await page.locator('[data-view=lineage]').click() | |
| ck('lineage artifact nodes shown',await page.locator('[data-node]').count()==22) | |
| await page.locator('[data-node=predictions]').click() | |
| ck('predictions upstream text', 'train' in (await page.locator('#content').inner_text()).lower()) | |
| ck('sha prefix shown', 'SHA-256' in await page.locator('#content').inner_text()) | |
| async with page.expect_download() as d: await page.locator('[data-export=graph]').click() | |
| download=await d.value; ck('graphml export',download.suggested_filename.endswith('.graphml')) | |
| await page.locator('[data-view=vault]').click() | |
| ck('vault 22 verified', '22' in await page.locator('#content').inner_text()) | |
| await page.locator('#tamper').click() | |
| ck('simulated tamper BLOCK',await page.locator('#statusBadge').inner_text()=='RESEARCH GATES BLOCK') | |
| ck('synthetic tamper warning', 'SIMULATION ONLY' in await page.locator('#content').inner_text()) | |
| await page.locator('#tamper').click() | |
| ck('recover gate after simulation',await page.locator('#statusBadge').inner_text()=='RESEARCH GATES PASS') | |
| await page.locator('#rescan').click() | |
| await page.wait_for_function("document.querySelector('#statusLine').textContent.startsWith('22/22')") | |
| ck('rescan matches 22 hashes',(await page.locator('#statusLine').inner_text()).startswith('22/22')) | |
| await page.locator('#baseline').select_option('hybrid') | |
| await page.locator('#candidate').select_option('nb') | |
| await page.locator('#replay').click() | |
| await page.wait_for_function("document.querySelector('#statusBadge').textContent.includes('BLOCK')") | |
| ck('reversed classifier comparison BLOCK',await page.locator('#statusBadge').inner_text()=='RESEARCH GATES BLOCK') | |
| await page.locator('#baseline').select_option('nb') | |
| await page.locator('#candidate').select_option('hybrid') | |
| await page.locator('#replay').click() | |
| await page.wait_for_function("document.querySelector('#statusBadge').textContent.includes('PASS')") | |
| ck('restore candidate PASS',await page.locator('#statusBadge').inner_text()=='RESEARCH GATES PASS') | |
| await page.locator('[data-view=governance]').click() | |
| ck('editable policy eight entries',await page.locator('[id^=p_]').count()==8) | |
| await page.locator('#p_minAccuracy').fill('0.95') | |
| await page.locator('#apply').click() | |
| await page.wait_for_function("document.querySelector('#statusBadge').textContent.includes('BLOCK')") | |
| ck('strict policy BLOCK',await page.locator('#statusBadge').inner_text()=='RESEARCH GATES BLOCK') | |
| await page.locator('#defaults').click() | |
| await page.wait_for_function("document.querySelector('#statusBadge').textContent.includes('PASS')") | |
| ck('policy reset restores PASS',await page.locator('#statusBadge').inner_text()=='RESEARCH GATES PASS') | |
| await page.locator('[data-view=replay]').click() | |
| ck('paired bootstrap interval displayed','bootstrap' in (await page.locator('#content').inner_text()).lower()) | |
| await page.locator('[data-view=runs]').click() | |
| ck('run registry contains >= 4 runs',await page.locator('table tbody tr').count()>=4) | |
| await page.locator('#regA').select_option('1') | |
| await page.locator('#regB').select_option('3') | |
| ck('run selector compares snapshots', 'Difference (B' in await page.locator('#content').inner_text()) | |
| await page.locator('[data-view=audit]').click() | |
| await page.locator('#auditVerify').click() | |
| await page.wait_for_function("document.querySelector('#auditMessage').textContent.startsWith('PASS:') || document.querySelector('#auditMessage').textContent.startsWith('FAILED:')") | |
| ck('audit chain verify successful','PASS:' in await page.locator('#auditMessage').inner_text()) | |
| await page.locator('[data-view=export]').click() | |
| for kind,ext in [('report','.md'),('run','.json'),('inventory','.csv'),('runs','.csv'),('graph','.graphml'),('bundle','.json'),('manifest','.json')]: | |
| async with page.expect_download() as d:await page.locator(f'[data-export={kind}]').click() | |
| item=await d.value;ck('export '+kind,item.suggested_filename.endswith(ext)) | |
| snap={'schema':'reprochain.run.v1','baseline':'nb','candidate':'hybrid','split':'challenge','accuracy':.7777,'bundleRoot':'f'*64} | |
| await page.locator('#importRun').set_input_files({'name':'test-run.json','mimeType':'application/json','buffer':json.dumps(snap).encode()}) | |
| await page.wait_for_function("document.querySelector('#importMsg').textContent.includes('UNVERIFIED')") | |
| ck('import unverified run warning', 'UNVERIFIED' in await page.locator('#importMsg').inner_text()) | |
| await page.locator('[data-view=runs]').click() | |
| ck('import run shown unverified', 'UNVERIFIED' in await page.locator('#content').inner_text()) | |
| await page.locator('[data-view=methods]').click() | |
| ck('limitations visible','not a trusted signature' in (await page.locator('#content').inner_text()).lower()) | |
| await page.locator('[data-view=overview]').click() | |
| await page.evaluate('window.scrollTo(0,0)') | |
| await page.screenshot(path=str(OUT/'ReproChain_AI_DESKTOP_PREVIEW.png'),full_page=True) | |
| ck('desktop no sideways scroll',await page.evaluate('document.documentElement.scrollWidth<=window.innerWidth+3')) | |
| await page.set_viewport_size({'width':390,'height':844});await page.evaluate('window.scrollTo(0,0)');await page.screenshot(path=str(OUT/'ReproChain_AI_MOBILE_PREVIEW.png'),full_page=True) | |
| ck('mobile no sideways scroll',await page.evaluate('document.documentElement.scrollWidth<=window.innerWidth+3')) | |
| ck('mobile navigation accessible',await page.locator('[data-view=export]').count()==1) | |
| ck('no browser JavaScript errors',len(errors)==0) | |
| print('BROWSER CHECKS PASSED',len(checks));await browser.close() | |
| asyncio.run(main()) | |