feat: add git security and commit standards skills and hooks
This commit is contained in:
parent
5bf93d1d3f
commit
27835a8259
43
config/gitleaks.toml
Normal file
43
config/gitleaks.toml
Normal file
@ -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"]
|
||||
24
scripts/hooks/install-hooks.sh
Executable file
24
scripts/hooks/install-hooks.sh
Executable file
@ -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."
|
||||
3
scripts/hooks/pre-commit
Executable file
3
scripts/hooks/pre-commit
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
# Git pre-commit hook
|
||||
./scripts/hooks/run-gitleaks.sh staged
|
||||
3
scripts/hooks/pre-push
Executable file
3
scripts/hooks/pre-push
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
# Git pre-push hook
|
||||
./scripts/hooks/run-gitleaks.sh full
|
||||
49
scripts/hooks/run-gitleaks.sh
Executable file
49
scripts/hooks/run-gitleaks.sh
Executable file
@ -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
|
||||
73
skills/git.commit-check.v1.md
Normal file
73
skills/git.commit-check.v1.md
Normal file
@ -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 中同样会失败(防绕过)
|
||||
54
skills/git.conventional-commits.v1.md
Normal file
54
skills/git.conventional-commits.v1.md
Normal file
@ -0,0 +1,54 @@
|
||||
# skill|conventional commits v1
|
||||
> 目标:统一 commit message 格式,提升可读性、自动化 changelog 生成、语义化版本管理。参考 Peter 的实践规范。
|
||||
|
||||
## 适用范围
|
||||
- 所有代码仓库
|
||||
- 所有团队成员的提交
|
||||
|
||||
## Commit Message 格式
|
||||
```
|
||||
<type>(<scope>): <subject>
|
||||
|
||||
<body>
|
||||
|
||||
<footer>
|
||||
```
|
||||
|
||||
### Type(必须)
|
||||
参考统计比例(Peter 的实践):
|
||||
- **fix**: 修复 bug(31%,最常用,对应 PATCH 版本)
|
||||
- **docs**: 仅文档变更(14%)
|
||||
- **feat**: 新功能(10%,对应 MINOR 版本)
|
||||
- **chore**: 构建过程或辅助工具的变动(9%)
|
||||
- **test**: 添加或修改测试(6%)
|
||||
- **refactor**: 代码重构(5%,既不修复 bug 也不添加功能)
|
||||
- **perf**: 性能优化
|
||||
- **style**: 代码格式调整(不影响代码含义的变更)
|
||||
- **ci**: CI 配置文件和脚本的变更
|
||||
- **revert**: 回滚之前的 commit
|
||||
|
||||
### Scope(可选)
|
||||
影响范围,例如:api, ui, auth, db, docs, iac, config
|
||||
|
||||
### Subject(必须)
|
||||
- 简短描述(50 字符以内)
|
||||
- 使用祈使句,现在时态
|
||||
- 首字母小写
|
||||
- 结尾不加句号
|
||||
|
||||
### Body(可选)
|
||||
- 详细描述变更的动机和实现细节
|
||||
|
||||
### Footer(可选)
|
||||
- BREAKING CHANGES:以 `BREAKING CHANGE:` 开头
|
||||
- Issue 引用:如 `Closes #123`
|
||||
|
||||
## 规则
|
||||
- 必须基于 `conventional-commits` 规范
|
||||
- 严禁模糊的描述(如 “update”, “fix”)
|
||||
- 大规模变更必须细化为多个原子提交
|
||||
|
||||
## 验收标准
|
||||
✅ 提交信息格式合规
|
||||
✅ CI/CD 流程能正确解析类型并触发对应流水线
|
||||
✅ 自动生成的 Changelog 结构清晰
|
||||
103
skills/git.secret-incident-response.v1.md
Normal file
103
skills/git.secret-incident-response.v1.md
Normal file
@ -0,0 +1,103 @@
|
||||
# skill|git secret incident response (auto-fix playbook) v1
|
||||
> 目标:当 gitleaks 发现泄露时,提供“自动止血 + 可回滚 + 可审计”的标准处理流程。
|
||||
> 原则:先撤销/轮换,再清理历史,最后加规则;不要反过来。
|
||||
|
||||
## 触发条件
|
||||
- 本地 hook / CI 中 `gitleaks detect` 失败
|
||||
- 或发现敏感信息已进入仓库(哪怕没有报警)
|
||||
|
||||
## 输入
|
||||
- gitleaks 报告:`.git/gitleaks/report.json`(或 CI artifact)
|
||||
- 泄露类型:API key / token / 私钥 / DB 密码 / 证书
|
||||
- 泄露范围:仅未提交(staged) / 已提交 but 未推送 / 已推送到远端
|
||||
|
||||
## 全局规则(强制)
|
||||
- 任何真实 secret 一律视为已泄露:必须 rotate/revoke
|
||||
- 不允许“先 allowlist 让它过”来掩盖问题
|
||||
- 清理历史是最后手段,但一旦推送过就必须执行
|
||||
|
||||
---
|
||||
|
||||
## 处理流程(按优先级执行)
|
||||
|
||||
### Step 0:立即止血(30 秒内)
|
||||
1) 取消暂存/撤回改动(避免误提交):
|
||||
```bash
|
||||
git restore --staged .
|
||||
```
|
||||
|
||||
2) 在本地删除/替换泄露内容(改为读取 Secret Manager / env / vault)
|
||||
|
||||
3) 重新 staged 后再跑 gitleaks(确保干净):
|
||||
```bash
|
||||
git add -A
|
||||
git diff --cached -U0 | gitleaks detect -v --no-git --pipe --redact --config config/gitleaks.toml
|
||||
```
|
||||
|
||||
### Step 1:撤销/轮换密钥(必须)
|
||||
根据类型选择动作(示例):
|
||||
- GitHub token:revoke + 重新生成
|
||||
- GCP SA key:禁用/删除 key,改用 Workload Identity(如可)
|
||||
- DB 密码:立即改密码 + 强制最小权限 + 限制来源 IP
|
||||
- TLS 私钥:重新签发证书
|
||||
|
||||
产物:记录 “rotated_at / rotated_by / secret_id / scope”。
|
||||
|
||||
### Step 2:判断是否进入 git 历史(分支决策)
|
||||
情况 A:仅 staged / 未 commit
|
||||
- 不需要清理历史,只需修复内容 + rotate 即可
|
||||
|
||||
情况 B:已 commit 但未 push
|
||||
- 可以用 reset/squash 直接抹掉 commit:
|
||||
```bash
|
||||
git reset --soft HEAD~1
|
||||
# 删除泄露内容后重新 commit
|
||||
```
|
||||
仍需 rotate(因为本地也可能被复制、日志、shell history 等)
|
||||
|
||||
情况 C:已 push 到远端(高危)
|
||||
- 必须清理历史:推荐 git filter-repo(比 filter-branch 稳、快)
|
||||
- 删除文件:
|
||||
```bash
|
||||
git filter-repo --path path/to/leaked.file --invert-paths
|
||||
```
|
||||
- 或按文本替换(需要准备 replacement rules):
|
||||
```bash
|
||||
git filter-repo --replace-text replacements.txt
|
||||
```
|
||||
- 强制推送并通知协作者重拉:
|
||||
```bash
|
||||
git push --force --all
|
||||
git push --force --tags
|
||||
```
|
||||
|
||||
注意:即便清理了 git 历史,也必须 rotate,因为泄露已经发生。
|
||||
|
||||
### Step 3:误报处理(允许,但必须最小化)
|
||||
仅当你确认它不是 secret(例如测试样例、公开字符串):
|
||||
1) 在 config/gitleaks.toml 里加 allowlist(最小范围)
|
||||
2) 优先 path allowlist
|
||||
3) 其次 regex allowlist(要尽量具体)
|
||||
4) 重新运行 gitleaks 验证通过
|
||||
|
||||
### Step 4:加固(防再犯)
|
||||
- CI 中强制 gitleaks(不可跳过)
|
||||
- 将 secrets 全部迁移到 Secret Manager(或 Vault)
|
||||
- 禁止在 docs/example 中出现真实 key(用 EXAMPLE_ 前缀)
|
||||
|
||||
## 自动化脚本建议(可选增强)
|
||||
你可以在仓库提供一个统一入口脚本:
|
||||
`scripts/security/secret-incident.sh`
|
||||
|
||||
功能:
|
||||
- 自动打开 report.json
|
||||
- 提示泄露文件/规则
|
||||
- 输出对应处理命令模板(reset/filter-repo/allowlist)
|
||||
- 生成一份 incident 记录(markdown)
|
||||
|
||||
## 验收标准
|
||||
✅ 泄露发生时:提交/CI 必然失败
|
||||
✅ 30 秒内可止血:撤回 staged 并定位报告
|
||||
✅ 轮换动作有记录
|
||||
✅ 已 push 泄露:历史清理可复现且协作指引明确
|
||||
✅ 误报 allowlist 不扩大攻击面
|
||||
Loading…
Reference in New Issue
Block a user