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 { checkEnvDrift, formatEnvDriftResult } from "./check-env-drift.mjs"; const fixtures = []; const ENV_FIXTURES = { ".env.example": `# Core APP_NAME=ToolCTRL DATABASE_URL="postgres://{USER}:{PASSWORD}@{HOST}:{PORT}/{DATABASE}" SESSION_SECRET= CRYPTO_SECRET= APP_BASE_DOMAIN=localhost WEB_APP_HOST=app.localhost ADMIN_APP_HOST=admin.localhost API_HOST=api.localhost # APP_PROTOCOL=http API_ACCESS_TOKEN= JWT_SECRET= # REDIS_URL is a fallback only when BULLMQ_REDIS_URL is absent; keep it commented if a platform injects it. # REDIS_URL=redis://localhost:6379/0 SITE_KEY_EXAMPLE_SITE= `, ".env.local.example": `APP_NAME=ToolCTRL Local DATABASE_URL="file:./dev.db?connection_limit=1&connect_timeout=30" SESSION_SECRET=replace-with-local-session-secret CRYPTO_SECRET=replace-with-local-crypto-secret APP_BASE_DOMAIN=localhost:3000 WEB_APP_HOST=app.localhost:3000 ADMIN_APP_HOST=admin.localhost:3000 API_HOST=api.localhost:3001 APP_PROTOCOL=http API_ACCESS_TOKEN=replace-with-local-api-token JWT_SECRET=replace-with-local-jwt-secret SITE_KEY_LOCAL=replace-with-local-site-key `, ".env.production.example": `APP_NAME=ToolCTRL DATABASE_URL="postgres://{USER}:{PASSWORD}@{HOST}:{PORT}/{DATABASE}" SESSION_SECRET= CRYPTO_SECRET= APP_BASE_DOMAIN=your-domain.invalid WEB_APP_HOST=app.your-domain.invalid ADMIN_APP_HOST=admin.your-domain.invalid API_HOST=api.your-domain.invalid APP_PROTOCOL=https API_ACCESS_TOKEN= JWT_SECRET= BULLMQ_REDIS_URL=redis://localhost:6379/0 # REDIS_URL=redis://localhost:6379/0 `, ".env.fly.example": `flyctl secrets set APP_NAME=YOUR_APP_NAME \\ DATABASE_URL=postgres://{USER}:{PASSWORD}@{HOST}:{PORT}/{DATABASE} \\ SESSION_SECRET= \\ CRYPTO_SECRET= \\ API_ACCESS_TOKEN= \\ JWT_SECRET= \\ APP_BASE_DOMAIN=your-domain.invalid \\ WEB_APP_HOST=app.your-domain.invalid \\ ADMIN_APP_HOST=admin.your-domain.invalid \\ API_HOST=api.your-domain.invalid \\ APP_PROTOCOL=https \\ BULLMQ_REDIS_URL=redis://default:@redis.your-domain.invalid:6379/0 \\ --app YOUR_APP_NAME # REDIS_URL=redis://default:@redis.your-domain.invalid:6379/0 `, ".env.test": `APP_NAME=ToolCTRL Test DATABASE_URL="file:./test.db?connection_limit=1&connect_timeout=30" SESSION_SECRET=test-session-secret-placeholder CRYPTO_SECRET=test-crypto-secret-placeholder APP_BASE_DOMAIN=localhost.test WEB_APP_HOST=app.localhost.test ADMIN_APP_HOST=admin.localhost.test API_HOST=api.localhost.test APP_PROTOCOL=http API_ACCESS_TOKEN=test-api-access-token-placeholder JWT_SECRET=test-jwt-secret-placeholder SITE_KEY_EXAMPLE_SITE=test-site-key-placeholder `, }; function writeFile(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(), "env-drift-")); fixtures.push(rootDir); for (const [relativePath, content] of Object.entries(ENV_FIXTURES)) { writeFile(rootDir, relativePath, overrides[relativePath] ?? content); } return rootDir; } afterEach(() => { while (fixtures.length > 0) { fs.rmSync(fixtures.pop(), { recursive: true, force: true }); } }); describe("check-env-drift", () => { it("prints PASS output for cataloged env fixtures", () => { const rootDir = createFixture(); const result = checkEnvDrift(rootDir); const output = formatEnvDriftResult(result); assert.deepEqual(result.failures, []); assert.match(output, /^PASS env drift verification/); assert.match(output, /PASS \.env\.test: \d+ active keys match catalog/); assert.match(output, /Summary: \d+ passed, 0 observed, 0 failed/); }); it("fails for unknown keys", () => { const rootDir = createFixture({ ".env.test": `${ENV_FIXTURES[".env.test"]}UNTRACKED_SECRET=super-secret-value `, }); const result = checkEnvDrift(rootDir); assert.match(result.failures.join("\n"), /\.env\.test:\d+: unknown-key UNTRACKED_SECRET/); }); it("fails for duplicate keys within one file", () => { const rootDir = createFixture({ ".env.local.example": `${ENV_FIXTURES[".env.local.example"]}APP_NAME=Duplicate `, }); const result = checkEnvDrift(rootDir); assert.match(result.failures.join("\n"), /\.env\.local\.example:\d+: duplicate-key APP_NAME/); }); it("allows dynamic SITE_KEY-prefixed variables", () => { const rootDir = createFixture({ ".env.test": `${ENV_FIXTURES[".env.test"]}SITE_KEY_CUSTOMER_PORTAL=test-site-key-placeholder `, }); const result = checkEnvDrift(rootDir); assert.deepEqual(result.failures, []); }); it("fails when production example files keep example.com placeholders", () => { const rootDir = createFixture({ ".env.production.example": ENV_FIXTURES[".env.production.example"].replaceAll("your-domain.invalid", "example.com"), }); const result = checkEnvDrift(rootDir); assert.match(result.failures.join("\n"), /\.env\.production\.example:\d+: production-domain-placeholder APP_BASE_DOMAIN/); }); it("requires production keys in fly secrets examples", () => { const rootDir = createFixture({ ".env.fly.example": ENV_FIXTURES[".env.fly.example"].replace(/JWT_SECRET= \\\n/, ""), }); const result = checkEnvDrift(rootDir); assert.match(result.failures.join("\n"), /\.env\.fly\.example: missing-required-key JWT_SECRET/); }); it("redacts values from diagnostics", () => { const leakedValue = "top-secret-token-value"; const rootDir = createFixture({ ".env.test": `${ENV_FIXTURES[".env.test"]}UNTRACKED_SECRET=${leakedValue} `, }); const result = checkEnvDrift(rootDir); const output = formatEnvDriftResult(result); assert.match(output, /unknown-key UNTRACKED_SECRET/); assert.doesNotMatch(output, new RegExp(leakedValue)); }); it("CLI exits non-zero without leaking values", () => { const leakedValue = "super-secret-cli-value"; const rootDir = createFixture({ ".env.test": `${ENV_FIXTURES[".env.test"]}UNTRACKED_SECRET=${leakedValue} `, }); const scriptPath = path.resolve("scripts/check-env-drift.mjs"); const nodePath = path.resolve("node_modules"); assert.throws( () => execFileSync(process.execPath, ["--import", path.join(nodePath, "tsx/dist/loader.mjs"), scriptPath], { cwd: rootDir, encoding: "utf8", stdio: "pipe", }), (error) => { assert.equal(error.status, 1); const output = `${error.stdout}${error.stderr}`; assert.match(output, /FAIL env drift verification/); assert.match(output, /unknown-key UNTRACKED_SECRET/); assert.doesNotMatch(output, new RegExp(leakedValue)); return true; }, ); }); });