36 lines
5.4 KiB
JavaScript
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);
|
|
}
|
|
});
|