Files
stack/packages/cli/tests/model-turn-reader.test.mjs
jason.woltje 362893d043 feat: integrate reviewed proxy page and managed model keys
Source-candidate: poe d9a564e6d20f5f0fd75ce45b12cbbf8bb4c9d568\nSource-candidate: magica38ba5762b06716db1dee00d0afec162656488f5c\nValidated321whole-file phase plus whole bus1349/model-proxy100/webui490; final gate tooling checks pending, not landed.
2026-10-26 12:04:21 -05:00

40 lines
6.1 KiB
JavaScript

// #650 strict reader negatives, real owned files only; prepared, not executed.
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 { spawn, execFileSync } from 'node:child_process';
import { syncBuiltinESMExports } from 'node:module';
import { watchModelOutput } from '../src/model-stall.mjs';
const delay=ms=>new Promise(resolve=>setTimeout(resolve,ms));
function scratch(t){const root=fs.mkdtempSync(join(tmpdir(),'reader650-'));t.after(()=>fs.rmSync(root,{recursive:true,force:true}));return root;}
const canonical=()=>Buffer.from(`turn ${process.hrtime.bigint()}\n`);
async function invalid(t,prepare){const root=scratch(t),file=join(root,'proxy-first-turn');prepare(file,root);let stops=0;const receipts=[];const watch=watchModelOutput({runDir:root,armAtFirstTurn:true,seconds:60,keyId:'0123456789ab',stop:async()=>{stops++;},receipt:r=>receipts.push(r)});t.after(watch.cancel);await delay(30);assert.equal(stops,1,'invalid first-turn metadata triggers single trusted stop');await delay(30);assert.equal(stops,1);assert.deepEqual(receipts,[{action:'proxy-stall',keyIds:['0123456789ab']}]);const targets=fs.readdirSync('/proc/self/fd').flatMap(n=>{try{return [fs.readlinkSync('/proc/self/fd/'+n)];}catch{return [];}});assert.equal(targets.includes(file),false,'invalid marker descriptor closed');return {root,file};}
const malformed=[
['oversized',()=>Buffer.alloc(65,120)],['empty',()=>Buffer.alloc(0)],['wrong prefix',()=>Buffer.from(`turns ${process.hrtime.bigint()}\n`)],
['zero',()=>Buffer.from('turn 0\n')],['future',()=>Buffer.from(`turn ${process.hrtime.bigint()+60_000_000_000n}\n`)],['leading zero',()=>Buffer.from(`turn 0${process.hrtime.bigint()}\n`)],
['extra trailing newline',()=>Buffer.concat([canonical(),Buffer.from('\n')])],['extra token',()=>Buffer.from(`turn ${process.hrtime.bigint()} extra\n`)],
['CRLF',()=>Buffer.from(`turn ${process.hrtime.bigint()}\r\n`)],['malformed digit',()=>Buffer.from('turn abc\n')],
...[['highbit prefix',0],['highbit digit',5],['highbit newline',-1]].map(([name,index])=>[name,()=>{const b=canonical();b[index<0?b.length-1:index]|=128;return b;}]),
];
for(const [name,bytes] of malformed)test(`650 reader rejects ${name} without exposing metadata`,async t=>{await invalid(t,file=>fs.writeFileSync(file,bytes(),{mode:0o600}));});
test('650 reader rejects wrong mode',async t=>{await invalid(t,file=>fs.writeFileSync(file,canonical(),{mode:0o644}));});
test('650 reader never follows owned symlink to a valid long-budget timestamp',async t=>{await invalid(t,(file,root)=>{const target=join(root,'owned-target');fs.writeFileSync(target,canonical(),{mode:0o600});fs.symlinkSync(target,file);});});
test('650 reader FIFO cannot block the watcher process',async t=>{
const root=scratch(t);execFileSync('mkfifo',['-m','600',join(root,'proxy-first-turn')]);
const probe=new URL('./fixtures/model-clock-probe.mjs',import.meta.url).pathname;
const child=spawn(process.execPath,[probe,root],{env:{PATH:process.env.PATH,HOME:process.env.HOME,TMPDIR:process.env.TMPDIR,MOSAIC_CONFIG:process.env.MOSAIC_CONFIG},stdio:['ignore','pipe','ignore']});
let output='',timedOut=false;child.stdout.on('data',b=>{output+=b;});const closed=new Promise((resolve,reject)=>{child.once('error',reject);child.once('close',(code,signal)=>resolve({code,signal}));});const timer=setTimeout(()=>{timedOut=true;child.kill('SIGKILL');},5000);t.after(async()=>{clearTimeout(timer);if(child.exitCode===null&&child.signalCode===null)child.kill('SIGKILL');await closed;});
const result=await closed;clearTimeout(timer);assert.equal(timedOut,false,'FIFO probe completes without blocking');assert.equal(result.code,0);const answer=JSON.parse(output);assert.equal(answer.stops,1,'FIFO metadata is refused through existing stop');assert.equal(answer.nice,19);assert.equal(answer.openMarkerFds,0,'FIFO descriptor closed before child exit');assert.deepEqual(answer.receipts,[{action:'proxy-stall',keyIds:['0123456789ab']}]);
});
test('650 reader late detection uses already-spent embedded budget',async t=>{const root=scratch(t);fs.writeFileSync(join(root,'proxy-first-turn'),`turn ${process.hrtime.bigint()-120_000_000_000n}\n`,{mode:0o600});let stops=0;const watch=watchModelOutput({runDir:root,armAtFirstTurn:true,seconds:60,keyId:'0123456789ab',stop:async()=>{stops++;},receipt:()=>{}});t.after(watch.cancel);await delay(30);assert.equal(stops,1,'embedded initial timestamp already spent the budget');});
test('650 reader closes owned marker descriptors and never rereads armed timestamp',async t=>{
const root=scratch(t),file=join(root,'proxy-first-turn');fs.writeFileSync(file,canonical(),{mode:0o600});const original=fs.openSync;let reads=0;fs.openSync=function(p,flags,...args){if(p===file&&typeof flags==='number')reads++;return original.call(this,p,flags,...args);};syncBuiltinESMExports();t.after(()=>{fs.openSync=original;syncBuiltinESMExports();});
const watch=watchModelOutput({runDir:root,armAtFirstTurn:true,seconds:0.1,keyId:'0123456789ab',stop:async()=>{},receipt:()=>{}});t.after(watch.cancel);await delay(30);assert.equal(reads,1,'first marker read observed');fs.writeFileSync(file,canonical());await watch.done;assert.equal(reads,1,'armed timestamp never reread');
const targets=fs.readdirSync('/proc/self/fd').flatMap(n=>{try{return [fs.readlinkSync('/proc/self/fd/'+n)];}catch{return [];}});assert.equal(targets.includes(file),false,'all owned marker descriptors closed');
});
// Wrong-owner and independently unreadable valid-0600 fixtures require changing
// another UID/ACL. Not forged here; those branches remain explicitly UNVERIFIED.
test('650 first output cancels before malformed metadata can request a stop',async t=>{const root=scratch(t);fs.writeFileSync(join(root,'proxy-first-turn'),'not-a-timestamp',{mode:0o644});fs.writeFileSync(join(root,'proxy-first-output'),'output\n',{mode:0o600});let stops=0;const receipts=[];const watch=watchModelOutput({runDir:root,armAtFirstTurn:true,seconds:60,keyId:'0123456789ab',stop:async()=>{stops++;},receipt:r=>receipts.push(r)});t.after(watch.cancel);await watch.done;assert.equal(stops,0);assert.deepEqual(receipts,[]);});