Git 钩子脚本可以通过以下几种方式检查和强制执行证书策略(例如签名要求、证书有效性等):

检查提交签名 (GPG 签名)
pre-receive 钩子 (服务端)
#!/bin/bash
# 检查所有推送的提交是否有有效 GPG 签名
while read oldrev newrev refname; do
# 获取所有新提交的 SHA
commits=$(git rev-list $oldrev..$newrev 2>/dev/null)
for commit in $commits; do
# 检查签名
if ! git verify-commit $commit 2>/dev/null; then
echo "错误: 提交 $commit 没有有效的 GPG 签名"
exit 1
fi
# 可选:检查签名者是否在允许列表中
signer=$(git log --format='%GG' $commit -1)
if [[ ! "$signer" =~ "authorized@company.com" ]]; then
echo "错误: 提交 $commit 的签名者未授权"
exit 1
fi
done
done
commit-msg 钩子 (客户端 - 使用 commit --signoff)
#!/bin/bash
# 检查 commit 消息是否包含 Signed-off-by
if ! grep -q "^Signed-off-by:" "$1"; then
echo "错误: 提交必须包含 Signed-off-by 行"
echo "请使用 git commit -s 重新提交"
exit 1
fi
检查 SSH 证书策略
pre-receive 钩子 (服务端)
#!/bin/bash
# 检查 SSH 证书是否有效
while read oldrev newrev refname; do
# 获取推送者的 SSH 公钥指纹
push_user=$(git log -1 --format='%ae' $newrev)
# 检查 SSH 证书是否在授权列表中
if ! grep -q "$push_user" /etc/git/authorized_users; then
echo "错误: 用户 $push_user 未授权"
exit 1
fi
done
检查提交者邮箱与证书匹配
pre-receive 钩子
#!/bin/bash
# 验证提交者身份
while read oldrev newrev refname; do
committer_email=$(git log -1 --format='%ce' $newrev)
author_email=$(git log -1 --format='%ae' $newrev)
# 获取推送者的证书信息
user_cert=$(ssh-keygen -L -f ~/.ssh/id_rsa.pub 2>/dev/null)
if [[ ! "$user_cert" =~ "$committer_email" ]]; then
echo "错误: 提交者 $committer_email 与证书不匹配"
exit 1
fi
done
检查 TLS/HTTPS 证书
update 钩子 (针对 webhook 或远程仓库)
#!/bin/bash
# 检查仓库 URL 的 TLS 证书
remote_url=$(git config --get remote.origin.url)
if [[ "$remote_url" =~ ^https:// ]]; then
# 使用 openssl 检查证书
host=$(echo $remote_url | sed 's|https://\([^/]*\).*|\1|')
port=443
if ! openssl s_client -connect $host:$port -servername $host </dev/null 2>/dev/null | grep -q "Verify return code: 0"; then
echo "错误: 仓库的 TLS 证书无效或已过期"
exit 1
fi
fi
综合策略检查脚本
完整的 pre-receive 钩子示例
#!/bin/bash
# 综合证书策略检查
POLICY_FAILURE=false
# 配置
SIGNED_COMMIT_REQUIRED=true
ALLOWED_SIGNERS=("authorized@company.com")
CERT_EXPIRY_DAYS=30
while read oldrev newrev refname; do
if [ "$SIGNED_COMMIT_REQUIRED" = true ]; then
# 检查签名
for commit in $(git rev-list $oldrev..$newrev); do
if ! git verify-commit $commit 2>/dev/null; then
echo "❌ 提交 $commit 缺少有效的 GPG 签名"
POLICY_FAILURE=true
fi
# 检查签名者
signer_key=$(git log --format='%GK' $commit -1)
signer_email=$(git log --format='%ae' $commit -1)
if [[ ! " ${ALLOWED_SIGNERS[@]} " =~ " $signer_email " ]]; then
echo "❌ 提交 $commit 的签名者 $signer_email 未授权"
POLICY_FAILURE=true
fi
# 检查证书有效期
if git log --format='%G?' $commit -1 | grep -q "E"; then
echo "❌ 提交 $commit 的证书已过期"
POLICY_FAILURE=true
fi
done
fi
done
if [ "$POLICY_FAILURE" = true ]; then
echo ""
echo "❌ 推送被拒绝,违反证书策略"
exit 1
fi
echo "✅ 所有证书策略检查通过"
exit 0
部署和测试建议
-
设置钩子权限:
chmod +x .git/hooks/pre-receive
-
测试脚本:
# 测试签名检查 git tag v1.0 -s -m "测试签名"
测试推送被拒绝的场景
git push origin main
3. **日志记录**:
```bash
# 在钩子中添加日志
echo "$(date): 用户 $USER 推送被拒绝" >> /var/log/git-hooks.log
- 服务端部署:
- 将钩子放到
hooks/目录 - 确保
git用户有执行权限 - 考虑使用
gitolite或gitea等工具管理
这些脚本可以根据实际需求组合使用,确保仓库的提交符合组织的安全策略。