import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import assert from "node:assert/strict"; import { execFileSync } from "node:child_process"; import { afterEach, describe, it } from "vitest"; import { formatProductionDocsDocsResult, verifyProductionDocsDocs } from "./verify-production-docs.mjs"; const fixtures = []; const VALID_DOCS = { "README.md": [ "# Project", "See [Quickstart](docs/quickstart.md), [New Project](docs/new-project.md), and [Local Dev](docs/local-dev.md).", "Run Corepack with pnpm@10.33.0 before installing dependencies.", ].join("\n"), "docs/quickstart.md": [ "# Quickstart", "Create `.env` from `.env.example` with placeholder values and no production secrets.", "Use DATABASE_URL for PostgreSQL and Prisma setup.", "Run `pnpm seed`, then `pnpm dev`, and open localhost:3000.", ].join("\n"), "docs/new-project.md": [ "# New Project", "Set WORKER_ENABLED and BULLMQ_REDIS_URL only when optional Redis worker behavior is in scope.", "Browser, Playwright, Cypress, and E2E checks are manual unless explicitly approved.", ].join("\n"), "docs/local-dev.md": [ "# Local Development", "Use focused non-E2E verification during local development.", "Troubleshooting covers PostgreSQL, Prisma, seed, and Redis issues.", ].join("\n"), "docs/env-vars.md": [ "# Environment Variables", "Environment and .env keys include API_KEY and TOKEN style secrets, but diagnostics must use redacted or masked output.", "Production troubleshooting must never print raw secrets or secret values.", ].join("\n"), "docs/database.md": [ "# Database Operations", "Database PostgreSQL operations cover migration deploy steps, status health checks, backup routines, and restore notes.", ].join("\n"), "docs/mail.md": [ "# Mail", "MailerSend handles outbound email and mail delivery.", "Webhook events require signing signature verification before processing.", ].join("\n"), "docs/worker.md": [ "# Worker Runtime", "WORKER_ENABLED controls worker enablement with BULLMQ_REDIS_URL or Redis configured for queue jobs.", "Queue health diagnostics stay redacted for production failure investigation.", "Separate Coolify workers include worker-general, worker-mail, and worker-plugin. The permanent mail worker uses WORKER_QUEUE_GROUP=mail; docs/ops/worker-queues.md is the canonical topology reference.", ].join("\n"), "docs/api.md": [ "# API Documentation", "The production API requires authentication with Bearer tokens or API key credentials.", "OpenAPI and swagger references describe endpoints and every response includes request-id correlation through X-Request-ID.", ].join("\n"), "docs/deployment.md": [ "# Deployment", "Deployment uses a Docker container image published for Coolify release rollout.", "Manual-only runtime checks document the start command and service boundary before traffic is switched.", "Coolify patches pre_deployment_command for `pnpm exec prisma migrate deploy` and post_deployment_command for `node packages/db/dist/production-seed.server.js`.", ].join("\n"), "docs/deployments/boiler-saas-ctrl-com.md": [ "# boiler.saas-ctrl.com", "Coolify patches pre_deployment_command for `cd /myapp && pnpm exec prisma migrate deploy --config prisma.config.ts`.", "Coolify patches post_deployment_command for `cd /myapp && NODE_ENV=production node packages/db/dist/production-seed.server.js`.", "Manual-only runtime checks document Coolify image containers, release rollout, start command, and service boundary.", ].join("\n"), "docs/security.md": [ "# Security", "Security headers include CSP and HSTS guidance.", "CORS allowed origins are explicit, and TOKEN, API_KEY, and other secrets are masked or redacted in diagnostics.", ].join("\n"), "docs/observability.md": [ "# Observability", "Observability diagnostics are redacted for health and readiness checks.", "Queue and job inspection supports incident failure triage without exposing raw values.", ].join("\n"), "docs/plugins.md": [ "# Plugin Candidate Boundaries", "Plugin candidates are extraction contracts, not already-packaged plugins.", "They document core, plugin-candidate, and remove-candidate boundaries with non-E2E verification.", ].join("\n"), "docs/upgrades.md": [ "# Upgrade Runbook", "Upgrade guidance keeps pnpm@10.33.0 pinned while reviewing Prisma database, runtime, and provider changes.", "The CI-safe workflow runs non-E2E checks including verify:docs-links before manual runtime review.", ].join("\n"), "docs/troubleshooting.md": [ "# Production Troubleshooting Runbook", "This troubleshooting runbook defines triage order for production incidents.", "Safe evidence collection records redacted diagnostics only and never raw secrets.", ].join("\n"), }; function writeFixtureFile(rootDir, relativePath, content) { const absolutePath = path.join(rootDir, relativePath); fs.mkdirSync(path.dirname(absolutePath), { recursive: true }); fs.writeFileSync(absolutePath, content); } function createFixture(overrides = {}) { const rootDir = fs.mkdtempSync(path.join(os.tmpdir(), "productionDocs-docs-")); fixtures.push(rootDir); for (const [relativePath, content] of Object.entries(VALID_DOCS)) { if (overrides[relativePath] === null) continue; writeFixtureFile(rootDir, relativePath, overrides[relativePath] ?? content); } return rootDir; } afterEach(() => { while (fixtures.length > 0) { fs.rmSync(fixtures.pop(), { recursive: true, force: true }); } }); describe("verify-production-docs", () => { it("passes for documentation that satisfies the Production Docs production documentation contract", () => { const rootDir = createFixture(); const result = verifyProductionDocsDocs(rootDir); const output = formatProductionDocsDocsResult(result); assert.deepEqual(result.failures, []); assert.match(output, /^PASS Production Docs production documentation verification/); assert.match(output, /16 required documentation files/); assert.match(output, /docs\/api\.md/); assert.match(output, /docs\/deployment\.md/); assert.match(output, /docs\/deployments\/boiler-saas-ctrl-com\.md/); assert.match(output, /docs\/security\.md/); assert.match(output, /docs\/observability\.md/); assert.match(output, /docs\/plugins\.md/); assert.match(output, /docs\/upgrades\.md/); assert.match(output, /docs\/troubleshooting\.md/); }); it("fails when a required documentation file is missing", () => { const rootDir = createFixture({ "docs/worker.md": null }); const result = verifyProductionDocsDocs(rootDir); assert.match(result.failures.join("\n"), /docs\/worker\.md: missing required documentation file/); }); it("fails when an S04 documentation entrypoint is missing", () => { const rootDir = createFixture({ "docs/api.md": null }); const result = verifyProductionDocsDocs(rootDir); assert.match(result.failures.join("\n"), /docs\/api\.md: missing required documentation file/); }); it("fails when forbidden placeholder markers are present", () => { const rootDir = createFixture({ "docs/quickstart.md": `${VALID_DOCS["docs/quickstart.md"]}\nTODO fill later` }); const result = verifyProductionDocsDocs(rootDir); assert.match(result.failures.join("\n"), /docs\/quickstart\.md:\d+:\d+: forbidden placeholder marker "TODO"/); }); it("fails when a required readiness term group is incomplete", () => { const rootDir = createFixture({ "docs/new-project.md": "# New Project\nManual browser checks are explicitly approved only.", "docs/worker.md": "# Worker Runtime\nQueue health diagnostics stay redacted for production failure investigation.", }); const result = verifyProductionDocsDocs(rootDir); assert.match(result.failures.join("\n"), /required term group "optional-worker-redis"/); }); it("fails when S03 mail operations are incomplete", () => { const rootDir = createFixture({ "docs/mail.md": "# Mail\nOutbound email delivery uses redacted production diagnostics." }); const result = verifyProductionDocsDocs(rootDir); assert.match(result.failures.join("\n"), /required term group "s03-mailersend-boundaries"/); }); it("fails when S04 API documentation coverage is incomplete", () => { const rootDir = createFixture({ "docs/api.md": "# API Documentation\nThe production API requires authentication only." }); const result = verifyProductionDocsDocs(rootDir); assert.match(result.failures.join("\n"), /required term group "s04-api-auth-openapi-request-id"/); }); it("fails when S04 deployment documentation coverage is incomplete", () => { const rootDir = createFixture(); const result = verifyProductionDocsDocs(rootDir, { termGroups: [ { id: "s04-deployment-image-coolify-runtime", description: "deployment image, Coolify, and manual runtime boundaries", terms: [/\bdeploy(?:ment)?\b|\brelease\b/i, /\bmust-not-exist-in-fixture\b/i], }, ], }); assert.match(result.failures.join("\n"), /required term group "s04-deployment-image-coolify-runtime"/); }); it("fails when deployment docs combine seed into the pre-deploy command slot", () => { const rootDir = createFixture({ "docs/deployment.md": [ "# Deployment", "Deployment uses a Docker container image published for Coolify release rollout.", "Manual-only runtime checks document the start command and service boundary before traffic is switched.", "Pre-deploy command: `cd /myapp && pnpm exec prisma migrate deploy --config prisma.config.ts && NODE_ENV=production node packages/db/dist/production-seed.server.js`.", ].join("\n"), }); const result = verifyProductionDocsDocs(rootDir); assert.match(result.failures.join("\n"), /docs\/deployment\.md: must document Coolify post_deployment_command as the guarded seed slot/); assert.match(result.failures.join("\n"), /docs\/deployment\.md: must not describe the guarded seed as combined into the pre-deploy command/); }); it("fails when separate worker group documentation is incomplete", () => { const rootDir = createFixture({ "docs/worker.md": "# Worker Runtime\nWORKER_ENABLED controls worker enablement with BULLMQ_REDIS_URL or Redis configured for queue jobs.\nQueue health diagnostics stay redacted for production failure investigation.", }); const result = verifyProductionDocsDocs(rootDir); assert.match(result.failures.join("\n"), /required term group "s04-separate-worker-groups"/); }); it("fails when live docs repeat superseded status blockers", () => { const rootDir = createFixture({ "docs/worker.md": `${VALID_DOCS["docs/worker.md"]}\nRemaining gap: persistent Coolify mail-worker service.`, }); const result = verifyProductionDocsDocs(rootDir); assert.match(result.failures.join("\n"), /superseded B-014 mail-worker blocker wording/); }); it("fails when plugin docs claim production enablement before signoff", () => { const rootDir = createFixture({ "docs/plugins.md": [ "# Plugin Candidate Boundaries", "Plugin candidates are extraction contracts, not already-packaged plugins.", "Third-party plugin execution is production-enabled with non-E2E verification.", ].join("\n"), }); const result = verifyProductionDocsDocs(rootDir); assert.match(result.failures.join("\n"), /third-party plugin execution must stay gated/); }); it("fails when S04 security documentation coverage is incomplete", () => { const rootDir = createFixture({ "docs/security.md": "# Security\nSecurity headers are configured." }); const result = verifyProductionDocsDocs(rootDir); assert.match(result.failures.join("\n"), /required term group "s04-security-headers-cors-secrets"/); }); it("fails when S04 observability documentation coverage is incomplete", () => { const rootDir = createFixture(); const result = verifyProductionDocsDocs(rootDir, { termGroups: [ { id: "s04-observability-diagnostics-health-queue-triage", description: "redacted diagnostics, health/readiness, queue inspection, and failure triage", terms: [/\bobservability\b/i, /\bmust-not-exist-in-fixture\b/i], }, ], }); assert.match(result.failures.join("\n"), /required term group "s04-observability-diagnostics-health-queue-triage"/); }); it("fails when plugin candidate documentation implies packaged plugins", () => { const rootDir = createFixture({ "docs/plugins.md": "# Plugin Candidate Boundaries\nPlugin candidates are installed packages with non-E2E verification." }); const result = verifyProductionDocsDocs(rootDir); assert.match(result.failures.join("\n"), /required term group "s05-plugin-candidates"/); }); it("fails when upgrade guidance is incomplete", () => { const rootDir = createFixture(); const result = verifyProductionDocsDocs(rootDir, { termGroups: [ { id: "s05-upgrade-guidance", description: "upgrade runbook covers pinned pnpm, database/runtime/provider upgrades, and non-E2E checks", terms: [/\bupgrade(?:s|d)?\b/i, /\bmust-not-exist-in-fixture\b/i], }, ], }); assert.match(result.failures.join("\n"), /required term group "s05-upgrade-guidance"/); }); it("fails when troubleshooting runbook redaction guidance is incomplete", () => { const rootDir = createFixture({ "docs/troubleshooting.md": "# Production Troubleshooting Runbook\nTriage order exists." }); const result = verifyProductionDocsDocs(rootDir); assert.match(result.failures.join("\n"), /required term group "s05-troubleshooting-runbook"/); }); it("fails when docs link-check CI guidance is absent", () => { const rootDir = createFixture({ "docs/upgrades.md": "# Upgrade Runbook\nUpgrade guidance keeps pnpm@10.33.0 pinned while reviewing Prisma database changes.\nUse non-E2E checks before manual runtime review." }); const result = verifyProductionDocsDocs(rootDir); assert.match(result.failures.join("\n"), /required term group "s05-docs-link-check-ci"/); }); it("fails for automatic E2E and browser command recommendations but allows manual notes", () => { const rootDir = createFixture({ "docs/local-dev.md": `${VALID_DOCS["docs/local-dev.md"]}\nManual Playwright review may be recorded.\n\`pnpm exec playwright test\``, }); const result = verifyProductionDocsDocs(rootDir); assert.match(result.failures.join("\n"), /forbidden automatic browser\/E2E command \(playwright-test-command\)/); assert.doesNotMatch(result.failures.join("\n"), /Manual Playwright review/); }); it("exits non-zero from the CLI when checks fail", () => { const rootDir = createFixture({ "README.md": "" }); assert.throws( () => execFileSync(process.execPath, [path.resolve("scripts/verify-production-docs.mjs")], { cwd: rootDir, encoding: "utf8", stdio: "pipe" }), /documentation file is empty/, ); }); });