把 code-audit 接进 GitHub Action 后,我发现最难的从来不是写 YAML

39 阅读3分钟

我原本以为,把本地安全扫描器接进 GitHub Actions,只要写十几行 YAML。

结果真正花时间的,是下面四个问题:

扫描结果有没有权限上传?
扫描失败了,报告还会不会上传?
输出文件和上传路径是不是同一个?
第一次接入就阻断,会不会把历史问题全部变成 PR 事故?

cover-掘金-Action-20260914.png Action 地址:

github.com/yuan1521913…

第一版工作流,看起来没有错

最初大概是这样:

permissions:
  contents: read

steps:
  - uses: actions/checkout@v4

  - uses: yuan1521913/code-audit-action@v0
    with:
      path: .
      format: sarif
      output: code-audit.sarif
      fail-on: high

  - uses: github/codeql-action/upload-sarif@v3
    with:
      sarif_file: code-audit.sarif

逻辑上没问题:

读取代码
扫描
生成 SARIF
上传 SARIF
发现 high 就失败

但这套配置有三个隐藏假设。

隐藏假设 1:读取代码的权限,等于上传安全结果的权限

actions/checkout 只需要读取代码。

GitHub Code Scanning 的 SARIF 上传是另一种权限。

需要加:

permissions:
  contents: read
  security-events: write

少了 security-events: write,扫描本身可能全绿,文件也已经生成,但上传阶段没有权限。问题不在扫描器,而在工作流权限边界。

另外,Fork PR 的令牌权限通常更低。不要为了解决上传问题,直接把不可信 PR 代码放进高权限工作流里执行。先让同仓库 PR 和主分支 push 跑通,再单独设计 Fork 场景。

这和代码里的权限问题很像:

能读取资源
不等于
能写入另一个系统

隐藏假设 2:前一步失败,后一步一定还会执行

如果设置:

fail-on: high

扫描发现 high 时,Action 返回退出码 1。

这时 job 已经失败。后续上传步骤默认不会执行。

结果就成了:

扫描失败了
但开发者看不到 SARIF
只知道 CI 红,不知道红在哪里

所以上传步骤要加:

if: always()

完整写法:

  - uses: github/codeql-action/upload-sarif@v3
    if: always()
    with:
      sarif_file: code-audit.sarif

这一步不是“忽略失败”,而是先保证失败证据仍然可见。

隐藏假设 3:危险位置等于应该阻断

第一次接入就写:

fail-on: high

听起来很安全。

但如果项目里有历史问题,结果通常是所有 PR 一起变红。

真正需要拆开的是:

扫描发现问题
人工确认问题
团队决定什么时候阻断

这三件事不是一回事。

更合理的第一轮是:

fail-on: none

先让 SARIF 出现在 Code Scanning 或 artifact 里,连续跑几次,确认:

  • 规则输出是否稳定。
  • 误报主要来自哪些规则。
  • 历史问题是否需要 baseline。
  • 哪些 high 能立即修复。

然后再把新增 high 设为阻断条件。

Action 到底解决了什么

它解决的是触发和分发:

PR 或 push
-> 自动扫描
-> 输出 SARIF
-> GitHub 展示文件、行号和规则

它没有解决的是:

这条 finding 是不是真实可达
输入是否来自不可信来源
中间是否有参数化、转义、校验或 allowlist
修复后是否需要契约测试和重新扫描

自动扫描给的是位置。

人工确认给的是结论。

我会怎么分阶段接

第一阶段,只收集:

fail-on: none

第二阶段,修复新增 high,再收紧:

fail-on: high

第三阶段,再把历史问题纳入 baseline,只审查新增结果。

这条路径比“第一天上 Action,第二天所有 PR 全红”慢一点,但团队真的会继续用。

Action:

github.com/yuan1521913…

社区版源码和规则:

github.com/yuan1521913…

自动扫描不是正式安全审计,0 findings 也不等于代码安全。