// Explicit Windows integration: run with the verified bundled Node executable // and SAFETYNET_NATIVE_BROKER_INSPECTION=1. Default unit suites skip this gate. import test from 'node:test'; import assert from 'node:assert/strict'; import fs from 'node:fs/promises'; import path from 'node:path'; import {createRequire} from 'node:module'; import {createHash,generateKeyPairSync} from 'node:crypto'; import {execFileSync} from 'node:child_process'; import http from 'node:http'; import https from 'node:https'; import tls from 'node:tls'; import {once} from 'node:events'; import {defaultPolicy,signPolicy,inspect} from '../packages/core/policy.mjs'; import {verifyBrokerRuntime} from '../scripts/provision-broker-runtime.mjs'; const require=createRequire(import.meta.url),{startInspector}=require('../apps/browser/inspection.cjs'); const {createManagedProxy}=require('../apps/network-broker/managed-proxy.cjs'); const {createPolicyAuthority}=require('../apps/network-broker/policy-authority.cjs'); const {createHttpsForwarder}=require('../apps/network-broker/https-forwarder.cjs'); const {createSyntheticAudit}=require('./fixtures/broker-durable-audit.cjs'); const hash=bytes=>createHash('sha256').update(bytes).digest('hex'); function pdf(text){ const stream=`BT /F1 12 Tf 72 720 Td <${Buffer.from(text).toString('hex')}> Tj ET`; const objects=['<< /Type /Catalog /Pages 2 0 R >>','<< /Type /Pages /Kids [3 0 R] /Count 1 >>','<< /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] /Resources << /Font << /F1 4 0 R >> >> /Contents 5 0 R >>','<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>',`<< /Length ${Buffer.byteLength(stream)} >>\nstream\n${stream}\nendstream`]; let output='%PDF-1.4\n';const offsets=[0]; objects.forEach((object,index)=>{offsets.push(Buffer.byteLength(output));output+=`${index+1} 0 obj\n${object}\nendobj\n`;}); const xref=Buffer.byteLength(output);output+=`xref\n0 6\n0000000000 65535 f \n${offsets.slice(1).map(offset=>String(offset).padStart(10,'0')+' 00000 n \n').join('')}trailer\n<< /Size 6 /Root 1 0 R >>\nstartxref\n${xref}\n%%EOF\n`; return Buffer.from(output); } function inspectorChildren(){ const script=`@(Get-CimInstance Win32_Process -Filter "ParentProcessId = ${process.pid}" | Where-Object { $_.Name -eq 'python.exe' -and $_.CommandLine -like '*apps*inspector*server.py*' } | Select-Object -ExpandProperty ProcessId) | ConvertTo-Json -Compress`; const output=execFileSync('powershell.exe',['-NoProfile','-NonInteractive','-Command',script],{encoding:'utf8',windowsHide:true,timeout:10000}).trim(); return output?[].concat(JSON.parse(output)):[]; } test('bundled Windows Node managed TLS broker uses real contained document inspection before dial',{ skip:process.platform!=='win32'||process.env.SAFETYNET_NATIVE_BROKER_INSPECTION!=='1',timeout:120000 },async t=>{ const root=path.resolve('.'),proofDirectory=path.join(root,'artifacts/broker-native-inspection');await fs.mkdir(proofDirectory,{recursive:true}); const proof={startedAt:new Date().toISOString(),outcome:'running',diagnosticsEnabled:false,scans:[],office:[]}; let inspector,proxy,target;const started=performance.now(); try{ const runtime=await verifyBrokerRuntime(path.join(root,'.runtime/windows/broker')); assert.equal(path.resolve(process.execPath).toLowerCase(),path.join(root,'.runtime/windows/broker/node.exe').toLowerCase(),'Run this gate with the bundled broker Node executable'); proof.runtime={version:runtime.version,executableSha256:runtime.files.find(file=>file.path==='node.exe').sha256}; inspector=startInspector(root,false);assert.ok(inspector,'Contained inspector runtime unavailable');await inspector.waitReady(); const children=inspectorChildren();assert.equal(children.length,1,'Expected one owned contained inspector parent');proof.inspectorOwnedPids=children; // startInspector only resolves readiness after validating Job Object plus // zero-network-capability AppContainer/private-pipe/read-only containment. proof.containmentStartupValidated=true; const key=await fs.readFile(new URL('./fixtures/icap/key.pem',import.meta.url)),cert=await fs.readFile(new URL('./fixtures/icap/cert.pem',import.meta.url)); const received=[];let connections=0; target=https.createServer({key,cert},async(req,res)=>{const chunks=[];for await(const chunk of req)chunks.push(chunk);const body=Buffer.concat(chunks);received.push({sha256:hash(body),bytes:body.length});res.end('public receiver acknowledgment');}); target.on('connection',()=>connections++);target.listen(0,'127.0.0.1');await once(target,'listening'); const port=target.address().port,destination=`localhost:${port}`; const keys=generateKeyPairSync('ed25519'),policy=defaultPolicy();policy.assignment={deviceId:'native-broker-device',groups:[]}; policy.dlp.rules=[{id:'synthetic-confidential-document',label:'Synthetic confidential',kind:'literal',value:'SYNTHETIC INTERNAL BLUEPRINT',action:'block'}]; assert.equal(policy.diagnostics.enabled,false); const authority=await createPolicyAuthority({deviceId:'native-broker-device',publicKey:keys.publicKey.export({type:'spki',format:'pem'})}); authority.accept(signPolicy(policy,keys.privateKey.export({type:'pkcs8',format:'pem'}))); const snapshot=authority.snapshot(); const forward=createHttpsForwarder({authority:snapshot.token,current:authority.current,resolveRoute:async value=>({approved:value.hostname==='localhost'&&value.port===port,address:'127.0.0.1',port:value.port}),ca:cert,deadlineMs:45000,maxResponseBytes:Math.min(16777216,policy.fileTransfers.download.maxBytes)}); const durableAudit=createSyntheticAudit(t); proxy=await createManagedProxy({policyAuthority:authority,authMode:'bearer',persistAudit:durableAudit.persist,resolveCertificate:binding=>binding.authority===destination?{authority:destination,key,cert}:undefined, localInspector:async(bytes,signedPolicy)=>{const before=performance.now(),result=await inspector.inspect(bytes,signedPolicy);proof.scans.push({durationMs:performance.now()-before,decision:result.decision,complete:result.coverage.complete,contentType:result.contentType,matchedSyntheticRule:result.ruleId==='synthetic-confidential-document'});return result;},forward,deadlineMs:45000}); const proxyPort=await proxy.listen(); const send=(body,mime='application/pdf')=>new Promise((resolve,reject)=>{ const request=http.request({host:'127.0.0.1',port:proxyPort,method:'CONNECT',path:destination,headers:{host:destination,'proxy-authorization':`Bearer ${proxy.capability}`}}); request.setTimeout(55000,()=>request.destroy(new Error('native-test-deadline')));request.once('error',reject); request.once('connect',(response,socket)=>{ if(response.statusCode!==200){socket.destroy();resolve(response.statusCode);return;} const secure=tls.connect({socket,servername:'localhost',ca:cert,rejectUnauthorized:true});let reply=''; secure.setTimeout(55000,()=>secure.destroy(new Error('native-test-deadline')));secure.once('error',reject); secure.once('secureConnect',()=>secure.write(Buffer.concat([Buffer.from(`POST /upload HTTP/1.1\r\nHost: ${destination}\r\nContent-Type: ${mime}\r\nContent-Length: ${body.length}\r\nConnection: close\r\n\r\n`),body]))); secure.on('data',chunk=>reply+=chunk.toString());secure.once('end',()=>{secure.destroy();resolve(Number(/^HTTP\/1.1 (\d+)/.exec(reply)?.[1]));}); });request.end(); }); const secret=pdf(policy.dlp.rules[0].value),publicDocument=pdf('Public example report'); assert.equal(inspect(secret,policy).decision,'allow','Encoded PDF must require genuine parsing, not raw literal detection'); assert.equal(await send(secret),403);assert.equal(connections,0);assert.equal(received.length,0); proof.secret={status:403,upstreamConnections:connections,receivedBytes:0}; assert.equal(await send(publicDocument),200);assert.deepEqual(received,[{sha256:hash(publicDocument),bytes:publicDocument.length}]); assert.ok(proof.scans.some(scan=>scan.decision==='block'&&scan.contentType==='pdf'&&scan.matchedSyntheticRule)); assert.ok(proof.scans.some(scan=>scan.decision==='allow'&&scan.complete&&scan.contentType==='pdf')); proof.public={status:200,upstreamConnections:connections,...received[0]}; const officeRoot=path.join(root,'artifacts/office-coverage-fixtures'); // Only synthetic fixtures are modified by stdlib ZIP/XML; no classifier, // document parser or OCR result is substituted in the actual broker gate. const mutate=[ 'import sys,zipfile,pathlib,xml.etree.ElementTree as ET', 'root=pathlib.Path(sys.argv[1]); marker=sys.argv[2]', "for source,destination,member in [('public-generated.docx','secret-metadata.docx','docProps/core.xml'),('public-generated.xlsx','secret-hidden.xlsx','xl/worksheets/sheet2.xml')]:", ' with zipfile.ZipFile(root/source) as archive:', ' records=[(entry,archive.read(entry)) for entry in archive.infolist()]', " if source.endswith('.xlsx'):", " workbook=ET.fromstring(archive.read('xl/workbook.xml'))", " sheets=[node for node in workbook.iter() if node.tag.endswith('}sheet')]", " assert len(sheets)==2 and sheets[1].attrib.get('state')=='hidden'", " with zipfile.ZipFile(root/destination,'w') as output:", ' changed=False', ' for entry,data in records:', ' if entry.filename==member:', ' document=ET.fromstring(data)', " if source.endswith('.docx'):", " title=document.find('{http://purl.org/dc/elements/1.1/}title')", " if title is None: title=ET.SubElement(document,'{http://purl.org/dc/elements/1.1/}title')", ' title.text=marker', ' else:', " namespace='{http://schemas.openxmlformats.org/spreadsheetml/2006/main}'", " sheet=document.find(namespace+'sheetData')", " if sheet is None: raise RuntimeError('Synthetic sheet data absent')", " row=ET.SubElement(sheet,namespace+'row',{'r':'1'})", " cell=ET.SubElement(row,namespace+'c',{'r':'A1','t':'inlineStr'})", " value=ET.SubElement(ET.SubElement(cell,namespace+'is'),namespace+'t'); value.text=marker", " data=ET.tostring(document,encoding='utf-8',xml_declaration=True);changed=True", ' output.writestr(entry,data)', " if not changed: raise RuntimeError('Synthetic fixture target part absent')", '' ].join('\n'); execFileSync(path.join(root,'.runtime/windows/python/python.exe'),['-c',mutate,officeRoot,policy.dlp.rules[0].value],{windowsHide:true,stdio:'pipe',timeout:10000}); const expectedPublic=[received[0]]; for(const [label,name,mime] of [ ['docx','public-generated.docx','application/vnd.openxmlformats-officedocument.wordprocessingml.document'], ['xlsx','public-generated.xlsx','application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']]){ const bytes=await fs.readFile(path.join(officeRoot,name)),firstScan=proof.scans.length; assert.equal(await send(bytes,mime),200); const observed=proof.scans.slice(firstScan);assert.ok(observed.some(scan=>scan.contentType==='office'&&scan.decision==='allow'&&scan.complete)); expectedPublic.push({sha256:hash(bytes),bytes:bytes.length});proof.office.push({case:label+'-public',status:200,complete:true,sha256:hash(bytes),bytes:bytes.length}); } for(const [label,name,mime] of [ ['docx-metadata','secret-metadata.docx','application/vnd.openxmlformats-officedocument.wordprocessingml.document'], ['xlsx-hidden-sheet','secret-hidden.xlsx','application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']]){ const before=connections,firstScan=proof.scans.length,bytes=await fs.readFile(path.join(officeRoot,name)); assert.equal(await send(bytes,mime),403);assert.equal(connections,before); assert.ok(proof.scans.slice(firstScan).some(scan=>scan.contentType==='office'&&scan.decision==='block'&&scan.matchedSyntheticRule)); proof.office.push({case:label,status:403,matchedSyntheticRule:true,newUpstreamConnections:0}); } const complex=await fs.readFile(path.join(officeRoot,'public-generated.pptx')),beforeComplex=connections,firstComplexScan=proof.scans.length; assert.equal(await send(complex,'application/vnd.openxmlformats-officedocument.presentationml.presentation'),403);assert.equal(connections,beforeComplex); assert.ok(proof.scans.slice(firstComplexScan).some(scan=>scan.contentType==='office'&&scan.decision==='block'&&!scan.complete)); proof.office.push({case:'unsupported-complex-pptx',status:403,complete:false,newUpstreamConnections:0}); assert.deepEqual(received,expectedPublic); const auditEvents=durableAudit.events(); assert.equal(auditEvents.filter(event=>event.kind==='upload.authorized').length,3); assert.equal(auditEvents.filter(event=>event.kind==='upload.block'&&event.ruleId==='synthetic-confidential-document').length,3); assert.equal(auditEvents.length,7); proof.audit={persistedEvents:auditEvents.length,authorizedEvents:3,matchedSecretBlocks:3,syntheticMetadataFsynced:true}; proof.outcome='passed'; }catch(error){proof.outcome='failed';proof.errorType=error.name;throw error;} finally{ if(proxy)await proxy.close();if(target){target.closeAllConnections();await new Promise(resolve=>target.close(resolve));} if(inspector){inspector.stop();const deadline=Date.now()+10000;while(inspectorChildren().length&&Date.now()setTimeout(resolve,100));proof.ownedInspectorParentsRemaining=inspectorChildren().length;} proof.durationMs=performance.now()-started;await fs.writeFile(path.join(proofDirectory,`proof-${proof.startedAt.replaceAll(':','-')}.json`),JSON.stringify(proof,null,2)+'\n'); await fs.writeFile(path.join(proofDirectory,`office-proof-${proof.startedAt.replaceAll(':','-')}.json`),JSON.stringify({startedAt:proof.startedAt,outcome:proof.outcome,diagnosticsEnabled:false,runtime:proof.runtime,office:proof.office,scans:proof.scans.filter(scan=>scan.contentType==='office'),audit:proof.audit,ownedInspectorParentsRemaining:proof.ownedInspectorParentsRemaining},null,2)+'\n'); assert.equal(proof.ownedInspectorParentsRemaining??0,0,'Owned inspector parent did not terminate'); } });