2026-10-13 16:58:15 +02:00
import test from 'node:test' ;
import assert from 'node:assert/strict' ;
import { createServer } from 'node:http' ;
import { mkdtempSync , rmSync } from 'node:fs' ;
import { tmpdir } from 'node:os' ;
import { join } from 'node:path' ;
import { openStore } from '../apps/server/store.mjs' ;
import { createApp } from '../apps/server/app.mjs' ;
import { librarySnapshotHash , validateLibraryPlan , LibraryPolicySchema } from '../packages/core/library.mjs' ;
import { verifyBookmarkSnapshot } from '../packages/core/bookmarks.mjs' ;
const bookmark = { id : 'personal' , title : 'Public project' , url : 'https://example.com/project' , folder : '' };
const tab = { id : 'tab-1' , title : 'Public documentation' , url : 'https://docs.example.com/path?session=private#secret' };
const plan = { bookmarks : [{ id : 'personal' , folder : 'Projects' }], tabs : [{ id : 'tab-1' , group : 'Research' }]};
async function fixture ( t ){
const dir = mkdtempSync ( join ( tmpdir (), 'library-test-' )), store = openStore ( dir ), adminToken = 'library-fixture-admin' ; let output = JSON . stringify ( plan ), calls = 0 , prompt = '' , gate = null ;
const provider = createServer ( async ( req , res )=>{ const chunks = []; for await ( const chunk of req ) chunks . push ( chunk ); prompt = JSON . parse ( Buffer . concat ( chunks ). toString ()). messages [ 0 ]. content ; calls ++ ; if ( gate ) await gate ; res . setHeader ( 'content-type' , 'application/json' ); res . end ( JSON . stringify ({ choices : [{ message : { content : output }}]}));});
await new Promise ( r => provider . listen ( 0 , '127.0.0.1' , r ));
const config = { adminToken , publicUrl : 'http://127.0.0.1' , secure : false , aiBaseUrl : `http://127.0.0.1: ${ provider . address (). port } ` , aiModel : 'fixture' , aiEndpointId : 'default' };
const server = createApp ( store , config ). listen ( 0 , '127.0.0.1' ); await new Promise ( r => server . on ( 'listening' , r ));
t . after ( async ()=>{ await Promise . all ([ new Promise ( r => server . close ( r )), new Promise ( r => provider . close ( r ))]); store . db . close (); rmSync ( dir ,{ recursive : true , force : true });});
async function api ( route , body , token = adminToken ){ const r = await fetch ( `http://127.0.0.1: ${ server . address (). port }${ route } ` ,{ method : body ? 'POST' : 'GET' , headers : { authorization : `Bearer ${ token } ` ,...( body ? { 'content-type' : 'application/json' } : {})}, body : body ? JSON . stringify ( body ) : undefined }); return { status : r . status , body : await r . json ()};}
const code = ( await api ( '/api/admin/enrollments' ,{ user : 'fixture-user' })). body . code , device = ( await api ( '/api/device/enroll' ,{ code , name : 'Fixture' , platform : 'win32' }, '' )). body ;
const p = store . get ( 'policy' ); p . ai = {... p . ai , enabled : true , trustMode : 'local' , model : 'fixture' }; p . library = { aiSuggestionsEnabled : true , aiAutoApplyEnabled : false }; store . put ( 'policy' , p );
await api ( '/api/device/bookmarks' ,{ action : 'add' , expectedRevision : 0 , policyVersion : 1 , bookmark }, device . token );
const request = { policyVersion : 1 , bookmarkRevision : 1 , tabs : [ tab ], snapshotHash : librarySnapshotHash ([ tab ])};
return { store , device , api , request , propose : ()=> api ( '/api/device/library/propose' , request , device . token ), setOutput : v =>{ output = v ;}, setGate : v =>{ gate = v ;}, calls : ()=> calls , prompt : ()=> prompt };
}
test ( 'AI library defaults disabled and strict organization permits only existing item IDs and labels' ,()=>{
assert . deepEqual ( LibraryPolicySchema . parse ({}),{ aiSuggestionsEnabled : false , aiAutoApplyEnabled : false }); assert . deepEqual ( validateLibraryPlan ( plan ,{ bookmarks : [ bookmark ], tabs : [ tab ]}), plan );
for ( const v of [{... plan , bookmarks : [{... plan . bookmarks [ 0 ], url : 'https://evil.test' }]},{... plan , tabs : [{ id : 'other' , group : 'Research' }]},{... plan , bookmarks : []},{... plan , tabs : [{ id : tab . id , group : 'a' . repeat ( 41 )}]},{... plan , bookmarks : [{ id : bookmark . id , folder : 'bad\nlabel' }]}]) assert . throws (()=> validateLibraryPlan ( v ,{ bookmarks : [ bookmark ], tabs : [ tab ]}));
});
test ( 'approved gateway proposes metadata-only AI plan and atomically applies signed personal bookmarks' , async t =>{
const f = await fixture ( t ), result = await f . propose (); assert . equal ( result . status , 200 ); assert . ok ( f . prompt (). includes ( 'docs.example.com' )); assert . ok ( ! f . prompt (). includes ( '/path' )); assert . ok ( ! f . prompt (). includes ( 'session=private' )); assert . ok ( ! f . prompt (). includes ( '/project' ));
const applied = await f . api ( '/api/device/library/apply' ,{ proposalId : result . body . proposalId , policyVersion : 1 , expectedRevision : 1 , snapshotHash : f . request . snapshotHash }, f . device . token ); assert . equal ( applied . status , 200 ); assert . equal ( applied . body . revision , 2 ); assert . equal ( applied . body . items [ 0 ]. folder , 'Projects' ); assert . deepEqual ( applied . body . tabs , plan . tabs );
assert . equal ( verifyBookmarkSnapshot ( applied . body . bookmarks , f . device . publicKey ,{ deviceId : f . device . id , policyVersion : 1 , minimumRevision : 2 }). items [ 0 ]. folder , 'Projects' );
assert . equal (( await f . api ( '/api/device/library/apply' ,{ proposalId : result . body . proposalId , policyVersion : 1 , expectedRevision : 2 , snapshotHash : f . request . snapshotHash }, f . device . token )). status , 404 );
const events = f . store . db . prepare ( "SELECT metadata FROM events WHERE kind LIKE 'library.%'" ). all (); assert . equal ( events . length , 2 ); assert . ok ( events . every ( e => ! e . metadata . includes ( bookmark . title ) &&! e . metadata . includes ( bookmark . url ) &&! e . metadata . includes ( 'Projects' )));
});
test ( 'central disable, hidden library, expired policy, malformed snapshot and disabled automatic application fail closed' , async t =>{
const f = await fixture ( t ), p = f . store . get ( 'policy' ); p . library . aiSuggestionsEnabled = false ; f . store . put ( 'policy' , p ); assert . equal (( await f . propose ()). status , 403 ); assert . equal ( f . calls (), 0 );
p . library . aiSuggestionsEnabled = true ; p . browser . settings . hiddenSections = [ 'library' ]; f . store . put ( 'policy' , p ); assert . equal (( await f . propose ()). status , 403 ); p . browser . settings . hiddenSections = []; f . store . put ( 'policy' , p );
assert . equal (( await f . api ( '/api/device/library/propose' ,{... f . request , snapshotHash : '0' . repeat ( 64 )}, f . device . token )). status , 409 ); const r = await f . propose (); assert . equal ( r . status , 200 );
assert . equal (( await f . api ( '/api/device/library/apply' ,{ proposalId : r . body . proposalId , policyVersion : 1 , expectedRevision : 1 , snapshotHash : f . request . snapshotHash , mode : 'automatic' }, f . device . token )). status , 403 );
p . expiresAt = new Date ( Date . now () - 1000 ). toISOString (); f . store . put ( 'policy' , p ); assert . equal (( await f . propose ()). status , 403 );
});
test ( 'malicious model output and protected metadata rejected before proposal or transmission' , async t =>{
const f = await fixture ( t ); for ( const bad of [{... plan , bookmarks : [{ id : 'managed' , folder : 'Work' }]},{... plan , delete : [ 'personal' ]},{... plan , tabs : [{... plan . tabs [ 0 ], url : 'https://evil.test' }]}]){ f . setOutput ( JSON . stringify ( bad )); assert . notEqual (( await f . propose ()). status , 200 ); assert . equal ( f . store . personalBookmarks ( f . device . id ). revision , 1 );}
const before = f . calls (), p = f . store . get ( 'policy' ); p . dlp . rules . push ({ id : 'confidential-title' , label : 'Protected title' , kind : 'literal' , value : bookmark . title , action : 'block' }); f . store . put ( 'policy' , p ); assert . equal (( await f . propose ()). status , 403 ); assert . equal ( f . calls (), before );
});
test ( 'stale bookmark revision, policy generation and managed collisions cannot apply or partially change library' , async t =>{
const f = await fixture ( t ), r = await f . propose (); assert . equal ( r . status , 200 ); const apply = { proposalId : r . body . proposalId , policyVersion : 1 , expectedRevision : 1 , snapshotHash : f . request . snapshotHash };
assert . equal (( await f . api ( '/api/device/library/apply' ,{... apply , snapshotHash : '0' . repeat ( 64 )}, f . device . token )). status , 409 );
f . store . db . prepare ( 'UPDATE bookmarks SET revision=2 WHERE device_id=?' ). run ( f . device . id ); assert . equal (( await f . api ( '/api/device/library/apply' , apply , f . device . token )). status , 409 ); assert . equal ( f . store . personalBookmarks ( f . device . id ). items [ 0 ]. folder , '' );
f . store . db . prepare ( 'UPDATE bookmarks SET revision=1 WHERE device_id=?' ). run ( f . device . id ); const p = f . store . get ( 'policy' ); p . version = 2 ; f . store . put ( 'policy' , p ); assert . equal (( await f . api ( '/api/device/library/apply' ,{... apply , policyVersion : 2 }, f . device . token )). status , 409 );
p . version = 1 ; p . browser . bookmarks . managed = [ bookmark ]; f . store . put ( 'policy' , p ); assert . equal (( await f . api ( '/api/device/library/apply' , apply , f . device . token )). status , 403 ); assert . equal ( f . store . personalBookmarks ( f . device . id ). revision , 1 );
});
test ( 'automatic organization is separately enabled and existing proposals cannot survive a remote disable' , async t =>{
const f = await fixture ( t ), p = f . store . get ( 'policy' ); p . library . aiAutoApplyEnabled = true ; f . store . put ( 'policy' , p ); const r = await f . propose (); assert . equal ( r . status , 200 );
const body = { proposalId : r . body . proposalId , policyVersion : 1 , expectedRevision : 1 , snapshotHash : f . request . snapshotHash , mode : 'automatic' };
p . library . aiSuggestionsEnabled = false ; f . store . put ( 'policy' , p ); assert . equal (( await f . api ( '/api/device/library/apply' , body , f . device . token )). status , 403 ); assert . equal ( f . store . personalBookmarks ( f . device . id ). revision , 1 );
p . library . aiSuggestionsEnabled = true ; f . store . put ( 'policy' , p ); const applied = await f . api ( '/api/device/library/apply' , body , f . device . token ); assert . equal ( applied . status , 200 ); assert . equal ( applied . body . revision , 2 );
});
test ( 'model output DLP and pending proposal bounds are enforced without storing rejected model data' , async t =>{
const f = await fixture ( t ), p = f . store . get ( 'policy' ); p . dlp . rules . push ({ id : 'protected-output' , label : 'Protected' , kind : 'literal' , value : 'Projects' , action : 'block' }); f . store . put ( 'policy' , p ); assert . equal (( await f . propose ()). status , 403 ); assert . equal ( f . store . personalBookmarks ( f . device . id ). revision , 1 );
p . dlp . rules = []; f . store . put ( 'policy' , p ); for ( let n = 0 ; n < 3 ; n ++ ) assert . equal (( await f . propose ()). status , 200 ); const before = f . calls (); assert . equal (( await f . propose ()). status , 409 ); assert . equal ( f . calls (), before );
});
test ( 'concurrent proposal requests are bounded and policy changes during provider execution invalidate results' , async t =>{
const f = await fixture ( t ); let release ; f . setGate ( new Promise ( r =>{ release = r ;})); const pending = f . propose ();
for ( let n = 0 ; n < 100 && f . calls () === 0 ; n ++ ) await new Promise ( r => setTimeout ( r , 10 )); assert . equal ( f . calls (), 1 );
assert . equal (( await f . propose ()). status , 409 ); assert . equal ( f . calls (), 1 );
2026-10-14 00:37:32 +02:00
const p = f . store . get ( 'policy' ); p . version ++ ; f . store . put ( 'policy' , p ); const rejected = await pending ; release (); assert . equal ( rejected . status , 409 ); assert . equal ( f . store . personalBookmarks ( f . device . id ). revision , 1 );
});
test ( 'provider deadline returns fixed 504 before held provider output is released' , async t =>{
const f = await fixture ( t ); let release , deadline ; f . setGate ( new Promise ( resolve =>{ release = resolve ;}));
const timeout = globalThis . setTimeout ;
t . mock . method ( globalThis , 'setTimeout' ,( callback , milliseconds ,... args )=>{ if ( milliseconds === 60000 ){ deadline = callback ; return timeout (()=>{}, 60000 );} return timeout ( callback , milliseconds ,... args );});
const pending = f . propose (); for ( let n = 0 ; n < 100 && f . calls () === 0 ; n ++ ) await new Promise ( resolve => timeout ( resolve , 10 )); assert . equal ( f . calls (), 1 ); assert . equal ( typeof deadline , 'function' );
deadline (); const result = await pending ; release (); assert . equal ( result . status , 504 ); assert . equal ( result . body . error , 'Request failed' ); assert . equal ( f . store . personalBookmarks ( f . device . id ). revision , 1 );
2026-10-13 16:58:15 +02:00
});