Files
store-scraper-bot/scripts/check-secret-leaks.js
T
tiennm99 797f040574 feat: Cloudflare Workers code port (deploy pending)
Refactors source to be Worker-shaped. No live deploy yet — sister deploy plan
runs Atlas provisioning + smoke later.

- wrangler.toml with nodejs_compat_v2, daily UTC 0 cron (= 7am Asia/Ho_Chi_Minh)
- package.json: drop node-telegram-bot-api, node-cron, dotenv, pino,
  pino-pretty; add wrangler devDep; bump to 0.2.0
- src/bot/telegram-api.js: raw fetch wrapper for Telegram Bot API
- src/bot/dispatch.js: per-message dispatcher extracted from polling loop
- src/repository/mongodb.js: memoized MongoClient per warm isolate, typed
  MongoUnavailable error, fast-fail timeouts
- src/repository/store.js: factory binding env once
- All 4 repositories converted to factory shape
- src/api/{apple,google}-scraper.js: take store instead of importing repos
- src/index.js: Worker entry exporting { fetch, scheduled }; webhook validates
  X-Telegram-Bot-Api-Secret-Token; ack-then-waitUntil pattern
- src/scheduler/scheduler.js: trimmed; runDailyCheck only (no node-cron)
- src/config.js, src/logger.js: env-driven, console.log JSON output
- scripts/register-webhook.js: setWebhook + setMyCommands; --dry-run supported
- scripts/check-secret-leaks.js: lint blocks console.log(env.<SECRET>)
- plans/260426-2015-cloudflare-worker-code-port: this code port plan
- plans/260426-2327-cloudflare-deploy-and-smoke: sister deploy plan

Validated via node --check on all 32 source files; lint clean. Real deploy
gates (bundle size, cold-start CPU) run in deploy plan.
2026-04-26 23:36:39 +07:00

42 lines
1.2 KiB
JavaScript

#!/usr/bin/env node
// Fails CI if any source file logs a secret via env.
// Pattern: console.{log,info,warn,error,debug}(... env.<SECRET> ...)
import { readdirSync, readFileSync, statSync } from 'node:fs';
import { join } from 'node:path';
const SECRETS = ['MONGODB_URI', 'TELEGRAM_BOT_TOKEN', 'TELEGRAM_WEBHOOK_SECRET', 'ADMIN_IDS'];
const ROOTS = ['src', 'scripts'];
function* walk(dir) {
let entries;
try {
entries = readdirSync(dir);
} catch {
return;
}
for (const entry of entries) {
const p = join(dir, entry);
const s = statSync(p);
if (s.isDirectory()) yield* walk(p);
else if (/\.(js|mjs|ts)$/.test(p)) yield p;
}
}
const violations = [];
for (const root of ROOTS) {
for (const file of walk(root)) {
const text = readFileSync(file, 'utf8');
for (const secret of SECRETS) {
const re = new RegExp(`console\\.(log|info|warn|error|debug)\\([^)]*\\benv\\.${secret}\\b`);
if (re.test(text)) violations.push({ file, secret });
}
}
}
if (violations.length > 0) {
console.error('Secret-leak violations:');
for (const v of violations) console.error(` ${v.file}: env.${v.secret} in console.*`);
process.exit(1);
}
console.log('check-secret-leaks: clean');