Files
SGF/scripts/payables-demo-entry-proof.mjs
2026-10-29 22:42:37 +02:00

39 lines
3.5 KiB
JavaScript

import assert from 'node:assert/strict';
import fs from 'node:fs/promises';
const reports=[];
for (const [host,port,page] of [['compras',8005,'/obrigacoes-fornecedores'],['sgf',8006,'/supplier-payables']]) {
const cookies=new Map();
async function request(path,method='GET',body) {
const r=await fetch(`http://127.0.0.1:${port}${path}`, {method,redirect:'manual',headers:{Cookie:[...cookies].map(([k,v])=>`${k}=${v}`).join('; '),...(body?{'Content-Type':'application/x-www-form-urlencoded'}:{})},...(body?{body:new URLSearchParams(body)}:{})});
for(const c of r.headers.getSetCookie()) {const pair=c.split(';',1)[0],i=pair.indexOf('=');cookies.set(pair.slice(0,i),pair.slice(i+1));}
return {status:r.status,text:await r.text(),location:r.headers.get('location')};
}
const token=text=>{const m=text.match(/name="_token" value="([^"]+)"/);assert(m,'CSRF token present');return m[1];};
const entry=await request('/demo');assert.equal(entry.status,200);assert(!entry.text.includes('type="password"'));
assert.equal((await request('/demo/entrar','POST',{role:'consulta'})).status,419);
assert.equal((await request('/demo/entrar','POST',{role:'admin',_token:token(entry.text)})).status,302);
let baseline;
for(const role of ['preparacao','validacao','consulta']) {
const landing=await request('/demo');
const login=await request('/demo/entrar','POST',{role,_token:token(landing.text)});
assert.equal(login.status,302,host+' '+role+' '+login.text.slice(0,150));assert(login.location.endsWith(page));
const ui=await request(page);assert.equal(ui.status,200,host+' authorised page');assert(ui.text.includes('Trocar função ou sair da demonstração'));
assert.equal(ui.text.includes('data-action="prepare"'),role==='preparacao');
if(role==='consulta')assert(!ui.text.includes('<form data-action='));
const data=JSON.parse((await request('/api/supplier-payables')).text);
assert.equal(data.documents[0].total_minor,1160000);
const counts=[data.proposals.length,data.obligations.length,data.events.length];
if(baseline)assert.deepEqual(counts,baseline);else baseline=counts;
if(host==='sgf'){const session=JSON.parse((await request('/api/session')).text);assert.equal(session.user.email,role+'-obrigacoes@example.test');assert(session.context);assert.equal((await request('/')).status,200);}
}
const landing=await request('/demo');assert.equal((await request('/demo/sair','POST',{_token:token(landing.text)})).status,302);
assert.notEqual((await request(page)).status,200);
const again=await request('/demo');assert.equal((await request('/demo/entrar','POST',{role:'consulta',_token:token(again.text)})).status,302);
const recovered=JSON.parse((await request('/api/supplier-payables')).text);assert.deepEqual([recovered.proposals.length,recovered.obligations.length,recovered.events.length],baseline);
await request('/demo/sair','POST',{_token:token((await request('/demo')).text)});
reports.push({host,passed:true,password_required:false,roles:['preparacao','validacao','consulta'],csrf_enforced:true,arbitrary_role_refused:true,context_selected:host==='sgf',history_preserved:true,financial_commands_executed:false});
}
await fs.writeFile('docs/proofs/payables-demo-entry.json',JSON.stringify({checked_at:new Date().toISOString(),hosts:reports,visual_review:false,public_deployment:false},null,2)+'\n');
console.log('Password-free synthetic entry passed in both compositions; no financial commands executed.');