Files
safetynet/tests/office-stage-otlp-native.test.mjs

36 lines
5.4 KiB
JavaScript

// Explicit native proof: private synthetic signed-policy OTLP receiver only.
// Never publishes/enables diagnostics on the user's browser or production tenant.
import test from 'node:test';
import assert from 'node:assert/strict';
import {createRequire} from 'node:module';
import {createServer} from 'node:http';
import {generateKeyPairSync,createHash} from 'node:crypto';
import {readFile,writeFile,mkdir} from 'node:fs/promises';
import {once} from 'node:events';
import path from 'node:path';
import {execFileSync} from 'node:child_process';
import {defaultPolicy,signPolicy} from '../packages/core/policy.mjs';
const require=createRequire(import.meta.url),{createDiagnostics}=require('../apps/browser/diagnostics.cjs'),{startInspector}=require('../apps/browser/inspection.cjs'),{createPolicyAuthority}=require('../apps/network-broker/policy-authority.cjs');
function children(){const text=execFileSync('powershell.exe',['-NoProfile','-NonInteractive','-Command',`@(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`],{encoding:'utf8',windowsHide:true,timeout:10000}).trim();return text?[].concat(JSON.parse(text)):[];}
test('real contained Office stages export parent-correlated OTLP with sanitized native errors',{
skip:process.platform!=='win32'||process.env.SAFETYNET_OFFICE_OTLP_NATIVE!=='1',timeout:90000
},async()=>{
const root=path.resolve('.'),payloads=[],diagnostics=createDiagnostics();let inspector;
const server=createServer(async(req,res)=>{const chunks=[];let size=0;for await(const chunk of req){size+=chunk.length;assert.ok(size<1048576);chunks.push(chunk);}payloads.push({path:req.url,body:JSON.parse(Buffer.concat(chunks).toString())});res.setHeader('content-type','application/json');res.end('{}');});server.listen(0,'127.0.0.1');await once(server,'listening');
try{
const keys=generateKeyPairSync('ed25519'),policy=defaultPolicy();policy.assignment={deviceId:'synthetic-office-otel',groups:[]};policy.diagnostics={...policy.diagnostics,enabled:true,mode:'debug',endpoint:`http://127.0.0.1:${server.address().port}`,sampleRate:1,debugSampleRate:1,flushIntervalMs:10000};
const authority=await createPolicyAuthority({deviceId:'synthetic-office-otel',publicKey:keys.publicKey.export({type:'spki',format:'pem'})});authority.accept(signPolicy(policy,keys.privateKey.export({type:'pkcs8',format:'pem'})));const trusted=authority.snapshot();diagnostics.configure(trusted.policy.diagnostics,{deviceId:'synthetic-office-otel',policyVersion:trusted.version});
inspector=startInspector(root,false,{onStages:envelope=>diagnostics.importStages(envelope)});assert.ok(inspector);await inspector.waitReady();assert.equal(children().length,1);
const bytes=await readFile(path.join(root,'artifacts/office-coverage-fixtures/public-generated.xlsx'));const verdict=await diagnostics.span('browser.inspect.local',{operation:'office.native-proof'},()=>inspector.inspect(bytes,trusted.policy));assert.equal(verdict.decision,'allow');assert.equal(verdict.coverage.complete,true);
const malformed=await diagnostics.span('browser.inspect.local',{operation:'office.native-error-proof'},()=>inspector.inspect(Buffer.from('PK\x03\x04SYNTHETIC PRIVATE ERROR BODY'),trusted.policy));assert.equal(malformed.decision,'block');
await diagnostics.flush();assert.equal(diagnostics.status().failedExports,0);assert.equal(diagnostics.status().lifetimeFailedExports,0);
const spans=payloads.flatMap(item=>item.body.resourceSpans||[]).flatMap(resource=>resource.scopeSpans||[]).flatMap(scope=>scope.spans||[]),names=['inspector.office.archive','inspector.office.xml','inspector.office.relationships','inspector.office.ocr'];
const all=spans.find(item=>item.name==='inspector.office.relationships'),parse=spans.find(item=>item.name==='inspector.parse'&&item.traceId===all?.traceId);assert.ok(all&&parse);
const stages=names.map(name=>{const span=spans.find(item=>item.name===name&&item.traceId===all.traceId);assert.ok(span,name);assert.equal(span.parentSpanId,parse.spanId);assert.ok(BigInt(span.endTimeUnixNano)>=BigInt(span.startTimeUnixNano));return {stage:name,spanId:span.spanId,parentSpanId:span.parentSpanId,durationMs:Number(BigInt(span.endTimeUnixNano)-BigInt(span.startTimeUnixNano))/1e6};});
assert.ok(spans.some(item=>item.name==='inspector.office.archive'&&item.status?.code===2));assert.equal(JSON.stringify(payloads).includes('SYNTHETIC PRIVATE ERROR BODY'),false);assert.equal(JSON.stringify(payloads).includes('Public revenue'),false);
const directory=path.join(root,'artifacts/office-native-observability');await mkdir(directory,{recursive:true});await writeFile(path.join(directory,'private-otlp-proof-'+new Date().toISOString().replaceAll(':','-')+'.json'),JSON.stringify({receiver:'private-synthetic-fixture',productionCollector:false,decision:'allow',coverageComplete:true,inputSha256:createHash('sha256').update(bytes).digest('hex'),traceId:all.traceId,parseSpanId:parse.spanId,stages,sanitizedErrorStage:true,failedExports:diagnostics.status().failedExports,lifetimeFailedExports:diagnostics.status().lifetimeFailedExports},null,2));
}finally{
inspector?.stop();await diagnostics.shutdown();server.closeAllConnections();await new Promise(resolve=>server.close(resolve));for(let attempt=0;attempt<20&&children().length;attempt++)await new Promise(resolve=>setTimeout(resolve,100));assert.equal(children().length,0);
}
});