Files
vendoo/tools/verify-production-updater-2.9.mjs
Masterluke77andGitHub 40071f718e Vendoo 1.43.0 – Production Update
Manifestbasierter Production-Updater 3.3, Modulnavigation, optionales Produktbild Studio, Listing-Studio-Aktionsleiste sowie plattformübergreifende Windows-/Linux-Release-Gates.
2026-07-10 13:16:21 +02:00

130 lines
6.1 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { existsSync, readFileSync } from 'node:fs';
import { resolve } from 'node:path';
const root = resolve(import.meta.dirname, '..');
const failures = [];
const required = [
'UPDATE_VENDOO.bat',
'.gitattributes',
'.editorconfig',
'scripts/update-vendoo-gui.ps1',
'scripts/updater/Vendoo.Updater.Preflight.ps1',
'scripts/updater/Vendoo.Updater.UI.ps1',
'scripts/updater/Vendoo.Updater.Host.ps1',
'scripts/updater/Vendoo.Updater.Worker.ps1',
'docs/PRODUCTION_UPDATER_2_9.md',
];
for (const file of required) {
if (!existsSync(resolve(root, file))) failures.push(`Pflichtdatei fehlt: ${file}`);
}
const batPath = resolve(root, 'UPDATE_VENDOO.bat');
const bat = readFileSync(batPath);
const batText = bat.toString('ascii');
if (bat.length < 16) failures.push('UPDATE_VENDOO.bat ist unerwartet leer.');
if (bat[0] === 0xef && bat[1] === 0xbb && bat[2] === 0xbf) failures.push('UPDATE_VENDOO.bat darf keine UTF-8-BOM besitzen.');
for (let i = 0; i < bat.length; i += 1) {
if (bat[i] > 0x7f) {
failures.push(`UPDATE_VENDOO.bat ist nicht reines ASCII (Byte ${i}: 0x${bat[i].toString(16)}).`);
break;
}
}
for (let i = 0; i < bat.length; i += 1) {
if (bat[i] === 0x0a && (i === 0 || bat[i - 1] !== 0x0d)) {
failures.push(`UPDATE_VENDOO.bat enthält LF ohne CR an Byte ${i}.`);
break;
}
if (bat[i] === 0x0d && (i + 1 >= bat.length || bat[i + 1] !== 0x0a)) {
failures.push(`UPDATE_VENDOO.bat enthält CR ohne LF an Byte ${i}.`);
break;
}
}
if (!batText.startsWith('@echo off\r\n')) failures.push('UPDATE_VENDOO.bat startet nicht exakt mit @echo off + CRLF.');
for (const needle of [
'cd /d "%~dp0"',
'%SystemRoot%\\System32\\WindowsPowerShell\\v1.0\\powershell.exe',
'Vendoo.Updater.Preflight.ps1',
'update-vendoo-gui.ps1',
':preflight_failed',
':gui_failed',
'pause',
]) {
if (!batText.includes(needle)) failures.push(`BAT-Startvertrag fehlt: ${needle}`);
}
for (const forbidden of ['chcp ', '-PackageRoot', 'start "', 'ä', 'ö', 'ü', 'ß']) {
if (batText.includes(forbidden)) failures.push(`BAT enthält verbotene Regression: ${forbidden}`);
}
const attrs = readFileSync(resolve(root, '.gitattributes'), 'ascii');
if (!attrs.includes('*.bat text eol=crlf')) failures.push('.gitattributes erzwingt CRLF für BAT nicht.');
if (!attrs.includes('*.cmd text eol=crlf')) failures.push('.gitattributes erzwingt CRLF für CMD nicht.');
const editor = readFileSync(resolve(root, '.editorconfig'), 'ascii');
for (const needle of ['[*.{bat,cmd}]', 'charset = latin1', 'end_of_line = crlf']) {
if (!editor.includes(needle)) failures.push(`.editorconfig fehlt: ${needle}`);
}
for (const rel of required.filter((file) => file.endsWith('.ps1'))) {
const bytes = readFileSync(resolve(root, rel));
if (!(bytes[0] === 0xef && bytes[1] === 0xbb && bytes[2] === 0xbf)) failures.push(`${rel} besitzt keine UTF-8-BOM.`);
const text = bytes.subarray(3).toString('utf8');
if (!text.includes('2.9.0') && rel.includes('updater/Vendoo.Updater.')) failures.push(`${rel} enthält nicht Updater-Version 2.9.0.`);
}
const workerText = readFileSync(resolve(root, 'scripts/updater/Vendoo.Updater.Worker.ps1'), 'utf8');
for (const marker of ['Coolify Auto Deploy', 'Es wird kein Webhook und kein GitHub Secret benötigt.', 'AddMinutes(15)', '/readyz']) {
if (!workerText.includes(marker)) failures.push(`Auto-Deploy-Vertrag fehlt: ${marker}`);
}
const packageJson = JSON.parse(readFileSync(resolve(root, 'package.json'), 'utf8'));
for (const [name, command] of Object.entries(packageJson.scripts || {})) {
if (/\bpython(?:3)?\b|\bpy(?:\.exe)?\s+-/i.test(command)) {
failures.push(`Aktiver npm-Script ${name} enthält weiterhin eine Python-Abhängigkeit: ${command}`);
}
}
for (const requiredNodeGate of [
'tools/verify-identity-db-1.40.0.mjs',
'tools/verify-db-migrations.mjs',
'tools/verify-production-operations-db-1.42.0.mjs',
]) {
if (!existsSync(resolve(root, requiredNodeGate))) failures.push(`Node-only-DB-Gate fehlt: ${requiredNodeGate}`);
}
if (!workerText.includes('StandardOutputEncoding') || !workerText.includes('StandardErrorEncoding')) {
failures.push('Worker setzt die UTF-8-Dekodierung für externe Prozesse nicht explizit.');
}
for (const utf8Marker of ["NPM_CONFIG_COLOR']='false", "FORCE_COLOR']='0", "Text.UTF8Encoding($false)"]) {
if (!workerText.includes(utf8Marker)) failures.push(`UTF-8-/Ausgabevertrag fehlt: ${utf8Marker}`);
}
const cleanupHelper = readFileSync(resolve(root, 'tools/test-runtime-cleanup.mjs'), 'utf8');
for (const marker of ["db.close()", "wal_checkpoint(TRUNCATE)", "maxRetries = 30", "retryDelay = 100"]) {
if (!cleanupHelper.includes(marker)) failures.push(`Zentraler Windows-SQLite-Cleanup-Vertrag fehlt: ${marker}`);
}
for (const requiredCleanupGate of [
'tools/verify-sqlite-cleanup-contract-1.43.0.mjs',
'tools/verify-windows-sqlite-cleanup-regression-1.43.0.mjs',
]) {
if (!existsSync(resolve(root, requiredCleanupGate))) failures.push(`SQLite-Cleanup-Pflichtgate fehlt: ${requiredCleanupGate}`);
}
for (const rel of ['tools/verify-initial-disabled-modules-1.41.2.mjs', 'tools/verify-controlled-invitations-1.42.0.mjs', 'tools/verify-capability-graph-1.41.2.mjs', 'tools/verify-platform-architecture-1.41.2.mjs']) {
const cleanupSource = readFileSync(resolve(root, rel), 'utf8');
for (const marker of ['closeVendooDatabase', 'removeTempDirectory']) {
if (!cleanupSource.includes(marker)) failures.push(`${rel} verwendet den zentralen SQLite-Cleanup nicht: ${marker}`);
}
}
if (!packageJson.scripts?.['verify:sqlite-cleanup'] || !packageJson.scripts['verify:all'].includes('verify:sqlite-cleanup')) {
failures.push('verify:sqlite-cleanup ist nicht verbindlich in verify:all verdrahtet.');
}
for (const forbidden of ['COOLIFY_DEPLOY_WEBHOOK_URL', 'Request-Secret', "'secret','set'", "'workflow','run'"]) {
if (workerText.includes(forbidden)) failures.push(`Verbotener Webhook-/Workflow-Rest im Updater: ${forbidden}`);
}
if (failures.length) {
console.error(`Production-Updater-2.9-Binary-Gate fehlgeschlagen (${failures.length})`);
for (const failure of failures) console.error(`- ${failure}`);
process.exit(1);
}
console.log('OK: Production Updater 2.9 BAT ist reines ASCII, BOM-frei und vollständig CRLF-normalisiert.');