Files
OpenCode 68a9071cf1 feat: reconcile local master with origin (exa/hot-platform hunters, leaks ledger, latest results)
Local branch had diverged from origin/master (sibling commits on the same base). Rewrote local history linearly on top of origin/master, folding in all local content: exa/hot-platform discovery hunters, leaks ledger, nightly sweep orchestrator, updated .gitignore and skill docs, plus the latest hunt output and vault state. Remote-only files (vault keys, channel scripts) were restored rather than dropped, so the resulting tree is a full union of both sides.
2026-08-07 12:53:47 +08:00

1 line
8.0 KiB
JSON

{"repo": "chicopanama/pokedao", "files": {"api/src/lib/__tests__/validate-env-real.test.ts": {"2b4d30cddcaab59e384dbc70dcb21a553349a5fd": {"t": 1786068274.6630602, "n": 4830, "h": "79e4bcc42742994f", "c": "import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';\nimport { loadAndValidateEnv } from '../validate-env.js';\n\ndescribe('validate-env - Real Function Tests', () => {\n const originalEnv = { ...process.env };\n const originalExit = process.exit;\n\n beforeEach(() => {\n // Reset env\n process.env = { ...originalEnv };\n\n // Mock process.exit\n process.exit = vi.fn() as any;\n });\n\n afterEach(() => {\n // Restore env and exit\n process.env = originalEnv;\n process.exit = originalExit;\n });\n\n describe('loadAndValidateEnv', () => {\n it('should not throw when all required vars are present', () => {\n process.env.DATABASE_URL = 'postgresql://localhost:5432/test';\n process.env.DEEPSEEK_API_KEY = 'test-key';\n\n expect(() => loadAndValidateEnv(['DATABASE_URL', 'DEEPSEEK_API_KEY'])).not.toThrow();\n });\n\n it('should call dotenv.config()', () => {\n // Just verify the function executes without throwing\n loadAndValidateEnv([]);\n\n // If dotenv.config() was called, process.env should have values from .env\n expect(process.env.DATABASE_URL).toBeDefined();\n });\n\n it('should validate multiple vars', () => {\n process.env.DATABASE_URL = 'postgresql://localhost:5432/test';\n process.env.DEEPSEEK_API_KEY = 'test-key';\n process.env.OPENAI_API_KEY = 'test-key';\n\n expect(() => loadAndValidateEnv(['DATABASE_URL', 'DEEPSEEK_API_KEY', 'OPENAI_API_KEY'])).not.toThrow();\n });\n\n it('should exit on first missing var', () => {\n process.env.DATABASE_URL = 'postgresql://localhost:5432/test';\n delete process.env.DEEPSEEK_API_KEY;\n delete process.env.OPENAI_API_KEY;\n\n loadAndValidateEnv(['DATABASE_URL', 'DEEPSEEK_API_KEY', 'OPENAI_API_KEY']);\n\n expect(process.exit).toHaveBeenCalledWith(1);\n });\n\n it('should work with empty required array', () => {\n expect(() => loadAndValidateEnv([])).not.toThrow();\n });\n\n it('should accept values with whitespace', () => {\n process.env.DATABASE_URL = ' postgresql://localhost:5432/test ';\n\n loadAndValidateEnv(['DATABASE_URL']);\n\n expect(process.exit).not.toHaveBeenCalled();\n });\n\n it('should treat empty string as missing', () => {\n process.env.DATABASE_URL = '';\n\n loadAndValidateEnv(['DATABASE_URL']);\n\n expect(process.exit).toHaveBeenCalledWith(1);\n });\n\n it('should treat whitespace-only as present (matches implementation)', () => {\n process.env.DATABASE_URL = ' ';\n\n loadAndValidateEnv(['DATABASE_URL']);\n\n // Current implementation accepts whitespace-only values\n expect(process.exit).not.toHaveBeenCalled();\n });\n\n it('should validate DATABASE_URL format when provided', () => {\n process.env.DATABASE_URL = 'postgresql://user:pass@localhost:5432/db';\n\n expect(() => loadAndValidateEnv(['DATABASE_URL'])).not.toThrow();\n });\n\n it('should allow postgresql:// URLs', () => {\n process.env.DATABASE_URL = 'postgresql://localhost:5432/test';\n\n expect(() => loadAndValidateEnv(['DATABASE_URL'])).not.toThrow();\n });\n\n it('should allow postgres:// URLs', () => {\n process.env.DATABASE_URL = 'postgres://localhost:5432/test';\n\n expect(() => loadAndValidateEnv(['DATABASE_URL'])).not.toThrow();\n });\n\n it('should work with file:// URLs for DATABASE_URL', () => {\n process.env.DATABASE_URL = 'file:./dev.db';\n\n expect(() => loadAndValidateEnv(['DATABASE_URL'])).not.toThrow();\n });\n\n it('should validate API keys', () => {\n process.env.DEEPSEEK_API_KEY = 'sk-1234567890abcdef';\n\n expect(() => loadAndValidateEnv(['DEEPSEEK_API_KEY'])).not.toThrow();\n });\n\n it('should handle missing optional vars gracefully', () => {\n process.env.DATABASE_URL = 'postgresql://localhost:5432/test';\n delete process.env.OPTIONAL_VAR;\n\n // Should not throw even if OPTIONAL_VAR is missing\n expect(() => loadAndValidateEnv(['DATABASE_URL'])).not.toThrow();\n });\n\n it('should validate in test mode', () => {\n process.env.NODE_ENV = 'test';\n delete process.env.DATABASE_URL;\n\n // Should not throw in test mode even without DATABASE_URL\n expect(() => loadAndValidateEnv([])).not.toThrow();\n });\n\n it('should validate in development mode', () => {\n process.env.NODE_ENV = 'development';\n process.env.DATABASE_URL = 'postgresql://localhost:5432/dev';\n\n expect(() => loadAndValidateEnv(['DATABASE_URL'])).not.toThrow();\n });\n\n it('should validate in production mode', () => {\n process.env.NODE_ENV = 'production';\n process.env.DATABASE_URL = 'postgresql://prod-server:5432/prod';\n process.env.DEEPSEEK_API_KEY = 'sk-prod-key';\n\n expect(() => loadAndValidateEnv(['DATABASE_URL', 'DEEPSEEK_API_KEY'])).not.toThrow();\n });\n });\n});\n"}}, ".github/pr/feature-env-validation.md": {"2b4d30cddcaab59e384dbc70dcb21a553349a5fd": {"t": 1786068539.249784, "n": 2755, "h": "2d65af0c267ac245", "c": "Title: chore(env): centralize env validation, add .env.example, and enforce fail-fast checks\n\nSummary\n-------\nThis change adds a centralized environment validator and wiring to the main entrypoints (API, bot, worker). It also\nprovides safe `.env.example` files (no real secrets), package-local shims for TypeScript compilation, and a small\nself-test script to validate environment variables locally and in CI.\n\nWhy\n---\n- Prevent accidental app startup with missing critical environment variables.\n- Avoid committing real secrets by providing placeholder examples and normalizing `.gitignore`.\n- Fail fast during development and CI with clear error messages for missing or malformed env vars.\n\nWhat changed\n------------\n- `scripts/validate-env.js` — runtime validator (loads `.env` and checks required keys; basic format checks for `PORT` and `REDIS_URL`).\n- `scripts/validate-env.ts` — TypeScript copy (kept for local dev reference).\n- `scripts/validate-env-selftest.js` — small runner to verify env locally or in CI.\n- `.env.example`, `worker/.env.example` — replaced literal example keys with placeholders.\n- `api/src/lib/validate-env.ts`, `bot/src/lib/validate-env.ts`, `worker/src/lib/validate-env.ts` — shims that re-export the runtime validator (keeps TypeScript rootDir safe).\n- Entrypoints updated:\n - `bot/src/index.ts` — validates `TELEGRAM_BOT_TOKEN` at startup.\n - `api/src/index.ts` — validates `PORT` and `REDIS_URL` at startup.\n - `worker/src/main.ts` — validates `POKEMON_TCG_API_KEY`, `PRICE_TRACKER_API_KEY`, `DEEPSEEK_API_KEY` at startup.\n- Normalized `.gitignore` to ensure `.env` is ignored.\n\nHow to test locally\n-------------------\n1. Create a local `.env` file in the repo root with the required keys (do not commit):\n\n PORT=3000\n REDIS_URL=redis://localhost:6379\n TELEGRAM_BOT_TOKEN=xxx\n POKEMON_TCG_API_KEY=xxx\n PRICE_TRACKER_API_KEY=xxx\n DEEPSEEK_API_KEY=xxx\n\n2. Run the env self-test:\n\n```bash\nnode ./scripts/validate-env-selftest.js\n```\n\nYou should see: \"✅ Env self-test passed\"\n\nCI\n--\nI originally added a GitHub Actions workflow to run the self-test on PRs but removed it from this branch because the push was blocked by token scope. Please add the workflow via the GitHub UI or with a token that has `workflow` scope when creating the PR.\n\nNotes\n-----\n- If you'd like a single shared TypeScript module rather than runtime `require` + shims, we can convert the validator into a workspace package and add types.\n- I recommend rotating any real keys if you discover they were previously committed.\n\nChecklist for reviewers\n----------------------\n- [ ] Confirm `.env.example` contains no real secrets\n- [ ] Run `node ./scripts/validate-env-selftest.js` locally\n- [ ] Review entrypoint wiring for early validation\n"}}}}