20 lines
2.7 KiB
JavaScript
20 lines
2.7 KiB
JavaScript
import {test} from 'node:test';
|
|||
|
|
import assert from 'node:assert/strict';
|
||
|
|
import fs from 'node:fs';
|
||
|
|
import vm from 'node:vm';
|
||
|
|
const source=fs.readFileSync(new URL('../apps/browser/renderer.js',import.meta.url),'utf8');
|
||
|
|
function fixture(state){
|
||
|
|
const elements=new Map(),calls=[];let tick;
|
||
|
|
class Element{constructor(tag){this.tag=tag;this.children=[];this.open=false;this.listeners={};this.textContent='';}set id(value){this._id=value;elements.set(value,this);}get id(){return this._id;}setAttribute(){}append(...nodes){this.children.push(...nodes);}replaceChildren(){this.children=[];}addEventListener(name,fn){this.listeners[name]=fn;}showModal(){this.open=true;}close(){this.open=false;this.listeners.close?.();}}
|
||
|
|
const agents=new Element('button');agents.id='agents';
|
||
|
|
const context={lastState:state,Date,JSON,Number,Array,Error,setInterval:fn=>{tick=fn;},document:{createElement:tag=>new Element(tag),body:new Element('body')},$:id=>elements.get(id),requireSection:()=>{if(state.blocked)throw Error('managed');},call:async(method,id)=>{calls.push({method,id});return {address:'http://127.0.0.1:4567',credentialPath:'protected.json'};},updateChrome:async()=>{},task:fn=>fn,button:(label,fn)=>{const e=new Element('button');e.textContent=label;e.onclick=fn;return e;}};
|
||
|
|
vm.createContext(context);vm.runInContext(source.slice(source.indexOf('// Pairing selects'),source.indexOf("$('ai-form').onsubmit")),context);
|
||
|
|
return {context,elements,calls,tick:()=>tick()};
|
||
|
|
}
|
||
|
|
const grant={id:'reviewer',name:'Security reviewer',generation:2,expiresAt:new Date(Date.now()+60000).toISOString()};
|
||
|
|
test('individual pairing requires selecting a published identity and closes on revocation',async()=>{
|
||
|
|
const f=fixture({ready:true,agentsEnabled:true,agentIdentityMode:'individual',agentGrants:[grant]});await f.context.openAgentPairing();assert.equal(f.calls.length,0);const list=f.elements.get('agent-grant-list');assert.equal(list.children.length,1);await list.children[0].onclick();assert.equal(f.calls[0].id,'reviewer');assert.match(f.elements.get('agent-pairing-result').textContent,/Security reviewer/);f.context.lastState.agentGrants=[];f.tick();assert.equal(f.elements.get('agent-pairing').open,false);assert.equal(f.elements.get('agent-pairing-result').textContent,'');
|
||
|
|
});
|
||
|
|
test('empty individual mode cannot issue legacy credential and managed section rejects pairing',async()=>{
|
||
|
|
const state={ready:true,agentsEnabled:true,agentIdentityMode:'individual',agentGrants:[]},f=fixture(state);await f.context.openAgentPairing();assert.match(f.elements.get('agent-grant-list').children[0].textContent,/No active agent/);assert.equal(f.calls.length,0);state.blocked=true;await assert.rejects(f.context.openAgentPairing(),/managed/);
|
||
|
|
});
|