import test from 'node:test'; import assert from 'node:assert/strict'; import {createRequire} from 'node:module'; import {defaultPolicy} from '../packages/core/policy.mjs'; const require=createRequire(import.meta.url),{createDownloadResponseGate}=require('../apps/network-broker/download-response-gate.cjs'); const input={request:{url:'https://intranet.example/document.pdf'},body:Buffer.alloc(0)}; const response=(body,headers={},statusCode=200)=>({statusCode,headers,body:Buffer.from(body)}); test('incoming confidential HTML/API is not outbound DLP; magic document requires actual scanner',async()=>{ const policy=defaultPolicy();policy.browser.allowDownloads=true;let calls=0; const page=createDownloadResponseGate({auditRequired:false,policy,current:()=>true,forward:async()=>response('company internal text',{'content-type':'text/html'}),inspector:{inspect:async()=>{calls++;assert.fail('incoming page not outgoingDLP');}}}); assert.equal((await page(input)).body.toString(),'company internal text');assert.equal(calls,0); const document=createDownloadResponseGate({auditRequired:false,policy,current:()=>true,forward:async()=>response('%PDF-1.4 public',{'content-type':'application/pdf'})});await assert.rejects(document(input),{code:'download-inspection-blocked'}); }); test('signed explicit no-malware-scanner still requires complete document parsing and preserves disposition',async()=>{ const policy=defaultPolicy();policy.browser.allowDownloads=true;policy.fileTransfers.download.allowWithoutMalwareScanner=true; let calls=0;const gate=createDownloadResponseGate({auditRequired:false,policy,current:()=>true,forward:async()=>response('%PDF-1.4 public',{'content-type':'application/pdf','content-disposition':'inline; filename="public.pdf"'}),inspector:{inspect:async()=>{calls++;return {decision:'allow',coverage:{complete:true}};}}}); const value=await gate(input);assert.equal(calls,1);assert.equal(value.headers['content-disposition'],'inline; filename="public.pdf"');assert.equal(value.body.toString(),'%PDF-1.4 public'); }); test('malware/DLP block, incomplete coverage, scanner mutation and revocation release no response',async()=>{ for(const inspect of [async()=>({decision:'block',ruleId:'registered'}),async()=>({decision:'allow',coverage:{complete:false}}),async bytes=>{bytes.fill(0);return {decision:'allow',coverage:{complete:true}};}]){ const policy=defaultPolicy();policy.browser.allowDownloads=true;policy.fileTransfers.download.allowWithoutMalwareScanner=true; const gate=createDownloadResponseGate({auditRequired:false,policy,current:()=>true,forward:async()=>response('%PDF-1.4 public'),inspector:{inspect}});await assert.rejects(gate(input),{code:'download-inspection-blocked'}); } const policy=defaultPolicy();policy.browser.allowDownloads=true;policy.fileTransfers.download.allowWithoutMalwareScanner=true;let current=true; const gate=createDownloadResponseGate({auditRequired:false,policy,current:()=>current,forward:async()=>response('%PDF-1.4 public'),inspector:{inspect:async()=>{current=false;return {decision:'allow',coverage:{complete:true}};}}});await assert.rejects(gate(input),{code:'authority-expired'}); }); test('magic mismatch, partial206 and compression cannot bypass full download inspection',async()=>{ const policy=defaultPolicy();policy.browser.allowDownloads=true;policy.fileTransfers.download.blockMimeMismatch=true; for(const record of [response('%PDF-1.4 public',{'content-type':'text/plain'}),response('%PDF-1.4 public',{},206),response('%PDF-1.4 public',{'content-encoding':'gzip'})]){ const gate=createDownloadResponseGate({auditRequired:false,policy,current:()=>true,forward:async()=>record,inspector:{inspect:async()=>assert.fail('invalidrepresentation must not scan')}});await assert.rejects(gate(input)); } }); import {randomUUID,createHash} from 'node:crypto'; import {createSyntheticAudit} from './fixtures/broker-durable-audit.cjs'; const {createBrokerAudit}=require('../apps/network-broker/audit-gate.cjs'),{createBrokerLifecycle}=require('../apps/network-broker/lifecycle-audit.cjs'); test('download verdict commits typed immutable real-file facts and registered detector before release',async t=>{ const policy=defaultPolicy();policy.browser.allowDownloads=true;policy.fileTransfers.download.allowWithoutMalwareScanner=true;policy.dlp.rules=[{id:'registered-secret',label:'Synthetic',kind:'literal',value:'synthetic',action:'block'}]; const journal=createSyntheticAudit(t),audit=createBrokerAudit({persist:journal.persist,current:()=>true,policyVersion:1,allowedRuleIds:['registered-secret']}),context=createBrokerLifecycle(audit).begin();await context.decision('allow',{bytes:0,detectedType:'text'}); const body=Buffer.from('%PDF-1.4 encodedsynthetic'),gate=createDownloadResponseGate({policy,current:()=>true,forward:async()=>response(body),inspector:{inspect:async()=>({decision:'block',ruleId:'registered-secret',coverage:{complete:true}})}}); await assert.rejects(gate({...input,auditContext:context}),{code:'download-inspection-blocked'});await context.reject('upstream-failed',{bytes:0,detectedType:'text'}); const events=journal.events();assert.equal(events.length,2);assert.equal(events[1].kind,'download.block');assert.equal(events[1].ruleId,'registered-secret');assert.equal(events[1].broker.phase,'response.block');assert.equal(events[1].broker.authorizedEventId,events[0].eventId);assert.equal(events[1].file.sha256,createHash('sha256').update(body).digest('hex'));assert.equal(events[1].request,undefined); }); test('pending or failed mandatory download commit cannot return document bytes',async()=>{ const policy=defaultPolicy();policy.browser.allowDownloads=true;policy.fileTransfers.download.allowWithoutMalwareScanner=true;let release,entered;const hold=new Promise(resolve=>release=resolve),started=new Promise(resolve=>entered=resolve);let completed=false; const audit=createBrokerAudit({current:()=>true,policyVersion:1,persist:async event=>{if(event.kind==='download.scan'){entered();await hold;}return {persisted:true,eventId:event.eventId};}}),context=createBrokerLifecycle(audit).begin();await context.decision('allow',{bytes:0,detectedType:'text'}); const gate=createDownloadResponseGate({policy,current:()=>true,forward:async()=>response('%PDF-1.4 public'),inspector:{inspect:async()=>({decision:'allow',coverage:{complete:true}})}}); const pending=gate({...input,auditContext:context}).then(()=>completed=true);await started;assert.equal(completed,false);release();await pending;assert.equal(completed,true); const fail=createBrokerAudit({current:()=>true,policyVersion:1,persist:async event=>{if(event.kind==='download.scan')throw Error('private journal detail');return {persisted:true,eventId:event.eventId};}}),denied=createBrokerLifecycle(fail).begin();await denied.decision('allow',{bytes:0,detectedType:'text'});await assert.rejects(gate({...input,auditContext:denied}),{code:'audit-persistence-failed'}); const missing=createDownloadResponseGate({policy,current:()=>true,forward:async()=>assert.fail('no unaudited dial')});await assert.rejects(missing(input),{code:'audit-unavailable'}); }); test('download causation refuses missing authorization and unknown matched detector',async()=>{ const audit=createBrokerAudit({current:()=>true,policyVersion:1,persist:async()=>assert.fail('invalid facts never persist')}); for(const broker of [{requestId:randomUUID(),phase:'response.block',reason:'broker-download-inspection-block'},{requestId:randomUUID(),phase:'response.scanned',reason:'broker-download-approved',authorizedEventId:randomUUID()}])await assert.rejects(audit.recordDownload('block',{bytes:3,detectedType:'pdf',sha256:'a'.repeat(64),broker}),{code:'audit-facts-invalid'}); }); test('OS save prohibition does not bypass or deny complete inline asset scans',async()=>{ const policy=defaultPolicy();policy.fileTransfers.download.allowWithoutMalwareScanner=true;const bytes=Buffer.from('89504e470d0a1a0a','hex');let scans=0; const gate=createDownloadResponseGate({auditRequired:false,policy,current:()=>true,forward:async()=>response(bytes,{'content-type':'image/png'}),inspector:{inspect:async()=>{scans++;return {decision:'allow',coverage:{complete:true}};}}}); assert.deepEqual((await gate({...input,request:{url:'https://intranet.example/icon.png'}})).body,bytes);assert.equal(scans,1); const attachment=createDownloadResponseGate({auditRequired:false,policy,current:()=>true,forward:async()=>response(bytes,{'content-type':'image/png','content-disposition':'attachment; filename=icon.png'}),inspector:{inspect:async()=>assert.fail('policy denies before scan')}});await assert.rejects(attachment(input),{code:'download-policy-blocked'}); }); test('late original classifier cannot commit another decision after a terminal scan timeout',async t=>{ const journal=createSyntheticAudit(t),audit=createBrokerAudit({persist:journal.persist,current:()=>true,policyVersion:1}),context=createBrokerLifecycle(audit).begin(); await context.reject('inspection-deadline',{bytes:6,detectedType:'text'});assert.throws(()=>context.decision('allow',{bytes:6,detectedType:'text'}),{code:'aborted'});assert.throws(()=>context.response('allow',{bytes:6,detectedType:'pdf',sha256:'a'.repeat(64)}),{code:'aborted'}); const events=journal.events();assert.equal(events.length,1);assert.equal(events[0].broker.reason,'broker-scan-timeout'); });