Files
zhuangang/topics/devops/git/scenarios/hotfix-and-leaked-secret.md

90 lines
4.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
id: devops.git.scenario.hotfix-and-leaked-secret
title: 线上紧急修复和密钥误提交:热修复分支、cherry-pick、清理历史和轮换密钥
type: scenario
domain: devops
stack: [git, cicd]
tags: [热修复, cherry-pick, 密钥泄露, 历史清理, 安全]
level: intermediate
prerequisites: [devops.git.merge-rebase-recovery]
est_hours: 1.5
related: [devops.git.interview, devops.cicd.pipeline]
week: [8, 15]
---
# 线上紧急修复和密钥误提交:热修复分支、cherry-pick、清理历史和轮换密钥
## 业务背景与问题
团队按“release 分支发版”的方式工作:`main` 上已经合入了下个版本的多个功能(未测试完),线上运行的是 `release/1.4`。周五下午出现两件事:
1. 线上 1.4 版本有一个金额计算的 bug,需要马上修复,但不能把 main 上未测试的功能带上线。
2. 有同事把含有大模型 API Key 的 `.env` 文件提交并推送到了远程仓库。
## 约束
- 热修复要在一小时内上线,而且下个版本也必须包含这个修复。
- 仓库在公司内部平台上,有十几个人已经拉取过包含密钥的提交。
## 方案设计
**热修复**
1. 从线上版本的标签 / release 分支创建 `hotfix/amount-rounding`;
2. 修复 + 补测试,走合并请求和 CI,合入 `release/1.4`,打标签 `v1.4.1` 发布;
3. 把修复提交 `cherry-pick` 到 main(或从 release 合并回 main),保证下个版本不会“复活”这个 bug。
**密钥泄露**——顺序很重要:
1. **第一时间轮换密钥**:在模型服务商控制台作废旧 Key、生成新 Key,并更新部署环境的密钥配置。只要密钥进过远程仓库,就必须当作已经泄露,**清理历史不能代替轮换**。
2. 检查旧 Key 的调用记录,确认是否有异常使用。
3. 删除文件并加入 `.gitignore`;提供 `.env.example`。
4. 评估是否需要清理历史:用 `git filter-repo` 从所有历史中移除文件,强制推送,通知所有人重新克隆;托管平台上的缓存、合并请求、fork 中可能仍有副本,需要联系平台管理员。
5. 预防:提交前钩子扫描密钥(本仓库的 `tools/check_sensitive.py`),CI 中也执行密钥扫描。
## 关键代码
```bash
# 热修复
git switch -c hotfix/amount-rounding v1.4.0
# ……修改代码、补测试……
git commit -am "fix(order): 金额四舍五入改为银行家舍入前先转换为分"
# 合并请求合入 release/1.4 后打标签
git tag -a v1.4.1 -m "热修复:金额计算"
git push origin v1.4.1
# 带回 main
git switch main && git cherry-pick <修复提交哈希>
# 密钥:先轮换!然后再处理仓库
git rm --cached .env
echo ".env" >> .gitignore
git commit -m "chore: 移除误提交的 .env,并忽略该文件"
# 需要清理历史时(会改写所有提交哈希,需要团队协调):
git filter-repo --path .env --invert-paths
git push --force --all && git push --force --tags
```
`git filter-repo` 需要单独安装,用法以官方说明为准:https://github.com/newren/git-filter-repo 。在临时仓库里练习 cherry-pick、revert、reflog 的脚本见 [examples/git-lab](../examples/git-lab/)。
## 取舍
| 做法 | 优点 | 缺点 |
| --- | --- | --- |
| **只轮换密钥 + 删除文件** | 快、不影响团队 | 旧密钥仍留在历史里(已作废,风险可控) |
| 轮换 + 清理历史 | 历史中不再有密钥 | 所有提交哈希改变,所有人要重新克隆;平台副本仍需单独处理 |
| 只清理历史不轮换 | —— | **错误做法**:密钥可能已被复制 |
热修复用 cherry-pick 还是“release 合并回 main”:cherry-pick 精确,只带修复;合并回 main 能保证 release 上所有改动都回到 main,但可能带来冲突。团队约定一种即可。
## 易错点
- 热修复只改了 release 分支,忘了带回 main:下个版本 bug 又出现。
- 从 main 拉热修复分支:把未测试的功能带上线。
- 以为“删除文件再提交一次”密钥就安全了:历史里仍然有。
- 先花半天清理历史再轮换密钥:轮换应该是第一步。
- 强制推送清理后的历史却没通知团队:有人基于旧历史推送,又把文件带回来。
## 面试怎么讲
> “线上版本出 bug 时,我从线上的标签拉热修复分支,修复并补测试后合入 release 分支打补丁版本发布,再 cherry-pick 回 main,避免把 main 上未测试的功能带上线。还处理过密钥误提交:第一步是作废并轮换密钥,检查调用记录;然后删除文件、加入 .gitignore,加上提交前的密钥扫描。是否清理历史要评估成本,清理时用 filter-repo 并通知团队重新克隆。”