Candidate527b9a1e6(gander/row196-r6-prd19, basef48725cfc), the 39 manifest paths of CANDIDATE.sha256 537d30aef70b6cd1 atec1e7fad8. Duckworth approved round 1 outside B1/B2 (rev 2973, comment 30145) and round 2 merge-scoped (rev 2986, comment 30156). Gate gander-0066 on grant sage-2145: 2334 pass, 0 fail, 1 skip; mutants 38/38 killed. BUILD-LOG lines and Duckworth's C1 DEFERRED entry follow as a doc-only append.
49 lines
3.1 KiB
JavaScript
49 lines
3.1 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { mkdtempSync,lstatSync,readdirSync,chmodSync,symlinkSync,mkdirSync,rmSync } from 'node:fs';
|
|
import { join } from 'node:path';
|
|
import { tmpdir } from 'node:os';
|
|
import { startTesterSocket, testerSocketPath } from '../src/tester-socket.mjs';
|
|
import { testerRequest } from '../../cli/src/tester-http.mjs';
|
|
async function refused(options, pattern) {
|
|
const result=await startTesterSocket(options).catch(e=>e);
|
|
if(!(result instanceof Error)) await new Promise(r=>result.close(r));
|
|
assert.ok(result instanceof Error,'unsafe tester bind must refuse');assert.match(result.message,pattern);
|
|
}
|
|
test('private tester HTTP serves on 0600 socket in 0700 parent and fixed origin',async t=>{
|
|
const root=mkdtempSync(join(tmpdir(),'g196-w-'));t.after(()=>rmSync(root,{recursive:true,force:true}));
|
|
const web=await startTesterSocket({dataRoot:root,board:'http://127.0.0.1:9'});t.after(()=>new Promise(r=>web.close(r)));
|
|
assert.equal(web.address(),testerSocketPath(root));
|
|
assert.equal(lstatSync(join(root,'console')).mode&0o777,0o700);
|
|
assert.equal(lstatSync(web.address()).mode&0o777,0o600);
|
|
assert.equal((await testerRequest({dataRoot:root,path:'/healthz'})).status,200);
|
|
for(const headers of [{host:'elsewhere.invalid'},{authorization:'Bearer fixture'},{cookie:'__Host-mosaic_session=fixture'},{origin:'http://elsewhere.invalid'}])
|
|
assert.equal((await testerRequest({dataRoot:root,path:'/api/config',headers})).status,403);
|
|
assert.equal((await testerRequest({dataRoot:root,path:'/auth/login'})).status,404);
|
|
assert.equal((await testerRequest({dataRoot:root,path:'/api/settings',method:'POST',body:{}})).status,403);
|
|
await refused({dataRoot:root},/tester-socket-exists/);
|
|
});
|
|
test('private tester refuses symlink, unsafe parent and long path without repairs',async t=>{
|
|
const root=mkdtempSync(join(tmpdir(),'g196-w-'));t.after(()=>rmSync(root,{recursive:true,force:true}));
|
|
mkdirSync(join(root,'console'),{mode:0o755});
|
|
await refused({dataRoot:root},/tester-socket-unsafe/);
|
|
chmodSync(join(root,'console'),0o700);rmSync(join(root,'console'),{recursive:true});
|
|
symlinkSync(root,join(root,'console'));
|
|
await refused({dataRoot:root},/tester-socket-unsafe/);
|
|
await refused({dataRoot:'/tmp/'+ 'a'.repeat(108)},/tester-socket-path/);
|
|
});
|
|
|
|
test('tester cleanup must leave a replacement inode untouched',async t=>{
|
|
const { createServer }=await import('node:http');
|
|
const { writeFileSync,existsSync }=await import('node:fs');
|
|
const { bindTesterSocket }=await import('../src/tester-socket.mjs');
|
|
const root=mkdtempSync(join(tmpdir(),'g196-clean-'));t.after(()=>rmSync(root,{recursive:true,force:true}));
|
|
const path=testerSocketPath(root);
|
|
const server=await bindTesterSocket(createServer(),path);
|
|
assert.deepEqual(readdirSync(join(root,'console')),['tester.sock'],'temporary name is absent after bind');
|
|
rmSync(path);writeFileSync(path,'replacement',{mode:0o600});
|
|
await new Promise(r=>server.close(r));
|
|
assert.equal(existsSync(path),true,'closing the listener must not unlink a replacement inode');
|
|
assert.deepEqual(readdirSync(join(root,'console')),['tester.sock'],'temporary name is absent after close');
|
|
});
|