#!/usr/bin/env python3 """Log into the task's Chrome QA session without credentials in CLI arguments, code, or logs. The protected configuration is read through File API on a separate about:blank page, never uploaded to the application; only two login values are filled, solely in memory. Requires the Playwright CLI skill and an already-open isolated round5v4 Chrome session. """ import argparse import json from pathlib import Path import subprocess import qa CODE = r'''async (page) => { if(!USE_CURRENT_PAGE){await page.context().clearCookies();await page.goto('http://127.0.0.1:18088/login');} await page.getByRole('textbox',{name:'账号',exact:true}).waitFor(); await page.waitForLoadState('networkidle'); page.__qaEvidence={responses:[],errors:[]}; if(page.__qaErrorListener)page.removeListener('pageerror',page.__qaErrorListener); if(page.__qaResponseListener)page.removeListener('response',page.__qaResponseListener); page.__qaErrorListener=error=>page.__qaEvidence.errors.push(error.message); page.__qaResponseListener=async response=>{const url=response.url();if(!url.includes('/prod-api/'))return;let code=null;try{code=(await response.json()).code;}catch{}page.__qaEvidence.responses.push({path:url.split('/prod-api')[1],status:response.status(),code});}; page.on('pageerror',page.__qaErrorListener);page.on('response',page.__qaResponseListener); const local=await page.context().newPage();let credentials={}; try { await local.goto('about:blank');await local.setContent(''); await local.locator('#protected-config').setInputFiles(CONFIG_PATH); credentials=await local.locator('#protected-config').evaluate(async input=>{ const text=await input.files[0].text();const vals={}; for(const line of text.split('\n')){const m=line.match(/^(?:export )?(QA_ADMIN_USERNAME|QA_ADMIN_PASSWORD)=(.*)$/);if(m){let v=m[2].trim();if((v.startsWith("'")&&v.endsWith("'"))||(v.startsWith('"')&&v.endsWith('"')))v=v.slice(1,-1);vals[m[1]]=v;}} return vals; }); }finally{await local.close();} if(!credentials.QA_ADMIN_USERNAME||!credentials.QA_ADMIN_PASSWORD)throw new Error('Protected QA login configuration missing'); if(await page.getByRole('textbox',{name:'验证码',exact:true}).isVisible()){ if(!CAPTCHA_ANSWER)throw new Error('Captcha enabled: complete visual captcha manually; do not disable it'); await page.getByRole('textbox',{name:'验证码',exact:true}).fill(CAPTCHA_ANSWER); } await page.getByRole('textbox',{name:'账号',exact:true}).fill(credentials.QA_ADMIN_USERNAME); await page.getByRole('textbox',{name:'密码',exact:true}).fill(credentials.QA_ADMIN_PASSWORD);credentials={}; await page.getByRole('button',{name:'登 录'}).click();await page.waitForURL(url=>url.origin==='http://127.0.0.1:18088'&&!['/login','/404','/401'].includes(url.pathname),{timeout:20000});await page.waitForLoadState('networkidle'); return {url:page.url(),title:await page.title(),api:page.__qaEvidence.responses,errors:page.__qaEvidence.errors}; }''' def main(): parser=argparse.ArgumentParser(description=__doc__) parser.add_argument('--config',type=Path,default=Path.home()/'.railwaysystem-qa.env') parser.add_argument('--cli',type=Path,default=Path.home()/'.codex/skills/playwright/scripts/playwright_cli.sh') parser.add_argument('--captcha',default='',help='Answer from the actual displayed captcha, never disable validation') parser.add_argument('--use-current-page',action='store_true') args=parser.parse_args();qa.load_config(args.config) code=CODE.replace('CONFIG_PATH',json.dumps(str(args.config.expanduser().resolve()))).replace('CAPTCHA_ANSWER',json.dumps(args.captcha)).replace('USE_CURRENT_PAGE',str(args.use_current_page).lower()) result=subprocess.run([str(args.cli),'-s=round5v4','run-code',code],text=True,capture_output=True,timeout=45) # The emitted code contains a path, never credential values. Do not snapshot a filled login form. print(result.stdout) return result.returncode if __name__=='__main__':raise SystemExit(main())