news 2026/9/15 15:48:19

Dawarich 安全扫描实践:从 CI 流水线到本地全量 Git 历史的完整指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Dawarich 安全扫描实践:从 CI 流水线到本地全量 Git 历史的完整指南

Dawarich 安全扫描实践:从 CI 流水线到本地全量 Git 历史的完整指南

【免费下载链接】dawarichYour favorite self-hostable alternative to Google Timeline (Google Location History)项目地址: https://gitcode.com/GitHub_Trending/da/dawarich

导读:Dawarich 是一个自托管的 Google Timeline(Google 位置历史)替代方案,代码库以 Rails(Ruby)为核心。为了保证"自托管 ≠ 自担全部风险",项目在 SECURITY-SCANNING.md 中沉淀了一套分层安全扫描体系:CI 侧用 Brakeman、bundler-audit、Semgrep、gitleaks 与 Trivy 覆盖 SAST、依赖漏洞、密钥泄漏与容器镜像漏洞,本地侧则提供全量 Git 历史密钥扫描与逐条可复现的扫描命令。读完本文,你将掌握这套扫描矩阵的触发时机、门禁策略(Report-only vs Blocking)、CI 工作流实现细节,以及如何在任意一台机器上复跑全部扫描器,为自己的 Rails/Docker 项目搭建同样的防线。

一、整体设计:三层防线与三种触发时机

Dawarich 的安全扫描由 GitHub Actions 自动驱动,核心目标是在合入代码之前尽可能发现四类问题:

  1. 应用代码自身的安全缺陷(SQL 注入、XSS、批量赋值、不安全跳转等 Rails 常见弱点)——由 SAST 类工具负责;
  2. 依赖链中的已知漏洞Gemfile.lock中的易受攻击 gem)——由 bundler-audit 负责;
  3. 密钥/凭据意外入库(API Key、Token 等敏感信息出现在 diff 或历史提交中)——由 gitleaks 负责;
  4. 容器产物与基础设施配置缺陷(Docker 镜像内操作系统/库的 CVE、Dockerfile/IaC 配置不当)——由 Trivy 负责。

根据 SECURITY-SCANNING.md 的说明,扫描在三种场景下自动触发:

  • 每次 Pull Request:变更进入主干前的第一道闸门;
  • 每次 push 到masterdev分支:主干/开发分支的持续守护;
  • 每周定时任务(周一):即使本周没有代码变更,也会用最新的漏洞库重新审视代码与镜像。

这一设计意味着漏洞情报(advisory 数据库、规则集)每周都会刷新,且不需要任何开发动作即可保持"最新基线"。

最小权限原则:工作流声明了permissions: contents: read,除上传 SARIF 结果所需的security-events: write外,不申请任何多余权限。除 GitHub 内置的GITHUB_TOKEN外,不需要任何额外机密,第三方 Action 全部以 commit SHA 固定版本,避免供应链投毒(详见下文 CI 实现)。

二、CI 扫描矩阵:六项任务的角色与门禁

文档用一张表明确了六个扫描任务的定位,这里逐项展开说明其职责边界:

工作流任务工具捕获范围门禁级别
security.ymlbrakemanBrakemanRails SAST(SQL 注入、XSS、批量赋值、不安全跳转等)仅报告
security.ymlbundler-auditbundler-auditGemfile.lock中已知漏洞 gem(advisory 数据库在任务内刷新)阻断
security.ymlsemgrepSemgrep(p/rubyp/railsp/secretsp/owasp-top-ten四套规则)SAST + 密钥模式仅报告
security.ymlgitleaksgitleaksPR/push 的 diff 中的密钥阻断
trivy.ymlimageTrivy(镜像扫描)构建出的 Docker 镜像中的 OS/库 CVE(有修复的 HIGH/CRITICAL)仅报告
trivy.ymlconfigTrivy(配置扫描)Dockerfile / IaC 配置错误仅报告

2.1 为什么用两套 SAST?Brakeman + Semgrep 互补

Brakeman是 Rails 生态事实标准的静态分析工具。Dawarich 将它与 bundler-audit 一起声明在 Gemfile 的开发/测试/staging 组中(gem 'brakeman', require: falsegem 'bundler-audit', require: false),专门针对 Rails 框架的惯用 API 做深度检查——例如params直接拼进 SQL、redirect_to使用外部输入、update_all/create_with类批量赋值路径等。

Semgrep则作为"广谱补充":它不绑定 Rails 框架,用p/rubyp/railsp/secretsp/owasp-top-ten四套公开规则集同时覆盖通用 Ruby 代码质量、Rails 最佳实践、密钥模式(如硬编码的 AWS Key、GitHub Token 等)以及 OWASP Top Ten 常见漏洞。两套工具规则来源不同、视角互补,同一类问题可以用不同模式交叉验证。

