import { readFileSync } from 'node:fs'; import { dirname, join, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; import { ModuleRegistry } from '../app/kernel/module-registry.mjs'; import { PolicyEngine } from '../app/kernel/policy-engine.mjs'; import { RouteRegistry } from '../app/kernel/route-registry.mjs'; import { loadBuiltInModules } from '../app/modules/catalog.mjs'; const root = resolve(dirname(fileURLToPath(import.meta.url)), '..'); const failures = []; const assert = (condition, message) => { if (!condition) failures.push(message); }; const expectThrow = async (fn, code, message) => { try { await fn(); failures.push(message); } catch (error) { if (error.code !== code) failures.push(`${message} (${error.code || error.message})`); } }; const pkg = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8')); assert(pkg.version === '1.38.0', `package.json ist ${pkg.version}`); const modules = loadBuiltInModules(); assert(modules.length === 14, `Erwartet 14 Module, erhalten ${modules.length}`); const nativeIds = modules.filter(item => item.manifest.status === 'native').map(item => item.manifest.id).sort(); for (const id of ['vendoo.auth','vendoo.security','vendoo.sessions','vendoo.settings','vendoo.themes','vendoo.users']) assert(nativeIds.includes(id), `Natives Modul fehlt: ${id}`); assert(nativeIds.length === 6, `Erwartet 6 native Module, erhalten ${nativeIds.length}`); assert(modules.filter(item => item.manifest.status === 'legacy-bridge').length === 8, 'Es müssen 8 Legacy-Bridges verbleiben'); const registry = new ModuleRegistry(); for (const module of modules) registry.register(module); assert(registry.snapshot().length === 14, 'Modulregistrierung unvollständig'); const cycle = new ModuleRegistry(); cycle.register({ manifest: { schemaVersion:1,id:'vendoo.a',name:'A',version:'1.0.0',type:'feature',status:'native',requires:['vendoo.b'],permissions:[],provides:['a.ready'],consumes:[],owns:['a.state'] } }); cycle.register({ manifest: { schemaVersion:1,id:'vendoo.b',name:'B',version:'1.0.0',type:'feature',status:'native',requires:['vendoo.a'],permissions:[],provides:['b.ready'],consumes:[],owns:['b.state'] } }); await expectThrow(() => cycle.startAll({}), 'MODULE_DEPENDENCY_CYCLE', 'Zyklus wurde nicht blockiert'); const policies = new PolicyEngine(); policies.register('users.self', ({ user }) => Boolean(user)); policies.register('users.manage', ({ user }) => Boolean(user?.admin)); const routes = new RouteRegistry({ policyEngine: policies }); const fake = { get(_path, handler) { this.handler = handler; } }; await expectThrow(() => routes.register(fake, { id:'users.no-policy',method:'GET',path:'/x',owner:'vendoo.users',handler(){} }), 'ROUTE_POLICY_REQUIRED', 'Route ohne Policy wurde akzeptiert'); routes.register(fake, { id:'users.self.read',method:'GET',path:'/x',owner:'vendoo.users',policy:'users.self',csrf:false,handler(_req,res){res.json({ok:true});} }); let status = 0; await fake.handler({ user:null, requestId:'test' }, { headersSent:false,status(code){status=code;return this;},json(){} },()=>{}); assert(status === 403, `Deny-by-default ergab ${status}`); const kernelSource = readFileSync(join(root, 'app/kernel/platform-kernel.mjs'), 'utf8'); for (const marker of [ "policies.register('auth.public'", "policies.register('users.manage'", "policies.register('sessions.self'", "policies.register('settings.manage'", "features.define('identity.native-auth'", "features.define('settings.native-module'", ]) assert(kernelSource.includes(marker), `Kernelvertrag fehlt: ${marker}`); if (failures.length) { console.error(`Platform-Architecture-Gate 1.38.0 fehlgeschlagen (${failures.length}):`); failures.forEach(item => console.error(`- ${item}`)); process.exit(1); } console.log('Platform-Architecture-Gate 1.38.0 erfolgreich: 14 Module, 6 native Module, 8 Legacy-Bridges, Identity-/Settings-Policies und Deny-by-default-Routen geprüft.');