合并请求审批策略
- 层级:Ultimate
- 提供方式:GitLab.com、GitLab 自托管、GitLab 专用
扫描结果策略功能在 GitLab 16.9 中更名为合并请求审批策略。
您可以使用合并请求审批策略实现多种目的,包括:
- 检测安全与许可证扫描器的结果以执行审批规则。例如,一种类型的合并请求策略是安全审批策略,该策略允许根据一个或多个安全扫描作业的结果要求进行审批。合并请求审批策略会在 CI 扫描作业完全执行后进行评估,并且漏洞和许可证类型策略会基于已发布于完成流水线中的作业工件报告进行评估。
- 对满足特定条件的所有合并请求强制执行审批规则。例如,强制要求针对默认分支的所有合并请求由具有开发者(Developer)和维护者(Maintainer)角色的多个用户进行审查。
- 在项目中强制执行安全和合规设置。例如,防止对合并请求进行了作者或提交更改的用户批准该合并请求。或者防止用户向默认分支推送或强制推送,以确保所有更改都通过合并请求进行。
当创建或删除受保护分支时,策略审批规则会同步,延迟时间为 1 分钟。
以下视频为您概述 GitLab 合并请求审批策略(以前称为扫描结果策略):
限制
- 您只能在 受保护 目标分支上强制执行合并请求审批策略。
- 您可以为每个策略最多分配五个规则。
- 您可以为每个安全策略项目最多分配五个合并请求审批策略。
- 为组或子组创建的策略可能需要一些时间才能应用于该组中的所有合并请求。所需时间取决于项目数量以及这些项目中的合并请求数量。通常,所需时间是几秒钟。对于拥有数千个项目和合并请求的组,根据我们之前的观察,这可能需要几分钟。
- 合并请求审批策略不会检查工件报告中生成的扫描结果的完整性或真实性。
- 合并请求审批策略会根据其规则进行评估。默认情况下,如果规则无效或无法评估,则需要审批。您可以通过
fallback_behavior字段 更改此行为。
流水线要求
合并请求的审批策略会依据流水线的执行结果来强制执行。在实施合并请求审批策略时,请考虑以下几点:
- 合并请求审批策略会评估已完成流水线作业的结果,忽略手动作业。当手动作业运行时,该策略会重新评估合并请求的作业。
- 对于评估安全扫描器结果的合并请求审批策略,所有指定的扫描器都必须输出安全报告。如果没有,则会强制执行审批以最小化引入漏洞的风险。这种行为可能影响到:
- 尚未建立安全扫描的新项目。
- 在安全扫描配置之前创建的分支。
- 分支间扫描器配置不一致的项目。
- 流水线必须为所有启用的扫描器生成制品,无论是源分支还是目标分支。如果没有,则缺乏比较的基础,因此无法评估该策略。你应该使用扫描执行策略来强制执行此要求。
- 策略评估依赖于成功且完成的合并基线流水线。如果合并基线流水线被跳过,那么带有合并基线流水线的合并请求会被阻塞。
- 策略中指定的安全扫描器必须在强制执行该策略的项目中进行配置和启用。如果没有,则无法评估合并请求审批策略,并且需要相应的审批。
结合合并请求审批策略使用安全扫描器的最佳实践
当你创建新项目时,可以在该项目上同时强制执行合并请求审批策略和安全扫描。然而,配置错误的安全扫描器可能会影响合并请求审批策略。
在新项目中配置安全扫描有多种方式:
- 在项目的CI/CD配置中,通过向初始
.gitlab-ci.yml配置文件添加扫描器来实现。 - 通过扫描执行策略来强制流水线运行特定的安全扫描器。
- 通过流水线执行策略来控制哪些作业必须在流水线中运行。
对于简单的用例,你可以使用项目的CI/CD配置。对于全面的安全策略,考虑将合并请求审批策略与其他策略类型相结合。
为了减少不必要的审批需求并确保准确的安全评估:
- 先在默认分支上运行安全扫描:在创建特性分支之前,确保安全扫描已在默认分支上成功运行。
- 使用一致的扫描器配置:在源分支和目标分支中使用相同的扫描器,最好是在单个流水线中。
- 验证扫描是否生成制品:确保扫描成功完成并生成用于比较的制品。
- 保持分支同步:定期将默认分支的更改合并到特性分支中。
- 考虑流水线配置:对于新项目,在初始
.gitlab-ci.yml配置中包含安全扫描器。
在应用合并请求审批策略前验证安全扫描器
通过在新项目中实现安全扫描后再应用合并请求审批策略,你可以确保在依赖合并请求审批策略之前安全扫描器能够持续运行,这有助于避免因缺少安全扫描而导致合并请求被阻塞的情况。
若要一起创建和验证安全扫描器及合并请求审批策略,请遵循以下推荐工作流程:
- 创建项目。
- 使用
.gitlab-ci.yml配置、扫描执行策略或流水线执行策略来配置安全扫描器。 - 等待默认分支上的初始流水线完成。解决任何问题并重新运行流水线,确保其成功完成后再继续。
- 使用配置了相同安全扫描器的特性分支创建合并请求。同样,确保安全扫描器成功完成。
- 应用你的合并请求审批策略。
包含多个流水线的合并请求
一个项目可以配置多种流水线类型。单个提交可能触发多个流水线,每个流水线都可能包含安全扫描。
- 在 GitLab 16.3 及更高版本中,会评估合并请求源分支和目标分支最新提交的所有已完成流水线的结果,并用于执行合并请求审批策略。按需 DAST 流水线不被考虑。
- 在 GitLab 16.2 及更早版本中,执行合并请求审批策略时仅评估最新完成的流水线结果。
如果项目使用 合并请求流水线,你必须将 CI/CD 变量 AST_ENABLE_MR_PIPELINES 设置为 "true",才能让安全扫描作业出现在流水线中。更多信息请参见 将安全扫描工具与合并请求流水线配合使用。
对于许多流水线已在最新提交上运行的的项目(例如休眠项目),策略评估最多考虑合并请求源分支和目标分支各 1000 个流水线。
对于父级子级流水线,策略评估最多考虑 1000 个子流水线。
合并请求审批策略编辑器
只有项目的 Owner 拥有选择安全策略项目的 权限。
完成策略后,通过点击编辑器底部的 通过合并请求配置 来保存。这将重定向到项目配置的安全策略项目的合并请求。如果没有安全策略项目链接到你的项目,GitLab 会为你创建这样的项目。现有策略也可以从编辑器界面删除,方法是点击编辑器底部的 删除策略。
大多数策略变更会在合并请求合并后立即生效。任何不通过合并请求直接提交到默认分支的变更,可能需要长达 10 分钟才能使策略变更生效。
策略编辑器 支持 YAML 模式和规则模式。
为具有大量项目的组创建的合并请求审批策略传播需要一段时间才能完成。
合并请求审批策略架构
包含合并请求审批策略架构对象的数组,嵌套在 approval_policy 键下。你可以在 approval_policy 键下配置最多五个策略。
合并请求审批策略最初定义在 scan_result_policy 键下。直到 GitLab 17.0,策略可以在这两个键下定义。从 GitLab 17.0 开始,仅支持 approval_policy 键。
当你保存新策略时,GitLab 会根据 此 JSON 架构 验证其内容。如果你不熟悉如何阅读 JSON 架构,以下章节和表格提供了替代方案。
| 字段 | 类型 | 必需 | 描述 |
|---|---|---|---|
approval_policy |
合并请求审批策略对象的数组 | 是 | 合并请求审批策略列表(最多 5 个)。 |
## 合并请求审批策略模式
| 字段 | 类型 | 必填 | 可能值 | 描述 |
|--------------------|--------------------|------|----------------|----------------------------------------------------------------------|
| `name` | `string` | 是 | | 策略名称。最大长度为 255 个字符。 |
| `description` | `string` | 否 | | 策略描述。 |
| `enabled` | `boolean` | 是 | `true`, `false` | 启用(`true`)或禁用(`false`)该策略的标志。 |
| `rules` | 规则数组 | 是 | | 该策略适用的规则列表。 |
| `actions` | 操作数组 | 否 | | 该策略执行的操作列表。 |
| `approval_settings`| 对象 | 否 | | 该策略覆盖的项目设置。 |
| `fallback_behavior`| 对象 | 否 | | 影响无效或不强制规则的设置。 |
| `policy_scope` | [`policy_scope`](../_index.md#配置策略范围) 对象 | 否 | | 根据你指定的项目、组或合规框架标签定义策略的范围。 |
| `policy_tuning` | 对象 | 否 | | (实验性)影响策略比较逻辑的设置。 |
| `bypass_settings` | 对象 | 否 | | 影响何时某些分支、令牌或账户可绕过策略的设置。 |## `scan_finding` 规则类型
此规则根据安全扫描结果执行定义的操作。
| Field | Type | Required | Possible values | Description |
|----------------------------|---------------------|--------------------------------------------|--------------------------------------------------------------------------------------------------------------------|-------------|
| `type` | `string` | true | `scan_finding` | 规则的类型。 |
| `branches` | `array` of `string` | true if `branch_type` field does not exist | `[]` 或 分支名称 | 仅适用于受保护的分支。空数组 `[]` 表示该规则适用于所有受保护的分支。不能与 `branch_type` 字段一起使用。 |
| `branch_type` | `string` | true if `branches` field does not exist | `default` 或 `protected` | 该策略适用的受保护分支类型。不能与 `branches` 字段一起使用。默认分支也必须处于受保护状态。 |
| `branch_exceptions` | `array` of `string` | false | 分支名称 | 要从该规则中排除的分支。 |
| `scanners` | `array` of `string` | true | `[]` 或 `sast`、`secret_detection`、`dependency_scanning`、`container_scanning`、`dast`、`coverage_fuzzing`、`api_fuzzing` | 此规则需考虑的安全扫描器。`sast` 包含 SAST 和 SAST IaC 扫描器的结果。空数组 `[]` 表示该规则适用于所有安全扫描器。 |
| `vulnerabilities_allowed` | `integer` | true | 大于或等于零 | 允许存在的漏洞数量,超过此数量后该规则将被触发。 |
| `severity_levels` | `array` of `string` | true | `info`、`unknown`、`low`、`medium`、`high`、`critical` | 此规则需考虑的严重性级别。 || vulnerability_states | array of string | true | [] or detected, confirmed, resolved, dismissed, new_needs_triage, new_dismissed | 所有漏洞分为两类:
新检测到的漏洞 - 在合并请求分支自身中被识别出、但目前不存在于该MR目标分支上的漏洞。此策略选项要求在评估规则前完成流水线,以判断漏洞是新检测到的还是已存在的。合并请求会被阻塞,直至流水线和必要的安全扫描完成。new_needs_triage选项考虑以下状态
• 已检测(Detected)
new_dismissed选项考虑以下状态
• 已驳回(Dismissed)
预先存在的漏洞 - 这类策略选项会立即评估,无需等待流水线完成,因它们仅关注默认分支中先前检测到的漏洞。
• Detected - 策略查找处于“已检测”状态的漏洞。
• Confirmed - 策略查找处于“已确认”状态的漏洞。
• Dismissed - 策略查找处于“已驳回”状态的漏洞。
• Resolved - 策略查找处于“已解决”状态的漏洞。
空数组 [] 覆盖与 ['new_needs_triage', 'new_dismissed'] 相同的状态。 |
| vulnerability_attributes | object | false | {false_positive: boolean, fix_available: boolean} | 默认情况下,所有漏洞发现都会被纳入考量。但可通过过滤器仅关注具备特定属性的漏洞发现:
• 有可用修复(fix_available: true)
• 无可用修复(fix_available: false)
• 是误报(false_positive: true)
• 非误报(false_positive: false)
• 或两者组合。例如(fix_available: true, false_positive: false) |
| vulnerability_age | object | false | N/A | 按年龄过滤预先存在的漏洞发现。漏洞年龄从其在项目中被首次检测时算起。筛选条件包含 operator、value 和 interval。
- operator 条件指定年龄比较使用的操作:大于(greater_than)或小于(less_than)。
- value 条件指定表示漏洞年龄的数值。
- interval 条件指定漏洞年龄的单位:day(天)、week(周)、month(月)或 year(年)。
示例:operator: greater_than,value: 30,interval: day。 |
license_finding 规则类型
此规则根据许可证检测结果执行定义的操作。
| Field | Type | Required | Possible values | Description |
|---|---|---|---|---|
type |
string |
true | license_finding |
规则的类型。 |
branches |
array of string |
true if branch_type field does not exist |
[] 或 分支名称 |
仅适用于受保护的分支。空数组 [] 将规则应用于所有受保护的分支。不能与 branch_type 字段一起使用。 |
branch_type |
string |
true if branches field does not exist |
default 或 protected |
该策略适用的受保护分支类型。不能与 branches 字段一起使用。默认分支也必须是 protected。 |
branch_exceptions |
array of string |
false | 分支名称 | 要从该规则中排除的分支。 |
match_on_inclusion_license |
boolean |
true if licenses field does not exists |
true, false |
规则是否匹配 license_types 中列出的许可证的包含或排除。 |
license_types |
array of string |
true if licenses field does not exists |
许可证类型 | 要匹配的SPDX许可证名称,例如 Affero General Public License v1.0 或 MIT License。 |
license_states |
array of string |
true | newly_detected, detected |
是否匹配新检测到和/或先前检测到的许可证。newly_detected 状态会在引入新软件包或检测到现有软件包的新许可证时触发审批。 |
licenses |
object |
true if license_types field does not exists |
licenses 对象 |
要匹配的SPDX许可证名称,包括软件包例外。 |
licenses 对象
| 字段 | 类型 | 必需性 | 可能值 | 描述 |
|---|---|---|---|---|
denied |
object |
若不存在 allowed 字段则为必需 |
licenses_with_package_exclusion 对象数组 |
包含包异常的拒绝许可证列表。 |
allowed |
object |
若不存在 denied 字段则为必需 |
licenses_with_package_exclusion 对象数组 |
包含包异常的允许许可证列表。 |
licenses_with_package_exclusion 对象
| 字段 | 类型 | 必需性 | 可能值 | 描述 |
|---|---|---|---|---|
name |
string |
是 | SPDX 许可证名称 | SPDX 许可证名称。 |
packages |
object |
否 | packages 对象 |
给定许可证的包异常列表。 |
packages 对象
| 字段 | 类型 | 必需性 | 可能值 | 描述 |
|---|---|---|---|---|
excluding |
object |
是 | {purls: 使用 uri 格式的字符串数组} |
给定许可证的包异常列表。使用 purl 组件 scheme:type/name@version 定义包异常列表。scheme:type/name 组件是必需的。@ 和 version 是可选的。如果指定了版本,则仅该版本被视为异常。如果未指定版本且在 purl 结尾添加了 @ 字符,则仅具有确切名称的包视为匹配项。如果未将 @ 字符添加到包名末尾,则所有具有相同前缀的包均视为匹配项。例如,purl pkg:gem/bundler 匹配 bundler 和 bundler-stats 包,因为这两个包使用相同的许可证。定义 purl pkg:gem/bundler@ 仅匹配 bundler 包。 |
any_merge_request 规则类型
此规则根据提交的签名对任何合并请求执行定义的操作。
| 字段 | 类型 | 必需 | 可能的值 | 描述 |\n|——————–|———————|—————————————-|——————–|——|\n| type | string | 是 | any_merge_request | 规则的类型。 |\n| branches | string 数组 | 如果不存在 branch_type 字段则为必需 | [] 或分支名称 | 仅适用于受保护的目标分支。空数组 [] 将规则应用于所有受保护的目标分支。不能与 branch_type 字段一起使用。 |\n| branch_type | string | 如果不存在 branches 字段则为必需 | default 或 protected | 此策略适用的受保护分支类型。不能与 branches 字段一起使用。默认分支也必须是 protected(受保护的)。 |\n| branch_exceptions | string 数组 | 否 | 分支名称 | 要从此规则中排除的分支。 |\n| commits | string | 是 | any, unsigned | 规则是否匹配任意提交,或仅在合并请求中发现未签名的提交时才匹配。 |
## `require_approval` 操作类型
当定义的策略中至少有一条规则满足条件时,此操作会要求执行审批规则。
如果在同一个 `require_approval` 块中指定多个审批者,任何符合条件的审批者均可满足审批要求。例如,若同时指定两个 `group_approvers` 且 `approvals_required` 为 `2`,这两个审批可来自同一组。若需从不同类型的审批者处获取多个审批,请使用多个 `require_approval` 操作。
| 字段 | 类型 | 必需 | 可能值 | 说明 |
|------|------|------|--------|------|
| `type` | `string` | 是 | `require_approval` | 操作的类型。 |
| `approvals_required` | `integer` | 是 | 大于或等于零 | 所需的 MR 审批数量。 |
| `user_approvers` | `string` 数组 | 否 | 一个或多个用户的用户名 | 视为审批者的用户。用户必须拥有项目访问权限才能具备审批资格。 |
| `user_approvers_ids` | `integer` 数组 | 否 | 一个或多个用户的 ID | 视为审批者的用户 ID。用户必须拥有项目访问权限才能具备审批资格。 |
| `group_approvers` | `string` 数组 | 否 | 一个或多个组的路径 | 视为审批者的组。具有[直接组成员身份](../../project/merge_requests/approvals/rules.md#group-approvers)的用户有资格审批。 |
| `group_approvers_ids` | `integer` 数组 | 否 | 一个或多个组的 ID | 视为审批者的组 ID。具有[直接组成员身份](../../project/merge_requests/approvals/rules.md#group-approvers)的用户有资格审批。 |
| `role_approvers` | `string` 数组 | 否 | 一个或多个[角色](../../permissions.md#roles)(例如:`owner`、`maintainer`)。也可指定自定义角色(或在 YAML 模式下指定自定义角色标识符)作为 `role_approvers`,前提是这些自定义角色拥有审批合并请求的权限。自定义角色可与用户和组审批者一同选择。 | 有资格审批的角色。 |
## `send_bot_message` 操作类型
此操作允许在检测到策略违规时配置合并请求中的机器人消息。
若未指定该操作,则机器人消息默认启用。若定义了多条策略,只要其中至少一条策略启用了 `send_bot_message` 操作,就会发送机器人消息。
| 字段 | 类型 | 必需 | 可能值 | 说明 |
|------|------|------|--------|------|
| `type` | `string` | 是 | `send_bot_message` | 操作的类型。 |
| `enabled` | `boolean` | 是 | `true`、`false` | 当检测到策略违规时是否创建机器人消息。默认值:`true` |示例机器人消息
警告模式
当启用警告模式且合并请求触发无需额外审批人的安全策略时,会在合并请求中添加一条机器人评论。该评论引导用户查看策略以获取更多信息。
approval_settings
策略中设置的选项会覆盖项目中的设置。
| 字段 | 类型 | 必需 | 可能值 | 适用规则类型 | 描述 |
|---|---|---|---|---|---|
block_branch_modification |
boolean |
false | true, false |
All | 当启用时,阻止用户从受保护分支列表中移除分支、删除受保护分支或更改默认分支(若该分支包含在安全策略中)。这能确保用户无法移除分支的保护状态以合并存在漏洞的代码。依据branches、branch_type和policy_scope强制执行,无论是否检测到漏洞。 |
block_group_branch_modification |
boolean 或 object |
false | true, false, { enabled: boolean, exceptions: [{ id: Integer}] } |
All | 当启用时,阻止用户移除策略所适用的每个组上的组级受保护分支。若block_branch_modification为true,则隐式默认为true。将支持组级受保护分支的顶级组作为exceptions添加 |
prevent_approval_by_author |
boolean |
false | true, false |
Any merge request |
当启用时,合并请求作者无法批准自己的MR。这能确保代码作者不会引入漏洞并批准代码合并。 |
prevent_approval_by_commit_author |
boolean |
false | true, false |
Any merge request |
当启用时,对合并请求贡献过代码的用户无资格批准。这能确保代码提交者不会引入漏洞并批准代码合并。 |
| remove_approvals_with_new_commit | boolean | false | true, false | Any merge request | 当启用此选项时,若合并请求已获得所有必要合并审批,但之后新增了提交,则需要新的审批。此举可确保可能包含漏洞的新提交不会被引入。 |
| require_password_to_approve | boolean | false | true, false | Any merge request | 启用后,审批操作会要求输入密码确认。密码确认能额外提升安全性。 |
| prevent_pushing_and_force_pushing | boolean | false | true, false | All | 启用后,若受保护分支被纳入安全策略,将阻止用户向该分支执行推送或强制推送操作。这能防止用户绕过合并请求流程,向分支添加存在漏洞的代码。 |
fallback_behavior
在 GitLab 自托管版中,默认情况下 fallback_behavior 字段可用。若要隐藏该功能,管理员可以禁用名为 security_scan_result_policies_unblock_fail_open_approval_rules 的功能开关。在 GitLab.com 和 GitLab Dedicated 上,此功能可用。
| Field | Type | Required | Possible values | Description |
|---|---|---|---|---|
fail |
string |
false | open 或 closed |
closed(默认):策略的无效或无法执行的规则需要审批。open:策略的无效或无法执行的规则不需要审批。 |
policy_tuning
流水线执行策略支持的可访问性由功能开关控制。有关更多信息,请参阅历史记录。
| Field | Type | Required | Possible values | Description |
|---|---|---|---|---|
unblock_rules_using_execution_policies |
boolean |
false | true、false |
启用后,当扫描由扫描执行策略或流水线执行策略要求,但目标分支缺少所需的扫描工件时,审批规则不会阻塞合并请求。仅当项目或组存在具有匹配扫描器的现有扫描执行策略或流水线执行策略时,此选项才有效。 |
示例
使用扫描执行策略的 policy_tuning 示例
你可以在存储于安全策略项目中的 .gitlab/security-policies/policy.yml 文件中使用以下示例:
scan_execution_policy:
- name: Enforce dependency scanning
description: ''
enabled: true
policy_scope:
projects:
excluding: []
rules:
- type: pipeline
branch_type: all
actions:
- scan: dependency_scanning
approval_policy:
- name: Dependency scanning approvals
description: ''
enabled: true
policy_scope:
projects:
excluding: []
rules:
- type: scan_finding
scanners:
- dependency_scanning
vulnerabilities_allowed: 0
severity_levels: []
vulnerability_states: []
branch_type: protected
actions:
- type: require_approval
approvals_required: 1
role_approvers:
- developer
- type: send_bot_message
enabled: true
fallback_behavior:
fail: closed
policy_tuning:
unblock_rules_using_execution_policies: true使用流水线执行策略的 policy_tuning 示例
此功能不适用于 GitLab 17.10 之前创建的流水线执行策略。若要在旧流水线执行策略中使用此功能,需复制、删除并重新创建这些策略。有关更多信息,请参阅重新创建 GitLab 17.10 之前创建的流水线执行策略。
你可以在存储于安全策略项目中的 .gitlab/security-policies/policy.yml 文件中使用以下示例:
---
pipeline_execution_policy:
- name: Enforce dependency scanning
description: ''
enabled: true
pipeline_config_strategy: inject_policy
content:
include:
- project: my-group/pipeline-execution-ci-project
file: policy-ci.yml
ref: main # 可选关联的流水线执行策略 CI/CD 配置位于 policy-ci.yml 中:
include:
- template: Jobs/Dependency-Scanning.gitlab-ci.yml重新创建在 GitLab 17.10 之前创建的流水线执行策略
在 GitLab 17.10 之前创建的流水线执行策略不包含使用 policy_tuning 功能所需的数据。若要在旧版流水线执行策略中使用此功能,请复制并删除旧策略,然后重新创建它们。
有关视频演示,请参阅 安全策略:重新创建用于 policy_tuning 的流水线执行策略。
若要重新创建流水线执行策略:
- 在左侧边栏中,选择 搜索或前往 并找到您的群组。
- 选择 安全 > 策略。
- 选择要重新创建的流水线执行策略。
- 在右侧边栏中,选择 YAML 标签页并复制整个策略文件的内容。
- 在策略表旁边,选择垂直省略号( ),然后选择 删除。
- 合并生成的合并请求。
- 返回 安全 > 策略 并选择 新建策略。
- 在 流水线执行策略 部分,选择 选择策略。
- 在 .YAML 模式 下,粘贴旧策略的内容。
- 选择 通过合并请求更新 并合并生成的合并请求。
策略范围架构
若要自定义策略执行,您可以定义策略的范围,以包含或排除指定的项目、群组或合规框架标签。更多详情,请参见 范围。
bypass_settings
bypass_settings 字段允许您指定针对特定分支、访问令牌或服务账户的策略例外情况。当满足绕过条件时,该策略不会对匹配的合并请求或分支强制执行。
| 字段 | 类型 | 必需 | 说明 |
|---|---|---|---|
branches |
数组 | 否 | 绕过策略的源分支和目标分支(按名称或模式)列表。 |
access_tokens |
数组 | 否 | 绕过策略的访问令牌 ID 列表。 |
service_accounts |
数组 | 否 | 绕过策略的服务账户 ID 列表。 |
源分支例外
借助基于分支的例外,您可以配置合并请求审批策略,自动豁免特定源分支与目标分支组合的审批要求。这使您能够在保持严格审批规则的同时,为某些类型的合并(例如特性分支到主分支)提供灵活性,而为其他类型(例如发布分支到主分支)提供更多灵活性。
| 字段 | 类型 | 必需 | 可能值 | 说明 |
|---|---|---|---|---|
source |
对象 | 否 | name(字符串)或 pattern(字符串) |
源分支例外。指定精确名称或模式。 |
target |
对象 | 否 | name(字符串)或 pattern(字符串) |
目标分支例外。指定精确名称或模式。 |
访问令牌和服务账户例外
借助访问令牌和服务账户例外,您可以指定可在必要时绕过合并请求审批策略的特定服务账户和访问令牌。这种方法使您信任的自动化无需手动审批即可运行,同时仍限制人类用户的操作。例如,受信任的自动化可能包括 CI/CD 流水线、仓库镜像和自动更新。绕过事件会被完全审计,以便支持您的合规性和紧急访问需求。
| 字段 | 类型 | 必需 | 说明 |
|---|---|---|---|
id |
整数 | 是 | 访问令牌或服务账户的 ID。 |
示例 YAML
bypass_settings:
access_tokens:
- id: 123
- id: 456
service_accounts:
- id: 789
- id: 1011安全策略项目中的示例 policy.yml
您可以在存储在安全策略项目中的 .gitlab/security-policies/policy.yml 文件中使用此示例:
---
approval_policy:
- name: 关键漏洞CS审批
description: 仅针对容器扫描的关键严重性级别
enabled: true
rules:
- type: scan_finding
branches:
- main
scanners:
- container_scanning
vulnerabilities_allowed: 0
severity_levels:
- critical
vulnerability_states: []
vulnerability_attributes:
false_positive: true
fix_available: true
actions:
- type: require_approval
approvals_required: 1
user_approvers:
- adalberto.dare
- name: 次要CS审批
description: 仅针对容器扫描的次要级别
enabled: true
rules:
- type: scan_finding
branches:
- main
scanners:
- container_scanning
vulnerabilities_allowed: 1
severity_levels:
- low
- unknown
vulnerability_states:
- detected
vulnerability_age:
operator: greater_than
value: 30
interval: day
actions:
- type: require_approval
approvals_required: 1
role_approvers:
- owner
- 1002816 # 示例自定义角色标识符称为"AppSec Engineer"在此示例中:
- 每个包含新
critical漏洞(由容器扫描识别)的MR都需要来自adalberto.dare的一个审批。 - 每个包含超过一个现有
low或unknown漏洞(超过30天,由容器扫描识别)的MR都需要来自拥有Owner角色的项目成员或具有自定义角色AppSec Engineer的用户的一个审批。
合并请求审批政策编辑器的示例
您可以在合并请求审批政策编辑器的YAML模式下使用此示例。它对应于上一个示例中的单个对象:
type: approval_policy
name: 关键漏洞CS审批
description: 仅针对容器扫描的关键严重性级别
enabled: true
rules:
- type: scan_finding
branches:
- main
scanners:
- container_scanning
vulnerabilities_allowed: 1
severity_levels:
- critical
vulnerability_states: []
actions:
- type: require_approval
approvals_required: 1
user_approvers:
- adalberto.dare理解合并请求审批政策的审批
合并请求审批政策的比较范围
- 为确定何时需要在合并请求上获得审批,我们比较源分支和目标分支(例如
feature/main)中每个支持的流水线源的已完成流水线。这确保了对扫描结果的最全面评估。 - 对于源分支,比较流水线是源分支最新提交中每个支持的流水线源的所有已完成流水线。
- 如果合并请求审批政策仅查找新检测到的状态(
new_needs_triage&new_dismissed),则在与源和目标分支之间的共同祖先中的所有支持流水线源进行比较。例外情况是使用合并结果流水线时,此时比较是在MR的目标分支尖端进行的。 - 如果合并请求审批政策查找现有状态(
detected、confirmed、resolved、dismissed),则始终与默认分支(例如main)的尖端进行比较。 - 如果合并请求审批政策查找新旧漏洞状态的组合,则在源和目标分支的共同祖先中进行比较。
- 合并请求审批政策在确定合并请求是否需要审批时,会比较源分支和目标分支的结果时考虑所有支持的流水线源(基于
CI_PIPELINE_SOURCE变量)。不支持来源为webide的流水线。 - 在GitLab 16.11及更高版本中,所选流水线的每个子流水线也会被考虑用于比较。
接受风险并忽略未来合并请求中的漏洞
对于范围限定为新检测到发现的合并请求审批策略(new_needs_triage 或 new_dismissed 状态),了解此漏洞状态的影响很重要。若某发现在合并请求的分支上存在但在目标分支上不存在,则该发现被视为新检测到的。当包含新检测到发现的分支的合并请求被批准并合并时,批准者即“接受了这些漏洞的风险”。若在此之后检测到一个或多个相同漏洞,其状态将为 detected,因此会被配置为考虑 new_needs_triage 或 new_dismissed 发现的策略忽略。例如:
- 创建了一个合并请求审批策略以阻止关键的 SAST 发现。若批准了针对 CVE-1234 的 SAST 发现,那么项目中具有相同违规的未来合并请求将不需要审批。
使用 new_needs_triage 和 new_dismissed 漏洞状态时,即使已驳回,只要发现是新检测到的且尚未分类,政策就会阻止符合政策规则的任何发现的 MR。若您想忽略在合并请求中新检测到然后又被驳回的漏洞,可仅使用 new_needs_triage 状态。
使用许可证审批策略时,评估中会考虑项目、组件(依赖项)和许可证的组合。若某许可证作为例外被批准,未来的合并请求就不需要再对相同的项目、组件(依赖项)和许可证组合进行审批。此时不考虑组件的版本。若之前批准的包更新到新版本,批准者无需重新批准。例如:
- 创建了一个许可证审批策略以阻止具有匹配
AGPL-1.0的新检测到许可证的合并请求。在项目demo中对组件osframework进行更改,违反了该政策。若获得批准并合并,那么项目中osframework组件带有AGPL-1.0许可证的后续合并请求就不再需要审批。
额外审批步骤
在某些情况下,合并请求审批策略需要额外的审批步骤。例如:
-
工作分支中的安全作业数量减少,不再与目标分支中的安全作业数量匹配。用户无法通过从 CI/CD 配置中移除扫描作业来跳过扫描结果策略。只有合并请求审批策略规则中配置的安全扫描才会检查是否被移除。
例如,假设默认分支流水线有四个安全扫描:
sast、secret_detection、container_scanning和dependency_scanning。一个合并请求审批策略强制执行两个扫描器:container_scanning和dependency_scanning。若一个 MR 移除了合并请求审批策略中配置的扫描(例如container_scanning),则需要额外的审批。 -
有人停止了流水线安全作业,用户无法跳过安全扫描。
-
合并请求中的一个作业失败并被配置为
allow_failure: false。结果是流水线处于阻塞状态。 -
流水线有一个手动作业,必须成功运行才能使整个流水线通过。
管理用于评估审批要求的扫描结果
合并请求审批策略会在流水线完成后评估扫描器生成的工件报告。合并请求审批策略专注于评估结果,并根据扫描结果来确定批准情况,以识别潜在风险、阻止合并请求并要求审批。
合并请求审批策略不会超出此范围深入到工件文件或扫描器中。相反,我们信任来自工件报告的结果。这使团队能够灵活地管理其扫描执行和供应链,并在必要时自定义工件报告中生成的扫描结果(例如过滤掉误报)。
锁定文件篡改(例如)不在安全策略管理的范围内,但可通过使用 Code owners 或 外部状态检查 来缓解。有关更多信息,请参阅 问题 433029。
使用属性“可修复”或“误报”过滤策略违规
为避免不必要的审批要求,这些额外过滤器有助于确保你仅在最具操作性的发现上阻止合并请求(MR)。
通过在YAML中将fix_available设置为false,或在策略编辑器中选择不是和可修复,当发现存在解决方案或补救措施时,该发现不会被视作策略违规。解决方案显示在漏洞对象底部,标题为解决方案。补救措施以漏洞对象内的通过合并请求解决按钮形式出现。
通过合并请求解决按钮仅在满足以下任一条件时出现:
- 在启用了GitLab Duo Enterprise的Ultimate层级项目中发现的SAST漏洞。
- 在设置了
GIT_STRATEGY: fetch作业的Ultimate层级项目中发现的容器扫描漏洞。此外,漏洞必须包含一个可用于容器镜像启用仓库的修复包。 - 在由yarn管理的Node.js项目中发现的依赖扫描漏洞且存在修复方案。此外,项目必须在Ultimate层级,并且实例的FIPS模式必须禁用。
可修复仅适用于依赖扫描和容器扫描。
同样地,通过使用误报属性,你可以忽略策略检测到的发现,方法是设置false_positive为false(或在策略编辑器中设置属性为不是和误报)。
误报属性仅适用于我们的Vulnerability Extraction Tool检测到的SAST结果中的发现。
故障排除
合并请求规则小部件显示合并请求审批策略无效或重复
- 层级:Ultimate
- 提供方式:GitLab 自托管、GitLab Dedicated
在GitLab自托管版本15.0至16.4中,最可能的原因是该项目的导出组被导入另一个组,且具有合并请求审批策略规则。这些规则存储在与导出项目不同的单独项目中。因此,该项目包含引用导入项目组中不存在实体的策略规则。结果是策略规则无效、重复或两者兼有。
若要从GitLab实例中移除所有无效的合并请求审批策略规则,管理员可在Rails控制台中运行以下脚本:
Project.joins(:approval_rules).where(approval_rules: { report_type: %i[scan_finding license_scanning] }).where.not(approval_rules: { security_orchestration_policy_configuration_id: nil }).find_in_batches.flat_map do |batch|
batch.map do |project|
# 获取适用项目规则的项目和配置ID
[project, project.approval_rules.where(report_type: %i[scan_finding license_scanning]).pluck(:security_orchestration_policy_configuration_id).uniq]
end.uniq.map do |project, configuration_ids| # 仅取项目+配置ID的唯一组合
# 若找到的配置多于项目可用配置,则提取多余记录
[project, configuration_ids - project.all_security_orchestration_policy_configurations.pluck(:id)]
end.select { |_project, configuration_ids| configuration_ids.any? }
end.each do |project, configuration_ids|
# 对每组找到的项目+幽灵配置,移除对应规则
Security::OrchestrationPolicyConfiguration.where(id: configuration_ids).each do |configuration|
configuration.delete_scan_finding_rules_for_project(project.id)
end
# 确保同步新组的潜在规则
Security::ScanResultPolicies::SyncProjectWorker.perform_async(project.id)
end新检测到的CVE
当使用new_needs_triage和new_dismissed时,某些发现可能需要审批,即使它们并非由合并请求引入(例如相关依赖项上的新CVE)。这些发现不会出现在MR小部件中,但会在策略机器人评论和管道报告中突出显示。
手动使 policy.yml 无效后策略仍生效
在 GitLab 17.2 及更早版本中,您可能会发现 policy.yml 文件中定义的策略仍在执行,即使该文件被手动编辑且不再通过策略模式验证。此问题由策略同步逻辑中的 bug 导致。
潜在症状包括:
approval_settings仍会阻止移除分支保护、阻止强制推送或以其他方式影响开放合并请求。any_merge_request策略仍适用于开放合并请求。
解决方法如下:
- 手动编辑定义策略的
policy.yml文件,使其再次有效。 - 取消分配并重新分配存储
policy.yml文件的安全策略项目。
缺少安全扫描
在使用合并请求审批策略时,您可能会遇到合并请求被阻塞的情况,包括在新项目中或某些安全扫描未执行时。此行为是设计用于降低将漏洞引入系统的风险。
示例场景:
-
源分支或目标分支缺少扫描
如果源分支或目标分支缺少安全扫描,GitLab 无法有效评估合并请求是否会引入新漏洞。在这种情况下,需要批准作为预防措施。
-
新项目
对于尚未在目标分支上设置或执行安全扫描的新项目,所有合并请求都需要批准。这可确保从项目创建之初就激活安全检查。
-
无需扫描文件的项目
即使项目中没有与所选安全扫描相关的文件,仍会执行批准要求。这可在所有项目中保持一致的安全实践。
-
首次合并请求
如果默认分支没有安全扫描,新项目中的首个合并请求可能被阻塞,即使源分支没有漏洞。
解决这些问题:
- 确保所有必需的安全扫描已在源分支和目标分支上正确配置并成功运行。
- 对于新项目,在创建合并请求之前,在默认分支上设置并运行必要的安全扫描。
- 考虑使用扫描执行策略或流水线执行策略,以确保所有分支上安全扫描的一致执行。
- 考虑对策略中使用
open的回退行为,防止策略中无效或无法执行的规则要求批准。 - 考虑使用
策略调优设置unblock_rules_using_execution_policies来应对安全扫描工件缺失且扫描执行策略已生效的场景。启用后,当目标分支缺少扫描工件且扫描执行策略要求扫描时,此设置会使审批规则变为可选。此功能仅适用于具有匹配扫描器的现有扫描执行策略。当因缺少工件而无法执行某些安全扫描时,它可为合并请求流程提供灵活性。
安全机器人评论中出现 Target: none
如果在安全机器人评论中看到 Target: none,表示 GitLab 未找到目标分支的安全报告。解决方法如下:
- 在目标分支上运行包含所需安全扫描器的流水线。
- 确保流水线成功完成并生成安全报告。
- 重跑源分支上的流水线。创建新提交也会触发流水线重跑。
安全机器人消息
当目标分支没有安全扫描时:
- 安全机器人可能会列出源分支中发现的所有漏洞。
- 其中一些漏洞可能已存在于目标分支中,但没有目标分支扫描,GitLab 无法确定哪些是新出现的。
潜在解决方案:
- 手动批准:对于新项目,在建立安全扫描前临时手动批准合并请求。
- 针对性策略:为新项目创建具有不同审批要求的独立策略。
- 回退行为:考虑对新项目上的策略使用
fail: open,但请注意这可能允许用户在扫描失败时合并漏洞。
合并请求审批策略调试的支持请求
GitLab.com 用户可提交标题为“Merge request approval policy debugging”的支持工单。请提供以下详细信息:
- 组路径、项目路径(可选合并请求 ID)
- 严重程度
- 当前行为
- 预期行为
GitLab.com
支持团队将调查日志(pubsub-sidekiq-inf-gprd*)以确定失败原因。以下是日志中的一个示例响应片段。你可以使用此查询查找与审批相关的日志:json.event.keyword: "update_approvals" 和 json.project_path: "group-path/project-path"。可选地,你可以通过 json.merge_request_iid 进一步按合并请求标识符过滤:
"json": {
"project_path": "group-path/project-path",
"merge_request_iid": 2,
"missing_scans": [
"api_fuzzing"
],
"reason": "Scanner removed by MR",
"event": "update_approvals",
}GitLab 自托管版
搜索关键词,例如 project-path、api_fuzzing 和 merge_request。示例:grep group-path/project-path,以及 grep merge_request。如果你知道关联ID,可以按关联ID搜索。例如,如果 correlation_id 的值是 01HWN2NFABCEDFG,则搜索 01HWN2NFABCEDFG。
在以下文件中搜索:
/gitlab/gitlab-rails/production_json.log/gitlab/sidekiq/current
常见失败原因:
- 扫描器被合并请求(MR)移除:合并请求审批策略期望策略中定义的扫描器存在且成功生成用于比较的工件。
合并请求审批策略的不一致批准
如果你注意到合并请求规则中存在任何不一致之处,你可以采取以下任一步骤来重新同步你的策略:
- 使用
resyncSecurityPoliciesGraphQL 突变 来重新同步策略。 - 取消分配,然后将安全策略项目重新分配给受影响的组或项目。
- 或者,你可以更新一个策略以触发该策略为受影响的组或项目重新同步。
- 确认安全策略项目中YAML文件的语法有效。
这些操作有助于确保你的合并请求审批策略正确应用并在所有合并请求中保持一致。
如果在执行这些步骤后你仍然遇到合并请求审批策略的问题,请联系GitLab支持寻求帮助。
修复已检测到漏洞的合并请求需要审批
如果你的策略配置包含 detected 状态,修复先前检测到的漏洞的合并请求仍需要审批。合并请求审批策略基于合并请求更改前存在的漏洞进行评估,这为影响已知漏洞的任何更改增加了额外的审查层。
如果你想允许因检测到的漏洞而无需额外审批即可进行的修复漏洞的合并请求,请考虑从策略配置中删除 detected 状态。