4. GitLab SAST内置模板与启用方式
GitLab SAST 的落地方式并不是从零编写扫描脚本,而是复用 GitLab 官方维护的 CI/CD 模板。理解模板的引入方式、变量覆盖机制以及扫描触发条件,是让 SAST 在流水线中稳定运行的关键。本节围绕 SAST.gitlab-ci.yml 模板展开,说明如何通过 include 引入、如何用变量调整行为、以及流水线在什么条件下才会真正执行扫描。
一、SAST 模板的本质与引入方式
GitLab 提供的 SAST 能力封装在官方模板仓库中,核心文件是 SAST.gitlab-ci.yml。它并不是一个独立运行的扫描器,而是一组 CI Job 定义:模板内部会根据当前项目语言和文件特征,决定启用哪些分析器(如 Semgrep、Gitleaks、SpotBugs 等),并为每个分析器生成对应的 Job。项目只需要在自己的 .gitlab-ci.yml 中通过 include 把这个模板拉进来,就能获得默认的 SAST 扫描能力。
最简引入方式如下:
include:
- template: Security/SAST.gitlab-ci.yml
这里的 template: 是 GitLab 内置模板的引用语法,指向 GitLab 实例自带的模板路径,不需要额外配置远程仓库地址。引入后,流水线中会出现形如 semgrep-sast、gitleaks-sast 的 Job。需要注意的是,模板只负责“定义 Job”,是否真正执行还取决于后面的触发条件。
如果希望锁定模板版本、避免官方模板更新导致行为变化,也可以使用远程 include 指向具体 tag:
include:
- remote: 'https://gitlab.com/gitlab-org/gitlab/-/raw/v16.11.0-ee/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml'
两种方式的选择取决于团队对稳定性和新特性的取舍:内置模板随 GitLab 版本升级,能获得最新规则;远程固定版本则更可控,适合对扫描结果有严格基线要求的项目。
二、变量覆盖:让模板适配项目实际
模板引入后,行为由一组预定义 CI/CD 变量控制。变量可以在项目 .gitlab-ci.yml 的 variables: 段声明,也可以在项目 Settings → CI/CD → Variables 中配置。前者随代码走,后者更适合存放敏感值或环境相关配置。
常用变量及其作用如下表所示:
| 变量 | 作用 | 示例值 |
|---|---|---|
SAST_DISABLED | 为 true 时完全关闭 SAST | "true" |
SAST_EXCLUDED_PATHS | 排除不扫描的路径 | spec,test,tmp |
SAST_EXCLUDED_ANALYZERS | 禁用指定分析器 | spotbugs |
SEARCH_MAX_DEPTH | 仓库目录搜索深度 | 4 |
SAST_FAIL_ON_ERROR | 分析器出错时是否失败 | "true" |
GITLAB_ADVANCED_SAST_ENABLED | 启用高级 SAST(如支持) | "true" |
例如,一个 Java 项目希望跳过测试目录、只保留 Semgrep 和 Gitleaks,可以这样写:
variables:
SAST_EXCLUDED_PATHS: "spec,test,tmp,vendor"
SAST_EXCLUDED_ANALYZERS: "spotbugs"
变量覆盖遵循“就近优先”原则:Job 级变量覆盖全局变量,项目级变量覆盖模板默认值。因此,如果只想对某个分析器单独调整,可以在对应 Job 上重写变量,而不影响其他分析器。
三、扫描触发条件:什么时候真正跑起来
模板中的 SAST Job 默认带有 rules,决定了它在哪些流水线中执行。默认行为是:在分支流水线和合并请求流水线中都会运行,但不会在标签流水线中运行。这意味着只要推送代码或创建 MR,SAST 就会自动触发。
如果项目希望只在合并请求阶段扫描,以节省 CI 资源,可以覆盖 Job 的 rules:
semgrep-sast:
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
反过来,如果希望主分支每次提交都扫描,可以追加分支条件:
semgrep-sast:
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
除了 rules,还有几个容易忽略的触发细节。第一,模板 Job 默认继承 stage: test,如果项目自定义了 stage 顺序,需要确认 test 阶段存在。第二,如果项目设置了 SAST_DISABLED: "true",即使 rules 匹配也不会执行。第三,某些分析器需要特定文件存在才会激活,例如 Gitleaks 会扫描整个仓库,而 SpotBugs 只在检测到 Java 构建产物时才运行。
四、模板、变量与触发条件的关系
把这三者放在一起看,可以形成一条清晰的链路:include 决定“有哪些 Job”,变量决定“Job 怎么跑”,rules 决定“Job 什么时候跑”。三者共同作用,才决定一次流水线中 SAST 的实际行为。下面的 SVG 展示了这一关系结构。
从图中可以看到,模板引入只是起点,变量和 rules 才是决定扫描实际行为的两把“调节阀”。在实际项目中,建议先保持默认模板和默认触发条件跑通一次,确认 Job 能正常生成并产出报告,再逐步通过变量收窄扫描范围、通过 rules 调整触发时机。这样既能快速验证链路,又能避免一开始就因过度定制而难以定位问题。
include 路径是否正确、SAST_DISABLED 是否被误设为 true、以及当前流水线类型是否被 rules 排除。多数“模板没生效”的问题都出在这三点上。