Files
stack/packages/webui/tests/settings-write.test.mjs
T
jason.woltjeandClaude Opus 5.5 7b5b682ae8 business: agent limits as settings with one organization write path (row 122, #1616)
launch.max becomes launch.models plus launch.limits (total, providers,
exact provider/model). The launcher re-reads limits on every attempt.
Settings and `mosaic limits` write through one locked, journaled
organization writer. `mosaic limits migrate` is print-only.

Candidate 00b84e311475f97ced0d9a9599fba23a28442971ed15d8d489d9422d84a8812e,
Rocko packet 4b6e50636, Filbert round 2 approve (comment 28542).
Landing gate at 0c56cc2d4: 23 suites green. Decision 123 go from Mos.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 20:50:52 -05:00

19 lines
2.4 KiB
JavaScript

// REQ-WEB-1 / REQ-LIMIT-1: Settings uses the Console's human send boundary.
import test from 'node:test';
import assert from 'node:assert/strict';
import {request} from 'node:http';
import {startServer} from '../src/serve.mjs';
const preview={host:'console.example',header:'x-user',user:'jason'};
const headers={host:'console.example','x-user':'jason',origin:'https://console.example','sec-fetch-site':'same-origin','content-type':'application/json'};
const payload={revision:'a'.repeat(64),limits:{total:0}};
async function setup(t,enabled=true){const calls=[];const server=await startServer({port:0,preview,send:enabled?async()=>({}):null,settingsWrite:async args=>{calls.push(args);return {...args,business:'acme'};}});t.after(()=>new Promise(r=>server.close(r)));return {calls,port:server.address().port};}
function post(s,hs=headers,data=payload){return new Promise((resolve,reject)=>{const req=request({hostname:'127.0.0.1',port:s.port,path:'/api/settings',method:'POST',headers:hs},r=>{let text='';r.on('data',c=>text+=c);r.on('end',()=>resolve({status:r.statusCode,text}));});req.on('error',reject);req.end(typeof data==='string'?data:JSON.stringify(data));});}
test('REQ-WEB-1 signed-in same-origin Settings write reaches exactly one human operation',async t=>{const s=await setup(t);const r=await post(s);assert.equal(r.status,200,r.text);assert.deepEqual(s.calls,[payload]);});
test('REQ-WEB-1 Settings writes require enabled send, named Host, identity, exact Origin and same-origin Fetch Metadata',async t=>{
const off=await setup(t,false);assert.equal((await post(off)).status,403);assert.equal(off.calls.length,0);
const s=await setup(t);for(const [key,value,status] of [['host','wrong.example',403],['x-user','other',401],['origin','https://else.example',403],['sec-fetch-site','cross-site',403],['origin',undefined,403],['sec-fetch-site',undefined,403],['x-user',['jason','jason'],401]]){const hs={...headers};if(value===undefined)delete hs[key];else hs[key]=value;assert.equal((await post(s,hs)).status,status,key);}assert.equal(s.calls.length,0);
});
test('REQ-WEB-1 Settings validates JSON, size, revision and strict writable keys before broker call',async t=>{
const s=await setup(t);for(const value of [{...payload,actor:'jason'},{limits:{}},[],null,'bad','x'.repeat(17000)])assert.equal((await post(s,headers,value)).status,400,String(value));assert.equal((await post(s,{...headers,'content-type':'text/plain'})).status,400);assert.equal(s.calls.length,0);
});