2.2 唯一默认"硬门禁":bundler-audit 与 gitleaks

bundler-audit直接读取Gemfile.lock,与 RubyGems Advisory Database 比对。由于 Dawarich 是一个长期演进、依赖较多的 Rails 项目,其 security.yml 中的实现是:

bundle exec bundle-audit update bundle exec bundle-audit check

先更新本地 advisory 数据库再检查——这正是文档强调的"advisory DB refreshed in-job":每次运行都拉取最新漏洞情报,而不是依赖某个缓存的旧库。一旦发现已知漏洞 gem,任务直接失败,阻断合并。

gitleaks则守护"密钥不落库"这条红线。CI 中仅扫描本次变更的 diff(详见下文第四节),发现任何疑似密钥即以失败收场。

2.3 镜像与基础设施:Trivy 双任务

trivy.ymlimage任务针对构建产物(本地docker build出来的镜像)执行漏洞扫描:

trivy image \ --scanners vuln \ --severity HIGH,CRITICAL \ --ignore-unfixed \ --format sarif --output /work/trivy-image.sarif \ --exit-code 0 \ dawarich:scan

三个关键参数的含义:

  • --severity HIGH,CRITICAL:只关注高危与严重级别,过滤掉大量低优先级噪声;
  • --ignore-unfixed:只看有修复版本可用的 CVE——没有修复方案的漏洞无法通过升级解决,先不阻塞交付;
  • --exit-code 0:本轮不阻断(Report-only),但结果照常上传到 Security 标签页。

config任务则用trivy config /work扫描仓库本身(主要是 docker/Dockerfile 等 Docker/IaC 文件),检查诸如基础镜像版本过旧、特权指令、危险环境变量等配置类问题。

值得一提的细节:Trivy 固定使用ghcr.io/aquasecurity/trivy:0.65.0容器镜像(trivy.yml 的env.TRIVY_IMAGE),并通过TRIVY_USERNAME/TRIVY_PASSWORD环境变量传递凭据拉取私有层;Docker 守护进程通过挂载/var/run/docker.sock提供给容器内的 Trivy,从而可以直接扫描宿主机构建出的本地镜像dawarich:scan

三、门禁分级策略:先"采集信号",再"收紧闸门"

文档明确指出,当前阶段四分之三的任务都是 Report-only(Brakeman、Semgrep、Trivy 的 image 与 config),只有 bundler-audit 和 gitleaks 是阻断性的。这是有意为之的设计决策:

"This is intentional for the first pass — gather signal before gating merges."

原因很务实:一个成熟代码库在第一次接入 SAST 时,历史存量问题可能非常多,如果直接全部设为阻断,所有 PR 都会红掉,团队会被迫在"修历史债"和"合入新功能"之间二选一,反而阻碍扫描体系的落地。先以 Report-only 运行一段时间,把真实告警量、误报率摸清楚,再逐步升级为门禁。

文档同时给出了从 Report-only 升级为 Blocking 的具体操作路径,这对应到源码中:

  • Brakeman / Semgrep / Trivy config:在 security.yml 与 trivy.yml 中删除对应 step 上的continue-on-error: true
  • Trivy image:将--exit-code 0改为--exit-code 1,让"存在可修复的 HIGH/CRITICAL CVE"直接导致任务失败。

升级节奏可以按工具逐个推进:先放开风险最高的(如 Trivy image 的可修复高危 CVE),再根据误报情况逐步覆盖其余任务。

四、CI 实现细节:从源码看安全实践如何落地

4.1 第三方 Action 全部固定到 commit SHA

打开 security.yml 可以看到,每一个uses:都带上了完整 SHA 与版本注释,例如:

uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0 uses: github/codeql-action/upload-sarif@db488ddef3bf6cb639b32c2e9a7c0a7ea8271d28 # v4.37.8 uses: gitleaks/gitleaks-action@e0c47f4f8be36e29cdc102c57e68cb5cbf0e8d1e # v3.0.0

SHA 固定意味着:即便上游仓库被恶意篡改或 Action 作者账号被盗,CI 也只会执行当初审核过的那个 commit的代码。这是供应链安全的基础实践,文档中"All third-party actions are pinned to a commit SHA"的承诺在源码层面得到了完整落实。

4.2 SARIF 统一汇入 Security → Code scanning

Brakeman、Semgrep、Trivy(image 与 config)四个任务都会产出 SARIF 格式报告,并通过github/codeql-action/upload-sarif上传(if: always()保证即使扫描失败也会上传报告),并且各自带独立category(如brakemansemgreptrivy-imagetrivy-config),在仓库的Security → Code scanning标签页按类别分组展示。这样所有工具的告警集中在一个入口,方便统一分类、指派与跟踪。

