feat(mcp): подготовить сервер и доступ к приёмке
This commit is contained in:
commit
bf3d50e1ff
3835 files changed
+537122
No files matched your search
@@ -0,0 +1,35 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import {X509Certificate} from 'node:crypto'
|
||||
import {checkServerIdentity} from 'node:tls'
|
||||
import {sha} from './operator-files.mjs'
|
||||
export const roleKeys=Object.freeze(['runtime','operator','capture','publisher','control'])
|
||||
export const STARTUP_OPTIONS='-c statement_timeout=10000 -c lock_timeout=5000 -c client_encoding=UTF8'
|
||||
export function assertJsDriverEnvironment(environment){assert(!Object.hasOwn(environment,'NODE_PG_FORCE_NATIVE'),'Native pg driver selector refused')}
|
||||
const hex=v=>typeof v==='string'&&/^[a-f0-9]{64}$/.test(v)
|
||||
const exact=(v,keys)=>v&&typeof v==='object'&&!Array.isArray(v)&&Object.keys(v).length===keys.length&&keys.every(k=>Object.hasOwn(v,k))
|
||||
function parsedApproval(value){
|
||||
assert(exact(value,['format','manifestSha256','definitionSha256','catalogSha256','expectedHeadSha256','validityMs','expiresAt']))
|
||||
assert(value.format==='application-writer-publication-approval-v1'&&['manifestSha256','definitionSha256','catalogSha256'].every(k=>hex(value[k]))&&(value.expectedHeadSha256===null||hex(value.expectedHeadSha256)))
|
||||
assert(Number.isSafeInteger(value.validityMs)&&value.validityMs>0&&value.validityMs<=86400000&&Number.isSafeInteger(value.expiresAt)&&value.expiresAt>0)
|
||||
return structuredClone(value)
|
||||
}
|
||||
export function approval(value){
|
||||
const pinned=parsedApproval(value);assert(pinned.expiresAt>Date.now());return pinned
|
||||
}
|
||||
// Pinned historical inspection data only; never publication authorization.
|
||||
export function reconciliationApproval(value){return parsedApproval(value)}
|
||||
export function poolOptions(transport,request,ca){
|
||||
assert(exact(transport,['host','port','user','password','database']))
|
||||
assert(typeof transport.host==='string'&&transport.host===request.tls.serverName&&Number.isSafeInteger(transport.port)&&transport.port>0&&transport.port<=65535&&transport.user===request.roles.publisher.name&&typeof transport.password==='string'&&transport.password.length>0&&transport.password.length<=4096&&transport.database===request.source.databaseName)
|
||||
assert(sha(ca)===request.tls.caSha256);new X509Certificate(ca)
|
||||
return {host:transport.host,port:transport.port,user:transport.user,password:transport.password,database:transport.database,max:1,connectionTimeoutMillis:5000,idleTimeoutMillis:5000,statement_timeout:10000,lock_timeout:5000,options:STARTUP_OPTIONS,application_name:'mmapp-writer-publisher',client_encoding:'UTF8',
|
||||
ssl:{ca,servername:request.tls.serverName,rejectUnauthorized:true,checkServerIdentity(host,cert){
|
||||
const failed=checkServerIdentity(request.tls.serverName,cert);if(failed)return failed
|
||||
try{if(host!==request.tls.serverName||sha(new X509Certificate(cert.raw).publicKey.export({format:'der',type:'spki'}))!==request.tls.spkiSha256)return Error('Publisher TLS SPKI refused')}catch{return Error('Publisher TLS certificate refused')}
|
||||
}}}
|
||||
}
|
||||
export function assertPublicationApproval(current,catalogue,structure,pinned,manifestSha256){
|
||||
assert(pinned.expiresAt>Date.now()&&pinned.manifestSha256===manifestSha256&&pinned.definitionSha256===catalogue.definitionSha256)
|
||||
assert(sha(JSON.stringify({base:catalogue.catalogSha256,security:structure.sha256}))===pinned.catalogSha256)
|
||||
assert((current?.headSha256??null)===pinned.expectedHeadSha256)
|
||||
}
|
||||
Reference in new issue
Block a user