7 lines
3.6 KiB
JavaScript
7 lines
3.6 KiB
JavaScript
import fs from 'node:fs';import assert from 'node:assert/strict';import {session} from './sgf-single-http.mjs';import {statementDownload} from '../resources/js/statement-download.js';
|
|
const root=JSON.parse(fs.readFileSync('C:/laragon/data/sgf-tempo/run/modular-regression-current.json')).root+'/private/receipt-composition-cc50a276c10c',progress=JSON.parse(fs.readFileSync(root+'/statements-http-progress.json')),sample=JSON.parse(fs.readFileSync(root+'/statements-sample-private.json')),id=progress.resultReview.result.id,sha256=sample.snapshot.csv_sha256,checks=[],ok=(v,n)=>{assert(v,n);checks.push(n);},s=await session('sgf:read_only','accounting');
|
|
let r=await s.get('/api/general-ledger/statements/exports/'+id,{headers:{'X-SGF-Context':''}});ok(r.status===409,'raw link without context still refused');let sent;const result=await statementDownload({id,token:s.identity.context.token,sha256,isCurrent:()=>true,fetcher:async(path,options)=>{sent={path,options};return s.get(path,{headers:options.headers});}});ok(result.sha256===sha256&&result.bytes.byteLength>0,'actual guarded export verified before saving');ok(sent.path.endsWith('/'+id)&&!sent.path.includes(s.identity.context.token)&&sent.options.headers['X-SGF-Context']===s.identity.context.token&&sent.options.credentials==='same-origin','token stays in header not URL');
|
|
const fixture=()=>new Response(result.bytes.slice(0),{status:200,headers:{'Content-Type':'text/csv; charset=UTF-8','X-Content-SHA256':sha256}}),args={id,token:'qa-test-context',sha256,isCurrent:()=>true};let called=false;await assert.rejects(statementDownload({...args,isCurrent:()=>false,fetcher:async()=>{called=true;return fixture();}}),/contexto mudou/);ok(!called,'stale context refused before request');let active=true;await assert.rejects(statementDownload({...args,isCurrent:()=>active,fetcher:async()=>{active=false;return fixture();}}),/contexto mudou/);ok(true,'late headers from old context rejected');active=true;await assert.rejects(statementDownload({...args,isCurrent:()=>active,fetcher:async()=>({ok:true,headers:fixture().headers,arrayBuffer:async()=>{active=false;return result.bytes;}})}),/contexto mudou/);ok(true,'late bytes from old context rejected');
|
|
await assert.rejects(statementDownload({...args,fetcher:async()=>new Response('denied',{status:200,headers:{'Content-Type':'text/html','X-Content-SHA256':sha256}})}),/não corresponde/);ok(true,'HTML cannot masquerade as downloaded CSV');await assert.rejects(statementDownload({...args,fetcher:async()=>new Response(result.bytes,{headers:{'Content-Type':'text/csv','X-Content-SHA256':'0'.repeat(64)}})}),/não corresponde/);ok(true,'different snapshot header refused');await assert.rejects(statementDownload({...args,fetcher:async()=>new Response('corrupted',{headers:{'Content-Type':'text/csv','X-Content-SHA256':sha256}})}),/não confere/);ok(true,'corrupted bytes refused despite matching header');await assert.rejects(statementDownload({...args,fetcher:async()=>new Response(JSON.stringify({message:'QA forbidden'}),{status:403,headers:{'Content-Type':'application/json'}})}),e=>e.status===403);ok(true,'access refusal remains an error not a file');await assert.rejects(statementDownload({...args,id:'invalid',fetcher:async()=>fixture()}),/indisponível/);ok(true,'invalid result identity refused');
|
|
fs.writeFileSync(root+'/statements-frozen-export-private.csv',Buffer.from(result.bytes));const file=root+'/statements-download-proof-20261111.json';fs.writeFileSync(file,JSON.stringify({passed:true,checks,actual_http_export:true,business_commands:0,context_guard_preserved:true,browser_visual_review:false},null,2));console.log(JSON.stringify({passed:true,checks:checks.length,proof:file}));
|