4.3 gitleaks 在 CI 中只扫 diff 的取舍

这是一个容易被忽视但很关键的设计。CI 中的 gitleaks 任务(security.yml)有两个值得注意的点:

  1. 触发范围if: github.event_name == 'pull_request' || github.event_name == 'push'——只有 PR 和 push 时运行,定时任务不跑gitleaks;
  2. 扫描对象:通过fetch-depth: 0拉取完整历史后,gitleaks-action 默认仍以本次变更的 diff为扫描范围。

原因写在任务注释里:CI 只扫 diff,是为了避免反复标记已知的历史提交。这个仓库是公开的,如果每周定时全量扫历史,每次都会命中多年前的历史密钥,产生大量无法通过"删掉提交"解决的噪声。全量历史扫描被有意放到本地手动执行(详见第六节),因为那才是有意为之的"排雷"动作,而不是 CI 的例行公事。

4.4 并发与失败取消

security.ymltrivy.yml都声明了:

concurrency: group: security-${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true

同一分支上连续多次 push 时,旧的扫描会被新的一次取代,避免排队积压和资源浪费。

五、依赖与基础镜像的持续更新:Dependabot

安全扫描只负责"发现",修复依赖要靠 .github/dependabot.yml 的自动化更新。它覆盖三个维度:

生态目录频率说明
bundler(RubyGems)/每周一minor/patch 分组批量更新,限制 10 个并发 PR
docker/docker每周一基础镜像更新,限制 5 个 PR
github-actions/每周一保持 SHA 固定版本不过期,限制 5 个 PR

三个更新目标都打在dev分支,便于先在开发分支验证再合入主干。

其中 docker 生态的ignore规则非常值得注意——它主动禁止Ubuntu 基础镜像的 major/minor 升级:

ignore: - dependency-name: 'ubuntu' update-types: - 'version-update:semver-major' - 'version-update:semver-minor'

原因注释写得很清楚:Dockerfile 中的mbgl_libs阶段依赖 Ubuntu 24.04 预编译的@maplibre/maplibre-gl-native二进制,它链接的是libicuuc/libicudata/libicui18n.so.74版本,而更新的 Ubuntu 不再提供 ICU 74。也就是说:基础镜像不能盲目升级,Dependabot 的自动化必须在兼容性约束下运行——这本身也是依赖管理安全实践的一部分("已知的破坏性升级比缓慢的 CVE 更危险")。

六、全量 Git 历史密钥扫描(本地执行)

这是 SECURITY-SCANNING.md 中最重要的实操章节,也是公开仓库必做的"体检"。

6.1 为什么 CI 扫不到历史密钥

CI 的 gitleaks 只扫 diff。而公开仓库的历史是不可磨灭的:一个多年前提交的密钥,即使后来从文件中删除,只要曾出现在任一历史 commit 中,就仍然暴露在互联网上。文档强调:

"a secret committed years ago remains exposed even if later removed"

所以必须在本地对完整 git 历史执行一次扫描,找出所有历史提交中残留的密钥。

6.2 全量扫描命令

docker run --rm -v "$(pwd):/repo" -w /repo \ ghcr.io/gitleaks/gitleaks:latest \ detect --source=. --redact -v

参数拆解:

  • -v "$(pwd):/repo" -w /repo:把当前目录挂载进容器并设为工作目录;
  • detect --source=.:以当前目录为 git 仓库根,扫描全部提交历史
  • --redact:输出中把密钥值打码,避免终端日志二次泄露;
  • -v:verbose,显示每个命中的详情。

6.3 输出 SARIF 报告便于分诊

如果需要把结果沉淀成报告文件、导入缺陷跟踪系统或交给团队逐一处理,使用:

docker run --rm -v "$(pwd):/repo" -w /repo \ ghcr.io/gitleaks/gitleaks:latest \ detect --source=. --redact --report-format sarif --report-path gitleaks-history.sarif

与 CI 上传到 Security 标签页的格式一致,可以直接用同一套流程管理。

6.4 命中后的处理流程

文档给出了明确的处置链路:

  1. 轮换(Rotate):凡是历史中出现的密钥,一律视为已泄露——即使看起来从未被使用。修改对应的 API Key、Token、密码,使其立即失效;
  2. 抑制(Suppress):确认已轮换、且不需要再被报出的历史命中,通过.gitleaks.toml的 allowlist 按finding fingerprint精确豁免,避免每次全量扫描都重复报警。注意:当前仓库根目录下并没有现成的.gitleaks.toml文件,这是文档建议的"可选动作",需要时自行创建。

七、在本地复跑全部扫描器

SECURITY-SCANNING.md 提供了完整的本地复现命令,适合在 CI 之外做"提交前自查"或"CI 之外环境的巡检"。逐条说明如下:

# 1) Rails SAST —— 与 CI 的 brakeman 任务一致 bundle exec brakeman --no-progress # 2) 依赖漏洞 —— 先更新 advisory 库再检查 Gemfile.lock bundle exec bundle-audit update && bundle exec bundle-audit check # 3) Semgrep —— 四套规则集与 CI 完全一致 pip install semgrep && semgrep scan \ --config p/ruby --config p/rails --config p/secrets --config p/owasp-top-ten # 4) 镜像漏洞 —— 先本地构建再扫 docker build -f docker/Dockerfile -t dawarich:scan . trivy image --ignore-unfixed --severity HIGH,CRITICAL dawarich:scan # 5) 基础设施配置 trivy config .

几点补充说明:

  • brakemanbundler-audit来自 Gemfile 的development, :test, :staging组,本地开发环境bundle install后即可直接使用;
  • Semgrep 通过pip install安装,参数与 CI 中 security.yml 的--config p/ruby --config p/rails --config p/secrets --config p/owasp-top-ten完全对齐,保证本地结果与 CI 可比;
  • Trivy 命令需要本机已安装dockertrivy,且镜像构建耗时较长(Dawarich 的 Dockerfile 包含多阶段构建与资产预编译),适合在发布前或 CI 环境外做增量巡检时使用;
  • trivy config .不依赖构建,直接对仓库中的 Dockerfile 等 IaC 文件做静态检查,速度最快。

八、落地经验小结

Dawarich 的安全扫描体系提供了一套可迁移的模板,核心经验可以总结为四点:

  1. 分层而非单点:SAST(Brakeman + Semgrep)、依赖审计(bundler-audit)、密钥扫描(gitleaks)、容器扫描(Trivy)各司其职,覆盖从源码到产物的完整链路;
  2. 渐进式门禁:先用 Report-only 采集信号、摸清误报率,再按工具逐个收紧为 Blocking——既保安全底线,又不阻塞开发;
  3. 自动化与人工分工:CI 例行扫 diff,全量历史"排雷"放到本地按需执行,避免定时任务制造噪声;
  4. 供应链安全贯穿始终:Action 固定 SHA、最小权限、Dependabot 每周更新,同时在兼容性约束下理性控制基础镜像升级。

对于任何一个自托管、公开源码的 Rails 项目,这套"CI 例行扫描 + 本地全量排雷 + 自动化依赖更新"的组合,都是一份可以直接照搬的安全基线。

【免费下载链接】dawarichYour favorite self-hostable alternative to Google Timeline (Google Location History)项目地址: https://gitcode.com/GitHub_Trending/da/dawarich

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/15 15:48:13

金融级测试管理:六个可交付物驱动的质量决策链

1. 这不是教科书,是我在三个金融级项目里踩出来的测试管理路线图“软件测试管理:从测试计划到测试报告的全流程指南”——这个标题听起来像培训PPT的副标题,但我要说,它背后藏着的是一个团队能否按时交付、一个系统能否扛住百万并…

作者头像 李华
网站建设 2026/9/15 15:48:12

苹果CMS仿爱电影模板部署排错:CSS加载顺序与Nginx伪静态配置实战

简介:面向使用苹果CMS搭建电影站、且预算有限的站点运营者,首涂第三十八套仿爱电影模板以轻量简洁的视觉风格模拟热门爱电影界面的布局与交互,适用于快速上线影视分类、搜索、播放页等核心场景。压缩包共123个文件,以75个html页面…

作者头像 李华
网站建设 2026/9/15 15:45:50

三微网互联系统低碳经济调度优化与Matlab实现

1. 多微网能量互联优化调度的背景与挑战在能源结构转型和"双碳"目标的大背景下,微电网作为分布式能源的重要载体,正从单一微网向多微网互联系统演进。三微网系统作为多微网的一种典型架构,由三个相互连接但又相对独立的微电网组成&…

作者头像 李华
网站建设 2026/9/15 15:45:45

Java异常处理机制与高并发系统实践

1. 异常知识体系概述异常(Exception)作为现代编程语言中普遍存在的错误处理机制,本质上是一种程序控制流的非预期转移。当我在处理一个支付系统的高并发场景时,曾遇到过一个典型案例:某次促销活动期间,系统…

作者头像 李华
网站建设 2026/9/15 15:45:32

文件共享协议怎么选:NFS与SMB混用避坑与部署调优实战

存储这块我折腾了不少年,踩过的坑比吃过的盐还多。今天直接说结论:Linux 和 Windows 做文件共享,尽量别混着用协议。Linux 服务器之间老老实实走 NFS,Windows 机器之间踏踏实实走 SMB。这两套协议设计之初就是给不同“体质”的操作…

作者头像 李华