Files
Investidor-V2/tools/portal-stability-cold-chromium.cjs
nala 287e991486
tests / ci (push) Waiting to run
oportunidades 7
2026-10-13 11:40:29 +02:00

51 lines
9.2 KiB
JavaScript

// Changed UUID consumers only. Existing A/B and C37 acceptance is preserved.
const fs=require('node:fs'),path=require('node:path'),assert=require('node:assert/strict'),crypto=require('node:crypto');
const {chromium}=require('C:/Users/macbook/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/node_modules/playwright');
const ROOT=path.resolve(__dirname,'..'),DIR=path.join(ROOT,'storage/app/private/investmoz-v2/portal-audit');
const plan=JSON.parse(fs.readFileSync(path.join(DIR,'portal-stability-latest.json'))),BASE=plan.qa_environment.base,TARGET=JSON.parse(fs.readFileSync(path.join(plan.source,'stability-qa.json'))).target.database+':55441';
const actors=JSON.parse(fs.readFileSync(path.join(plan.source,'storage/app/private/stability-cold-actors.json')));
actors.geo=JSON.parse(fs.readFileSync(path.join(DIR,'i0-qa-actor-private.json')));
const receipt=path.join(DIR,'portal-stability-cold-chromium.json');
if(fs.existsSync(receipt))fs.copyFileSync(receipt,receipt.replace('.json','-attempt-'+Date.now()+'.json'));
const proof={at:new Date().toISOString(),origin:BASE,target:TARGET,checks:[],operations:[],errors:[],active_writes:0,AB_C37_not_repeated:true};
const resume=process.argv.includes('--resume');
if(resume){const prior=JSON.parse(fs.readFileSync(receipt));assert.equal(prior.target,TARGET);assert.equal(prior.errors.length,0);assert.equal(prior.checks.length,7);assert(prior.new_opportunity_id&&prior.new_partnership_path);fs.copyFileSync(receipt,receipt.replace('.json','-before-consent-retry.json'));Object.assign(proof,prior,{at:new Date().toISOString(),previous_harness_missing_consent:prior.failure});delete proof.failure;delete proof.result;}
const remaining=process.argv.includes('--remaining');
if(remaining){const prior=JSON.parse(fs.readFileSync(receipt));assert.equal(prior.target,TARGET);assert.equal(prior.errors.length,0);assert.equal(prior.checks.length,15);fs.copyFileSync(receipt,receipt.replace('.json','-before-geometry-memory-correction.json'));Object.assign(proof,prior,{at:new Date().toISOString(),previous_missing_geometry_exemplar:prior.failure});delete proof.failure;delete proof.result;}
const save=()=>fs.writeFileSync(receipt,JSON.stringify(proof,null,2));
const redact=e=>Object.values(actors).reduce((s,a)=>['password','totp_secret','secret'].reduce((v,k)=>a[k]?v.replaceAll(a[k],'[REDACTED]'):v,s),String(e.message||e)).split('\nCall log:')[0].replace(/\b\d{6}\b/g,'[OTP OMITTED]').slice(0,1200);
function otp(secret){let bits=0,v=0;const b=[],abc='ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';for(const c of secret.toUpperCase().replace(/=+$/,'')){v=(v<<5)|abc.indexOf(c);bits+=5;if(bits>=8){b.push((v>>>(bits-8))&255);bits-=8;}}const n=Buffer.alloc(8);n.writeBigUInt64BE(BigInt(Math.floor(Date.now()/30000)));const d=crypto.createHmac('sha1',Buffer.from(b)).update(n).digest(),o=d[19]&15;return String((d.readUInt32BE(o)&0x7fffffff)%1000000).padStart(6,'0');}
(async()=>{const browser=await chromium.launch({headless:true,executablePath:'C:/Users/macbook/AppData/Local/ms-playwright/chromium-1243/chrome-win64/chrome.exe',args:['--host-resolver-rules=MAP portal-investidor.test 127.0.0.1','--no-proxy-server']});let ctx,page,role;
async function actor(name){if(ctx)await ctx.close();role=name;ctx=await browser.newContext({ignoreHTTPSErrors:false,viewport:{width:1440,height:1000}});
await ctx.addInitScript(()=>Object.defineProperty(Crypto.prototype,'randomUUID',{value:undefined,configurable:true}));
await ctx.route('**/*',r=>new URL(r.request().url()).origin===BASE?r.continue():r.abort());page=await ctx.newPage();page.setDefaultTimeout(35000);
page.on('pageerror',e=>{proof.errors.push({role,path:new URL(page.url()).pathname,message:redact(e)});save();});
page.on('request',r=>{if(!['POST','PUT'].includes(r.method())||['/login','/two-factor-challenge'].includes(new URL(r.url()).pathname))return;
let data;try{data=r.postDataJSON();}catch{return;}for(const key of ['client_key','creation_key','idempotency_key'])if(data?.[key]){
assert.match(data[key],/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i);
proof.operations.push({role,path:new URL(r.url()).pathname,method:r.method(),key_field:key,key_sha256:crypto.createHash('sha256').update(data[key]).digest('hex')});save();}});
await open('/login');const a=actors[name];await page.locator('#email').fill(a.email);await page.locator('#password').fill(a.password);await page.locator('[data-test="login-button"]').click();
await page.waitForURL(u=>u.pathname!=='/login');if(new URL(page.url()).pathname==='/two-factor-challenge'){await page.waitForTimeout(30500-(Date.now()%30000));await page.locator('input[name="code"]').fill(otp(a.totp_secret??a.secret));await page.getByRole('button',{name:'Continue',exact:true}).click();await page.waitForURL(u=>!['/login','/two-factor-challenge'].includes(u.pathname));}}
async function open(route){const r=await page.goto(BASE+route,{waitUntil:'networkidle'});assert.equal(r.headers()['x-investmoz-qa-target'],TARGET);return r;}
async function observed(component,route,expected=200){const r=await open(route);assert.equal(r.status(),expected);await page.locator('h1').first().waitFor();assert(await page.evaluate(()=>isSecureContext&&typeof crypto.randomUUID==='undefined'&&typeof crypto.getRandomValues==='function'));
const row={component,role,route,status:r.status(),uuid_api_absent:true,visible_heading:(await page.locator('h1').first().innerText()).slice(0,150),errors:proof.errors.length};proof.checks.push(row);save();return row;}
async function recover(route,label){await open(route);await page.reload({waitUntil:'networkidle'});assert(await page.locator('h1').first().isVisible());proof.checks.push({criterion:label,role,route,refresh_recovery:true});save();}
try{
await actor('approver');await observed('profile-installation','/management/profile-install');
const bootstrapOnly=process.argv.includes('--bootstrap-only');
if(bootstrapOnly){const prior=JSON.parse(fs.readFileSync(receipt));fs.writeFileSync(receipt.replace('.json','-before-normal-enrollment-fix.json'),JSON.stringify(prior,null,2));proof.previous_bootstrap_status=prior.bootstrap_status;}
if(!bootstrapOnly){
const before=await page.evaluate(async()=>await (await fetch('/management/profile-install',{headers:{Accept:'application/json'}})).json());assert(before.ready&&before.consistent);proof.before={installed:before.installed,dependencies:before.dependencies,bootstrap:before.bootstrap};save();
let lost=false,payload;
await page.route('**/management/profile-install',async route=>{if(route.request().method()==='POST'&&!lost){payload=route.request().postDataJSON();lost=true;proof.initial_connection_interrupted_before_commit=true;save();await route.abort('failed');}else await route.continue();});
await page.getByLabel('Fundamento',{exact:true}).fill('Synthetic QA cold installer: recover committed operation after lost response');await page.getByLabel('Confirmo exclusivamente a ação indicada nesta base').check();
const install=page.getByRole('button',{name:'Instalar schema 040000',exact:true});await install.click();await page.getByRole('status').filter({hasText:/Failed to fetch|ligação|resposta|fetch/i}).waitFor();await install.click();
await page.getByRole('status').filter({hasText:'Schema instalado.'}).waitFor();assert.equal(proof.operations.at(-1).key_sha256,proof.operations.at(-2).key_sha256);
const repeat=await page.evaluate(async body=>{const cookie=document.cookie.split('; ').find(v=>v.startsWith('XSRF-TOKEN='))?.slice(11);const r=await fetch('/management/profile-install',{method:'POST',headers:{Accept:'application/json','Content-Type':'application/json','X-XSRF-TOKEN':decodeURIComponent(cookie??'')},body:JSON.stringify(body)});return {status:r.status,json:await r.json()};},payload);assert.equal(repeat.status,200);assert(repeat.json.installed);proof.checks.push({criterion:'cold040 interrupted attempt/retry preserves key; replay returns same receipt',passed:true});
}
if(bootstrapOnly)await page.getByLabel('Fundamento',{exact:true}).fill('Synthetic QA normal Fortify MFA bootstrap after compatibility correction');
await page.getByLabel('ID da primeira conta explicitamente designada').fill(String(actors.first.id));await page.getByLabel('ID da segunda conta explicitamente designada').fill(String(actors.second.id));await page.getByLabel('Confirmo exclusivamente a ação indicada nesta base').check();
const answer=page.waitForResponse(r=>new URL(r.url()).pathname==='/management/profile-install/bootstrap'&&r.request().method()==='POST');await page.getByRole('button',{name:'Inicializar apenas estas duas contas',exact:true}).click();const r=await answer;proof.bootstrap_status=r.status();proof.bootstrap_message=(await r.json()).message??null;save();assert.equal(r.status(),200);
await page.getByRole('status').filter({hasText:'Dupla inicializada.'}).waitFor();await actor('first');await recover('/management/profile-install','explicit synthetic pair initialization recovered as designated holder in new session');proof.result='passed';save();console.log(JSON.stringify({result:proof.result,checks:proof.checks.length,active_writes:0}));
}catch(e){proof.result='failed';proof.failure=redact(e);save();console.log(JSON.stringify({result:'failed',failure:proof.failure,bootstrap_status:proof.bootstrap_status,bootstrap_message:proof.bootstrap_message,active_writes:0}));process.exitCode=1;}finally{if(ctx)await ctx.close();await browser.close();}})();