44 lines
3.9 KiB
JavaScript
44 lines
3.9 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import fs from 'node:fs';
|
|
import {join} from 'node:path';
|
|
import {tmpdir} from 'node:os';
|
|
import {DatabaseSync} from 'node:sqlite';
|
|
import {startBroker} from '../src/runtime.mjs';
|
|
import {businessDoc,rolesCopy,systemFor,writeJson} from '../../organization/tests/helpers.mjs';
|
|
test('role must not materialize a new catalogue key by submitting legacy entry shape',async t=>{
|
|
const root=fs.mkdtempSync(join(tmpdir(),'materialize-'));t.after(()=>fs.rmSync(root,{recursive:true,force:true}));
|
|
const rolesDir=rolesCopy(root),doc=businessDoc(root,'demo'),file=join(root,'businesses/demo.json');
|
|
doc.plugins={...doc.plugins,harness:['pi'],'model-provider':['cliproxy']};doc.roles.coder.vars={...doc.roles.coder.vars,harness:'pi',thinking:'low'};
|
|
writeJson(file,doc);fs.mkdirSync(join(root,'data'),{mode:0o700});
|
|
const authority=JSON.parse(fs.readFileSync('./roles/chief-of-staff.json','utf8')).authority;
|
|
const offered={key:'zai-fixture-new',module:'cliproxy',upstream:'zai',provider:'zai',model:'fixture-new',label:'Fixture',available:true,reason:null,harnesses:['pi']};
|
|
let status='ready';
|
|
const modelCatalogue={invalidate(){},read:async()=>({status,models:[offered],notices:[]})};
|
|
const bus=await startBroker({dataRoot:join(root,'data'),businesses:{demo:{id:'demo',human:'jason',arbiters:{technical:'chief',delivery:'chief'},roles:{coder:{authority:{withinRole:[],crossRole:[]}},chief:{definition:'chief-of-staff',authority}}}},organization:{dir:root,rolesDir,system:systemFor(root)},modelCatalogue});t.after(()=>bus.close());
|
|
const db=new DatabaseSync(join(root,'data/bus/bus.sqlite'),{readOnly:true});t.after(()=>db.close());
|
|
const allowed=()=>db.prepare("SELECT count(*) AS n FROM events WHERE kind='action.allowed' AND json_extract(body,'$.action')='organization.change'").get().n;
|
|
const human=bus.broker.bindHuman({business:'demo',human:'jason',via:'cli',outsideAgent:true});
|
|
const cap=bus.broker.bindLaunch({business:'demo',role:'chief',run:'materialize-chief',harness:'pi'});bus.broker.request(cap,{verb:'role.claim'});
|
|
const view=bus.broker.request(human,{verb:'limits'});assert.equal(Object.hasOwn(view.models,offered.key),false);
|
|
const models={...view.models,[offered.key]:{provider:offered.provider,model:offered.model,module:offered.module,upstream:offered.upstream}};
|
|
const args={revision:view.revision,models,instances:{coder:offered.key}}, bytes=fs.readFileSync(file,'utf8');
|
|
await assert.rejects(bus.broker.request(cap,{verb:'organization.set',args}),{code:'organization-model-provider-human-only'});
|
|
assert.equal(allowed(),0);assert.equal(fs.readFileSync(file,'utf8'),bytes);
|
|
delete models[offered.key].module;delete models[offered.key].upstream;
|
|
await assert.rejects(bus.broker.request(cap,{verb:'organization.set',args}),{code:'organization-model-provider-human-only'});
|
|
assert.equal(allowed(),0);assert.equal(fs.readFileSync(file,'utf8'),bytes);
|
|
// A different, unselected key is still materialization of the trusted identity.
|
|
const aliasModels={...view.models,'new-alias':{provider:offered.provider,model:offered.model}};
|
|
await assert.rejects(bus.broker.request(cap,{verb:'organization.set',args:{revision:view.revision,models:aliasModels}}),{code:'organization-model-provider-human-only'});
|
|
status='unavailable';
|
|
await assert.rejects(bus.broker.request(cap,{verb:'organization.set',args:{revision:view.revision,models:aliasModels}}),{code:'model-provider-unavailable'});
|
|
assert.equal(allowed(),0);assert.equal(fs.readFileSync(file,'utf8'),bytes);
|
|
// A human may add the entry; a role may then select that existing key.
|
|
status='ready';
|
|
const saved=await bus.broker.request(human,{verb:'limits.set',args:{revision:view.revision,models:aliasModels}});
|
|
await bus.broker.request(cap,{verb:'organization.set',args:{revision:saved.revision,instances:{coder:'new-alias'}}});
|
|
assert.equal(JSON.parse(fs.readFileSync(file,'utf8')).roles.coder.vars.model,'new-alias');
|
|
assert.equal(allowed(),1);
|
|
});
|