Files
vendoo/tools/verify-release-1.31.0.mjs
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

82 lines
5.3 KiB
JavaScript

import { readFileSync, readdirSync, statSync } from 'fs';
import { join, extname } from 'path';
const root = new URL('..', import.meta.url).pathname;
const read = rel => readFileSync(join(root, rel), 'utf8');
const failures = [];
const expect = (text, marker, label = marker) => { if (!text.includes(marker)) failures.push(`Fehlt: ${label}`); };
const pkg = JSON.parse(read('package.json'));
const lock = JSON.parse(read('package-lock.json'));
const manifest = JSON.parse(read('update-manifest.json'));
const server = read('server.mjs');
const auth = read('lib/auth.mjs');
const security = read('lib/security.mjs');
const db = read('lib/db.mjs');
const html = read('public/index.html');
const app = read('public/app.js');
const login = read('public/login.html');
const css = read('public/style.css');
const env = read('.env.example');
const schema = read('db/schema.sql');
if (pkg.version !== '1.31.0') failures.push(`package.json-Version ist ${pkg.version}`);
if (lock.version !== '1.31.0' || lock.packages?.['']?.version !== '1.31.0') failures.push('package-lock-Version ist nicht 1.31.0');
if (manifest.version !== '1.31.0') failures.push('Update-Manifest ist nicht 1.31.0');
for (const marker of ['content="1.31.0"', 'style.css?v=1.31.0', 'app.js?v=1.31.0']) expect(html, marker, `Build-Marker ${marker}`);
if (!app.startsWith("const VENDOO_UI_BUILD = '1.31.0';")) failures.push('UI-Build ist nicht 1.31.0');
expect(server, "version: '1.31.0'", 'Health-Version 1.31.0');
expect(server, "VENDOO_BIND_HOST || '127.0.0.1'", 'localhost als Standard-Bind-Adresse');
expect(server, 'apiPermissionGuard', 'serverseitige Berechtigungsprüfung');
expect(server, 'apiRateLimit', 'API-Rate-Limit');
expect(server, "requirePermission('settings.manage')", 'OAuth-Einstellungen geschützt');
expect(server, 'X-Vendoo-Request-ID', 'Request-ID');
expect(server, 'https://cdn.jsdelivr.net', 'CSP-Freigabe für vorhandene UI-CDN-Assets');
for (const role of ['admin', 'manager', 'editor', 'publisher', 'viewer']) expect(security, `${role}: {`, `Rolle ${role}`);
for (const permission of ['listings.edit', 'media.delete', 'publishing.manage', 'operations.manage', 'security.manage']) expect(security, `'${permission}'`, `Berechtigung ${permission}`);
for (const marker of ['CREATE TABLE IF NOT EXISTS resource_locks', 'acquireResourceLock', 'renewResourceLock', 'releaseResourceLock', 'multiuser-security-1.31.0']) expect(security, marker);
for (const marker of ['failed_login_count', 'locked_until', 'password_changed_at', 'last_seen_at', 'revoked_at', 'validatePasswordStrength', 'isUserLocked']) expect(auth, marker);
for (const marker of ['created_by', 'updated_by']) { expect(db, marker); expect(schema, marker); }
for (const marker of ['admin-roles-panel', 'admin-security-panel', 'admin-audit-panel']) expect(html, marker);
for (const marker of ['loadRoleMatrix', 'loadSecurityCenter', 'acquireListingLock', 'releaseListingLock', 'applyPermissionUi']) expect(app, marker);
expect(login, 'mindestens 10 Zeichen', 'starke Passwortmeldung');
for (const marker of ['VENDOO_BIND_HOST=', 'VENDOO_ALLOWED_HOSTS=', 'VENDOO_ALLOWED_ORIGINS=', 'VENDOO_SESSION_IDLE_MINUTES=', 'VENDOO_MUTATION_RATE_LIMIT=']) expect(env, marker);
for (const marker of ['role-cards', 'listing-lock-banner', 'security-grid', 'audit-toolbar']) expect(css, marker);
// No active VTO/FASHN implementation and free FLUX workflow remains prompt-only.
const workflow = read('local-ai/workflows/vendoo_flux_schnell_api.json');
if (workflow.includes('LoadImage')) failures.push('Freier FLUX-Workflow enthält LoadImage');
for (const rel of ['server.mjs', 'public/app.js', 'public/index.html']) {
const text = read(rel).toLowerCase();
if (text.includes('fashn') || text.includes('virtual try-on') || text.includes('virtual try on')) failures.push(`${rel} enthält aktive VTO/FASHN-Referenz`);
}
// Basic duplicate HTML id check.
const ids = [...html.matchAll(/\sid="([^"]+)"/g)].map(match => match[1]);
const duplicateIds = ids.filter((id, index) => ids.indexOf(id) !== index);
if (duplicateIds.length) failures.push(`Doppelte HTML-IDs: ${[...new Set(duplicateIds)].join(', ')}`);
// CSS brace balance ignoring strings/comments sufficiently for release gate.
const strippedCss = css.replace(/\/\*[\s\S]*?\*\//g, '').replace(/"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'/g, '');
let balance = 0;
for (const char of strippedCss) { if (char === '{') balance++; else if (char === '}') balance--; if (balance < 0) break; }
if (balance !== 0) failures.push(`CSS-Klammerbilanz ist ${balance}`);
function walk(dir, rel = '') {
const out = [];
for (const name of readdirSync(dir)) {
const path = join(dir, name); const child = join(rel, name);
if (statSync(path).isDirectory()) out.push(...walk(path, child)); else out.push(child);
}
return out;
}
const forbidden = walk(root).filter(rel => /(^|\/)(vendoo\.db|\.env|node_modules|uploads|backups|logs)(\/|$)/i.test(rel) && rel !== '.env.example');
if (forbidden.length) failures.push(`Verbotene Laufzeitdaten im Paket: ${forbidden.slice(0, 8).join(', ')}`);
if (failures.length) {
console.error(`Release-Gate 1.31.0 fehlgeschlagen (${failures.length}):`);
failures.forEach(item => console.error(`- ${item}`));
process.exit(1);
}
console.log(`Release-Gate 1.31.0 erfolgreich: ${ids.length} eindeutige HTML-IDs, Rollen/RBAC, Sitzungen, Locks, Audit und Server-Härtung geprüft.`);