| 123456789101112131415161718192021222324252627282930313233343536373839 |
- import test from 'node:test';
- import assert from 'node:assert/strict';
- import crypto from 'node:crypto';
- import {EventEmitter} from 'node:events';
- import {PassThrough} from 'node:stream';
- import {createResearchLibraryBridge} from '../src/research-library-bridge.mjs';
- function fixture(){
- const calls=[];
- const stat={uid:1001,gid:1001,mode:0o100600,isFile:()=>true,isSymbolicLink:()=>false};
- const bridge=createResearchLibraryBridge({Parse:{applicationId:'FKieRbIoGt_main',masterKey:'test-secret'},crypto,
- fs:{lstat:async()=>stat,stat:async()=>stat,readFile:async()=>Buffer.from('fixed wrapper')},
- loadDatabase:async()=>({one:async()=>({database:'FKieRbIoGt_master',role:'FKieRbIoGt_admin'}),any:async()=>[]}),
- spawn:(command,args,options)=>{calls.push({command,args,options});const c=new EventEmitter();
- c.stdout=new PassThrough();c.stderr=new PassThrough();c.stdin=new PassThrough();c.kill=()=>{};
- c.stdin.on('finish',()=>{c.stdout.write(JSON.stringify({ok:true,readOnly:true,databaseWrites:0}));c.emit('close',0);});return c;}});
- const headers={'x-parse-application-id':'FKieRbIoGt_main','x-parse-master-key':'test-secret'};
- async function call(params,h=headers){const response={statusCode:200,setHeader(){},status(c){this.statusCode=c;return this;},json(v){this.value=v;return this;}};await bridge({headers:h,body:{params}},response);return response;}
- return{call,calls};
- }
- test('rejects missing or wrong admin key before executing any receiver',async()=>{const{call,calls}=fixture();for(const h of [{},{'x-parse-application-id':'FKieRbIoGt_main','x-parse-master-key':'wrong'}]){const r=await call({action:'probe'},h);assert.equal(r.statusCode,401);}assert.equal(calls.length,0);});
- test('does not accept arbitrary commands, paths or SQL',async()=>{const{call,calls}=fixture();for(const p of [{sql:'DELETE'}, {channel:{schema:'ksf.library-channel.v1',action:'shell'}},{channel:{schema:'ksf.library-channel.v1',action:'read',command:'build',params:{}}},{channel:{schema:'ksf.library-channel.v1',action:'read',command:'get',params:{db:'/etc/passwd'}}}]){assert.equal((await call(p)).value.result.ok,false);}assert.equal(calls.length,0);});
- test('rejects a tampered intake before receiver execution',async()=>{const{call,calls}=fixture();const r=await call({channel:{schema:'ksf.library-channel.v1',action:'intake',params:{archiveSha256:'0'.repeat(64),expectedGeneration:'1'.repeat(64),apply:true,label:'补采'},archiveBase64:Buffer.from('original').toString('base64')}});assert.equal(r.value.result.error.code,'ARCHIVE_HASH_MISMATCH');assert.equal(calls.length,0);});
- test('read probe uses the existing database connection without requesting credentials',async()=>{const{call}=fixture();const r=await call({action:'probe'});assert.equal(r.value.result.identity.database,'FKieRbIoGt_master');assert.equal(r.value.result.databaseWrites,0);});
- test('valid read uses only the fixed receiver and isolated environment',async()=>{const{call,calls}=fixture();const r=await call({channel:{schema:'ksf.library-channel.v1',action:'read',command:'contract',params:{}}});if(r.value.result.error?.code==='RECEIVER_USER_UNAVAILABLE')return;assert.equal(r.value.result.ok,true);assert.equal(calls[0].command,'/opt/ksf-voc-publisher/code/receiver-r3.sh');assert.equal(calls[0].options.shell,false);assert.equal(calls[0].options.env.SSH_ORIGINAL_COMMAND,'ksf-library-v1');assert.equal(calls[0].options.env.KSF_SERVICE_TOKEN,undefined);});
- test('a large source archive validates without recursive-regex stack overflow',async()=>{
- const {call,calls}=fixture(),raw=Buffer.alloc(12867817,37);
- const r=await call({channel:{schema:'ksf.library-channel.v1',action:'intake',params:{archiveSha256:crypto.createHash('sha256').update(raw).digest('hex'),expectedGeneration:'1'.repeat(64),apply:false,label:'历史原件大包'},archiveBase64:raw.toString('base64')}});
- if(r.value.result.error?.code==='RECEIVER_USER_UNAVAILABLE')return;
- assert.equal(r.value.result.ok,true);assert.equal(calls.length,1);
- });
- test('noncanonical base64 and misplaced padding remain rejected before execution',async()=>{
- const {call,calls}=fixture();
- for(const text of ['YQ=','Y=Q=','YQ===','YQ==\n','YR==','====']){
- const raw=Buffer.from(text,'base64');
- const r=await call({channel:{schema:'ksf.library-channel.v1',action:'intake',params:{archiveSha256:crypto.createHash('sha256').update(raw).digest('hex'),expectedGeneration:'1'.repeat(64),apply:false,label:'格式校验'},archiveBase64:text}});
- assert.equal(r.value.result.ok,false);
- }
- assert.equal(calls.length,0);
- });
|