* docs: prepare Vendoo 1.41.2 git-ignore boundary hotfix * fix: track native source modules with root-anchored runtime ignores
86 lines
6.0 KiB
JavaScript
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.2 fehlgeschlagen (${failures.length}):`);
|
|
failures.forEach(item => console.error(`- ${item}`));
|
|
process.exit(1);
|
|
}
|
|
console.log('Module-Manager-Gate 1.41.2 erfolgreich: Kernschutz, Abhängigkeitskaskade, Persistenz, .vmod-Import/Export, Entfernung und Quarantäne geprüft.');
|