#!/usr/bin/env node import fs from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; const REQUIRED_FILES = [ "Dockerfile", "docker-compose.yml", "docker-compose.staging.yml", ".dockerignore", "start.sh", "package.json", "pnpm-workspace.yaml", "apps/web/package.json", "apps/api/package.json", "apps/hocuspocus/Dockerfile", "apps/portal-domain-controller/package.json", "apps/worker/package.json", "packages/db/package.json", "packages/db/scripts/build-runtime-artifacts.mjs", "runtime/api/package.json", "runtime/hocuspocus/package.json", "runtime/mcp/package.json", "runtime/portal-domain-controller/package.json", "runtime/web/package.json", "runtime/worker/package.json", "scripts/ci/deploy-production-closures.sh", ]; const ROOT_REQUIRED_SCRIPTS = ["build", "lint", "test", "typecheck"]; const API_REQUIRED_SCRIPTS = ["build"]; const REQUIRED_WORKER_GROUPS = [ { service: "worker-general", group: "general", healthPort: "9101", adminPort: "9201", concurrencyEnv: "WORKER_CONCURRENCY_GENERAL" }, { service: "worker-mail", group: "mail", healthPort: "9102", adminPort: "9202", concurrencyEnv: "WORKER_CONCURRENCY_MAIL" }, { service: "worker-import", group: "import", healthPort: "9103", adminPort: "9203", concurrencyEnv: "WORKER_CONCURRENCY_IMPORT" }, { service: "worker-webhook", group: "webhook", healthPort: "9104", adminPort: "9204", concurrencyEnv: "WORKER_CONCURRENCY_WEBHOOK" }, { service: "worker-plugin", group: "plugin", healthPort: "9105", adminPort: "9205", concurrencyEnv: "WORKER_CONCURRENCY_PLUGIN" }, ]; const REQUIRED_WORKER_GENERAL_WORKFLOW_ENV = [ "APP_URL", "OUTBOX_DISPATCHER_ENABLED", "OUTBOX_DISPATCHER_REQUIRED", "WORKFLOW_TRIGGER_EXECUTOR_MODE", "WORKFLOW_TRIGGER_EXECUTOR_URL", "API_ACCESS_TOKEN", "WORKFLOW_TRIGGER_EXECUTOR_TIMEOUT_MS", "WORKFLOW_TRIGGER_OUTBOX_ENABLED", "WORKFLOW_TRIGGER_OUTBOX_CONCURRENCY", "WORKFLOW_TRIGGER_OUTBOX_REQUIRED", ]; const REQUIRED_STAGING_WORKER_GENERAL_ENV = [ ["OUTBOX_DISPATCHER_ENABLED", "true"], ["OUTBOX_DISPATCHER_REQUIRED", "true"], ["WORKFLOW_TRIGGER_OUTBOX_ENABLED", "true"], ["WORKFLOW_TRIGGER_OUTBOX_REQUIRED", "true"], ]; const REQUIRED_WORKER_GENERAL_BILLING_ENV = [ "LAGO_API_URL", "LAGO_API_KEY", "LAGO_TIMEOUT_MS", "MOLLIE_API_KEY", "MOLLIE_PROFILE_ID", "MOLLIE_TIMEOUT_MS", "BILLING_MOLLIE_WEBHOOK_URL", ]; const REQUIRED_WORKER_GENERAL_SEARCH_ENV = ["MEILI_URL", "MEILI_API_KEY"]; const REQUIRED_WORKER_SCAN_ENV = [ "STORAGE_ENDPOINT", "STORAGE_REGION", "STORAGE_BUCKET", "STORAGE_ACCESS_KEY_ID", "STORAGE_SECRET_ACCESS_KEY", "STORAGE_SESSION_TOKEN", "STORAGE_FORCE_PATH_STYLE", "STORAGE_QUARANTINE_BUCKET", ]; const REQUIRED_WEBHOOK_VAPID_ENV = ["WEB_PUSH_VAPID_SUBJECT", "WEB_PUSH_VAPID_PUBLIC_KEY", "WEB_PUSH_VAPID_PRIVATE_KEY"]; const REQUIRED_STAGING_WEB_AIRCALL_ENV = ["AIRCALL_CLIENT_ID", "AIRCALL_CLIENT_SECRET", "AIRCALL_REDIRECT_URI", "AIRCALL_WEBHOOK_URL"]; const REQUIRED_STAGING_WEB_GDPR_EXPORT_STORAGE_ENV = [ "STORAGE_ENDPOINT", "STORAGE_REGION", "STORAGE_BUCKET", "STORAGE_ACCESS_KEY_ID", "STORAGE_SECRET_ACCESS_KEY", "GDPR_EXPORT_SSE_C_KEY_BASE64", ]; const OPTIONAL_STAGING_WEB_GDPR_EXPORT_STORAGE_ENV = ["STORAGE_SESSION_TOKEN", "STORAGE_FORCE_PATH_STYLE"]; const STAGING_STORAGE_CREDENTIAL_SOURCES = Object.freeze({ web: Object.freeze({ STORAGE_ACCESS_KEY_ID: "WEB_STORAGE_ACCESS_KEY_ID", STORAGE_SECRET_ACCESS_KEY: "WEB_STORAGE_SECRET_ACCESS_KEY", STORAGE_SESSION_TOKEN: "WEB_STORAGE_SESSION_TOKEN", }), "worker-general": Object.freeze({ STORAGE_ACCESS_KEY_ID: "WORKER_GENERAL_STORAGE_ACCESS_KEY_ID", STORAGE_SECRET_ACCESS_KEY: "WORKER_GENERAL_STORAGE_SECRET_ACCESS_KEY", STORAGE_SESSION_TOKEN: "WORKER_GENERAL_STORAGE_SESSION_TOKEN", }), "worker-import": Object.freeze({ STORAGE_ACCESS_KEY_ID: "WORKER_IMPORT_STORAGE_ACCESS_KEY_ID", STORAGE_SECRET_ACCESS_KEY: "WORKER_IMPORT_STORAGE_SECRET_ACCESS_KEY", STORAGE_SESSION_TOKEN: "WORKER_IMPORT_STORAGE_SESSION_TOKEN", }), }); const REQUIRED_WORKER_IMPORT_DEDICATED_GATE_ENV = [ ["IMPORT_QUEUE_ENABLED", "false"], ["IMPORT_QUEUE_RUNTIME_READY", "false"], ["PORTAL_GDPR_EXPORT_QUEUE_ENABLED", "true"], ]; const SCAN_WORKER_SERVICE = "worker-general"; const NON_SCAN_WORKER_SERVICES = REQUIRED_WORKER_GROUPS.map((worker) => worker.service).filter((service) => service !== SCAN_WORKER_SERVICE); function stagingStorageSource(service, envName) { return STAGING_STORAGE_CREDENTIAL_SOURCES[service]?.[envName] ?? envName; } const WEB_TARGET_PATTERN = /^FROM\s+base\s+AS\s+web\s*$/im; const API_TARGET_PATTERN = /^FROM\s+base\s+AS\s+api\s*$/im; const MCP_TARGET_PATTERN = /^FROM\s+base\s+AS\s+mcp\s*$/im; const WORKER_TARGET_PATTERN = /^FROM\s+base\s+AS\s+worker\s*$/im; const WEB_BUILD_TARGET_PATTERN = /^FROM\s+build\s+AS\s+web-build\s*$/im; const API_BUILD_TARGET_PATTERN = /^FROM\s+build\s+AS\s+api-build\s*$/im; const MCP_BUILD_TARGET_PATTERN = /^FROM\s+build\s+AS\s+mcp-build\s*$/im; const PORTAL_CONTROLLER_BUILD_TARGET_PATTERN = /^FROM\s+build\s+AS\s+portal-domain-controller-build\s*$/im; const WORKER_BUILD_TARGET_PATTERN = /^FROM\s+build\s+AS\s+worker-build\s*$/im; const BUILD_STAGE_FORBIDDEN_APP_BUILD_PATTERN = /\bpnpm\s+(?:run\s+)?build\b|\bpnpm\s+--filter\s+@hivegrid\/web\s+build\b|\bpnpm\s+--filter\s+@hivegrid\/api\s+build\b|\bpnpm\s+--filter\s+@hivegrid\/worker\s+build\b/; const SHARED_BUILD_FORBIDDEN_VITE_PATTERN = /\b(?:ARG|ENV)\s+VITE_[A-Z0-9_]+/; const WEB_BUILD_COMMAND_PATTERN = /^RUN\s+node\s+scripts\/build-web-surfaces\.mjs\s+&&\s+node\s+scripts\/build-web-server\.mjs\s*$/im; const WEB_HOCUSPOCUS_BUILD_ARG_PATTERN = /^ARG\s+VITE_HOCUSPOCUS_URL=""\s*$/im; const WEB_HOCUSPOCUS_BUILD_ENV_PATTERN = /^ENV\s+VITE_HOCUSPOCUS_URL="\$\{VITE_HOCUSPOCUS_URL\}"\s*$/im; const API_BUILD_COMMAND_PATTERN = /^RUN\s+node\s+apps\/api\/scripts\/build\.mjs\s*$/im; const MCP_BUILD_COMMAND_PATTERN = /^RUN\s+node\s+apps\/mcp\/scripts\/build\.mjs\s*$/im; const PORTAL_CONTROLLER_BUILD_COMMAND_PATTERN = /^RUN\s+cd\s+apps\/portal-domain-controller\s+&&\s+node\s+scripts\/build\.mjs\s*$/im; const WORKER_BUILD_COMMAND_PATTERN = /^RUN\s+cd\s+apps\/worker\s+&&\s+node\s+scripts\/build\.mjs\s*$/im; const WEB_RUNTIME_ARTIFACTS_TARGET_PATTERN = /^FROM\s+web-build\s+AS\s+web-runtime-artifacts\s*$/im; const API_RUNTIME_ARTIFACTS_TARGET_PATTERN = /^FROM\s+api-build\s+AS\s+api-runtime-artifacts\s*$/im; const WORKER_RUNTIME_ARTIFACTS_TARGET_PATTERN = /^FROM\s+worker-build\s+AS\s+worker-runtime-artifacts\s*$/im; const WEB_RUNTIME_ARTIFACTS_SOURCEMAP_DELETE_PATTERN = /^RUN\s+find\s+\/myapp\/build\s+\/myapp\/apps\/web\/build\s+\/myapp\/apps\/web\/build-portal\s+-type\s+f\s+-name\s+['"]\*\.map['"]\s+-delete\s*$/im; const API_RUNTIME_ARTIFACTS_SOURCEMAP_DELETE_PATTERN = /^RUN\s+find\s+\/myapp\/apps\/api\/dist\s+-type\s+f\s+-name\s+['"]\*\.map['"]\s+-delete\s*$/im; const WORKER_RUNTIME_ARTIFACTS_SOURCEMAP_DELETE_PATTERN = /^RUN\s+find\s+\/myapp\/apps\/worker\/dist\s+-type\s+f\s+-name\s+['"]\*\.map['"]\s+-delete\s*$/im; const RUNTIME_DEPLOY_TARGETS = [ { target: "web", stage: "web-production-deps", packageName: "@hivegrid/runtime-web", helperFunction: "deploy_web", prunePrisma: true }, { target: "api", stage: "api-production-deps", packageName: "@hivegrid/runtime-api", helperFunction: "deploy_api", omitOptional: true, prunePrisma: true, }, { target: "mcp", stage: "mcp-production-deps", packageName: "@hivegrid/runtime-mcp", helperFunction: "deploy_mcp", omitOptional: true, prunePrisma: true, }, { target: "portal-domain-controller", stage: "portal-domain-controller-production-deps", packageName: "@hivegrid/runtime-portal-domain-controller", helperFunction: "deploy_portal_controller", omitOptional: true, prunePrisma: false, }, { target: "worker", stage: "worker-production-deps", packageName: "@hivegrid/runtime-worker", helperFunction: "deploy_worker", prunePrisma: true }, ]; const PRODUCTION_DEPS_HELPER_PATH = "scripts/ci/deploy-production-closures.sh"; const PRODUCTION_DEPS_BUNDLE_TARGET_PATTERN = /^FROM\s+build\s+AS\s+production-deps-bundle\s*$/im; const SERVER_RUNTIME_COPY_PATTERN = /^COPY\s+--from=web-runtime-artifacts\s+\/myapp\/build\/server-runtime\s+\/myapp\/build\/server-runtime\s*$/im; const START_SH_ENTRYPOINT_PATTERN = /^ENTRYPOINT\s+\[\s*["']\.\/start\.sh["']\s*\]\s*$/im; const APP_REVISION_ARG_PATTERN = /\bARG\s+APP_REVISION(?:=unknown)?\b/; const APP_REVISION_ENV_PATTERN = /\bENV\s+APP_REVISION=["']?\$\{APP_REVISION\}["']?/; const APP_REVISION_LABEL_PATTERN = /\bLABEL\s+org\.opencontainers\.image\.revision=["']?\$\{APP_REVISION\}["']?/; const WEB_HEALTHCHECK_PATTERN = /\bHEALTHCHECK[\s\S]*?(?:(?:\bcurl\b|\bnode\s+-e\b)[\s\S]*?127\.0\.0\.1:\$\{PORT\}\/healthz|hostname\s*:\s*["']127\.0\.0\.1["'][\s\S]*?port\s*:\s*process\.env\.PORT[\s\S]*?path\s*:\s*["']\/healthz["'])/; const WEB_HEALTHCHECK_HOST_PATTERN = /headers\s*:\s*\{\s*host\s*:\s*process\.env\.WEB_APP_HOST/; const API_HEALTHCHECK_PATTERN = /\bHEALTHCHECK[\s\S]*?(?:\bcurl\b|\bnode\s+-e\b)[\s\S]*?127\.0\.0\.1:\$\{API_PORT:-\$\{PORT\}\}\/healthz/; const MCP_HEALTHCHECK_PATTERN = /\bHEALTHCHECK[\s\S]*?\bnode\s+-e\b[\s\S]*?127\.0\.0\.1:\$\{MCP_PORT:-\$\{PORT\}\}\/healthz/; const IMAGE_REVISION_FILE_PATTERN = /^RUN\s+printf\s+'%s\\n'\s+"\$APP_REVISION"\s+>\s+\/myapp\/\.image-revision\s*$/im; const RECURSIVE_CHOWN_PATTERN = /\bchown\s+-R\b/; const EXPOSE_8080_PATTERN = /^EXPOSE\s+8080\s*$/im; const API_RUNTIME_PATTERN = /\bnode\b[\s\S]*?(?:\/myapp\/)?apps\/api\/dist\/server\.js\b/; const MCP_RUNTIME_PATTERN = /\bnode\b[\s\S]*?(?:\/myapp\/)?apps\/mcp\/dist\/server\.js\b/; const WORKER_RUNTIME_PATTERN = /\bnode\b[\s\S]*?(?:\/myapp\/)?apps\/worker\/dist\/index\.js\b/; const WORKER_HEALTH_PATTERN = /\bnode\b[\s\S]*?(?:\/myapp\/)?apps\/worker\/dist\/health\.js\b/; const FAST_START_HEALTHCHECK_CADENCE_PATTERN = /\bHEALTHCHECK\s+--interval=30s\b[^\n]*--start-interval=2s\b[^\n]*--retries=3\b/; const DIRECT_PRISMA_GENERATE_PATTERN = /^RUN\s+\.\/node_modules\/\.bin\/prisma\s+generate\s+--config\s+prisma\.config\.ts\s*$/im; const DIRECT_DB_RUNTIME_BUILD_PATTERN = /^RUN\s+node\s+packages\/db\/scripts\/build-runtime-artifacts\.mjs\s*$/im; const DB_RUNTIME_BUILD_SCRIPT_PATH = "packages/db/scripts/build-runtime-artifacts.mjs"; const DB_RUNTIME_ARTIFACTS = [ ["packages/db/src/permissions-seed.server.ts", "packages/db/dist/permissions-seed.server.js"], ["packages/db/src/deploy-permission-catalog-sync.server.ts", "packages/db/dist/deploy-permission-catalog-sync.server.js"], ["prisma/seed.ts", "packages/db/dist/production-seed.server.js"], ["scripts/seed-e2e-readiness.ts", "packages/db/dist/e2e-readiness-seed.server.js"], ]; const FORBIDDEN_DOCKERIGNORE_PATTERNS = [ ["build", "**/build"], ["dist", "**/dist"], ["cache", "**/cache"], ["report", "**/report"], ]; const REQUIRED_DOCKERIGNORE_PATTERNS = ["public/build", "/build", "/apps/*/build", "apps/*/dist", "packages/*/dist"]; const REQUIRED_DOCKERIGNORE_ARTIFACT_PATTERNS = [ "/docs", "/secrets", "/.gitea", "/.github", "/tests", "/e2e", "**/*.test.ts", "**/*.test.tsx", "**/*.test.mjs", "**/*.test.js", "**/*.spec.ts", "/scripts/ci/deploy-buildkitd.toml", "/scripts/ci/verify-deploy-buildkit-config.mjs", "/scripts/verify-gitea-ci-workflow.mjs", "/scripts/verify-gitea-deploy-workflow.mjs", ".cache", "**/.cache", ".eslintcache", "**/.eslintcache", "coverage", "**/coverage", ".nyc_output", "**/.nyc_output", "reports", "**/reports", "playwright-report", "**/playwright-report", "test-results", "**/test-results", "blob-report", "**/blob-report", ]; const API_REQUIRED_COPY_PATTERNS = [ [ "target-specific node_modules", /^COPY\s+--exclude=\*\*\/\*\.map\s+--exclude=\*\*\/\*\.d\.ts\s+--from=api-production-deps\s+\/prod\/api\/node_modules\s+\/myapp\/node_modules\s*$/im, ], ["apps/api/dist", /^COPY\s+--from=api-runtime-artifacts\s+\/myapp\/apps\/api\/dist\s+\/myapp\/apps\/api\/dist\s*$/im], ]; const WORKER_REQUIRED_COPY_PATTERNS = [ [ "target-specific node_modules", /^COPY\s+--exclude=\*\*\/\*\.map\s+--exclude=\*\*\/\*\.d\.ts\s+--from=worker-production-deps\s+\/prod\/worker\/node_modules\s+\/myapp\/node_modules\s*$/im, ], ["apps/worker/dist", /^COPY\s+--from=worker-runtime-artifacts\s+\/myapp\/apps\/worker\/dist\s+\/myapp\/apps\/worker\/dist\s*$/im], ]; const WEB_REQUIRED_COPY_PATTERNS = [ [ "target-specific node_modules", /^COPY\s+--exclude=\*\*\/\*\.map\s+--exclude=\*\*\/\*\.d\.ts\s+--from=web-production-deps\s+\/prod\/web\/node_modules\s+\/myapp\/node_modules\s*$/im, ], ["Core React Router build", /^COPY\s+--from=web-runtime-artifacts\s+\/myapp\/apps\/web\/build\s+\/myapp\/apps\/web\/build\s*$/im], ["Customer Portal React Router build", /^COPY\s+--from=web-runtime-artifacts\s+\/myapp\/apps\/web\/build-portal\s+\/myapp\/apps\/web\/build-portal\s*$/im], ["migrator role verifier", /^COPY\s+--from=build\s+\/myapp\/scripts\/verify-migrator-role\.mjs\s+\/myapp\/scripts\/verify-migrator-role\.mjs\s*$/im], ["Prisma baseline adopter", /^COPY\s+--from=build\s+\/myapp\/scripts\/adopt-prisma-baseline\.mjs\s+\/myapp\/scripts\/adopt-prisma-baseline\.mjs\s*$/im], ["prisma.config.ts", /^COPY\s+--from=build\s+\/myapp\/prisma\.config\.ts\s+\/myapp\/prisma\.config\.ts\s*$/im], ["packages/db production seed artifact", /^COPY\s+--from=build\s+\/myapp\/packages\/db\/dist\s+\/myapp\/packages\/db\/dist\s*$/im], ["prisma", /^COPY\s+--from=build\s+\/myapp\/prisma\s+\/myapp\/prisma\s*$/im], ]; const START_SCRIPT_EXEC_PATTERN = /^exec\s+node\s+build\/server-runtime\/server\.js\s*$/m; const START_SCRIPT_MIGRATE_PATTERN = /^\s*node\s+\/myapp\/node_modules\/prisma\/build\/index\.js\s+migrate\s+deploy\s+--config\s+prisma\.config\.ts\s*$/m; const START_SCRIPT_MIGRATOR_ROLE_VERIFY_PATTERN = /^\s*node\s+\/myapp\/scripts\/verify-migrator-role\.mjs\s*$/m; const START_SCRIPT_BASELINE_ADOPTION_PATTERN = /^\s*node\s+\/myapp\/scripts\/adopt-prisma-baseline\.mjs\s+--adopt\s*$/m; const START_SCRIPT_CURRENT_SCHEMA_VERIFY_PATTERN = /^\s*node\s+\/myapp\/scripts\/adopt-prisma-baseline\.mjs\s+--verify-current-schema\s*$/m; const START_SCRIPT_PERMISSION_CATALOG_SYNC_PATTERN = /^\s*node\s+\/myapp\/packages\/db\/dist\/deploy-permission-catalog-sync\.server\.js\s*$/m; const FULL_WORKSPACE_SOURCE_COPY_PATTERN = /^(?:ADD|COPY)\s+(apps|packages)\s+\1\s*$/im; const FROZEN_FETCH_PATTERN = /^RUN\s+--mount=type=cache,[^\n]*target=\/pnpm\/store[^\n]*\s+\\?\s*\n\s*pnpm\s+fetch\s+--frozen-lockfile\s*$/im; const FROZEN_DEV_INSTALL_PATTERN = /^RUN\s+(?:--mount=type=cache,[^\n]*\s+)?(?:\\\s*\n\s*)?pnpm\s+install\s+--frozen-lockfile\s+--prod=false(?:\s+--offline)?\s*$/im; const PNPM_BUILDKIT_CACHE_PATTERN = /^RUN\s+--mount=type=cache,[^\n]*target=\/pnpm\/store[^\n]*\s+\\?\s*\n\s*pnpm\s+install\b/im; const GENERIC_PRODUCTION_NODE_MODULES_COPY_PATTERN = /^COPY\s+--from=production-deps\s+\/myapp\/node_modules\s+\/myapp\/node_modules\s*$/im; function manifestPath(relativePath) { return relativePath.split(path.sep).join("/"); } function escapeRegExp(value) { return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); } function readJsonFile(rootDir, relativePath) { const absolutePath = path.join(rootDir, relativePath); return JSON.parse(fs.readFileSync(absolutePath, "utf8")); } function hasScript(manifest, scriptName) { return typeof manifest.scripts?.[scriptName] === "string" && manifest.scripts[scriptName].trim().length > 0; } function getComposeServiceBlock(content, serviceName) { const escaped = escapeRegExp(serviceName); return ( content.match(new RegExp(`^ ${escaped}:[^\\n]*\\n([\\s\\S]*?)(?=^ [A-Za-z0-9_-]+:[^\\n]*\\n|^volumes:\\n|^networks:\\n|(?![\\s\\S]))`, "m"))?.[1] ?? "" ); } function listWorkspacePackageManifests(rootDir) { const manifests = []; for (const workspaceRoot of ["apps", "packages", "runtime"]) { const absoluteWorkspaceRoot = path.join(rootDir, workspaceRoot); if (!fs.existsSync(absoluteWorkspaceRoot)) { continue; } for (const entry of fs.readdirSync(absoluteWorkspaceRoot, { withFileTypes: true })) { if (!entry.isDirectory()) { continue; } const relativePath = manifestPath(path.join(workspaceRoot, entry.name, "package.json")); if (fs.existsSync(path.join(rootDir, relativePath))) { manifests.push(relativePath); } } } return manifests.sort(); } export function checkRequiredFiles(rootDir) { const passes = []; const failures = []; for (const relativePath of REQUIRED_FILES) { if (fs.existsSync(path.join(rootDir, relativePath))) { passes.push(`${relativePath}: exists`); } else { failures.push(`${relativePath}: missing required Docker baseline file`); } } return { passes, failures, observations: [] }; } export function checkDockerignoreContract(rootDir) { const relativePath = ".dockerignore"; const passes = []; const failures = []; const content = fs.readFileSync(path.join(rootDir, relativePath), "utf8"); const patterns = content .split(/\r?\n/) .map((line) => line.trim()) .filter((line) => line.length > 0 && !line.startsWith("#")); for (const [sourceName, pattern] of FORBIDDEN_DOCKERIGNORE_PATTERNS) { if (patterns.includes(pattern)) { failures.push(`${relativePath}: must not use broad ${pattern}; it can exclude source directories named ${sourceName}`); } else { passes.push(`${relativePath}: does not exclude all ${sourceName} directories recursively`); } } for (const pattern of REQUIRED_DOCKERIGNORE_PATTERNS) { if (patterns.includes(pattern)) { passes.push(`${relativePath}: ignores generated ${pattern}`); } else { failures.push(`${relativePath}: must ignore generated ${pattern} without broad recursive source exclusions`); } } for (const pattern of REQUIRED_DOCKERIGNORE_ARTIFACT_PATTERNS) { if (patterns.includes(pattern)) { passes.push(`${relativePath}: ignores Docker context artifact ${pattern}`); } else { failures.push(`${relativePath}: must ignore Docker context artifact ${pattern} without broad recursive source exclusions`); } } return { passes, failures, observations: [] }; } export function checkStartScript(rootDir) { const relativePath = "start.sh"; const passes = []; const failures = []; const content = fs.readFileSync(path.join(rootDir, relativePath), "utf8"); if (/^#!\/bin\/sh\s*$/m.test(content)) { passes.push(`${relativePath}: uses POSIX shell shebang`); } else { failures.push(`${relativePath}: must use #!/bin/sh`); } if (START_SCRIPT_EXEC_PATTERN.test(content)) { passes.push(`${relativePath}: execs the production start process for container signal handling`); } else { failures.push(`${relativePath}: must use "exec node build/server-runtime/server.js" so container signals reach the web process without pnpm indirection`); } if (/^set -eu\s*$/m.test(content)) { passes.push(`${relativePath}: fails closed on command errors and unset variables (set -eu)`); } else { failures.push(`${relativePath}: must set -eu so migration and runtime credential mistakes fail closed`); } if ( /if \[ "\$\{1:-\}" = "migrate" \]; then/.test(content) && /DIRECT_URL is required for the one-shot migrator/.test(content) && /DATABASE_URL must not be forwarded to the one-shot migrator/.test(content) && /AUTHENTIK_ADMIN_JIT_DATABASE_URL belongs only to the web runtime/.test(content) && /MIGRATOR_\* aliases must not be forwarded to the one-shot migrator/.test(content) && START_SCRIPT_MIGRATOR_ROLE_VERIFY_PATTERN.test(content) && START_SCRIPT_BASELINE_ADOPTION_PATTERN.test(content) && content.indexOf("node /myapp/scripts/verify-migrator-role.mjs") < content.indexOf("node /myapp/scripts/adopt-prisma-baseline.mjs --adopt") && content.indexOf("node /myapp/scripts/adopt-prisma-baseline.mjs --adopt") < content.indexOf('export DATABASE_URL="$DIRECT_URL"') && /export DATABASE_URL="\$DIRECT_URL"/.test(content) && START_SCRIPT_MIGRATE_PATTERN.test(content) && START_SCRIPT_CURRENT_SCHEMA_VERIFY_PATTERN.test(content) && content.indexOf("node /myapp/node_modules/prisma/build/index.js migrate deploy --config prisma.config.ts") < content.indexOf("node /myapp/scripts/adopt-prisma-baseline.mjs --verify-current-schema") ) { passes.push(`${relativePath}: isolates migrate deploy behind the DIRECT_URL-only one-shot mode`); } else { failures.push( `${relativePath}: must verify the exact non-superuser migrator role and safely adopt the reviewed baseline before running the installed Prisma CLI in a DIRECT_URL-only "migrate" mode without package-manager indirection` ); } const migrateModeStartMarker = 'if [ "${1:-}" = "migrate" ]; then'; const migrateModeEndMarker = " exit 0\nfi"; const permissionCatalogSyncCommand = "node /myapp/packages/db/dist/deploy-permission-catalog-sync.server.js"; const migrateModeStartIndex = content.indexOf(migrateModeStartMarker); const migrateModeEndIndex = migrateModeStartIndex >= 0 ? content.indexOf(migrateModeEndMarker, migrateModeStartIndex) : -1; const migrateModeBlock = migrateModeStartIndex >= 0 && migrateModeEndIndex >= 0 ? content.slice(migrateModeStartIndex, migrateModeEndIndex + migrateModeEndMarker.length) : ""; const migratorRoleProbeIndex = migrateModeBlock.indexOf("node /myapp/scripts/verify-migrator-role.mjs"); const baselineAdoptionIndex = migrateModeBlock.indexOf("node /myapp/scripts/adopt-prisma-baseline.mjs --adopt"); const databaseAliasIndex = migrateModeBlock.indexOf('export DATABASE_URL="$DIRECT_URL"'); const migrateIndex = migrateModeBlock.indexOf("node /myapp/node_modules/prisma/build/index.js migrate deploy --config prisma.config.ts"); const currentSchemaVerifyIndex = migrateModeBlock.indexOf("node /myapp/scripts/adopt-prisma-baseline.mjs --verify-current-schema"); const permissionCatalogSyncIndex = migrateModeBlock.indexOf(permissionCatalogSyncCommand); const migrateModeExitIndex = migrateModeBlock.indexOf(" exit 0"); const permissionCatalogSyncOccurrences = content.split(permissionCatalogSyncCommand).length - 1; if ( permissionCatalogSyncOccurrences === 1 && START_SCRIPT_PERMISSION_CATALOG_SYNC_PATTERN.test(migrateModeBlock) && migratorRoleProbeIndex >= 0 && migratorRoleProbeIndex < baselineAdoptionIndex && baselineAdoptionIndex < databaseAliasIndex && databaseAliasIndex < migrateIndex && migrateIndex < currentSchemaVerifyIndex && currentSchemaVerifyIndex < permissionCatalogSyncIndex && permissionCatalogSyncIndex < migrateModeExitIndex ) { passes.push(`${relativePath}: syncs the permission catalog inside one-shot migrate mode only after successful migrations`); } else { failures.push( `${relativePath}: must run the bundled permission catalog sync exactly once inside one-shot migrate mode after baseline adoption, prisma migrate deploy, and current schema verification` ); } if ( /seed credentials and flags must not be forwarded to the one-shot migrator/.test(content) && !/\bnode packages\/db\/dist\/production-seed\.server\.js\b/.test(content) ) { passes.push(`${relativePath}: keeps seeding outside the non-superuser migration authority`); } else { failures.push(`${relativePath}: one-shot migrator must reject SEED_* and must not execute the cross-tenant production seed`); } if ( /RLS_RUNTIME_MODE=required is mandatory for the web runtime/.test(content) && /DATABASE_RUNTIME_ROLE=hivegrid_app is mandatory for the web runtime/.test(content) && /DIRECT_URL must not be forwarded to the web runtime/.test(content) && /MIGRATOR_\* credentials must not be forwarded to the web runtime/.test(content) && /AUTHENTIK_ADMIN_JIT_DATABASE_URL must use the dedicated hivegrid_authentik_jit login/.test(content) && /MIGRATE_ON_BOOT is forbidden/.test(content) && /SEED_ON_BOOT is forbidden/.test(content) && !/RLS_RUNTIME_MODE=off/.test(content) ) { passes.push(`${relativePath}: rejects privileged credentials and RLS bypasses in the long-lived web runtime`); } else { failures.push(`${relativePath}: web runtime must require hivegrid_app with RLS required and reject direct, migrate, and seed env`); } if ( /forbidden core session, OAuth, billing, ingress, or domain-controller credential in the portal web runtime/.test(content) && /AUTHENTIK_/.test(content) && /OAUTH/.test(content) && /BILLING/.test(content) && /COOLIFY/.test(content) && /SSH/.test(content) && /TRAEFIK/.test(content) && /CLOUDFLARE/.test(content) && /DOMAIN_CONTROLLER/.test(content) ) { passes.push(`${relativePath}: rejects Core and operator credentials inside the portal process itself`); } else { failures.push(`${relativePath}: portal runtime must reject Core session, OAuth, billing, ingress, and domain-controller credentials before Node starts`); } if ( /WEB_RUNTIME_SURFACE must be explicitly set to core, admin, or portal/.test(content) && /HIVEGRID_RUNTIME_SURFACE must match WEB_RUNTIME_SURFACE/.test(content) && /export HIVEGRID_RUNTIME_SURFACE="\$WEB_RUNTIME_SURFACE"/.test(content) ) { passes.push(`${relativePath}: binds the selected runtime to the matching isolated React Router build`); } else { failures.push(`${relativePath}: must validate WEB_RUNTIME_SURFACE and export the matching HIVEGRID_RUNTIME_SURFACE`); } return { passes, failures, observations: [] }; } export function checkDockerComposeWorkerTopology(rootDir) { const passes = []; const failures = []; const composePath = "docker-compose.yml"; const stagingPath = "docker-compose.staging.yml"; const compose = fs.readFileSync(path.join(rootDir, composePath), "utf8"); const staging = fs.readFileSync(path.join(rootDir, stagingPath), "utf8"); for (const [service, port] of [ ["redis", "6379"], ["clamav", "3310"], ]) { const block = getComposeServiceBlock(compose, service); if (block.includes(`127.0.0.1:${port}:${port}`)) { passes.push(`${composePath}: ${service} host port ${port} is loopback-only`); } else { failures.push(`${composePath}: ${service} host port ${port} must bind to 127.0.0.1 or remain unpublished`); } } for (const { service, group, healthPort, adminPort, concurrencyEnv } of REQUIRED_WORKER_GROUPS) { const block = getComposeServiceBlock(compose, service); if (!block) { failures.push(`${composePath}: missing ${service} service for WORKER_QUEUE_GROUP=${group}`); } else if (block.includes(`WORKER_QUEUE_GROUP=${group}`)) { passes.push(`${composePath}: ${service} sets WORKER_QUEUE_GROUP=${group}`); } else { failures.push(`${composePath}: ${service} must set WORKER_QUEUE_GROUP=${group}`); } if (!block) { // Already reported above. } else if (block.includes(concurrencyEnv)) { passes.push(`${composePath}: ${service} exposes ${concurrencyEnv}`); } else { failures.push(`${composePath}: ${service} must expose ${concurrencyEnv}`); } if (!block) { // Already reported above. } else if (block.includes(`WORKER_HEALTH_PORT=${healthPort}`) && /test:\s*\["CMD",\s*"node",\s*"apps\/worker\/dist\/health\.js"\]/.test(block)) { passes.push(`${composePath}: ${service} uses the dependency-free health probe on port ${healthPort}`); } else { failures.push(`${composePath}: ${service} must use WORKER_HEALTH_PORT=${healthPort} and the node apps/worker/dist/health.js probe`); } if (!block) { // Already reported above. } else if (block.includes(`WORKER_ADMIN_PORT=${adminPort}`) && adminPort !== healthPort) { passes.push(`${composePath}: ${service} uses distinct WORKER_ADMIN_PORT=${adminPort}`); } else { failures.push(`${composePath}: ${service} must set WORKER_ADMIN_PORT=${adminPort} distinct from WORKER_HEALTH_PORT=${healthPort}`); } const stagingBlock = getComposeServiceBlock(staging, service); if (!stagingBlock) { failures.push(`${stagingPath}: missing ${service} staging overlay`); continue; } if ( stagingBlock.includes("WORKER_DATABASE_URL") && stagingBlock.includes("DATABASE_RUNTIME_ROLE=hivegrid_worker") && stagingBlock.includes("RLS_RUNTIME_MODE=required") && !stagingBlock.includes("DIRECT_URL=") && !stagingBlock.includes("AUTHENTIK_ADMIN_JIT_DATABASE_URL") && stagingBlock.includes("condition: service_healthy") ) { passes.push(`${stagingPath}: ${service} receives only the RLS-enforced worker database credential`); } else { failures.push(`${stagingPath}: ${service} must use WORKER_DATABASE_URL with hivegrid_worker, RLS required, no DIRECT_URL, and a PgBouncer dependency`); } } for (const service of ["api", "web", "hocuspocus"]) { const block = getComposeServiceBlock(staging, service); const hasExpectedJitCredential = service === "web" ? block.includes("AUTHENTIK_ADMIN_JIT_DATABASE_URL=${AUTHENTIK_ADMIN_JIT_DATABASE_URL:-}") : !block.includes("AUTHENTIK_ADMIN_JIT_DATABASE_URL"); if ( block.includes("APP_DATABASE_URL") && block.includes("DATABASE_RUNTIME_ROLE=hivegrid_app") && block.includes("RLS_RUNTIME_MODE=required") && !block.includes("DIRECT_URL=") && hasExpectedJitCredential ) { passes.push(`${stagingPath}: ${service} receives only its RLS-enforced database capability`); } else { failures.push(`${stagingPath}: ${service} must use hivegrid_app with RLS required while the Authentik JIT credential remains web-only`); } } const migratorBlock = getComposeServiceBlock(staging, "migrator"); if ( migratorBlock.includes('entrypoint: ["./start.sh", "migrate"]') && migratorBlock.includes("DIRECT_URL=${MIGRATOR_DIRECT_URL") && !migratorBlock.includes("DATABASE_URL=") && !migratorBlock.includes("AUTHENTIK_ADMIN_JIT_DATABASE_URL") ) { passes.push(`${stagingPath}: migrator is a DIRECT_URL-only one-shot service`); } else { failures.push(`${stagingPath}: migrator must be a DIRECT_URL-only ./start.sh migrate service`); } if (!staging.includes("RLS_RUNTIME_MODE=off")) { passes.push(`${stagingPath}: contains no RLS runtime bypass`); } else { failures.push(`${stagingPath}: must not set RLS_RUNTIME_MODE=off`); } const generalBlock = getComposeServiceBlock(compose, "worker-general"); const stagingGeneralBlock = getComposeServiceBlock(staging, "worker-general"); for (const envName of REQUIRED_WORKER_GENERAL_WORKFLOW_ENV) { if (generalBlock.includes(`${envName}=`)) { passes.push(`${composePath}: worker-general passes through ${envName}`); } else { failures.push(`${composePath}: worker-general must pass through ${envName} so outbox.workflow is explicitly configured`); } } for (const [envName, expectedValue] of REQUIRED_STAGING_WORKER_GENERAL_ENV) { if (stagingGeneralBlock.includes(`${envName}=${expectedValue}`)) { passes.push(`${stagingPath}: worker-general forces ${envName}=${expectedValue}`); } else { failures.push(`${stagingPath}: worker-general must force ${envName}=${expectedValue} so staging/prod outbox.workflow cannot silently idle`); } } for (const envName of REQUIRED_WORKER_GENERAL_BILLING_ENV) { if (generalBlock.includes(`${envName}=`)) { passes.push(`${composePath}: worker-general passes through ${envName} for billing reconciliation`); } else { failures.push(`${composePath}: worker-general must pass through ${envName} for billing reconciliation`); } if (stagingGeneralBlock.includes(`${envName}=`)) { passes.push(`${stagingPath}: worker-general configures ${envName} for required billing reconciliation`); } else { failures.push(`${stagingPath}: worker-general must configure ${envName} for required billing reconciliation`); } } for (const envName of REQUIRED_WORKER_GENERAL_SEARCH_ENV) { if (generalBlock.includes(`${envName}=\${${envName}:-}`)) { passes.push(`${composePath}: worker-general passes through ${envName} for tenant hard-delete search cleanup`); } else { failures.push(`${composePath}: worker-general must pass through ${envName} for tenant hard-delete search cleanup`); } if (stagingGeneralBlock.includes(`${envName}=\${${envName}:?`)) { passes.push(`${stagingPath}: worker-general requires ${envName} for tenant hard-delete search cleanup`); } else { failures.push(`${stagingPath}: worker-general must require ${envName} for tenant hard-delete search cleanup`); } } if (generalBlock.includes("CLAMAV_HOST=") && generalBlock.includes("CLAMAV_PORT=") && generalBlock.includes("clamav:")) { passes.push(`${composePath}: worker-general owns ClamAV dependency for file scanning`); } else { failures.push(`${composePath}: worker-general must keep CLAMAV_* env and depend on clamav for file scanning`); } if (generalBlock.includes("SCAN_QUEUE_ENABLED=${SCAN_QUEUE_ENABLED:-true}")) { passes.push(`${composePath}: worker-general enables the fail-closed scan queue by default`); } else { failures.push(`${composePath}: worker-general must default SCAN_QUEUE_ENABLED to true`); } for (const envName of REQUIRED_WORKER_SCAN_ENV) { if (generalBlock.includes(`${envName}=`)) { passes.push(`${composePath}: worker-general passes through ${envName} for scan and preview storage`); } else { failures.push(`${composePath}: worker-general must pass through ${envName} for scan and preview storage`); } } if (stagingGeneralBlock.includes("SCAN_QUEUE_ENABLED=true")) { passes.push(`${stagingPath}: worker-general forces SCAN_QUEUE_ENABLED=true`); } else { failures.push(`${stagingPath}: worker-general must force SCAN_QUEUE_ENABLED=true`); } if (generalBlock.includes("EXPORT_RETENTION_QUEUE_ENABLED=${EXPORT_RETENTION_QUEUE_ENABLED:-false}")) { passes.push(`${composePath}: worker-general passes through EXPORT_RETENTION_QUEUE_ENABLED with a fail-closed default`); } else { failures.push(`${composePath}: worker-general must pass through EXPORT_RETENTION_QUEUE_ENABLED with a fail-closed false default`); } if (stagingGeneralBlock.includes("EXPORT_RETENTION_QUEUE_ENABLED=true")) { passes.push(`${stagingPath}: worker-general forces EXPORT_RETENTION_QUEUE_ENABLED=true for GDPR export hard-delete`); } else { failures.push(`${stagingPath}: worker-general must force EXPORT_RETENTION_QUEUE_ENABLED=true for GDPR export hard-delete`); } for (const envName of REQUIRED_STAGING_WEB_GDPR_EXPORT_STORAGE_ENV.filter((name) => name !== "GDPR_EXPORT_SSE_C_KEY_BASE64")) { const sourceName = stagingStorageSource("worker-general", envName); if (stagingGeneralBlock.includes(`${envName}=\${${sourceName}:?`)) { passes.push(`${stagingPath}: worker-general requires ${envName} for GDPR export retention`); } else { failures.push(`${stagingPath}: worker-general must require ${envName} for GDPR export retention`); } } if (stagingGeneralBlock.includes(`STORAGE_SESSION_TOKEN=\${${stagingStorageSource("worker-general", "STORAGE_SESSION_TOKEN")}:-`)) { passes.push(`${stagingPath}: worker-general uses its dedicated optional storage session-token source`); } else { failures.push(`${stagingPath}: worker-general must use its dedicated optional storage session-token source`); } for (const service of NON_SCAN_WORKER_SERVICES) { const block = getComposeServiceBlock(compose, service); if (!block) { continue; } if (!block.includes("depends_on:")) { failures.push(`${composePath}: ${service} must override worker-base depends_on so it does not inherit clamav`); continue; } if (block.includes("clamav:") || block.includes("CLAMAV_HOST=") || block.includes("CLAMAV_PORT=")) { failures.push(`${composePath}: ${service} must not depend on clamav or receive CLAMAV_* scan env`); } else if (block.includes("redis:") && block.includes("condition: service_healthy")) { passes.push(`${composePath}: ${service} depends on redis only and does not wait for ClamAV`); } else { failures.push(`${composePath}: ${service} must depend on redis with condition: service_healthy after overriding worker-base depends_on`); } } const importBlock = getComposeServiceBlock(compose, "worker-import"); const stagingImportBlock = getComposeServiceBlock(staging, "worker-import"); for (const [envName] of REQUIRED_WORKER_IMPORT_DEDICATED_GATE_ENV) { if (importBlock.includes(`${envName}=\${${envName}:-false}`)) { passes.push(`${composePath}: worker-import passes through ${envName}`); } else { failures.push(`${composePath}: worker-import must pass through ${envName} with a fail-closed false default`); } } for (const envName of [...REQUIRED_STAGING_WEB_GDPR_EXPORT_STORAGE_ENV, ...OPTIONAL_STAGING_WEB_GDPR_EXPORT_STORAGE_ENV]) { if (importBlock.includes(`${envName}=\${${envName}:-`)) { passes.push(`${composePath}: worker-import passes through ${envName} for encrypted GDPR exports`); } else { failures.push(`${composePath}: worker-import must pass through ${envName} for encrypted GDPR exports`); } } for (const [envName, expectedValue] of REQUIRED_WORKER_IMPORT_DEDICATED_GATE_ENV) { if (stagingImportBlock.includes(`${envName}=${expectedValue}`)) { passes.push(`${stagingPath}: worker-import forces ${envName}=${expectedValue}`); } else { failures.push(`${stagingPath}: worker-import must force ${envName}=${expectedValue} for dedicated encrypted GDPR exports`); } } for (const envName of REQUIRED_STAGING_WEB_GDPR_EXPORT_STORAGE_ENV) { const sourceName = stagingStorageSource("worker-import", envName); if (stagingImportBlock.includes(`${envName}=\${${sourceName}:?`)) { passes.push(`${stagingPath}: worker-import requires ${envName} for encrypted GDPR exports`); } else { failures.push(`${stagingPath}: worker-import must require ${envName} for encrypted GDPR exports`); } } for (const envName of OPTIONAL_STAGING_WEB_GDPR_EXPORT_STORAGE_ENV) { const sourceName = stagingStorageSource("worker-import", envName); if (stagingImportBlock.includes(`${envName}=\${${sourceName}:-`)) { passes.push(`${stagingPath}: worker-import passes through optional ${envName} for encrypted GDPR exports`); } else { failures.push(`${stagingPath}: worker-import must pass through optional ${envName} for encrypted GDPR exports`); } } const webhookBlock = getComposeServiceBlock(compose, "worker-webhook"); const stagingWebhookBlock = getComposeServiceBlock(staging, "worker-webhook"); const stagingWebBlock = getComposeServiceBlock(staging, "web"); if (stagingWebBlock.includes("REDIS_URL=${REDIS_URL:?")) { passes.push(`${stagingPath}: web requires REDIS_URL for distributed GDPR export download gates`); } else { failures.push(`${stagingPath}: web must require REDIS_URL for distributed GDPR export download gates`); } for (const envName of REQUIRED_WEBHOOK_VAPID_ENV) { const optionalSource = `${envName}=\${${envName}:-}`; const requiredSource = `${envName}=\${${envName}:?`; if (webhookBlock.includes(optionalSource) && stagingWebhookBlock.includes(requiredSource)) { passes.push(`${composePath}: worker-webhook and staging overlay pass through ${envName}`); } else { failures.push(`${composePath}: worker-webhook and staging overlay must pass through ${envName}`); } } const requiredPublicKeySource = "WEB_PUSH_VAPID_PUBLIC_KEY=${WEB_PUSH_VAPID_PUBLIC_KEY:?"; if (stagingWebBlock.includes(requiredPublicKeySource) && stagingWebhookBlock.includes(requiredPublicKeySource)) { passes.push(`${stagingPath}: web and worker-webhook share the VAPID public key source`); } else { failures.push(`${stagingPath}: web must receive WEB_PUSH_VAPID_PUBLIC_KEY from the shared deployment source`); } for (const envName of REQUIRED_STAGING_WEB_AIRCALL_ENV) { if (stagingWebBlock.includes(`${envName}=`)) { passes.push(`${stagingPath}: web passes through ${envName}`); } else { failures.push(`${stagingPath}: web must pass through ${envName} for Aircall OAuth`); } } for (const envName of REQUIRED_STAGING_WEB_GDPR_EXPORT_STORAGE_ENV) { const sourceName = stagingStorageSource("web", envName); if (stagingWebBlock.includes(`${envName}=\${${sourceName}:?`)) { passes.push(`${stagingPath}: web requires ${envName} for encrypted GDPR export downloads`); } else { failures.push(`${stagingPath}: web must require ${envName} for encrypted GDPR export downloads`); } } for (const envName of OPTIONAL_STAGING_WEB_GDPR_EXPORT_STORAGE_ENV) { const sourceName = stagingStorageSource("web", envName); if (stagingWebBlock.includes(`${envName}=\${${sourceName}:-`)) { passes.push(`${stagingPath}: web passes through optional ${envName} for encrypted GDPR export downloads`); } else { failures.push(`${stagingPath}: web must pass through optional ${envName} for encrypted GDPR export downloads`); } } const missingCommandServices = REQUIRED_WORKER_GROUPS.map((worker) => worker.service).filter((service) => !staging.includes(service)); if (missingCommandServices.length === 0) { passes.push(`${stagingPath}: reference compose command includes all worker group services`); } else { failures.push(`${stagingPath}: reference compose command must include ${missingCommandServices.join(", ")}`); } return { passes, failures, observations: [] }; } export function checkRootManifest(rootDir) { const relativePath = "package.json"; const passes = []; const failures = []; const manifest = readJsonFile(rootDir, relativePath); for (const scriptName of ROOT_REQUIRED_SCRIPTS) { if (hasScript(manifest, scriptName)) { passes.push(`${relativePath}: script "${scriptName}" is defined`); } else { failures.push(`${relativePath}: missing required script "${scriptName}"`); } } if (!hasScript(manifest, "start")) { failures.push(`${relativePath}: missing required script "start"`); } else { const startCommand = manifest.scripts.start; if (startCommand === "pnpm --filter @hivegrid/web start") { passes.push(`${relativePath}: production start script delegates to @hivegrid/web`); } else { failures.push(`${relativePath}: script "start" must delegate to @hivegrid/web`); } if (/\btsx\b/.test(startCommand)) { failures.push(`${relativePath}: script "start" must not use tsx for web production runtime`); } else { passes.push(`${relativePath}: production start script does not use tsx`); } } return { passes, failures, observations: [] }; } export function checkDbManifest(rootDir) { const relativePath = "packages/db/package.json"; const passes = []; const failures = []; const manifest = readJsonFile(rootDir, relativePath); const buildCommand = manifest.scripts?.build; const bundleCommand = typeof buildCommand === "string" ? buildCommand .split("&&") .map((command) => command.trim()) .find((command) => command.includes("packages/db/src/deploy-permission-catalog-sync.server.ts")) : undefined; if ( bundleCommand?.includes("--bundle") && bundleCommand.includes("--platform=node") && bundleCommand.includes("--format=esm") && bundleCommand.includes("--alias:@hivegrid/logger=./packages/logger/src/index.ts") && bundleCommand.includes("--outfile=packages/db/dist/deploy-permission-catalog-sync.server.js") ) { passes.push(`${relativePath}: builds the self-contained deploy permission catalog sync artifact`); } else { failures.push( `${relativePath}: build must bundle deploy-permission-catalog-sync.server.ts for Node and inline the workspace logger into dist/deploy-permission-catalog-sync.server.js` ); } return { passes, failures, observations: [] }; } export function checkWebManifest(rootDir) { const relativePath = "apps/web/package.json"; const passes = []; const failures = []; const manifest = readJsonFile(rootDir, relativePath); if (!hasScript(manifest, "start")) { failures.push(`${relativePath}: missing required script "start"`); } else { const startCommand = manifest.scripts.start; if (startCommand === "node ../../build/server-runtime/server.js") { passes.push(`${relativePath}: owns production web server start command`); } else { failures.push(`${relativePath}: script "start" must run node ../../build/server-runtime/server.js`); } if (/\btsx\b/.test(startCommand)) { failures.push(`${relativePath}: script "start" must not use tsx for web production runtime`); } else { passes.push(`${relativePath}: production start script does not use tsx`); } } if (manifest.dependencies?.["@hivegrid/api"]) { failures.push(`${relativePath}: web must not depend on the separately deployed @hivegrid/api app`); } else { passes.push(`${relativePath}: does not depend on the separate API application`); } return { passes, failures, observations: [] }; } export function checkApiManifest(rootDir) { const relativePath = "apps/api/package.json"; const passes = []; const failures = []; const manifest = readJsonFile(rootDir, relativePath); for (const scriptName of API_REQUIRED_SCRIPTS) { if (hasScript(manifest, scriptName)) { passes.push(`${relativePath}: script "${scriptName}" is defined`); } else { failures.push(`${relativePath}: missing required script "${scriptName}"`); } } if (!hasScript(manifest, "start")) { failures.push(`${relativePath}: missing required script "start"`); } else if (/\bnode\b/.test(manifest.scripts.start)) { passes.push(`${relativePath}: production start script uses node`); } else { failures.push(`${relativePath}: script "start" must contain node for production runtime`); } return { passes, failures, observations: [] }; } export function checkWorkerManifest(rootDir) { const relativePath = "apps/worker/package.json"; const passes = []; const failures = []; const manifest = readJsonFile(rootDir, relativePath); const requiredScripts = [ ["start", /\bdist\/index\.js\b/], ["health", /\bdist\/health\.js\b/], ]; for (const [scriptName, distPattern] of requiredScripts) { if (!hasScript(manifest, scriptName)) { failures.push(`${relativePath}: missing required script "${scriptName}"`); continue; } const command = manifest.scripts[scriptName]; if (/\bnode\b/.test(command)) { passes.push(`${relativePath}: script "${scriptName}" uses node`); } else { failures.push(`${relativePath}: script "${scriptName}" must contain node for worker production runtime`); } if (distPattern.test(command)) { passes.push(`${relativePath}: script "${scriptName}" targets ${scriptName === "start" ? "dist/index.js" : "dist/health.js"}`); } else { failures.push(`${relativePath}: script "${scriptName}" must target ${scriptName === "start" ? "dist/index.js" : "dist/health.js"}`); } if (/\btsx\b/.test(command)) { failures.push(`${relativePath}: script "${scriptName}" must not use tsx for worker production runtime`); } else { passes.push(`${relativePath}: script "${scriptName}" does not use tsx`); } } return { passes, failures, observations: [] }; } export function checkDockerfileWebContract(rootDir) { const relativePath = "Dockerfile"; const dockerfile = fs.readFileSync(path.join(rootDir, relativePath), "utf8"); const passes = []; const failures = []; const buildBody = getDockerfileTargetBody(dockerfile, "build"); const webBuildBody = getDockerfileTargetBody(dockerfile, "web-build"); const apiBuildBody = getDockerfileTargetBody(dockerfile, "api-build"); const mcpBuildBody = getDockerfileTargetBody(dockerfile, "mcp-build"); const portalControllerBuildBody = getDockerfileTargetBody(dockerfile, "portal-domain-controller-build"); const workerBuildBody = getDockerfileTargetBody(dockerfile, "worker-build"); const webBody = getDockerfileTargetBody(dockerfile, "web"); const webRuntimeArtifactsBody = getDockerfileTargetBody(dockerfile, "web-runtime-artifacts"); const apiRuntimeArtifactsBody = getDockerfileTargetBody(dockerfile, "api-runtime-artifacts"); const workerRuntimeArtifactsBody = getDockerfileTargetBody(dockerfile, "worker-runtime-artifacts"); const dbRuntimeBuildScriptPath = path.join(rootDir, DB_RUNTIME_BUILD_SCRIPT_PATH); const dbRuntimeBuildSource = fs.existsSync(dbRuntimeBuildScriptPath) ? fs.readFileSync(dbRuntimeBuildScriptPath, "utf8") : ""; if (WEB_TARGET_PATTERN.test(dockerfile)) { passes.push(`${relativePath}: defines named web target from base`); } else { failures.push(`${relativePath}: must define web target with "FROM base AS web"`); } if (webBody && SERVER_RUNTIME_COPY_PATTERN.test(webBody)) { passes.push(`${relativePath}: copies build/server-runtime into web image`); } else { failures.push(`${relativePath}: web target must copy /myapp/build/server-runtime from web-runtime-artifacts stage`); } if (buildBody && !BUILD_STAGE_FORBIDDEN_APP_BUILD_PATTERN.test(buildBody)) { passes.push(`${relativePath}: build target leaves web, api, and worker app builds to split stages`); } else { failures.push(`${relativePath}: build target must not run root/web/api/worker app builds; use web-build, api-build, and worker-build stages`); } if (buildBody && !SHARED_BUILD_FORBIDDEN_VITE_PATTERN.test(buildBody)) { passes.push(`${relativePath}: build target keeps VITE build args out of api/worker cache paths`); } else { failures.push(`${relativePath}: build target must not declare VITE_* ARG/ENV values; keep them in web-build only`); } if ( buildBody && DIRECT_PRISMA_GENERATE_PATTERN.test(buildBody) && !/pnpm\s+(?:--filter\s+@hivegrid\/db\s+)?(?:run\s+)?prisma(?::generate|\s+generate)/u.test(buildBody) ) { passes.push(`${relativePath}: shared build invokes the pinned Prisma CLI directly`); } else { failures.push(`${relativePath}: shared build must invoke ./node_modules/.bin/prisma generate --config prisma.config.ts directly`); } if (buildBody && DIRECT_DB_RUNTIME_BUILD_PATTERN.test(buildBody) && !/pnpm\s+--filter\s+@hivegrid\/db\s+build/u.test(buildBody)) { passes.push(`${relativePath}: shared build invokes the DB runtime artifact builder directly`); } else { failures.push(`${relativePath}: shared build must invoke node ${DB_RUNTIME_BUILD_SCRIPT_PATH} directly`); } for (const [entryPoint, outfile] of DB_RUNTIME_ARTIFACTS) { const artifactPattern = new RegExp(`entryPoints:\\s*\\["${escapeRegExp(entryPoint)}"\\][\\s\\S]{0,500}?outfile:\\s*"${escapeRegExp(outfile)}"`, "u"); if (artifactPattern.test(dbRuntimeBuildSource)) { passes.push(`${DB_RUNTIME_BUILD_SCRIPT_PATH}: builds ${outfile} from ${entryPoint}`); } else { failures.push(`${DB_RUNTIME_BUILD_SCRIPT_PATH}: must build ${outfile} from ${entryPoint}`); } } if ( /import\s+\{\s*build\s*\}\s+from\s+"esbuild"/u.test(dbRuntimeBuildSource) && /await\s+Promise\.all/u.test(dbRuntimeBuildSource) && /packages:\s*"external"/u.test(dbRuntimeBuildSource) && /"@hivegrid\/logger":\s*"\.\/packages\/logger\/src\/index\.ts"/u.test(dbRuntimeBuildSource) && /"~":\s*"\.\/apps\/web\/app"/u.test(dbRuntimeBuildSource) && /createRequire\(import\.meta\.url\)/u.test(dbRuntimeBuildSource) && !/child_process|\bpnpm\b/u.test(dbRuntimeBuildSource) ) { passes.push(`${DB_RUNTIME_BUILD_SCRIPT_PATH}: preserves the four bundled runtime contracts without package-manager subprocesses`); } else { failures.push( `${DB_RUNTIME_BUILD_SCRIPT_PATH}: must use the esbuild API in parallel and preserve external packages, logger/web aliases, and the seed createRequire banner` ); } if (WEB_BUILD_TARGET_PATTERN.test(dockerfile) && webBuildBody && WEB_BUILD_COMMAND_PATTERN.test(webBuildBody)) { passes.push(`${relativePath}: web-build target invokes both direct web build entry points`); } else { failures.push(`${relativePath}: web-build must run node scripts/build-web-surfaces.mjs && node scripts/build-web-server.mjs directly`); } if (webBuildBody && WEB_HOCUSPOCUS_BUILD_ARG_PATTERN.test(webBuildBody) && WEB_HOCUSPOCUS_BUILD_ENV_PATTERN.test(webBuildBody)) { passes.push(`${relativePath}: web-build target forwards VITE_HOCUSPOCUS_URL into the Vite and CSP builds`); } else { failures.push(`${relativePath}: web-build target must declare ARG VITE_HOCUSPOCUS_URL and forward it with ENV before the web build`); } if (API_BUILD_TARGET_PATTERN.test(dockerfile) && apiBuildBody && API_BUILD_COMMAND_PATTERN.test(apiBuildBody)) { passes.push(`${relativePath}: api-build target invokes its direct build entry point`); } else { failures.push(`${relativePath}: api-build must run node apps/api/scripts/build.mjs directly`); } if (MCP_BUILD_TARGET_PATTERN.test(dockerfile) && mcpBuildBody && MCP_BUILD_COMMAND_PATTERN.test(mcpBuildBody)) { passes.push(`${relativePath}: mcp-build target invokes its direct build entry point`); } else { failures.push(`${relativePath}: mcp-build must run node apps/mcp/scripts/build.mjs directly`); } if ( PORTAL_CONTROLLER_BUILD_TARGET_PATTERN.test(dockerfile) && portalControllerBuildBody && PORTAL_CONTROLLER_BUILD_COMMAND_PATTERN.test(portalControllerBuildBody) ) { passes.push(`${relativePath}: portal controller build target invokes its direct cwd-aware entry point`); } else { failures.push(`${relativePath}: portal controller build must cd into its app and run node scripts/build.mjs directly`); } if (WORKER_BUILD_TARGET_PATTERN.test(dockerfile) && workerBuildBody && WORKER_BUILD_COMMAND_PATTERN.test(workerBuildBody)) { passes.push(`${relativePath}: worker-build target invokes its direct cwd-aware build entry point`); } else { failures.push(`${relativePath}: worker-build must cd into apps/worker and run node scripts/build.mjs directly`); } if ( WEB_RUNTIME_ARTIFACTS_TARGET_PATTERN.test(dockerfile) && API_RUNTIME_ARTIFACTS_TARGET_PATTERN.test(dockerfile) && WORKER_RUNTIME_ARTIFACTS_TARGET_PATTERN.test(dockerfile) && webRuntimeArtifactsBody && apiRuntimeArtifactsBody && workerRuntimeArtifactsBody && WEB_RUNTIME_ARTIFACTS_SOURCEMAP_DELETE_PATTERN.test(webRuntimeArtifactsBody) && API_RUNTIME_ARTIFACTS_SOURCEMAP_DELETE_PATTERN.test(apiRuntimeArtifactsBody) && WORKER_RUNTIME_ARTIFACTS_SOURCEMAP_DELETE_PATTERN.test(workerRuntimeArtifactsBody) ) { passes.push(`${relativePath}: target-specific runtime artifacts remove web, api, and worker sourcemaps before runtime COPY`); } else { failures.push(`${relativePath}: web/api/worker runtime artifact targets must delete their own *.map files before runtime COPY`); } if (webBody && (START_SH_ENTRYPOINT_PATTERN.test(webBody) || /\bpnpm\s+start\b|\bnpm\s+start\b|\bnode\s+build\/server-runtime\/server\.js\b/.test(webBody))) { passes.push(`${relativePath}: web runtime invokes production start path`); } else { failures.push(`${relativePath}: web target must keep ENTRYPOINT [ "./start.sh" ] or invoke the root production start path`); } if (webBody && RECURSIVE_CHOWN_PATTERN.test(webBody)) { failures.push(`${relativePath}: web target must not use recursive chown in the runtime image`); } else if (webBody) { passes.push(`${relativePath}: web target avoids recursive runtime chown`); } if (webBody && WEB_HEALTHCHECK_PATTERN.test(webBody)) { passes.push(`${relativePath}: web target contains HEALTHCHECK using /healthz`); } else { failures.push(`${relativePath}: web target HEALTHCHECK must probe http://127.0.0.1:${"${PORT}"}/healthz`); } if (webBody && WEB_HEALTHCHECK_HOST_PATTERN.test(webBody)) { passes.push(`${relativePath}: web target HEALTHCHECK uses the canonical WEB_APP_HOST`); } else { failures.push(`${relativePath}: web target HEALTHCHECK must send WEB_APP_HOST for host-aware routing`); } checkFastHealthcheckCadence(webBody, relativePath, "web", passes, failures); if (webBody && EXPOSE_8080_PATTERN.test(webBody)) { passes.push(`${relativePath}: web target exposes port 8080`); } else { failures.push(`${relativePath}: web target must declare EXPOSE 8080 for Coolify port discovery`); } if (webBody && APP_REVISION_ARG_PATTERN.test(webBody) && APP_REVISION_ENV_PATTERN.test(webBody) && APP_REVISION_LABEL_PATTERN.test(webBody)) { passes.push(`${relativePath}: web target persists APP_REVISION in env and OCI label`); } else { failures.push(`${relativePath}: web target must persist APP_REVISION in ENV and org.opencontainers.image.revision label`); } for (const [copyName, copyPattern] of WEB_REQUIRED_COPY_PATTERNS) { if (webBody && copyPattern.test(webBody)) { passes.push(`${relativePath}: web target copies ${copyName}`); } else { failures.push(`${relativePath}: web target must copy /myapp/${copyName}`); } } if (webBody && /\/myapp\/apps\/api(?:\/|\s)/.test(webBody)) { failures.push(`${relativePath}: web target must not copy API source, manifests, or artifacts`); } else if (webBody) { passes.push(`${relativePath}: web target excludes the separate API application`); } return { passes, failures, observations: [] }; } function getDockerfileTargetBody(dockerfile, targetName) { const targetPattern = new RegExp(`^FROM\\s+\\S+(?:\\s+AS\\s+${targetName})\\s*$`, "im"); const targetMatch = targetPattern.exec(dockerfile); if (!targetMatch) { return null; } const bodyStart = targetMatch.index + targetMatch[0].length; const nextTargetMatch = /^FROM\s+/gim.exec(dockerfile.slice(bodyStart)); const bodyEnd = nextTargetMatch ? bodyStart + nextTargetMatch.index : dockerfile.length; return dockerfile.slice(bodyStart, bodyEnd); } function normalizeContinuedCommand(value) { return value .replace(/\\\s*\n\s*/g, " ") .replace(/\s+/g, " ") .trim(); } function getDockerfileInstructions(targetBody) { if (!targetBody) { return []; } const withoutComments = targetBody .split(/\r?\n/) .filter((line) => !line.trimStart().startsWith("#")) .join("\n"); return withoutComments .split(/\n(?=[A-Z][A-Z0-9_]*\s)/) .map(normalizeContinuedCommand) .filter(Boolean); } function getShellFunctionBody(source, functionName) { const functionPattern = new RegExp(`^${escapeRegExp(functionName)}\\(\\)\\s*\\{\\s*\\n([\\s\\S]*?)^\\}`, "m"); return functionPattern.exec(source)?.[1] ?? null; } function getShellArrayItems(source, variableName) { const arrayPattern = new RegExp(`^${escapeRegExp(variableName)}=\\(([^)]*)\\)\\s*$`, "m"); return arrayPattern.exec(source)?.[1]?.trim().split(/\s+/).filter(Boolean) ?? []; } function checkFastHealthcheckCadence(targetBody, relativePath, target, passes, failures) { if (targetBody && FAST_START_HEALTHCHECK_CADENCE_PATTERN.test(targetBody)) { passes.push(`${relativePath}: ${target} HEALTHCHECK starts at 2s and keeps the 30s/3 steady-state budget`); } else { failures.push(`${relativePath}: ${target} HEALTHCHECK must use --start-interval=2s with steady --interval=30s and --retries=3`); } } function supportsCopyExcludeSyntax(dockerfile) { const match = /^#\s*syntax=docker\/dockerfile:(\d+)\.(\d+)\s*$/mu.exec(dockerfile); if (!match) return false; const major = Number(match[1]); const minor = Number(match[2]); return major > 1 || (major === 1 && minor >= 19); } function expectedProductionDepsInstructions({ target, prunePrisma }) { const instructions = []; if (target === "worker") { instructions.push("RUN node /myapp/scripts/prune-pnpm-runtime-closure.mjs /prod/worker/node_modules prisma typescript"); } if (prunePrisma) { instructions.push( `RUN node /myapp/scripts/prune-prisma-client-runtime.mjs /prod/${target}/node_modules /myapp/packages/db/generated/prisma/client/internal/class.ts` ); } instructions.push( `RUN SBOM_TARGET=${target} SBOM_ROOT_PATH=/prod/${target} SBOM_NODE_MODULES_PATH=/prod/${target}/node_modules SBOM_OUTPUT_PATH=/prod/${target}/sbom-pnpm.json node /myapp/scripts/generate-sbom.mjs` ); return instructions; } export function checkDockerfileDepsManifestContract(rootDir) { const relativePath = "Dockerfile"; const dockerfile = fs.readFileSync(path.join(rootDir, relativePath), "utf8"); const passes = []; const failures = []; const depsBody = getDockerfileTargetBody(dockerfile, "deps"); const workspaceManifests = listWorkspacePackageManifests(rootDir); if (supportsCopyExcludeSyntax(dockerfile)) { passes.push(`${relativePath}: Dockerfile syntax supports COPY --exclude`); } else { failures.push(`${relativePath}: must declare docker/dockerfile syntax 1.19 or newer for COPY --exclude`); } if (!depsBody) { failures.push(`${relativePath}: must define deps target with "FROM base AS deps"`); } else { if (FULL_WORKSPACE_SOURCE_COPY_PATTERN.test(depsBody)) { failures.push(`${relativePath}: deps target must copy workspace package manifests, not full apps or packages source, before pnpm install`); } else { passes.push(`${relativePath}: deps target does not copy full workspace source before pnpm install`); } for (const workspaceManifest of workspaceManifests) { const copyPattern = new RegExp(`^COPY\\s+${escapeRegExp(workspaceManifest)}\\s+${escapeRegExp(workspaceManifest)}\\s*$`, "m"); if (copyPattern.test(depsBody)) { passes.push(`${relativePath}: deps target copies ${workspaceManifest}`); } else { failures.push(`${relativePath}: deps target must copy ${workspaceManifest} before pnpm install`); } } if (FROZEN_FETCH_PATTERN.test(depsBody)) { passes.push(`${relativePath}: deps target fetches lockfile dependencies before offline install`); } else { failures.push(`${relativePath}: deps target must run pnpm fetch --frozen-lockfile with BuildKit cache before install`); } if (FROZEN_DEV_INSTALL_PATTERN.test(depsBody) && /\bpnpm\s+install\s+--frozen-lockfile\s+--prod=false\s+--offline\b/.test(depsBody)) { passes.push(`${relativePath}: deps target uses frozen offline dev dependency install`); } else { failures.push(`${relativePath}: deps target must run pnpm install --frozen-lockfile --prod=false --offline`); } if (PNPM_BUILDKIT_CACHE_PATTERN.test(depsBody)) { passes.push(`${relativePath}: deps target uses BuildKit pnpm store cache`); } else { failures.push(`${relativePath}: deps target must use BuildKit cache mount for /pnpm/store during pnpm install`); } if ( workspaceManifests.length > 0 && workspaceManifests.every((workspaceManifest) => { const copyPattern = new RegExp(`^COPY\\s+${escapeRegExp(workspaceManifest)}\\s+${escapeRegExp(workspaceManifest)}\\s*$`, "m"); return copyPattern.test(depsBody); }) ) { passes.push(`${relativePath}: deps stage copies all workspace package manifests before install`); } } const productionDepsBundleBody = getDockerfileTargetBody(dockerfile, "production-deps-bundle"); const expectedBundleInstruction = "RUN --mount=type=cache,id=hivegrid-pnpm-store-v2,target=/pnpm/store,sharing=locked bash scripts/ci/deploy-production-closures.sh"; const productionDepsBundleInstructions = getDockerfileInstructions(productionDepsBundleBody); const productionDepsBundleStageCount = (dockerfile.match(/^FROM\s+\S+\s+AS\s+production-deps-bundle\s*$/gim) ?? []).length; if ( productionDepsBundleStageCount === 1 && PRODUCTION_DEPS_BUNDLE_TARGET_PATTERN.test(dockerfile) && productionDepsBundleInstructions.length === 1 && productionDepsBundleInstructions[0] === expectedBundleInstruction ) { passes.push(`${relativePath}: production-deps-bundle delegates one locked warm v2 store directly to the closure helper`); } else { failures.push( `${relativePath}: production-deps-bundle must derive from build and contain only one locked hivegrid-pnpm-store-v2 invocation of scripts/ci/deploy-production-closures.sh` ); } const helperPath = path.join(rootDir, PRODUCTION_DEPS_HELPER_PATH); const helperSource = fs.existsSync(helperPath) ? fs.readFileSync(helperPath, "utf8") : ""; const normalizedHelper = normalizeContinuedCommand(helperSource); if (helperSource && /^set\s+-euo\s+pipefail\s*$/m.test(helperSource)) { passes.push(`${PRODUCTION_DEPS_HELPER_PATH}: fails closed on command errors, unset variables, and pipeline failures`); } else { failures.push(`${PRODUCTION_DEPS_HELPER_PATH}: must enable set -euo pipefail`); } const expectedTasks = RUNTIME_DEPLOY_TARGETS.map(({ helperFunction }) => helperFunction).join(" "); const expectedTargets = RUNTIME_DEPLOY_TARGETS.map(({ target }) => target).join(" "); const helperTasks = getShellArrayItems(helperSource, "tasks"); const helperTargets = getShellArrayItems(helperSource, "targets"); const runWaveBody = getShellFunctionBody(helperSource, "run_wave") ?? ""; const normalizedRunWave = normalizeContinuedCommand(runWaveBody); const hasParallelLaunch = new RegExp( `local -a pids=\\(\\)[\\s\\S]*for task in "\\$\\{tasks\\[@\\]\\}"; do[\\s\\S]*"\\$task" &[\\s\\S]*pids\\+=\\("\\$!"\\)[\\s\\S]*done` ).test(normalizedRunWave); const hasCompleteWaitAndFailurePropagation = /local status=0[\s\S]*for index in "\$\{!pids\[@\]\}"; do[\s\S]*if wait "\$\{pids\[\$index\]\}"; then[\s\S]*else child_status=\$\?;? fi[\s\S]*if \[\[ "\$status" -eq 0 \]\]; then status="\$child_status";? fi[\s\S]*done[\s\S]*return "\$status"/.test( normalizedRunWave ) && (normalizedRunWave.match(/\bwait\b/g) ?? []).length === 1; if (helperTasks.join(" ") === expectedTasks && helperTargets.join(" ") === expectedTargets && hasParallelLaunch && hasCompleteWaitAndFailurePropagation) { passes.push(`${PRODUCTION_DEPS_HELPER_PATH}: each wave starts all five closures in parallel, reaps every PID, and returns the first failure`); } else { failures.push( `${PRODUCTION_DEPS_HELPER_PATH}: tasks and targets must list the exact five closures and run_wave must collect all five background PIDs, wait for every child, preserve the first non-zero status, and return after all children are reaped` ); } const initialWaveCall = "run_wave offline-first || initial_status=$?"; const cleanupLoop = 'for target in "${targets[@]}"; do rm -rf -- "/prod/${target}" done'; const fetchCommand = "pnpm fetch --frozen-lockfile"; const retryWaveCall = "run_wave after-fetch || retry_status=$?"; const initialWaveIndex = normalizedHelper.indexOf(initialWaveCall); const cleanupIndex = normalizedHelper.indexOf(cleanupLoop); const fetchIndex = normalizedHelper.indexOf(`if ${fetchCommand}; then`); const retryWaveIndex = normalizedHelper.indexOf(retryWaveCall); const hasExactFallbackSequence = initialWaveIndex >= 0 && cleanupIndex > initialWaveIndex && fetchIndex > cleanupIndex && retryWaveIndex > fetchIndex && (normalizedHelper.match(/\brun_wave\s+(?:offline-first|after-fetch)\b/g) ?? []).length === 2 && (normalizedHelper.match(/\bpnpm\s+fetch\s+--frozen-lockfile\b/g) ?? []).length === 1 && (normalizedHelper.match(/\brm\s+-rf\b/g) ?? []).length === 1 && /initial_status=0 run_wave offline-first \|\| initial_status=\$\? if \[\[ "\$initial_status" -eq 0 \]\]; then[\s\S]*exit 0[\s\S]*fi/.test( normalizedHelper ) && /if pnpm fetch --frozen-lockfile; then[\s\S]*else fetch_status=\$\?[\s\S]*exit "\$fetch_status"[\s\S]*fi/.test(normalizedHelper) && /retry_status=0 run_wave after-fetch \|\| retry_status=\$\? if \[\[ "\$retry_status" -ne 0 \]\]; then[\s\S]*exit "\$retry_status"[\s\S]*fi/.test( normalizedHelper ); const hasForbiddenFallbackShortcut = /sentinel|sha256sum|lockfile[_-]?hash/i.test(helperSource) || /\|\|\s*(?:true|:|exit\s+0)\b/.test(helperSource) || /\brm\s+-rf\s+(?:--\s+)?["']?\/prod["']?(?:\s|;|$)/.test(helperSource) || /\brm\s+-rf\s+(?:--\s+)?["']?\/prod\/\*/.test(helperSource); if (hasExactFallbackSequence && !hasForbiddenFallbackShortcut) { passes.push( `${PRODUCTION_DEPS_HELPER_PATH}: retries one complete wave only after exact-target cleanup and one frozen fetch, with no sentinel or fail-open bypass` ); } else { failures.push( `${PRODUCTION_DEPS_HELPER_PATH}: must try one offline-first wave, exit on success, clean exactly the five /prod targets on failure, fetch once, retry one complete wave, and propagate fetch or retry failure without a sentinel` ); } if ((normalizedHelper.match(/\bpnpm\s+--offline\b/g) ?? []).length !== RUNTIME_DEPLOY_TARGETS.length) { failures.push(`${PRODUCTION_DEPS_HELPER_PATH}: must contain exactly five offline pnpm deployment commands`); } else { passes.push(`${PRODUCTION_DEPS_HELPER_PATH}: contains exactly five offline pnpm deployment commands`); } const hasLockedMetadataWalk = /prune_runtime_metadata/u.test(helperSource) || /find\s+[^\n]*node_modules[^\n]*(?:\*\.map|\*\.d\.ts)/u.test(helperSource); if (!hasLockedMetadataWalk) { passes.push(`${PRODUCTION_DEPS_HELPER_PATH}: releases the pnpm store lock without recursive metadata walks`); } else { failures.push(`${PRODUCTION_DEPS_HELPER_PATH}: must not run metadata find/delete work while the locked production closure RUN is active`); } for (const { target, stage, packageName, helperFunction, omitOptional, prunePrisma } of RUNTIME_DEPLOY_TARGETS) { const productionDepsBody = getDockerfileTargetBody(dockerfile, stage); const helperFunctionBody = getShellFunctionBody(helperSource, helperFunction); const expectedDeployCommand = `pnpm --offline --config.inject-workspace-packages=true --filter ${packageName} deploy --prod${ omitOptional ? " --no-optional" : "" } /prod/${target}`; const helperFunctionCount = (helperSource.match(new RegExp(`^${escapeRegExp(helperFunction)}\\(\\)\\s*\\{`, "gm")) ?? []).length; const hasExactDeployCommand = helperFunctionCount === 1 && helperFunctionBody && normalizeContinuedCommand(helperFunctionBody) === expectedDeployCommand; if (hasExactDeployCommand) { passes.push(`${PRODUCTION_DEPS_HELPER_PATH}: ${helperFunction} deploys exactly the isolated ${packageName} production closure`); } else { failures.push(`${PRODUCTION_DEPS_HELPER_PATH}: ${helperFunction} must run exactly "${expectedDeployCommand}" with no extra or missing flags`); } const stagePattern = new RegExp(`^FROM\\s+production-deps-bundle\\s+AS\\s+${escapeRegExp(stage)}\\s*$`, "im"); const stageDeclarationCount = (dockerfile.match(new RegExp(`^FROM\\s+\\S+\\s+AS\\s+${escapeRegExp(stage)}\\s*$`, "gim")) ?? []).length; const expectedStageInstructions = expectedProductionDepsInstructions({ target, prunePrisma }); const actualStageInstructions = getDockerfileInstructions(productionDepsBody); if ( stageDeclarationCount === 1 && stagePattern.test(dockerfile) && actualStageInstructions.length === expectedStageInstructions.length && actualStageInstructions.every((instruction, index) => instruction === expectedStageInstructions[index]) ) { passes.push(`${relativePath}: ${stage} derives from production-deps-bundle and performs only required reachability pruning and SBOM generation`); } else { failures.push(`${relativePath}: ${stage} must derive from production-deps-bundle and contain only its required post-deploy prune and SBOM instructions`); } if (omitOptional && hasExactDeployCommand) { passes.push(`${PRODUCTION_DEPS_HELPER_PATH}: ${helperFunction} omits optional peer toolchains from the runtime closure`); } const normalizedProductionDepsBody = normalizeContinuedCommand(productionDepsBody ?? ""); if (prunePrisma) { const prismaRuntimePruneCommand = `node /myapp/scripts/prune-prisma-client-runtime.mjs /prod/${target}/node_modules /myapp/packages/db/generated/prisma/client/internal/class.ts`; if (normalizedProductionDepsBody.includes(prismaRuntimePruneCommand)) { passes.push(`${relativePath}: ${stage} keeps only the generated PostgreSQL Prisma runtime`); } else { failures.push(`${relativePath}: ${stage} must prune unused Prisma query compilers before SBOM generation`); } } const targetSbomPattern = new RegExp( `SBOM_TARGET=${target}[\\s\\S]*SBOM_ROOT_PATH=\\/prod\\/${target}[\\s\\S]*SBOM_NODE_MODULES_PATH=\\/prod\\/${target}\\/node_modules[\\s\\S]*SBOM_OUTPUT_PATH=\\/prod\\/${target}\\/sbom-pnpm\\.json[\\s\\S]*generate-sbom\\.mjs` ); if (productionDepsBody && targetSbomPattern.test(productionDepsBody)) { passes.push(`${relativePath}: ${stage} generates an SBOM from its pruned runtime tree`); } else { failures.push(`${relativePath}: ${stage} must generate its SBOM from /prod/${target}/node_modules after pruning`); } if (target === "worker") { const removesOptionalToolchains = normalizedProductionDepsBody.includes( "node /myapp/scripts/prune-pnpm-runtime-closure.mjs /prod/worker/node_modules prisma typescript" ); if (removesOptionalToolchains) { passes.push(`${relativePath}: worker-production-deps removes optional peer toolchains and their unreachable dependencies`); } else { failures.push(`${relativePath}: worker-production-deps must prune optional Prisma and TypeScript peer closures by reachability`); } } const runtimeBody = getDockerfileTargetBody(dockerfile, target); const expectedDependencyCopy = `COPY --exclude=**/*.map --exclude=**/*.d.ts --from=${stage} /prod/${target}/node_modules /myapp/node_modules`; const dependencyCopyInstructions = getDockerfileInstructions(runtimeBody).filter((instruction) => instruction.endsWith(`/prod/${target}/node_modules /myapp/node_modules`) ); if (dependencyCopyInstructions.length === 1 && dependencyCopyInstructions[0] === expectedDependencyCopy) { passes.push(`${relativePath}: ${target} target copies only its deployed dependency closure without maps or declarations`); } else { failures.push(`${relativePath}: ${target} target dependency COPY must use both --exclude=**/*.map and --exclude=**/*.d.ts from ${stage}`); } const sbomCopyPattern = new RegExp( `^COPY\\s+--from=${escapeRegExp(stage)}\\s+\\/prod\\/${target}\\/sbom-pnpm\\.json\\s+\\/myapp\\/sbom-pnpm\\.json\\s*$`, "im" ); if (runtimeBody && sbomCopyPattern.test(runtimeBody)) { passes.push(`${relativePath}: ${target} target ships its target-specific runtime SBOM`); } else { failures.push(`${relativePath}: ${target} target must copy its SBOM from ${stage}`); } if (target === "web" || target === "api" || target === "mcp" || target === "portal-domain-controller" || target === "worker") { const removesPackageManagers = runtimeBody && /rm\s+-rf[\s\S]*\/usr\/local\/lib\/node_modules\/corepack/.test(runtimeBody) && /\/usr\/local\/bin\/pnpm/.test(runtimeBody) && /\/usr\/local\/bin\/yarn/.test(runtimeBody); if (removesPackageManagers) { passes.push(`${relativePath}: ${target} target removes inherited package-manager executables`); } else { failures.push(`${relativePath}: ${target} target must remove inherited Corepack, pnpm, and Yarn executables`); } } } if (GENERIC_PRODUCTION_NODE_MODULES_COPY_PATTERN.test(dockerfile) || /^FROM\s+base\s+AS\s+production-deps\s*$/im.test(dockerfile)) { failures.push(`${relativePath}: must not build or copy a generic whole-workspace production node_modules closure`); } else { passes.push(`${relativePath}: excludes generic whole-workspace production node_modules from runtime images`); } if (/^COPY\s+--from=build\s+\/myapp\/sbom-pnpm\.json\s+\/myapp\/sbom-pnpm\.json\s*$/im.test(dockerfile)) { failures.push(`${relativePath}: runtime targets must not copy the full-workspace build SBOM`); } else { passes.push(`${relativePath}: runtime targets do not ship a full-workspace build SBOM`); } return { passes, failures, observations: [] }; } export function checkDockerfileWorkerContract(rootDir) { const relativePath = "Dockerfile"; const dockerfile = fs.readFileSync(path.join(rootDir, relativePath), "utf8"); const passes = []; const failures = []; const workerBody = getDockerfileTargetBody(dockerfile, "worker"); if (WORKER_TARGET_PATTERN.test(dockerfile)) { passes.push(`${relativePath}: defines named worker target from base`); } else { failures.push(`${relativePath}: must define worker target with "FROM base AS worker"`); } if (workerBody && WORKER_RUNTIME_PATTERN.test(workerBody)) { passes.push(`${relativePath}: worker runtime invokes @hivegrid/worker production start path`); } else { failures.push(`${relativePath}: worker target must invoke node apps/worker/dist/index.js directly`); } if (workerBody && WORKER_HEALTH_PATTERN.test(workerBody)) { passes.push(`${relativePath}: worker target invokes worker health path directly`); } else { failures.push(`${relativePath}: worker target must invoke node apps/worker/dist/health.js directly`); } checkFastHealthcheckCadence(workerBody, relativePath, "worker", passes, failures); if (workerBody && APP_REVISION_ARG_PATTERN.test(workerBody) && APP_REVISION_ENV_PATTERN.test(workerBody) && APP_REVISION_LABEL_PATTERN.test(workerBody)) { passes.push(`${relativePath}: worker target persists APP_REVISION in env and OCI label`); } else { failures.push(`${relativePath}: worker target must persist APP_REVISION in ENV and org.opencontainers.image.revision label`); } if (workerBody && IMAGE_REVISION_FILE_PATTERN.test(workerBody)) { passes.push(`${relativePath}: worker target writes the immutable image revision file before dropping privileges`); } else { failures.push(`${relativePath}: worker target must write root-owned /myapp/.image-revision from APP_REVISION`); } if (workerBody && /\btsx\b/.test(workerBody)) { failures.push(`${relativePath}: worker target must not use tsx at runtime`); } else if (workerBody) { passes.push(`${relativePath}: worker target runtime does not use tsx`); } if (workerBody && RECURSIVE_CHOWN_PATTERN.test(workerBody)) { failures.push(`${relativePath}: worker target must not use recursive chown in the runtime image`); } else if (workerBody) { passes.push(`${relativePath}: worker target avoids recursive runtime chown`); } for (const [copyName, copyPattern] of WORKER_REQUIRED_COPY_PATTERNS) { if (workerBody && copyPattern.test(workerBody)) { passes.push(`${relativePath}: worker target copies ${copyName}`); } else { failures.push(`${relativePath}: worker target must copy /myapp/${copyName}`); } } return { passes, failures, observations: [] }; } export function checkDockerfileMcpContract(rootDir) { const relativePath = "Dockerfile"; const dockerfile = fs.readFileSync(path.join(rootDir, relativePath), "utf8"); const passes = []; const failures = []; const mcpBody = getDockerfileTargetBody(dockerfile, "mcp"); if (MCP_TARGET_PATTERN.test(dockerfile)) { passes.push(`${relativePath}: defines named MCP target from base`); } else { failures.push(`${relativePath}: must define MCP target with "FROM base AS mcp"`); } if (mcpBody && MCP_RUNTIME_PATTERN.test(mcpBody)) { passes.push(`${relativePath}: MCP target invokes node apps/mcp/dist/server.js directly`); } else { failures.push(`${relativePath}: MCP target must invoke node apps/mcp/dist/server.js directly`); } if (mcpBody && MCP_HEALTHCHECK_PATTERN.test(mcpBody)) { passes.push(`${relativePath}: MCP target contains dependency-free Node HEALTHCHECK using /healthz`); } else { failures.push(`${relativePath}: MCP target HEALTHCHECK must probe http://127.0.0.1:\${MCP_PORT:-\${PORT}}/healthz with Node`); } checkFastHealthcheckCadence(mcpBody, relativePath, "MCP", passes, failures); if (mcpBody && APP_REVISION_ARG_PATTERN.test(mcpBody) && APP_REVISION_ENV_PATTERN.test(mcpBody) && APP_REVISION_LABEL_PATTERN.test(mcpBody)) { passes.push(`${relativePath}: MCP target persists APP_REVISION in env and OCI label`); } else { failures.push(`${relativePath}: MCP target must persist APP_REVISION in ENV and org.opencontainers.image.revision label`); } if (mcpBody && IMAGE_REVISION_FILE_PATTERN.test(mcpBody)) { passes.push(`${relativePath}: MCP target writes the immutable image revision file before dropping privileges`); } else { failures.push(`${relativePath}: MCP target must write root-owned /myapp/.image-revision from APP_REVISION`); } if (mcpBody && /^COPY\s+--from=mcp-runtime-artifacts\s+\/myapp\/apps\/mcp\/dist\s+\/myapp\/apps\/mcp\/dist\s*$/im.test(mcpBody)) { passes.push(`${relativePath}: MCP target copies the compiled runtime including deploy health`); } else { failures.push(`${relativePath}: MCP target must copy /myapp/apps/mcp/dist from mcp-runtime-artifacts`); } if (mcpBody && /^USER\s+node\s*$/im.test(mcpBody)) { passes.push(`${relativePath}: MCP target runs as the non-root node user`); } else { failures.push(`${relativePath}: MCP target must run as USER node`); } if (mcpBody && RECURSIVE_CHOWN_PATTERN.test(mcpBody)) { failures.push(`${relativePath}: MCP target must not use recursive chown in the runtime image`); } else if (mcpBody) { passes.push(`${relativePath}: MCP target avoids recursive runtime chown`); } if (mcpBody && /\btsx\b/.test(mcpBody)) { failures.push(`${relativePath}: MCP target must not use tsx at runtime`); } else if (mcpBody) { passes.push(`${relativePath}: MCP target runtime does not use tsx`); } if (mcpBody && EXPOSE_8080_PATTERN.test(mcpBody)) { passes.push(`${relativePath}: MCP target exposes port 8080`); } else { failures.push(`${relativePath}: MCP target must declare EXPOSE 8080 for Coolify port discovery`); } return { passes, failures, observations: [] }; } export function checkDockerfileApiContract(rootDir) { const relativePath = "Dockerfile"; const dockerfile = fs.readFileSync(path.join(rootDir, relativePath), "utf8"); const passes = []; const failures = []; const apiBody = getDockerfileTargetBody(dockerfile, "api"); if (API_TARGET_PATTERN.test(dockerfile)) { passes.push(`${relativePath}: defines named api target from base`); } else { failures.push(`${relativePath}: must define api target with "FROM base AS api"`); } if (apiBody && API_RUNTIME_PATTERN.test(apiBody)) { passes.push(`${relativePath}: api runtime invokes @hivegrid/api production start path`); } else { failures.push(`${relativePath}: api target must invoke node apps/api/dist/server.js directly`); } if (apiBody && /\btsx\b/.test(apiBody)) { failures.push(`${relativePath}: api target must not use tsx at runtime`); } else if (apiBody) { passes.push(`${relativePath}: api target runtime does not use tsx`); } if (apiBody && RECURSIVE_CHOWN_PATTERN.test(apiBody)) { failures.push(`${relativePath}: api target must not use recursive chown in the runtime image`); } else if (apiBody) { passes.push(`${relativePath}: api target avoids recursive runtime chown`); } if (apiBody && API_HEALTHCHECK_PATTERN.test(apiBody)) { passes.push(`${relativePath}: api target contains HEALTHCHECK using /healthz`); } else { failures.push(`${relativePath}: api target HEALTHCHECK must probe http://127.0.0.1:\${API_PORT:-\${PORT}}/healthz`); } checkFastHealthcheckCadence(apiBody, relativePath, "api", passes, failures); if (apiBody && EXPOSE_8080_PATTERN.test(apiBody)) { passes.push(`${relativePath}: api target exposes port 8080`); } else { failures.push(`${relativePath}: api target must declare EXPOSE 8080 for Coolify port discovery`); } if (apiBody && APP_REVISION_ARG_PATTERN.test(apiBody) && APP_REVISION_ENV_PATTERN.test(apiBody) && APP_REVISION_LABEL_PATTERN.test(apiBody)) { passes.push(`${relativePath}: api target persists APP_REVISION in env and OCI label`); } else { failures.push(`${relativePath}: api target must persist APP_REVISION in ENV and org.opencontainers.image.revision label`); } for (const [copyName, copyPattern] of API_REQUIRED_COPY_PATTERNS) { if (apiBody && copyPattern.test(apiBody)) { passes.push(`${relativePath}: api target copies ${copyName}`); } else { failures.push(`${relativePath}: api target must copy /myapp/${copyName}`); } } return { passes, failures, observations: [] }; } export function checkHocuspocusDockerfileContract(rootDir) { const relativePath = "apps/hocuspocus/Dockerfile"; const dockerfile = fs.readFileSync(path.join(rootDir, relativePath), "utf8"); const passes = []; const failures = []; const depsBody = getDockerfileTargetBody(dockerfile, "deps"); const buildBody = getDockerfileTargetBody(dockerfile, "build"); const runtimeBody = getDockerfileTargetBody(dockerfile, "hocuspocus"); const productionDepsBody = getDockerfileTargetBody(dockerfile, "hocuspocus-production-deps"); if (supportsCopyExcludeSyntax(dockerfile)) { passes.push(`${relativePath}: Dockerfile syntax supports COPY --exclude`); } else { failures.push(`${relativePath}: must declare docker/dockerfile syntax 1.19 or newer for COPY --exclude`); } if (/^FROM\s+deps\s+AS\s+hocuspocus-production-deps\s*$/imu.test(dockerfile)) { passes.push(`${relativePath}: production dependency closure is cached independently from application source`); } else { failures.push(`${relativePath}: hocuspocus-production-deps must derive from the manifest-only deps stage`); } if (!depsBody) { failures.push(`${relativePath}: must define a manifest-only deps target`); } else { const allowedCopyPatterns = [ /^ADD\s+package\.json\s+pnpm-lock\.yaml\s+pnpm-workspace\.yaml\s+\.\/$/u, /^COPY\s+patches\s+\.\/patches$/u, /^COPY\s+(apps|packages|runtime)\/[^/]+\/package\.json\s+\1\/[^/]+\/package\.json$/u, ]; const invalidDependencyInputs = depsBody .split(/\r?\n/u) .map((line) => line.trim()) .filter((line) => /^(?:ADD|COPY)\s+/u.test(line)) .filter((line) => !allowedCopyPatterns.some((pattern) => pattern.test(line))); if (invalidDependencyInputs.length === 0) { passes.push(`${relativePath}: dependency cache is invalidated only by manifests, lockfiles, workspace config, and patches`); } else { failures.push(`${relativePath}: deps target must not copy source inputs before install (${invalidDependencyInputs.join(", ")})`); } const workspaceManifests = listWorkspacePackageManifests(rootDir); const missingManifests = workspaceManifests.filter( (workspaceManifest) => !new RegExp(`^COPY\\s+${escapeRegExp(workspaceManifest)}\\s+${escapeRegExp(workspaceManifest)}\\s*$`, "m").test(depsBody) ); if (missingManifests.length === 0) { passes.push(`${relativePath}: deps target copies every required workspace package manifest before install`); } else { failures.push(`${relativePath}: deps target must copy workspace manifests before install (${missingManifests.join(", ")})`); } if ( /\bpnpm\s+fetch\s+--frozen-lockfile\b/u.test(depsBody) && /\bpnpm\s+install\s+--frozen-lockfile\s+--prod=false\s+--offline\b/u.test(depsBody) && (depsBody.match(/target=\/pnpm\/store/gu)?.length ?? 0) >= 2 ) { passes.push(`${relativePath}: deps target uses a frozen fetched dependency set and offline install`); } else { failures.push(`${relativePath}: deps target must use pnpm fetch --frozen-lockfile followed by frozen offline install`); } } if ( buildBody && /^RUN\s+\.\/node_modules\/\.bin\/prisma\s+generate\s+--config\s+prisma\.config\.ts\s*$/imu.test(buildBody) && /^RUN\s+node\s+apps\/hocuspocus\/scripts\/build\.mjs\s*$/imu.test(buildBody) && !/pnpm\s+--filter\s+@hivegrid\/(?:db|hocuspocus)\s+build/u.test(buildBody) ) { passes.push(`${relativePath}: source-only rebuilds skip workspace resolution and unused database seed builds`); } else { failures.push(`${relativePath}: build target must invoke pinned Prisma and Hocuspocus build scripts directly and skip unused database seed artifacts`); } const hocusDeployCommand = "pnpm --offline --config.inject-workspace-packages=true --filter @hivegrid/runtime-hocuspocus deploy --prod --no-optional /prod/hocuspocus"; const hocusClosureInstruction = getDockerfileInstructions(productionDepsBody).find((instruction) => instruction.includes(hocusDeployCommand)); const hasLockedMetadataWalk = /find\s+[^\n]*node_modules[^\n]*(?:\*\.map|\*\.d\.ts)/u.test(productionDepsBody ?? ""); if (hocusClosureInstruction?.endsWith(hocusDeployCommand) && !hasLockedMetadataWalk) { passes.push(`${relativePath}: deploys the Hocuspocus closure without extending the store lock for metadata walks`); } else { failures.push(`${relativePath}: must deploy @hivegrid/runtime-hocuspocus without metadata find/delete work in the locked RUN`); } if ( productionDepsBody && /COPY\s+--from=build\s+\/myapp\/packages\/db\/generated\/prisma\/client\/internal\/class\.ts\s+\/myapp\/packages\/db\/generated\/prisma\/client\/internal\/class\.ts/u.test( productionDepsBody.replace(/\\\r?\n\s*/gu, " ") ) && /COPY\s+scripts\/prune-prisma-client-runtime\.mjs\s+\/myapp\/scripts\/prune-prisma-client-runtime\.mjs/u.test(productionDepsBody) && /node\s+\/myapp\/scripts\/prune-prisma-client-runtime\.mjs\s+\/prod\/hocuspocus\/node_modules\s+\/myapp\/packages\/db\/generated\/prisma\/client\/internal\/class\.ts/u.test( productionDepsBody.replace(/\\\r?\n\s*/gu, " ") ) ) { passes.push(`${relativePath}: fail-closed Prisma runtime pruning follows the generated client contract`); } else { failures.push(`${relativePath}: must use the generated-client-aware Prisma runtime pruner`); } if ( productionDepsBody && /SBOM_TARGET=hocuspocus[\s\S]*SBOM_NODE_MODULES_PATH=\/prod\/hocuspocus\/node_modules[\s\S]*SBOM_OUTPUT_PATH=\/prod\/hocuspocus\/sbom-pnpm\.json[\s\S]*generate-sbom\.mjs/.test( productionDepsBody ) ) { passes.push(`${relativePath}: generates a target-specific SBOM from the pruned runtime tree`); } else { failures.push(`${relativePath}: must generate its SBOM from the pruned Hocuspocus runtime tree`); } const expectedHocusDependencyCopy = "COPY --exclude=**/*.map --exclude=**/*.d.ts --from=hocuspocus-production-deps /prod/hocuspocus/node_modules /myapp/node_modules"; const hocusDependencyCopyInstructions = getDockerfileInstructions(runtimeBody).filter((instruction) => instruction.endsWith("/prod/hocuspocus/node_modules /myapp/node_modules") ); if (hocusDependencyCopyInstructions.length === 1 && hocusDependencyCopyInstructions[0] === expectedHocusDependencyCopy) { passes.push(`${relativePath}: final image copies production node_modules without maps or declarations`); } else { failures.push(`${relativePath}: final dependency COPY must use both --exclude=**/*.map and --exclude=**/*.d.ts from hocuspocus-production-deps`); } if (runtimeBody && /^COPY\s+--from=hocuspocus-production-deps\s+\/prod\/hocuspocus\/sbom-pnpm\.json\s+\/myapp\/sbom-pnpm\.json\s*$/im.test(runtimeBody)) { passes.push(`${relativePath}: final image ships the target-specific runtime SBOM`); } else { failures.push(`${relativePath}: final image must copy its SBOM from hocuspocus-production-deps`); } if ( /^FROM\s+build\s+AS\s+hocuspocus-runtime-artifacts\s*$/im.test(dockerfile) && /find\s+\/myapp\/apps\/hocuspocus\/dist\s+-type\s+f\s+-name\s+['"]\*\.map['"]\s+-delete/.test(dockerfile) && runtimeBody && /^COPY\s+--from=hocuspocus-runtime-artifacts\s+\/myapp\/apps\/hocuspocus\/dist\s+\/myapp\/apps\/hocuspocus\/dist\s*$/im.test(runtimeBody) ) { passes.push(`${relativePath}: strips source maps before the runtime copy`); } else { failures.push(`${relativePath}: must strip dist source maps in a runtime-artifacts stage`); } if (runtimeBody && /^USER\s+node\s*$/im.test(runtimeBody)) { passes.push(`${relativePath}: final image runs as the non-root node user`); } else { failures.push(`${relativePath}: final image must run as USER node`); } checkFastHealthcheckCadence(runtimeBody, relativePath, "Hocuspocus", passes, failures); if ( runtimeBody && /rm\s+-rf[\s\S]*\/usr\/local\/lib\/node_modules\/corepack/.test(runtimeBody) && /\/usr\/local\/bin\/pnpm/.test(runtimeBody) && /\/usr\/local\/bin\/yarn/.test(runtimeBody) ) { passes.push(`${relativePath}: removes inherited package-manager executables`); } else { failures.push(`${relativePath}: must remove inherited Corepack, pnpm, and Yarn executables`); } return { passes, failures, observations: [] }; } export function verifyDockerBaseline(rootDir = process.cwd()) { const requiredFilesResult = checkRequiredFiles(rootDir); const results = [requiredFilesResult]; if (fs.existsSync(path.join(rootDir, "Dockerfile"))) { results.push(checkDockerfileDepsManifestContract(rootDir)); results.push(checkDockerfileWebContract(rootDir)); results.push(checkDockerfileWorkerContract(rootDir)); results.push(checkDockerfileApiContract(rootDir)); results.push(checkDockerfileMcpContract(rootDir)); } if (fs.existsSync(path.join(rootDir, "apps/hocuspocus/Dockerfile"))) { results.push(checkHocuspocusDockerfileContract(rootDir)); } if (fs.existsSync(path.join(rootDir, ".dockerignore"))) { results.push(checkDockerignoreContract(rootDir)); } if (fs.existsSync(path.join(rootDir, "start.sh"))) { results.push(checkStartScript(rootDir)); } if (fs.existsSync(path.join(rootDir, "docker-compose.yml")) && fs.existsSync(path.join(rootDir, "docker-compose.staging.yml"))) { results.push(checkDockerComposeWorkerTopology(rootDir)); } const manifestChecks = [ ["package.json", checkRootManifest], ["packages/db/package.json", checkDbManifest], ["apps/web/package.json", checkWebManifest], ["apps/api/package.json", checkApiManifest], ["apps/worker/package.json", checkWorkerManifest], ]; for (const [relativePath, check] of manifestChecks) { if (fs.existsSync(path.join(rootDir, relativePath))) { try { results.push(check(rootDir)); } catch (error) { results.push({ passes: [], failures: [`${manifestPath(relativePath)}: failed to read manifest JSON: ${error.message}`], observations: [], }); } } } return results.reduce( (result, check) => ({ passes: [...result.passes, ...check.passes], failures: [...result.failures, ...check.failures], observations: [...result.observations, ...check.observations], }), { passes: [], failures: [], observations: [] } ); } export function formatVerificationResult(result) { const status = result.failures.length > 0 ? "FAIL" : "PASS"; return [ `${status} Docker baseline verification`, ...result.passes.map((pass) => `PASS ${pass}`), ...result.observations.map((observation) => `OBSERVE ${observation}`), ...result.failures.map((failure) => `FAIL ${failure}`), `Summary: ${result.passes.length} passed, ${result.observations.length} observed, ${result.failures.length} failed`, "", ].join("\n"); } const isCli = process.argv[1] && fileURLToPath(import.meta.url) === path.resolve(process.argv[1]); if (isCli) { const result = verifyDockerBaseline(process.cwd()); const output = formatVerificationResult(result); if (result.failures.length > 0) { process.stderr.write(output); process.exitCode = 1; } else { process.stdout.write(output); } }