Capture guarded human gestures and verify agent administration

This commit is contained in:
Karl committed 2026-10-13 18:24:44 +02:00
1 parent 244f01630b
commit adf0940e5f
32 files changed
+523 -52

No files matched your search

+12
View File
@@ -7,6 +7,18 @@ function protectFixtureKey(file){
async function fixture(t,{configured=true}={}){const dir=mkdtempSync(join(tmpdir(),'safetynet-evidence-')),keyFile=join(dir,'evidence.key');writeFileSync(keyFile,randomBytes(32),{mode:0o600});protectFixtureKey(keyFile);const store=openStore(dir);const evidencePolicy=store.get('policy');evidencePolicy.evidence={enabled:true,captureDownloads:true,captureInteractions:true};store.put('policy',evidencePolicy);const deviceToken='synthetic-device-evidence-credential-1234567890',id=randomUUID();store.db.prepare('INSERT INTO devices(id,token_hash,revoked) VALUES(?,?,0)').run(id,digest(deviceToken));const config={publicUrl:'http://127.0.0.1:4310',...(configured?{evidenceKeyFile:keyFile}:{})},server=createApp(store,config).listen(0,'127.0.0.1');await new Promise(r=>server.once('listening',r));t.after(async()=>{await new Promise(r=>server.close(r));store.db.close();rmSync(dir,{recursive:true,force:true});});const api=async(path,method='GET',body,role='device')=>{const credential=`synthetic-${role}-evidence-credential-1234567890`;if(role!=='device')store.db.prepare('INSERT OR REPLACE INTO sessions VALUES(?,?,?)').run(digest(credential),Date.now()+60000,JSON.stringify({sub:role,role}));const r=await fetch(`http://127.0.0.1:${server.address().port}${path}`,{method,headers:{...(role==='device'?{authorization:`Bearer ${deviceToken}`}:{cookie:`sn_session=${credential}`}),origin:config.publicUrl,'content-type':'application/json'},body:body?JSON.stringify(body):undefined});return {status:r.status,body:await r.json()};};const eventId=randomUUID();store.event(id,'clipboard.copy',{eventId,policyVersion:1,interaction:{action:'copy',outcome:'completed',sessionId:'00000000-0000-4000-8000-000000000001'}});return {store,api,id,eventId,config};}
const evidence=eventId=>({eventId,type:'interaction',payload:{pageUrl:'https://intranet.example/document',action:'copy',sessionId:'00000000-0000-4000-8000-000000000001',outcome:'completed',captureSource:'guarded-clipboard',sensitiveField:false}});
test('human observations bind exact event action and session without claiming transfer completion',async t=>{
const {api,store,id}=await fixture(t),sessionId=randomUUID();
for(const action of ['click','submit']){
const eventId=randomUUID(),payload={pageUrl:'https://intranet.example/',action,sessionId,outcome:'observed',captureSource:'human-observer',sensitiveField:false,target:{tag:'BUTTON'}};
assert.equal((await api('/api/device/events','POST',{eventId,kind:'browser.interaction',policyVersion:1,interaction:{action,sessionId,outcome:'observed'}})).status,200);
for(const outcome of ['completed','authorized','denied'])assert.equal((await api('/api/device/events','POST',{eventId:randomUUID(),kind:'browser.interaction',policyVersion:1,interaction:{action,sessionId,outcome}})).status,400);
for(const extra of [{action:action==='click'?'submit':'click'},{outcome:'completed'},{sessionId:randomUUID()},{captureSource:'agent-adapter'},{bytes:1},{content:'PRIVATE_BODY'}])assert.equal((await api('/api/device/evidence','POST',{eventId,type:'interaction',payload:{...payload,...extra}})).status,400);
const accepted=await api('/api/device/evidence','POST',{eventId,type:'interaction',payload});assert.equal(accepted.status,201);
assert.deepEqual((await api(`/api/admin/evidence/${accepted.body.id}?reason=investigation`,'GET',undefined,'analyst')).body.payload,payload);
}
});
test('interaction collection is independent and binds completed action, session and capture source',async t=>{
const {api,store,id,eventId}=await fixture(t),body=evidence(eventId),p=store.get('policy');
p.evidence.captureInteractions=false;store.put('policy',p);assert.equal((await api('/api/device/evidence','POST',body)).status,403);