Files
MikrotikManager/backend/scripts/acceptance/gre-native-identity-sql.mjs
T

27 lines
5.3 KiB
JavaScript

import assert from 'node:assert/strict'
import fs from 'node:fs'
import {createServer} from 'node:http'
import {randomBytes} from 'node:crypto'
const database=process.env.MMAPP_OWN_SQL_DB,url=new URL(process.env.DATABASE_URL)
assert(/^mm_accept_166_\d+$/.test(database??''));assert.equal(url.pathname,'/'+database);assert.equal(url.username,database)
process.env.AUTH_REQUIRED='true';process.env.AUTH_JWT_SECRET=randomBytes(32).toString('hex');process.env.AUTH_ISSUER='https://own221.invalid';process.env.AUTH_PORTAL_URL='https://own221.invalid'
const {pool,closePool}=await import('/app/backend/dist/db/index.js'),{initDatabase}=await import('/app/backend/dist/db/bootstrap.js'),{collectGreBgpSnapshotOnce}=await import('/app/backend/dist/services/gre-bgp-snapshot-collector.js'),{buildApp}=await import('/app/backend/dist/index.js')
assert.equal((await pool.query('SELECT current_database() AS name')).rows[0].name,database);assert(Object.values((await pool.query('SELECT rolsuper,rolcreatedb,rolcreaterole,rolbypassrls FROM pg_roles WHERE rolname=current_user')).rows[0]).every(v=>v===false))
const baseline=process.env.MMAPP_BASELINE==='true',cases=[];let app,nativeCalls=0,nativeWrites=0,disabledCalls=0,variant='valid'
const fixture=label=>createServer((req,res)=>{nativeCalls++;if(label==='disabled')disabledCalls++;if(req.method!=='GET')nativeWrites++;res.setHeader('content-type','application/json');const gre=req.url==='/rest/interface/gre',bgp=req.url==='/rest/routing/bgp/session',normal={'.id':'*A',name:'own221-GRE «тест» / peer',disabled:'false',running:'true'},kinds={valid:[normal],empty:[],'missing-id':[{name:normal.name,disabled:'false',running:'true'}],'missing-name':[{'.id':'*A',disabled:'false',running:'true'}],'blank-id':[{...normal,'.id':''}],'blank-name':[{...normal,name:' '}],'whitespace-id':[{...normal,'.id':' *A'}],'number-field':[{...normal,mtu:1400}],'duplicate-id':[normal,{...normal,name:'other-GRE'}],'duplicate-name':[normal,{...normal,'.id':'*B'}],'trimmed-name-collision':[normal,{...normal,'.id':'*B',name:' '+normal.name+' '}]},rows=gre?(label==='second'?kinds[variant]:[normal]):bgp?[{'.id':'*1',name:'own221-peer',established:'true','remote.as':'65221','local.as':'65222'}]:[];res.end(JSON.stringify(rows))})
const natives=['first','second','disabled'].map(fixture);for(const n of natives)await new Promise(r=>n.listen(0,'127.0.0.1',r))
const report={date:'2026-10-14',block:'12.5.221',baseline,database,cases,scope:'Actual compiled Native GRE identity and actual API/config/snapshot paths, owned SQL/native HTTP fixture; signed reader/authenticated GRE API',passed:false}
try{
await initDatabase();const ids=[];for(let i=0;i<natives.length;i++)ids.push(Number((await pool.query("INSERT INTO servers(name,host,port,use_ssl,enabled,username,password,type) VALUES($1,'127.0.0.1',$2,false,$3,'fixture','fixture',$4) RETURNING id",['own221-'+i,natives[i].address().port,i<2,i===2?'home-router':'exit-node'])).rows[0].id))
app=await buildApp({logger:false,startScheduler:false});await app.ready();const token=app.jwt.sign({sub:'own221-reader',apps:['mm'],permissions:['mm:network:read'],iss:process.env.AUTH_ISSUER},{expiresIn:'5m'}),headers={authorization:'Bearer '+token};
for(variant of ['valid','empty','missing-id','missing-name','blank-id','blank-name','whitespace-id','number-field','duplicate-id','duplicate-name','trimmed-name-collision']){
const bad=!['valid','empty'].includes(variant),oldSourceAccepts=['valid','empty','whitespace-id','duplicate-name','trimmed-name-collision'].includes(variant),sourceUnknown=baseline?!oldSourceAccepts:bad,oldCount=['duplicate-id','duplicate-name','trimmed-name-collision'].includes(variant)?3:variant==='empty'?1:2,snapshot=await collectGreBgpSnapshotOnce()
assert.equal(snapshot.greWritten,sourceUnknown?0:oldCount);assert.equal(snapshot.bgpWritten,2);assert.equal(snapshot.errors.length,sourceUnknown?1:0);assert.equal(snapshot.fatalError,undefined)
cases.push({phase:variant,endpoint:'compiled collector',greWritten:snapshot.greWritten,bgpWritten:2,sourceErrors:snapshot.errors.length})
const before=Number((await pool.query("SELECT count(*) AS count FROM config_revisions WHERE server_id=$1 AND section='gre'",[ids[1]])).rows[0].count),api=await app.inject({method:'GET',url:'/api/gre/tunnels',headers}),body=api.json();assert.equal(api.statusCode,200);assert.equal(body.failures.length,bad&&!baseline?1:0);assert.equal(body.tunnels.length,bad&&!baseline?1:oldCount);const after=Number((await pool.query("SELECT count(*) AS count FROM config_revisions WHERE server_id=$1 AND section='gre'",[ids[1]])).rows[0].count);if(bad&&!baseline)assert.equal(after,before)
cases.push({phase:variant,endpoint:'signed GRE catalog',status:200,tunnels:body.tunnels.length,failures:body.failures.length,observedRevisionsAdded:after-before})
}
assert.equal(nativeWrites,0);assert.equal(disabledCalls,0);report.passed=true
}catch(e){report.errorName=e.name;fs.writeFileSync('/app/backend/acceptance/gre221-private.log',String(e.stack??e),{mode:0o600})}finally{if(app)await app.close();for(const n of natives){n.closeAllConnections();await new Promise(r=>n.close(r))}await closePool();report.nativeWrites=nativeWrites;report.disabledHomeRouterCalls=disabledCalls;fs.writeFileSync('/app/backend/acceptance/gre221-'+(baseline?'baseline':'fixed')+'.json',JSON.stringify(report,null,2));console.log(JSON.stringify(report))}if(!report.passed)process.exitCode=1