- CLAUDE.md 升版至 V11.0:整合 P7/P9/P10 工作模式、12 人專家團隊、 委派鐵律、三條紅線(保留狙擊手模式精神) - .claude/hooks/:新增 8 個 Hook(momo-prod-guard / commit-quality / large-file-warner / mcp-health / audit-log / suggest-compact / cost-tracker / session-summary) - .claude/agents/:新增 11 個 Agent 定義(critic / debugger / db-expert / vuln-verifier / fullstack-engineer / planner / refactor-specialist / migration-engineer / onboarder / tool-expert / web-researcher) - .claude/settings.json:啟用 bypassPermissions + Hook 自動政策架構 - .gitignore:加入 settings.local.json 防止 Secret 意外 commit Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
60 lines
2.2 KiB
JavaScript
60 lines
2.2 KiB
JavaScript
/**
|
|
* 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);
|
|
});
|