Files
vendoo/tools/verify-module-manager-1.41.1.mjs
T
Masterluke77andGitHub 6f48827f4d Vendoo 1.41.2 – Git Ignore Boundary & Module Tracking Hotfix (#18)
* docs: prepare Vendoo 1.41.2 git-ignore boundary hotfix

* fix: track native source modules with root-anchored runtime ignores
2026-07-09 17:09:00 +02:00

86 lines
6.0 KiB
JavaScript

import { mkdtempSync, readFileSync, rmSync, writeFileSync, mkdirSync } from 'node:fs';
import { join } from 'node:path';
import { tmpdir } from 'node:os';
import { ModuleRegistry } from '../app/kernel/module-registry.mjs';
import { ModuleStateStore } from '../app/core/modules/module-state-store.mjs';
import { ModulePackageStore } from '../app/core/modules/module-package-store.mjs';
import { buildModulePackage } from '../app/core/modules/module-package-contract.mjs';
import { ModuleManagerService } from '../app/modules/module-manager/service.mjs';
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 (code && error.code !== code) failures.push(`${message} (${error.code || error.message})`); }
};
function manifest(id, { requires = [], type = 'feature', status = 'native', owns = [], provides = [], consumes = [] } = {}) {
return { schemaVersion: 1, id, name: id, version: '1.0.0', type, status, description: id, requires, permissions: [], provides, consumes, owns };
}
const temp = mkdtempSync(join(tmpdir(), 'vendoo-modules-140-'));
try {
const stateStore = new ModuleStateStore(join(temp, 'config', 'modules-state.json'));
const packageStore = new ModulePackageStore(join(temp, 'modules'));
const registry = new ModuleRegistry();
registry.register({ manifest: manifest('vendoo.security', { type: 'core', provides: ['security.policies'], owns: ['security.state'] }), lifecycle: { async health(){return {ok:true}} } });
registry.register({ manifest: manifest('vendoo.settings', { type: 'core', requires: ['vendoo.security'], provides: ['settings.configuration'], consumes: ['security.policies'], owns: ['settings.state'] }), lifecycle: { async health(){return {ok:true}} } });
registry.register({ manifest: manifest('vendoo.ai', { requires: ['vendoo.security'], provides: ['ai.images'], consumes: ['security.policies'], owns: ['ai.jobs'] }), lifecycle: { async health(){return {ok:true}} } });
registry.register({ manifest: manifest('vendoo.flux-studio', { requires: ['vendoo.ai'], consumes: ['ai.images'], owns: ['flux.jobs'] }), lifecycle: { async health(){return {ok:true}} } });
const context = { modules: registry, moduleStateStore: stateStore, modulePackageStore: packageStore };
await registry.startAll(context);
const service = new ModuleManagerService({ modules: registry, stateStore, packageStore, context });
await expectThrow(() => service.disable('vendoo.security'), 'MODULE_PROTECTED', 'Geschütztes Kernmodul konnte deaktiviert werden');
await service.disable('vendoo.ai', { cascade: true });
assert(!registry.isEnabled('vendoo.ai') && !registry.isEnabled('vendoo.flux-studio'), 'Abhängige optionale Module wurden nicht gemeinsam deaktiviert');
await service.enable('vendoo.flux-studio');
assert(registry.isEnabled('vendoo.ai') && registry.isEnabled('vendoo.flux-studio'), 'Abhängigkeiten wurden beim Aktivieren nicht automatisch gestartet');
assert(stateStore.isEnabled('vendoo.ai') && stateStore.isEnabled('vendoo.flux-studio'), 'Aktivierungsstatus wurde nicht persistiert');
const externalManifest = manifest('vendoo.ext-demo', { type: 'extension-host', owns: ['ext-demo.state'], provides: ['ext-demo.metadata'] });
const packageData = buildModulePackage({
manifest: externalManifest,
runtime: { mode: 'declarative', entry: null },
files: [{ path: 'README.md', content: '# Demo\n' }, { path: 'module-ui.json', content: '{"label":"Demo"}\n' }],
});
const installed = service.install(Buffer.from(JSON.stringify(packageData), 'utf8'));
assert(installed.id === 'vendoo.ext-demo' && installed.source === 'external', 'Deklaratives Fremdmodul wurde nicht installiert');
await service.enable('vendoo.ext-demo');
assert(registry.isEnabled('vendoo.ext-demo'), 'Deklaratives Fremdmodul wurde nicht aktiviert');
const exported = service.export('vendoo.ext-demo');
assert(exported.length > 100 && JSON.parse(exported.toString('utf8')).manifest.id === 'vendoo.ext-demo', 'Fremdmodul-Export ist ungültig');
await service.disable('vendoo.ext-demo');
await service.remove('vendoo.ext-demo');
assert(!registry.has('vendoo.ext-demo') && !packageStore.get('vendoo.ext-demo'), 'Fremdmodul wurde nicht vollständig entfernt');
const executableDraft = {
manifest: manifest('vendoo.ext-unsafe', { type: 'extension-host', owns: ['ext-unsafe.state'] }),
runtime: { mode: 'declarative', entry: null },
files: [{ path: 'index.mjs', content: 'export default 1;' }],
};
await expectThrow(() => Promise.resolve(buildModulePackage(executableDraft)), 'MODULE_PACKAGE_EXECUTABLE_FORBIDDEN', 'Ausführbarer Code wurde in deklarativem Paket akzeptiert');
const isolated = buildModulePackage({
manifest: manifest('vendoo.ext-isolated', { type: 'extension-host', owns: ['ext-isolated.state'] }),
runtime: { mode: 'isolated', entry: 'index.mjs' },
files: [{ path: 'index.mjs', content: 'export default {};' }],
});
const isolatedInstalled = service.install(Buffer.from(JSON.stringify(isolated), 'utf8'));
assert(isolatedInstalled.package?.activatable === false, 'Unsigniertes ausführbares Modul ist aktivierbar');
await expectThrow(() => service.enable('vendoo.ext-isolated'), 'MODULE_NOT_ACTIVATABLE', 'Unsigniertes ausführbares Modul wurde aktiviert');
const stateFile = JSON.parse(readFileSync(join(temp, 'config', 'modules-state.json'), 'utf8'));
assert(stateFile.schemaVersion === 1 && stateFile.modules['vendoo.ai'], 'Persistente Modulstatusdatei ist unvollständig');
assert(service.catalog().summary.total >= 5, 'Modulkatalog ist unvollständig');
} finally {
rmSync(temp, { recursive: true, force: true });
}
if (failures.length) {
console.error(`Module-Manager-Gate 1.41.1 fehlgeschlagen (${failures.length}):`);
failures.forEach(item => console.error(`- ${item}`));
process.exit(1);
}
console.log('Module-Manager-Gate 1.41.1 erfolgreich: Kernschutz, Abhängigkeitskaskade, Persistenz, .vmod-Import/Export, Entfernung und Quarantäne geprüft.');