GitLab 仓库治理
一个 GitLab 项目能够 clone、push 和创建 Merge Request,不等于它已经适合团队协作。真正危险的空档通常藏在“看起来已经配置过”里面:默认分支虽然显示为 protected,Developer 却仍能直推;审批规则存在,新提交却保留旧审批;CODEOWNERS 写得很完整,却没有在目标分支启用 Code Owner approval;组级 Push Rules 改过,存量项目仍保持旧副本。
仓库治理的目标不是增加点击步骤,而是让一次代码变更只能沿着可解释的路径进入关键分支:身份可归属,变更先进入 MR,正确的人完成评审,规则在新提交后仍然有效,例外有时限和审计证据,最后还能用普通成员账号证明绕不过去。
治理后的变更路径还应当可以被普通成员账号反向证明:保护规则拒绝直推,机器身份不能借个人权限绕过,例外有时限和审计证据。GitLab.com、GitLab Self-Managed 和 GitLab Dedicated 共享这套协作模型,但具体按钮、套餐和 API 必须与目标 offering、tier 和实例版本对应。
先建立一个没有业务代码的测试项目,并准备两个独立测试身份:
maintainer:项目 Maintainer,负责配置规则和合并;developer:项目 Developer,负责创建分支、push 和提交 MR。
不要用管理员账号代替 Maintainer,也不要只用一个账号切换角色。管理员、Owner、继承自父组的高权限和显式允许的 deploy key 都可能改变结果;只有用普通 Developer 做负向测试,才能知道规则是否真的阻断日常成员。
本机需要 Git,并已经通过团队批准的 HTTPS 或 SSH 方式登录测试项目:
git --version
git config --show-origin --get user.name
git config --show-origin --get user.email
git remote -vuser.email 应对应测试身份的已验证邮箱或 GitLab 提供的私有提交邮箱。示例远端统一使用 https://gitlab.example.com/platform/repository-governance-lab.git,它只是占位地址。不要把真实 PAT、OAuth token、SSH 私钥、代理密码、内部域名或员工邮箱写进仓库、命令历史和文章。
开始前记录 GitLab 的 offering、tier 和版本。GitLab.com 由平台持续升级;Self-Managed 需要从管理员页面或受控接口确认实例版本。不同 tier 对 Approval Rules、Push Rules、组级策略、审计导出与流式审计的开放范围不同,不能把 Ultimate 的界面截图当作 Free 项目的默认能力。
仓库治理不要求在开发机额外安装 GitLab 客户端。它由 Git 客户端、GitLab Web/API 和服务端接收规则共同组成。第一次接入应先跑通没有复杂规则的 MR,分清“连接问题”和“规则问题”。
GitLab 的 Merge request approvals 文档区分了可选批准与强制门禁:Free 允许 Developer 及以上角色批准,但这种批准不会阻止未获批的合并;Required approvals 与 Code Owners 需要 Premium 或 Ultimate。Push Rules同样属于付费能力。采购判断不要绑定某个静态价格,应该按目标 offering、仓库数量、强制审批、审计与策略需求核对当前 tier;缺少能力时记录控制缺口,并决定用外部接收钩子、CI 检查还是迁移平台补偿。
Developer 克隆测试项目并创建功能分支:
git clone https://gitlab.example.com/platform/repository-governance-lab.git
cd repository-governance-lab
git switch -c feature/governance-smoke
printf "governance smoke test\n" > governance-smoke.txt
git add governance-smoke.txt
git commit -m "test: verify merge request path"
git push -u origin feature/governance-smoke预期远端创建功能分支,GitLab 页面可从该分支发起 MR,目标分支为 main。MR 描述至少写明目的、验证方式、风险和回退,不要只写“please review”。Maintainer 在变更页检查 diff 后合并,并删除源分支。Developer 随后验证:
git fetch --prune origin
git log --oneline --decorate -5 origin/main
git ls-remote --heads origin feature/governance-smoke应在 origin/main 看到合并结果,源分支查询为空或已按团队策略保留。若此时连普通 MR 都不能创建,先处理成员权限、目标分支、网络和凭证,不要急着叠加保护规则。
保护分支:把“建议走 MR”变成“只能走 MR”
进入项目 Settings > Repository > Branch rules,为 main 创建或编辑规则。面向关键分支的一套可解释基线是:
Allowed to merge:只给承担合并责任的 Maintainers,或给经过设计的 Developers + Maintainers;Allowed to push and merge:显式选择 No one;force push:关闭;
Code Owner approval:在已配置 CODEOWNERS 时开启;分支删除:保持保护,不通过临时取消保护完成日常操作。
最关键的是第二项。Allowed to push and merge 同时授予直推和通过 MR 合并的能力;把 Maintainers 放进去,会让他们绕开审批和 Code Owners。Protected branches当前说明该项未配置时默认无人可推,但治理基线仍应保存显式 No one,这样 API 比对、迁移和人工复核不必猜测实例历史默认值。
规则保存后,Developer 立即做负向验证:
git switch main
git pull --ff-only
printf "must be rejected\n" >> governance-smoke.txt
git add governance-smoke.txt
git commit -m "test: direct push must fail"
git push origin main成功标准是 push 被远端拒绝,错误信息指出 protected branch 或无权限。这个本地提交不要强行清掉整个工作区,可安全移到新分支继续走 MR:
git switch -c feature/protection-negative-test
git push -u origin feature/protection-negative-test如果 push 意外成功,先不要归咎于缓存。依次检查实际登录身份、父组继承角色、是否匹配另一条更宽松的通配规则、Allowed to push and merge 是否真的为 No one、deploy key 是否被允许写保护分支。重叠 branch rules 对 push/merge 权限可能采用更宽松结果,因此 main 与 m* 同时存在时必须把组合视为一个整体测试。
配置审批:新提交必须重新获得有效同意
在 Settings > Merge requests 的 approvals 区域建立规则,例如对 main 要求至少一名非作者评审者。高风险目录可由 Code Owners 追加责任人。治理重点不是审批人数越多越好,而是回答四个问题:
谁有资格审批,是否与作者、提交者和合并者形成必要分离;规则作用于所有 protected branches,还是只作用于特定目标分支;新 commit、rebase 或目标分支变化后,旧审批是否仍有效;
项目成员能否在单个 MR 中改掉默认 approver 或审批数量。
通常应保持“作者不能自批”,对敏感仓库再启用“添加过 commit 的用户不能审批”,并阻止单个 MR 覆盖默认审批规则。是否启用“新提交重置审批”要与团队节奏一起设计:完全重置最容易解释;选择性移除 Code Owner 审批能减少重复劳动,但要求团队清楚哪些文件变化会使哪类审批失效。
验证时,先让 MR 获得批准,再由 Developer 添加一个新提交:
git switch feature/protection-negative-test
printf "approval must be reevaluated\n" >> governance-smoke.txt
git add governance-smoke.txt
git commit -m "test: change after approval"
git push预期 MR 回到需要审批的状态,或至少移除受本次文件变化影响的 Code Owner 审批。若仍可立即合并,要检查 reset approvals on push、选择性 Code Owner removal、实例级审批策略和该 MR 是否被允许覆盖规则。自动化账号如果先批准再 push,也会遇到同样的重置;正确顺序是所有提交稳定后再申请审批,而不是关闭重置换取脚本方便。
用 CODEOWNERS 表达目录责任
CODEOWNERS 适合回答“这类文件由谁负责”,不适合替代成员权限、值班表或组织架构。把文件放在目标分支可识别的位置,并使用 GitLab 支持的用户或组:
# 默认兜底
* @platform/reviewers
# 身份与权限策略
/config/auth/ @platform/security-reviewers
# 数据结构变更
/database/migrations/ @platform/data-reviewers提交后,在 main 的 Branch rule 中开启 Require approval from code owners。仅有文件不会自动形成不可绕过的门禁;仅开启开关却没有可解析、可审批的 owner 也无法形成有效责任链。Code Owner 通常还要具备足够项目角色,组必须对项目可见,路径匹配必须用实际 MR 验证。
建议建立三个测试 MR:改普通文件、改单一 owner 目录、一次修改两个不同 owner 目录。预期审批要求分别体现兜底 owner、对应 owner 和两组责任。如果所有 MR 都只出现同一个人,检查规则顺序、路径斜杠、组可见性和目标分支中的 CODEOWNERS 版本。
不要为了“紧急方便”把 Code Owners 加入 Allowed to push and merge。获得直推权限的用户可以跳过 MR 审批;Code Owner 的价值恰恰在于评审某类变更,而不是拥有绕过该评审的通道。
用 Push Rules 管提交入口,但不要误当内容安全平台
Push Rules 在服务端接收阶段检查 push,可用于约束提交消息、分支名、作者邮箱、签名、文件名、单文件大小、tag 删除等。它比本地 hook 更难绕过,但仍有明确边界:
正则使用 RE2 语法,并受长度限制;不能照搬依赖回溯或环视的 PCRE;“Prevent pushing secret files”按预定义文件名模式阻断,不等于完整 secret scanning,也不能清除历史中已有密钥;最大文件大小对 Git LFS 跟踪对象有例外,不能替代 LFS 配额和对象完整性治理;
fork 同步存在绕过 fork 项目 Push Rules 的官方边界;全局和组级规则是新项目模板,存量项目不会自动跟随更新。
先在测试项目启用一条低风险、容易验证的规则,例如分支名必须以 feature/、fix/ 或 docs/ 开头;再创建 bad-branch-name 并 push。预期远端拒绝,同时 feature/push-rule-smoke 能成功。不要一上来同时启用邮箱、签名、提交消息和文件规则,否则第一次失败很难定位是哪条规则触发。
对身份校验要理解证据强度。“Reject unverified users”或作者邮箱匹配能发现误配,但不能提供密码学不可否认性;需要更强证据时再要求 signed commits,并单独治理签名密钥。机器人账号、项目 access token 或 group access token 产生的 bot 邮箱也要进入允许范围,不能为了让自动化恢复而把邮箱规则整体关闭。
组或实例模板更新后,应通过清单或 API 对存量项目做 drift 检查。看到新项目符合规则,只能证明模板当前有效,不能证明旧项目已同步。
分支合并权与生产部署权分开治理
允许 MR 合入 main 不应自动获得生产部署权。Protected environments通过 Allowed to deploy、approver 和环境级规则建立第二道身份边界,当前属于 Premium/Ultimate;CI/CD 被关闭时,受保护环境的 UI 与 API 也不可用。代码 owner 负责最终差异,Maintainer 负责仓库规则,运维或发布角色负责生产环境,三者不应默认由同一个大组承担。
先在测试项目创建 governance-staging 环境,把允许部署者限定为独立测试组,并配置一项部署批准。普通 Developer 能提交 MR、触发流水线,却不能自行批准或执行受保护部署;授权部署者批准后,部署才进入可执行状态。负向证据是 blocked deployment、403 或权限拒绝,正向证据是批准身份、部署 commit 与环境记录一致。
环境权限与分支权限会交叉影响停止、删除环境以及运行部署任务。GitLab 的权限说明还规定角色从多条成员关系取最高值,因此排障时要同时核对父组继承、项目角色、Allowed to deploy、批准组和触发者身份。实验结束后删除临时环境规则、测试变量和部署任务;真实 production 变量不得复制到练习环境。
最小验证不是截一张设置页,而是由不同身份完成四条黑盒路径。每条路径只改变一个变量,并保存远端结果、MR 状态和执行角色:
正常路径:Developer 向 feature/verify-normal push,创建目标为 main 的 MR;正确审批者批准后,由授权角色合并。预期功能分支可写、MR 可追踪、目标分支出现关联提交。直推负测:Developer 向 main push。预期远端拒绝;若成功,整套治理立即失效,先修保护规则再继续。责任人负测:MR 只修改一个受 CODEOWNERS 管理的测试路径。预期未获得对应 owner 批准前不可合并;普通目录不应凭空要求无关 owner。
陈旧审批负测:MR 获批后再修改同一受控文件并 push。预期审批按团队配置被重置或选择性移除,不能沿用未覆盖最终 diff 的同意。
若项目启用了 Push Rules,再增加一对单变量样例:合规分支名成功,违规分支名被拒绝。测试结束后删除功能分支、关闭未合并 MR、恢复临时测试成员;不要为了清理负测提交而 force push 真实分支。
实验必须在团队自己的 GitLab offering、tier 和版本上执行。预期结果只是判断基准,真正的证据应来自测试项目中的远端拒绝信息、MR 审批状态、命中规则和执行身份。
一个真实项目的接入顺序应让每一步都可验证、可回退:
盘点默认分支、现有角色、deploy keys、access tokens、已有 branch rules 和历史直推习惯。先建立 MR 模板和普通审批,观察一个迭代,不立即收紧所有路径。配置 main 的保护规则并用 Developer 做直推负测;保留紧急例外入口但默认关闭。
把敏感目录责任写进 CODEOWNERS,逐类验证匹配与审批资格。在测试项目验证 Push Rules,再分批复制到项目;对既有项目单独检查,不依赖模板追溯。记录当前 tier 无法提供的能力、替代控制、owner 与复审日期。
将成员、规则、例外、失败证据和清理结果纳入季度巡检。
仓库内可以提交 MR 描述模板、CODEOWNERS 和不含凭证的贡献说明;平台上的角色、Branch rules、Approval Rules、Push Rules 与审计导出配置不能只靠 README 记忆。团队应维护一份声明式期望清单,再通过受控 API 或人工双人复核比对实际状态。API token 只授予读取或必要管理 scope,放入凭证系统,不写进脚本参数和仓库。
日常开发者主要做四件事:从最新目标分支创建短期分支、push 后创建 MR、响应评审、在合并后清理分支。Maintainer 额外负责判断 MR 是否满足规则,而不是替作者修复分支或临时放开保护。
git fetch origin
git switch -c feature/<topic> origin/main
# 修改并本地验证
git push -u origin feature/<topic>评审者先看 MR 当前 diff、提交列表、审批状态、目标分支和 Code Owner 匹配,再看自动检查结果。网页显示“可合并”只代表当前平台条件满足,不代表业务风险已经被理解。合并后应验证目标分支 commit 与 MR 记录关联,并确认没有出现 merged manually。若 MR 被标记为手工合并,常见原因是有人在 GitLab UI 外把同一提交直接推入目标分支,首先复查直推权限。
紧急修复也应走短分支和 MR。确需绕过时,例外应包含事件号、批准人、开始与结束时间、允许对象、操作命令、审计证据和事后补审;结束后恢复规则并再次执行 Developer 直推负测。永久给 Maintainer 保留直推权不是应急方案,而是一条长期旁路。
网络代理与企业 CA
GitLab Web 可访问而 Git push 失败,通常是浏览器代理与 Git/SSH 链路不同。HTTPS 先查看配置来源:
git config --show-origin --get-regexp 'http\..*proxy|http\.proxy|http\.sslCAInfo'SSH 则使用受控诊断:
ssh -Tv git@gitlab.example.com诊断日志可能包含用户名、主机、密钥指纹和内部网络信息,只在受控渠道分享。企业 CA 应通过系统信任库或 http.sslCAInfo 配置,不要设置 http.sslVerify=false。代理凭证应由系统凭据库、Git Credential Manager、环境注入或 SSH agent 承载,不写入 remote URL。
人员凭证与机器凭证分离
个人 HTTPS 使用 OAuth/PAT 时只给当前任务所需 scope,设置到期时间并由凭据管理器保存;SSH 使用个人密钥和 agent。Personal access tokens当前要求 token 有到期日,默认最大生命周期与实例策略、版本功能相关,不能在团队规范里写死一个永久天数。项目 access token、group access token、deploy token 与 deploy key 是机器身份,不应共用个人账号,也不应默认获得保护分支写权限。
当自动化确需创建 MR、读取规则或推功能分支时,给它独立 bot 身份、最小角色和可轮换凭证。到期前演练轮换,到期后验证旧 token 失效。任何“为了自动化方便”而把机器人加入 Allowed to push and merge 的设计,都必须被视为审批旁路并经过更高级别审查。
Project access token轮换后旧 token 会立即失效,消费方未同步更新就会直接中断。稳妥顺序是先盘点调用者和 scope,在受控窗口轮换,更新凭证系统,执行一次只读与一次最小写操作,再确认旧 token 不可用。退出项目或关闭自动化时,不只删除流水线变量,还要撤销 token、deploy key 和 bot 成员,并检查最近使用时间与来源 IP 是否符合预期。
权限从哪里来
GitLab 权限可从项目直接成员、父组继承、共享组、自定义角色、管理员身份和某些 key/token 入口叠加。排查时不要只看项目 Members 页的一行角色;要确认父组和共享关系,并以实际身份测试。权限复核的目标是解释“为什么有权”,而不只是列出“谁在名单里”。
现象一:Developer 仍能直推 main
用 Developer 新建一个仅含测试文件的 commit,执行 git push origin main;同时记录远端实际身份和命中的 branch rules。
常见原因:Allowed to push and merge 授予 Developers/Maintainers;另一条通配规则更宽松;用户从父组继承更高角色;可写 deploy key 或 token 被用于 push。留空按当前平台默认应无人可推,若实际行为不同,应先核对实例版本、API 返回值和所有命中规则。
将所有命中 main 的规则一起审查,显式设为 No one,关闭 force push,回收多余角色和写 key。不要只删除其中一条规则后假定最严格规则会自动胜出。
Developer 直推被拒绝,功能分支 push 成功,MR 满足审批后可由授权角色合并。
现象二:改了敏感目录,却没有要求 Code Owner
确认 MR 目标分支受保护,查看目标分支中的 CODEOWNERS,用具体变更路径逐条匹配 owner。
常见原因:只提交了文件但未开启 Code Owner approval;规则路径不匹配;组对项目不可见;owner 角色不足;MR 目标分支使用了旧文件;直推权限让合并者绕开 MR。
修正规则和成员资格,在 Branch rule 开启要求,移除直推旁路。用一个目录一条变更的小 MR 验证,不要用大 MR 猜匹配结果。
普通目录和敏感目录显示不同审批要求;新增 commit 后受影响审批按策略失效。
现象三:组级 Push Rules 已更新,老项目仍接受旧格式
对比新建项目和存量项目的项目级 Push Rules;不要只看组设置页。
常见原因:把模板复制机制误解成实时继承。GitLab 会在项目创建时复制最近父组或实例模板,后续各项目是独立配置。
先在测试项目验证新规则,再使用项目 API 或受控脚本逐项目更新;批量写操作先导出旧值并准备回退。Self-Managed 的 Rails console 属于实例管理操作,不应由普通项目 Maintainer在生产直接执行。
抽取新旧项目分别做允许与拒绝样例,并将实际规则与期望清单比较。
现象四:MR 已获批,新 push 后仍显示可合并
确认新增 commit 是否真正进入该 MR,查看审批设置、选择性移除和规则覆盖权限。
常见原因:未启用新提交重置;只对 Code Owner 做选择性移除且修改未触及其文件;MR 可以覆盖默认规则;自动化顺序是先批准后提交。
根据风险选择完全重置或选择性重置,锁定规则覆盖,调整自动化顺序。不要通过增加一个形式审批人掩盖旧审批仍有效的问题。
批准 MR,追加目标文件修改并 push,确认对应审批失效后才能再次合并。
现象五:push 被拒绝,但页面没有清楚说明是哪条 Push Rule
保留完整远端错误,逐项检查提交消息、作者/提交者邮箱、签名、分支名、文件名和大小;用单变量测试复现。
常见原因:多条规则同时启用;RE2 正则与本地测试器语法不同;bot 邮箱不在允许范围;历史 commit 也被本次 push 带入检查。
在测试项目按一条规则一次启用,使用 RE2 兼容表达式,为 bot 明确设计允许模式。不要临时关闭所有规则后直接推生产分支。
准备一条应允许和一条应拒绝的样例,两者结果稳定且错误可被开发者理解。
架构取舍:项目规则、组模板还是实例策略
小团队只有少量仓库时,项目级规则最直观,例外也容易看见;代价是配置漂移和新仓库漏配。组级模板适合边界一致的产品线,但 Push Rules 的复制语义要求额外做存量同步。实例级策略适合 Self-Managed 的统一合规要求,影响面最大,变更前必须在代表性项目验证,并为历史仓库、机器人和导入任务准备兼容窗口。
治理强度也要分层。普通内部工具可以采用“禁止关键分支直推 + 一名独立审批者”;核心库可增加 Code Owners、新提交重置审批、签名提交和更严格 Push Rules;受监管仓库再考虑安全策略、流式审计和职责分离。不要给所有仓库堆同一套最重规则,否则团队会通过长期例外、共享账号或仓库外传文件来恢复速度,最终比轻量规则更不可控。
GitLab.com 减少实例运维并快速获得平台能力,但升级节奏和某些实例级控制由服务方管理;Self-Managed 提供版本窗口、网络与实例策略控制,同时增加升级、备份、审计存储和安全补丁责任;Dedicated 位于两者之间,具体控制面以合同和当前文档为准。仓库侧应保留选择标准,服务端生产架构、正式变更和故障接管则进入部署运维 SOP。
退出 GitLab 时先冻结写入口
git clone --mirror 只能迁移 Git 对象和 refs。Merge Request 的讨论与审批、成员继承、Protected Branch、Push Rules、CODEOWNERS 之外的审批规则、access token、deploy key、环境、审计事件、Issue 关联和 package/registry 元数据都需要单独导出或重建。迁移清单应为每类对象指定目标映射、owner、数量校验、敏感字段处理和无法迁移时的只读保留策略。
切换前先冻结成员和规则变更,完成代码与 LFS 对象镜像,再重建身份、保护规则、审批、机器人和部署权限。随后分别用 Developer、Maintainer 与机器身份跑直推失败、正常 MR、Code Owner、陈旧审批和受保护部署实验。旧平台保持只读,直到默认分支、tag、commit 数、MR/PR 关联和审计查询达到标准;两边同时开放写入会制造双主历史,出现后应停止切换,而不是依赖事后强制同步。
规则重叠会产生反直觉的“更宽松”结果
main、m*、* 同时存在时,不能凭视觉顺序判断最终 push/merge 权限。GitLab 对多条保护规则的权限组合与 Code Owner requirement 采用不同逻辑。上线前应为每个关键分支生成“命中规则集合”,用 Developer、Maintainer 和机器身份逐一做 push、force push、MR merge 负测。
机器人会迫使团队暴露真实边界
版本机器人、同步任务和仓库迁移经常需要写入。若设计默认依赖保护分支直推,开启治理后必然要求旁路。优先让机器人推普通分支并创建 MR;确需直接写入时,把权限限定到特定项目/分支/时间,使用独立身份和审计事件,并明确为何审批不适用。
审计日志不是无限可检索的数据仓库
GitLab Audit events当前说明事件长期保留,但“保留”不等于“容易检索”:项目与组页面受套餐、角色和筛选能力约束,API 单次起止时间最多相差 30 天,UI 也不支持对详情做任意文本搜索。事故发生后才发现无法按目标字段检索已经太迟。团队应提前定义必须留存的事件、时区、字段、导出频率、外部存储、访问权限和脱敏规则,并用一次规则变更演练从“操作”追到“人、时间、对象、前后状态”。Ultimate 的外部流式审计适合集中检索,但接收端仍要负责完整性、重试、去重和访问控制。
紧急旁路最容易永久化
临时取消保护或授予 Maintainer 直推,通常能立即解除阻塞,也最容易忘记恢复。例外必须有自动到期或明确结束动作;结束标准不是“代码已上线”,而是规则恢复、额外权限回收、Developer 负测重新失败、审计证据归档、事后 MR 或复核完成。
导入、镜像和 fork 同步并不天然服从同一入口
镜像、导入、fork synchronization、deploy key 和 API 修改各有不同执行身份与规则边界。迁移仓库前要分开验证“普通 Git push”“平台同步”“机器人 API”“管理员操作”,不能用其中一个成功代表其他入口也受控。尤其不要把 Push Rules 对普通 push 的结论外推到 fork 同步。
建议明确四类 owner:仓库 Owner 对业务和成员负责;治理 Owner 维护规则基线与例外;身份 Owner 管理组、SSO 和机器凭证;审计 Owner 负责事件留存与复核。Maintainer 是日常角色,不应自动兼任所有 owner。
每季度至少复核:成员及继承权限、长期未使用 access token/deploy key、关键分支规则、重叠通配符、审批覆盖、CODEOWNERS 无效 owner、Push Rules drift、管理员或旁路例外、审计可检索性。新增仓库应从已验证模板创建,但创建后仍运行一套黑盒验证,不能把模板存在当作配置已经生效。
平台升级前在测试组复演四条主路径:Developer 直推失败、普通分支 push 成功、敏感目录要求正确 owner、新提交使审批按策略失效。升级后重复同一组测试并比较审计事件。若套餐变化导致能力消失,先冻结治理降级,再决定替代控制或迁移,不能静默放宽。
清理测试项目
完成实验后,用 Maintainer 关闭未合并 MR、删除测试功能分支,再删除本地测试目录。不要删除共享组、全局 Push Rules 或真实默认分支。若测试中临时改了项目规则,先恢复原值并再次做负测。
git push origin --delete feature/protection-negative-test
cd ..
# 删除本地目录前确认它确实是本次独立测试仓库平台侧保留一份脱敏运行记录:项目标识、GitLab offering/tier/version、规则摘要、允许样例、拒绝样例、执行角色、时间和清理结果。不得保存 token、私钥、代理凭证或完整内部 URL。
已记录 GitLab offering、tier、版本与缺失能力,不混用 GitLab.com 和 Self-Managed 结论。main 等关键分支的 Allowed to push and merge 已显式设为 No one,force push 已关闭。已用普通 Developer 证明关键分支直推失败、普通分支 push 成功。
审批规则限制作者/提交者自批,并验证新提交后的审批状态。CODEOWNERS 位于目标分支、路径匹配正确、owner 可见且角色足够,Branch rule 已开启要求。Push Rules 已逐条做允许/拒绝实验,并确认 RE2、bot 邮箱、LFS 与 fork 同步边界。
已检查重叠 branch rules、父组继承、共享组、deploy key、access token 和管理员旁路。代理、企业 CA、HTTPS/SSH 凭证均使用安全存储,没有关闭 TLS 校验。组/实例模板与存量项目 drift 已有检查机制,没有假设模板自动追溯。
紧急例外有批准、时限、审计、恢复和再验证步骤。审计事件能回答谁在何时修改了成员或规则,并具备符合团队要求的导出与留存路径。测试 MR、分支和临时权限已清理,未改动真实业务历史。
