diff --git a/config/gitleaks.toml b/config/gitleaks.toml new file mode 100644 index 0000000..d4ca863 --- /dev/null +++ b/config/gitleaks.toml @@ -0,0 +1,43 @@ +# Gitleaks configuration file +# For more information, see https://github.com/gitleaks/gitleaks/blob/master/config/gitleaks.toml + +[allowlist] +description = "Global allowlist" +paths = [ + '''vendor/''', + '''node_modules/''', + '''\.env\.example$''', + '''\.env\.test$''', + '''go\.sum$''', + '''package-lock\.json$''', + '''\.next/''', + '''dist/''', + '''out/''', + '''build/''', + '''\.turbo/''', +] +stopwords = [ + "example", + "placeholder", + "test-password", +] + +[[rules]] +id = "generic-api-key" +description = "Generic API Key" +regex = '''(?i)(api_key|apikey|secret|password|token)[-|_| ]*[=|\:][-|_| ]*['|"]([0-9a-zA-Z]{16,128})['|"]''' +description_id = "potential_secret" +entropy = 3.5 +keywords = ["api_key", "apikey", "secret", "password", "token"] + +[[rules]] +id = "github-pat" +description = "GitHub Personal Access Token" +regex = '''ghp_[0-9a-zA-Z]{36}''' +keywords = ["ghp_"] + +[[rules]] +id = "google-oauth-client-secret" +description = "Google OAuth Client Secret" +regex = '''(?i)client_secret[-|_| ]*[=|\:][-|_| ]*['|"]([0-9a-zA-Z\-_]{24})['|"]''' +keywords = ["client_secret"] diff --git a/scripts/hooks/install-hooks.sh b/scripts/hooks/install-hooks.sh new file mode 100755 index 0000000..2fd4c6c --- /dev/null +++ b/scripts/hooks/install-hooks.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +# install-hooks.sh - Deploy Git hooks to the current repository + +HOOKS_DIR=$(git rev-parse --git-path hooks) +SOURCE_DIR="scripts/hooks" + +echo "Installing Git hooks to $HOOKS_DIR..." + +install_hook() { + local hook_name=$1 + if [ -f "$SOURCE_DIR/$hook_name" ]; then + cp "$SOURCE_DIR/$hook_name" "$HOOKS_DIR/$hook_name" + chmod +x "$HOOKS_DIR/$hook_name" + echo "✅ Installed $hook_name" + else + echo "❌ Hook $hook_name not found in $SOURCE_DIR" + fi +} + +install_hook "pre-commit" +install_hook "pre-push" + +echo "Done. Gitleaks integration is now active." diff --git a/scripts/hooks/pre-commit b/scripts/hooks/pre-commit new file mode 100755 index 0000000..d89baba --- /dev/null +++ b/scripts/hooks/pre-commit @@ -0,0 +1,3 @@ +#!/bin/bash +# Git pre-commit hook +./scripts/hooks/run-gitleaks.sh staged diff --git a/scripts/hooks/pre-push b/scripts/hooks/pre-push new file mode 100755 index 0000000..edc79bf --- /dev/null +++ b/scripts/hooks/pre-push @@ -0,0 +1,3 @@ +#!/bin/bash +# Git pre-push hook +./scripts/hooks/run-gitleaks.sh full diff --git a/scripts/hooks/run-gitleaks.sh b/scripts/hooks/run-gitleaks.sh new file mode 100755 index 0000000..88ef529 --- /dev/null +++ b/scripts/hooks/run-gitleaks.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +# run-gitleaks.sh - Wrapper for gitleaks detection modes +# Usage: ./run-gitleaks.sh [staged|full] + +MODE=${1:-staged} +GITLEAKS_BIN=${GITLEAKS_BIN:-gitleaks} +GITLEAKS_CONFIG=${GITLEAKS_CONFIG:-config/gitleaks.toml} +GITLEAKS_REPORT_DIR=${GITLEAKS_REPORT_DIR:-.git/gitleaks} +REPORT_PATH="$GITLEAKS_REPORT_DIR/report.json" + +# Check if gitleaks is installed +if ! command -v "$GITLEAKS_BIN" &> /dev/null; then + echo "Error: gitleaks is not installed or not in PATH." + echo "Install it from: https://github.com/gitleaks/gitleaks/releases" + exit 1 +fi + +# Create report directory +mkdir -p "$GITLEAKS_REPORT_DIR" + +if [ "$MODE" == "staged" ]; then + echo "Running Gitleaks protect on staged changes (respecting .gitignore)..." + # 'protect --staged' is the recommended way to scan staged changes + "$GITLEAKS_BIN" protect -v --staged --redact --config "$GITLEAKS_CONFIG" --report-path "$REPORT_PATH" + EXIT_CODE=$? +else + echo "Running full Gitleaks detection on commits..." + # 'detect' scans the git history (commits). In-progress worktree files + # that are .gitignored will NOT be scanned unless they were previously committed. + # To ignore specific files/folders always, use config/gitleaks.toml [allowlist] + "$GITLEAKS_BIN" detect -v --redact --config "$GITLEAKS_CONFIG" --report-path "$REPORT_PATH" + EXIT_CODE=$? +fi + +if [ $EXIT_CODE -ne 0 ]; then + echo "" + echo "⚠️ Potential secrets detected!" + echo "Report generated at: $REPORT_PATH" + echo "" + echo "Please review the findings and refer to the security playbook:" + echo "skills/git.secret-incident-response.v1.md" + exit $EXIT_CODE +else + echo "✅ No secrets detected." + # Clean up empty report + [ -f "$REPORT_PATH" ] && [ ! -s "$REPORT_PATH" ] && rm "$REPORT_PATH" + exit 0 +fi diff --git a/skills/git.commit-check.v1.md b/skills/git.commit-check.v1.md new file mode 100644 index 0000000..302b845 --- /dev/null +++ b/skills/git.commit-check.v1.md @@ -0,0 +1,73 @@ +# skill|git commit check (gitleaks) v1 +> 目标:在提交/推送前阻止 secrets 进入 git 历史。默认:本地 pre-commit 扫 staged;pre-push 全仓复检;CI 再复检一次。 + +## 适用范围 +- 所有代码仓库(尤其:Cloud Run / Vercel / infra / IaC) +- 所有会接触 token、证书、DB 账号、API Key 的变更 + +## 全局规则 +- 默认阻断提交:检测到疑似 secret => 退出码非 0 => commit/push 失败 +- 输出必须可操作:指出报告路径、下一步动作 +- 误报必须可控:只允许在 `gitleaks.toml` 做最小 allowlist(路径/regex) +- 误报放行必须由项目负责人审核,且永不把真实 secret 写进 allowlist(只 allow “确定无害”的模式) + +## 依赖 +- gitleaks v8+(必须支持 `detect --pipe`) +- bash / sh +- git + +## 安装/启用(仓库内) +1) 放置脚本(建议路径): +- `scripts/hooks/run-gitleaks.sh` +- `scripts/hooks/pre-commit` +- `scripts/hooks/pre-push` +- `scripts/hooks/install-hooks.sh` +- `config/gitleaks.toml` + +2) 一键安装 hooks: +```bash +bash scripts/hooks/install-hooks.sh +``` + +## Hook 行为设计 +### pre-commit(快) +只扫描 staged 变更(自动遵循 `.gitignore`,仅扫暂存区)。 +命令(参考): +```bash +gitleaks protect -v --staged --redact --config config/gitleaks.toml +``` + +### pre-push(稳) +推送前扫描历史 commits(兜底)。 +命令(参考): +```bash +gitleaks detect -v --redact --config config/gitleaks.toml +``` + +## 输出与报告 +- 报告目录:`.git/gitleaks/report.json` +- 发现泄露时输出: + - “Potential secrets detected” + - 报告路径 + - 处理动作(见 skills/git.secret-incident-response.v1.md) + +## 可配置项(环境变量) +- GITLEAKS_BIN:默认 gitleaks +- GITLEAKS_CONFIG:默认 config/gitleaks.toml +- GITLEAKS_REPORT_DIR:默认 .git/gitleaks +- GITLEAKS_MODE:staged|full + +## CI 复检(必须) +任何人都能绕过本地 hook,CI 必须复检: +```bash +gitleaks detect -v --redact --config config/gitleaks.toml +``` + +## 失败处理入口 +统一转交到:skills/git.secret-incident-response.v1.md + +## 验收标准 +✅ 提交包含假 key 时,commit 被阻止并生成 report.json +✅ 误报可通过 allowlist 精准放行 +✅ push 前全仓复检能挡住“漏网之鱼” +✅ CI 中同样会失败(防绕过) diff --git a/skills/git.conventional-commits.v1.md b/skills/git.conventional-commits.v1.md new file mode 100644 index 0000000..f43ef96 --- /dev/null +++ b/skills/git.conventional-commits.v1.md @@ -0,0 +1,54 @@ +# skill|conventional commits v1 +> 目标:统一 commit message 格式,提升可读性、自动化 changelog 生成、语义化版本管理。参考 Peter 的实践规范。 + +## 适用范围 +- 所有代码仓库 +- 所有团队成员的提交 + +## Commit Message 格式 +``` +(): + + + +