17 lines
6.3 KiB
JavaScript
17 lines
6.3 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import {readFileSync} from 'node:fs';
|
|
import vm from 'node:vm';
|
|
import {DiagnosticsSchema} from '../packages/core/diagnostics.mjs';
|
|
const html=readFileSync(new URL('../apps/server/public/index.html',import.meta.url),'utf8');
|
|
test('every centrally offered agent scope has an accessible structured control',()=>{const source=readFileSync(new URL('../apps/server/public/admin.js',import.meta.url),'utf8'),scopes=vm.runInNewContext(source.match(/const agentScopes=(\[[^;]+\]);/)[1]);for(const scope of scopes)assert.ok(html.includes(`id="agent-scope-${scope}"`),scope);for(const scope of ['inspect','scroll','library:organize-plan','library:organize-apply','history:list','history:go','window:state','window:control'])assert.ok(scopes.includes(scope));});
|
|
test('diagnostic admin roundtrip retains bounded export settings and denies auditors',()=>{const fields=new Map(),get=id=>{if(!fields.has(id))fields.set(id,{value:'',checked:false,disabled:false,addEventListener(){}});return fields.get(id);};let p={diagnostics:DiagnosticsSchema.parse({enabled:true,mode:'debug',endpoint:'https://collector.example',maxQueueSize:123,flushIntervalMs:333,maxRecordAgeMs:4567,exportTimeoutMs:999})};const context=vm.createContext({$:get,fill(){},draft:()=>structuredClone(p),applyOperatorPermissions(){},independentApprovalRequired:true,policy:null,currentPrincipal:null,updateDraftStatus(){}});vm.runInContext(readFileSync(new URL('../apps/server/public/diagnostics-admin.js',import.meta.url),'utf8'),context);context.fill(p);assert.deepEqual(DiagnosticsSchema.parse(context.draft().diagnostics),p.diagnostics);context.applyOperatorPermissions({role:'auditor',permissions:['policy.read']});assert.equal(get('diagnostics-enabled').disabled,true);context.applyOperatorPermissions({role:'operator',permissions:['policy.prepare']});assert.equal(get('diagnostics-enabled').disabled,false);get('diagnostics-enabled').checked=false;assert.equal(DiagnosticsSchema.parse(context.draft().diagnostics).enabled,false);});
|
|
test('SIEM control is administrator-only and writes the loaded revision',async()=>{const fields=new Map(),get=id=>{if(!fields.has(id))fields.set(id,{value:'',checked:false,disabled:false,hidden:false,textContent:'',addEventListener(type,fn){this.listener=fn;}});return fields.get(id);};const calls=[],context=vm.createContext({$:get,applyOperatorPermissions(){},load:async()=>{},task:fn=>fn,currentPrincipal:null,api:async(path,body,method)=>{calls.push({path,body,method});return {enabled:body?.enabled??true,revision:8,format:'ecs',pending:2,failures:0,configured:true};}});vm.runInContext(readFileSync(new URL('../apps/server/public/siem-admin.js',import.meta.url),'utf8'),context);context.currentPrincipal={role:'auditor',permissions:['policy.read']};context.applyOperatorPermissions(context.currentPrincipal);assert.equal(get('siem-controls').hidden,true);assert.equal(calls.length,0);await assert.rejects(get('siem-save').listener(),/Administrator/);context.currentPrincipal={role:'admin',permissions:['policy.read']};context.fillSIEMExport({enabled:true,revision:7,format:'cef'});context.applyOperatorPermissions(context.currentPrincipal);get('siem-enabled').checked=false;await get('siem-save').listener();assert.equal(calls[0].path,'/api/admin/siem');assert.equal(calls[0].method,'PUT');assert.equal(calls[0].body.enabled,false);assert.equal(calls[0].body.expectedRevision,7);});
|
|
|
|
import {FileTransfersSchema} from '../packages/core/file-transfer.mjs';
|
|
test('download scan settings remain explicit and cannot alter upload policy',()=>{const fields=new Map(),get=id=>{if(!fields.has(id))fields.set(id,{checked:false,disabled:false});return fields.get(id);};const policy={fileTransfers:FileTransfersSchema.parse({upload:{blockUnknown:true},download:{}}),security:{yara:{enabled:true,rules:[],scanOfficeMacros:true}}};const context=vm.createContext({$:get,fill(){},draft:()=>structuredClone(policy),applyOperatorPermissions(){},independentApprovalRequired:true,policy:null,currentPrincipal:null});vm.runInContext(readFileSync(new URL('../apps/server/public/download-scan-admin.js',import.meta.url),'utf8'),context);context.fill(policy);assert.equal(get('download-document-dlp').checked,true);get('download-document-dlp').checked=false;get('yara-office-macros').checked=false;const updated=context.draft();assert.equal(FileTransfersSchema.parse(updated.fileTransfers).download.requireDocumentDlp,false);assert.deepEqual(updated.fileTransfers.upload,policy.fileTransfers.upload);assert.equal(updated.security.yara.scanOfficeMacros,false);context.applyOperatorPermissions({role:'auditor',permissions:['policy.read']});assert.equal(get('yara-office-macros').disabled,true);});
|
|
|
|
test('new history and window capability controls require explicit opt-in and explain limits',()=>{for(const scope of ['history:list','history:go','window:state','window:control']){const tag=html.match(new RegExp(`<input[^>]*id="agent-scope-${scope}"[^>]*>`))[0];assert.equal(/\bchecked\b/.test(tag),false);}assert.ok(html.includes('History read and history navigation are separate capabilities'));assert.ok(html.includes('never grants OS or administrator access'));const editor=readFileSync(new URL('../apps/server/public/agent-grants-admin.js',import.meta.url),'utf8');assert.ok(editor.includes('enabled:false'));assert.ok(editor.includes('scopes:[]'));assert.ok(editor.includes('check.disabled=!agentGrantsEditable'));});
|
|
|
|
test('vault agent capabilities start unchecked and describe human-unlocked exact-origin access',()=>{const source=readFileSync(new URL('../apps/server/public/admin.js',import.meta.url),'utf8'),scopes=vm.runInNewContext(source.match(/const agentScopes=(\[[^;]+\]);/)[1]);for(const scope of ['vault:status','vault:list','vault:fill']){assert.ok(scopes.includes(scope));const tag=html.match(new RegExp(`<input[^>]*id="agent-scope-${scope}"[^>]*>`))[0];assert.equal(/\bchecked\b/.test(tag),false);}for(const text of ['A person must unlock the local vault','agents cannot unlock it or export passwords',"credential's exact origin"])assert.ok(html.includes(text));const editor=readFileSync(new URL('../apps/server/public/agent-grants-admin.js',import.meta.url),'utf8');for(const text of ['human unlock','Agents cannot unlock the vault or export passwords'])assert.ok(editor.includes(text));for(const unsupported of ['vault:unlock','vault:export','vault:mutate'])assert.ok(!scopes.includes(unsupported));});
|