import { existsSync, lstatSync, readFileSync, readdirSync } from 'node:fs'; import { dirname, join, relative, sep } from 'node:path'; import { fileURLToPath } from 'node:url'; const root = dirname(dirname(fileURLToPath(import.meta.url))); 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 forbid = (text, marker, label = marker) => { if (text.includes(marker)) failures.push(`Darf nicht enthalten sein: ${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 html = read('public/index.html'); const app = read('public/app.js'); const bootstrap = read('bootstrap.mjs'); const configStore = read('lib/config-store.mjs'); const runtimePaths = read('lib/runtime-paths.mjs'); const setupPs = read('setup.ps1'); const setupGui = read('setup-gui.ps1'); const setupBat = read('setup.bat'); const setupSh = read('setup.sh'); const compose = read('compose.yaml'); const composeVps = read('compose.vps.yaml'); const caddy = read('deploy/Caddyfile'); const env = read('.env.example'); const gitignore = read('.gitignore'); const ci = read('.github/workflows/ci.yml'); const release = read('.github/workflows/release.yml'); const gitDeploy = read('scripts/github-deploy.ps1'); const gitSafety = read('tools/verify-git-safety.mjs'); const gitSafetyRegression = read('tools/verify-git-safety-regression.mjs'); const releaseBuilder = read('tools/build-release.mjs'); const installerShellGate = read('tools/verify-installer-shell.sh'); const gitStaging = read('tools/prepare-git-staging.mjs'); const gitStagingRegression = read('tools/verify-git-staging.mjs'); for (const [label, value] of [ ['package.json', pkg.version], ['package-lock.json', lock.version], ['package-lock root', lock.packages?.['']?.version], ['update-manifest', manifest.version], ]) if (value !== '1.34.2') failures.push(`${label}-Version ist ${value}`); for (const marker of ['content="1.34.2"', 'style.css?v=1.34.2', 'app.js?v=1.34.2']) expect(html, marker, `UI-Build ${marker}`); if (!app.startsWith("const VENDOO_UI_BUILD = '1.34.2';")) failures.push('UI-Build ist nicht 1.34.2'); for (const marker of ['VENDOO_CONFIG_PATH', "await import('./server.mjs')", 'override: true']) expect(bootstrap, marker, `Bootstrap ${marker}`); for (const marker of ['CONFIG_PATH', 'writeRuntimeConfig', 'updateRuntimeConfig', 'mode: 0o600']) expect(configStore, marker, `Konfigurationsspeicher ${marker}`); for (const marker of ['VENDOO_CONFIG_PATH', 'runtime_config: CONFIG_PATH']) expect(runtimePaths, marker, `Runtime-Pfade ${marker}`); for (const marker of ['readRuntimeConfig()', 'writeRuntimeConfig(envContent)', 'updateRuntimeConfig({ LOCAL_IMAGE_TOKEN: token })', 'runtime_config_path: CONFIG_PATH']) expect(read('server.mjs'), marker, `Server-Konfiguration ${marker}`); forbid(read('server.mjs'), "join(__dirname, '.env')", 'direktes Schreiben in schreibgeschütztes App-.env'); for (const marker of ["$Version = '1.34.2'", '?build=1.34.2', "'install-local'", "'install-docker'", 'Configure-VendooConsole', 'Initialize-VendooEnvironment']) expect(setupPs, marker, `Windows-Setup ${marker}`); for (const marker of [ 'Vendoo 1.34.2 – Installation', 'Lokal auf diesem Windows-PC', 'Docker Desktop auf diesem Windows-PC', 'Set-Configuration', 'VENDOO_SETUP_TOKEN', 'Clipboard', 'AI- und Marktplatz-Schlüssel werden später', ]) expect(setupGui, marker, `Windows-GUI ${marker}`); forbid(setupGui, 'PlaceholderText', 'nicht mit Windows PowerShell 5.1 kompatible PlaceholderText-Eigenschaft'); for (const marker of ['setup-gui.ps1', '-STA', 'Parser]::ParseFile']) expect(setupBat, marker, `setup.bat ${marker}`); for (const marker of [ 'Zero-Edit Deployment Assistant', 'configure_wizard', 'VPS / öffentlicher Server mit automatischem HTTPS', 'VENDOO_DOMAIN', 'compose.vps.yaml', 'Caddy übernimmt HTTPS automatisch', 'keine Datei musste manuell bearbeitet werden', 'Aktualisieren (mit Sicherheitsbackup)', 'docker-backup.sh', ]) expect(setupSh, marker, `Linux-Assistent ${marker}`); for (const marker of ['VENDOO_CONFIG_PATH: /app/data/config/vendoo.env', 'vendoo_config:/app/data/config']) expect(compose, marker, `Basis-Compose-Konfiguration ${marker}`); for (const marker of ['caddy:2-alpine', '80:80', '443:443', './deploy/Caddyfile', 'condition: service_healthy', 'read_only: true', 'vendoo_config:/app/data/config']) expect(composeVps, marker, `VPS-Compose ${marker}`); for (const marker of ['{$VENDOO_DOMAIN}', 'reverse_proxy vendoo:8124', 'Strict-Transport-Security']) expect(caddy, marker, `Caddy ${marker}`); for (const marker of ['VENDOO_DOMAIN=', 'VENDOO_SETUP_TOKEN=', 'VENDOO_COOKIE_SECURE=', 'LOCAL_IMAGE_ENABLED=false']) expect(env, marker, `.env.example ${marker}`); for (const marker of ['name: Vendoo CI', 'npm ci', 'npm run verify:git', 'npm run verify:git-regression', 'npm run verify:git-staging', 'npm run verify:deployment', 'npm run verify:config', 'npm run verify:installer-shell', 'docker build --pull', 'compose.vps.yaml']) expect(ci, marker, `CI ${marker}`); for (const marker of ['name: Vendoo Release', 'Release-Tag gegen Paketversion prüfen', 'npm run verify:git-staging', 'npm run verify:config', 'npm run verify:installer-shell', 'release-output', 'gh release upload', 'ghcr.io', 'docker/build-push-action@v6', 'actions/attest@v4', 'attestations: write', 'id-token: write', 'steps.push.outputs.digest', 'linux/amd64,linux/arm64']) expect(release, marker, `Release-Workflow ${marker}`); for (const marker of ['release/1.34.2-initial-import', 'verify-git-safety.mjs', 'prepare-git-staging.mjs', 'RedirectStandardOutput', 'github-deploy-safety-report.txt', 'Zum Fortfahren PUSH eingeben', 'vendoo/pull/5']) expect(gitDeploy, marker, `GitHub-Deploy ${marker}`); for (const marker of ['fileURLToPath', 'kompletten Arbeitsbaum', 'forbiddenPathPatterns', 'secretPatterns', 'Git-Sicherheitsgate erfolgreich']) expect(gitSafety, marker, `Git-Sicherheitsgate ${marker}`); for (const marker of ['unversioniert', '.env.local', 'untracked-secret.txt', 'Git-Sicherheitsgate-Regressionstest erfolgreich']) expect(gitSafetyRegression, marker, `Git-Sicherheitsgate-Regression ${marker}`); for (const marker of ['prepareGitStaging', 'shouldSkipStagingEntry', 'allowedEnvTemplates', 'skippedTopLevelDirs', 'operations', 'Ziel ist kein geklontes Git-Repository']) expect(gitStaging, marker, `Git-Staging ${marker}`); for (const marker of ['.env.local', 'operations/staging/job.json', '.git/marker', 'Git-Staging-Regressionstest erfolgreich']) expect(gitStagingRegression, marker, `Git-Staging-Regression ${marker}`); for (const marker of ['release-output', 'FILE_CHECKSUMS_SHA256.txt', 'createHash', 'shouldSkipStagingEntry']) expect(releaseBuilder, marker, `Release-Builder ${marker}`); for (const marker of ['run_mode docker', 'run_mode nas', 'run_mode vps', 'VENDOO_SETUP_TOKEN', 'stat -c']) expect(installerShellGate, marker, `Shell-Installer-Gate ${marker}`); for (const marker of ['.env', 'runtime/', 'local-ai/comfyui/', '.vendoo-install-mode', 'release-output/']) expect(gitignore, marker, `.gitignore ${marker}`); for (const marker of ['read_only: true', 'no-new-privileges:true', 'cap_drop:', '/readyz', 'host.docker.internal:host-gateway']) expect(compose, marker, `Basis-Compose ${marker}`); for (const required of [ '.github/workflows/ci.yml', '.github/workflows/release.yml', '.github/dependabot.yml', '.github/CODEOWNERS', 'GitHub-Deploy-Assistent.bat', 'scripts/github-deploy.ps1', 'scripts/github-deploy.sh', 'setup-gui.ps1', 'bootstrap.mjs', 'lib/config-store.mjs', 'compose.vps.yaml', 'deploy/Caddyfile', 'tools/verify-git-safety.mjs', 'tools/verify-git-safety-regression.mjs', 'tools/prepare-git-staging.mjs', 'tools/verify-git-staging.mjs', 'tools/verify-installer-shell.sh', 'tools/build-release.mjs', ]) if (!existsSync(join(root, required))) failures.push(`Pflichtdatei fehlt: ${required}`); function walk(dir, out = []) { for (const name of readdirSync(dir)) { if (name === 'node_modules' || name === 'release-output' || name === '.git') continue; const abs = join(dir, name); const rel = relative(root, abs).split(sep).join('/'); const stat = lstatSync(abs); if (stat.isDirectory()) walk(abs, out); else out.push(rel); } return out; } const files = walk(root); const forbiddenRuntime = files.filter(rel => rel === '.env' || rel === '.vendoo-install-mode' || /(^|\/)(runtime|node_modules|uploads|backups|logs)(\/|$)/i.test(rel) || /^db\/.*\.(db|sqlite|sqlite3)(-wal|-shm)?$/i.test(rel) || /^local-ai\/(comfyui|downloads|extract-temp)\//i.test(rel) ); if (forbiddenRuntime.length) failures.push(`Verbotene Laufzeitdaten im Paket: ${forbiddenRuntime.slice(0, 10).join(', ')}`); forbid(read('README.md'), '.env.example` nach `.env` kopieren', 'alte manuelle .env-Anweisung im README'); if (failures.length) { console.error(`Deployment-Gate 1.34.2 fehlgeschlagen (${failures.length}):`); failures.forEach(item => console.error(`- ${item}`)); process.exit(1); } console.log('Deployment-Gate 1.34.2 erfolgreich: gemeinsamer Git-Staging-Builder, vollständige Windows-Diagnose, Arbeitsbaumscan, Regressionstests, Zero-Edit-Installer, CI und Release-Workflow geprüft.');