/** * commit-quality.js — PreToolUse Hook * 阻擋 debugger 語句 + 硬編碼 Secret 進入 commit。 * 已針對 momo 環境加入 Telegram/Gemini/Gitea/Anthropic pattern。 */ const { spawnSync } = require('child_process'); let d = ''; process.stdin.on('data', c => d += c); process.stdin.on('end', () => { try { const i = JSON.parse(d); const cmd = i.tool_input?.command || ''; if (!/git commit/.test(cmd) || /--amend/.test(cmd)) { process.stdout.write(d); return; } const r = spawnSync('git', ['diff', '--cached', '--name-only', '--diff-filter=ACMR'], { encoding: 'utf8' }); const files = (r.stdout || '').trim().split('\n').filter(Boolean); let blocked = false; for (const f of files) { if (!/\.(js|jsx|ts|tsx|py|sh|json|yaml|yml)$/.test(f)) continue; const cr = spawnSync('git', ['show', ':' + f], { encoding: 'utf8' }); const c = cr.stdout || ''; if (/\.(js|jsx|ts|tsx)$/.test(f) && /\bdebugger\b/.test(c)) { process.stderr.write(`[commit-quality] ERROR: debugger statement in ${f}\n`); blocked = true; } const secrets = [ // 通用 API Keys [/sk-[a-zA-Z0-9]{20,}/, 'OpenAI API Key'], [/ghp_[a-zA-Z0-9]{36}/, 'GitHub PAT'], [/AKIA[A-Z0-9]{16}/, 'AWS Access Key'], [/AIza[a-zA-Z0-9_-]{35}/, 'Google API Key'], // momo 專屬 [/\d{8,12}:[A-Za-z0-9_-]{35}/, 'Telegram Bot Token'], [/TELEGRAM[_\s]*(?:BOT[_\s]*)?TOKEN\s*=\s*["']?[^\s"']{20,}/, 'Telegram Token 環境變數'], [/GEMINI_API_KEY\s*=\s*["']?[A-Za-z0-9_-]{20,}/, 'Gemini API Key'], [/sk-ant-api[0-9a-zA-Z_-]{20,}/, 'Anthropic API Key'], [/glpat-[a-zA-Z0-9_-]{20}/, 'Gitea/GitLab PAT'], [/GITEA[_\s]*TOKEN\s*=\s*["']?[^\s"']{20,}/, 'Gitea Token 環境變數'], ]; for (const [pattern, label] of secrets) { if (pattern.test(c)) { process.stderr.write(`[commit-quality] ERROR: 偵測到 ${label} in ${f}\n`); blocked = true; } } } if (blocked) { process.stderr.write('[commit-quality] Commit 已阻擋。請移除上述敏感資訊後重試。\n'); process.exit(2); } } catch (e) {} process.stdout.write(d); });