TomTonic/grype_me

GitHub: TomTonic/grype_me

基于 Anchore Grype 的 GitHub Action,可对仓库、容器镜像和 SBOM 进行漏洞扫描,自动生成安全徽章和详细报告。

Stars: 1 | Forks: 1

# ✊ grype_me [![Action 的漏洞情况](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/TomTonic/e0a34e0c03120db2400fc0480169498c/raw/grype_me-action_release.json)](https://gist.github.com/TomTonic/e0a34e0c03120db2400fc0480169498c#file-grype_me-action_release-md) [![Docker 镜像的漏洞情况](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/TomTonic/e0a34e0c03120db2400fc0480169498c/raw/grype_me-docker_image.json)](https://gist.github.com/TomTonic/e0a34e0c03120db2400fc0480169498c#file-grype_me-docker_image-md) 一个易于使用的 GitHub Action,利用 [Anchore Grype](https://github.com/anchore/grype) 扫描您项目的供应链是否存在已知漏洞,并生成包含详细报告的徽章。 ## 快速开始 ``` - uses: actions/checkout@v4 with: { fetch-depth: 0, fetch-tags: true } - uses: TomTonic/grype_me@v1 with: scan: 'latest_release' description: | Nightly vulnerability scan of latest stable release. Includes application dependencies from source manifests. fail-build: false gist-token: ${{ secrets.GIST_TOKEN }} gist-id: ${{ vars.GRYPE_BADGE_GIST_ID }} ``` 这将扫描您的最新 release,将 shields.io 徽章 JSON 和详细的 Markdown 报告上传到 GitHub Gist,并使徽章 URL 作为步骤输出可用。点击上方的徽章查看实时示例报告。 有关完整示例,请参阅本项目如何[运行每日扫描](./.github/workflows/security-badge.yml)以更新此 README 中的两个徽章。 ## 功能特性 - 🔍 使用最新版本的 Grype 及每日更新的漏洞数据库(捆绑在 action 镜像中) - ⚡ 比 workflow 运行期间安装 Grype **快约 2 倍**(无需下载约 200 MB 的数据库) - 📦 **多种扫描目标**:repositories、container images、目录或 SBOMs - 🎯 **最新 release 扫描**:非常适合对已发布的 release 进行夜间扫描 - 📊 按严重程度(Critical, High, Medium, Low)详细统计漏洞数量 - 🚨 当漏洞达到或超过配置的阈值时让构建失败 - 🔧 选项:仅显示有可用修复方案的漏洞 - 🏷️ **动态徽章生成**,附带链接的 Markdown 报告——无需额外的 action ## 工作原理 此 action 在 Docker 容器内运行 Grype,并使用预先下载的漏洞数据库。它支持两种模式: | 模式 | 输入 | 描述 | |------|-------|-------------| | **Repository** | `scan` | 通过依赖清单(`go.mod`, `package.json`, `requirements.txt` 等)扫描源代码 | | **Artifact** | `image` / `path` / `sbom` | 扫描 container images、目录或 SBOM 文件 | ### Repository 模式 Grype 直接从 repo 读取依赖清单——无需构建。这对 **Go 项目**特别有效。 - ✅ 无需编译即可检测源码声明的依赖 - ✅ 非常适合对带标签的 release 进行夜间扫描 - ❌ 仅运行时存在或动态下载的依赖需要使用 artifact 模式 **扫描模式:** - `latest_release` – 扫描最高的稳定 semver 标签(默认) - `head` – 扫描当前工作目录 - `` – 扫描特定的 ref ### Artifact 模式 使用 `image`、`path` 或 `sbom` 扫描构建产物。这些输入与 `scan` 互斥。 ## 用法 ### 带徽章的夜间 Release 扫描 请参阅 [`.github/workflows/security-badge.yml`](./.github/workflows/security-badge.yml),了解生成此 README 中所示徽章的 workflow。以下是基本模式: ``` name: Security Badge on: schedule: - cron: '0 2 * * *' workflow_dispatch: jobs: update-badge: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: { fetch-depth: 0, fetch-tags: true } - uses: TomTonic/grype_me@v1 with: scan: 'latest_release' description: | Nightly release scan for the public badge report. Scans the latest semver tag in this repository. fail-build: false gist-token: ${{ secrets.GIST_TOKEN }} gist-id: ${{ vars.GRYPE_BADGE_GIST_ID }} gist-filename: 'my-project' ``` 这会将三个文件写入 gist: - `my-project.json` — shields.io endpoint badge JSON - `my-project.md` — 包含 CVE 表格的详细 Markdown 报告 - `my-project-grype.json` — 原始 Grype 扫描输出 ### Container Image 扫描 ``` - name: Build image run: docker build -t myapp:${{ github.sha }} . - uses: TomTonic/grype_me@v1 with: image: 'myapp:${{ github.sha }}' image-source: 'registry' description: | PR build image scan for commit `${{ github.sha }}`. Used as release gate for container publishing. fail-build: true severity-cutoff: 'high' ``` `image-source: registry` 直接从 registry 拉取,避免访问 Docker daemon。 ### 在 README 中使用徽章 首次 workflow 运行后,将徽章添加到您的 README: ``` [![Vulnerabilities](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/YOUR_USER/YOUR_GIST_ID/raw/my-project.json)](https://gist.github.com/YOUR_USER/YOUR_GIST_ID#file-my-project-md) ``` 徽章链接到渲染后的 gist 报告(而非原始文件视图)。点击它会显示完整的 CVE 明细。 GitHub gist 文件锚点基于渲染后的 DOM ID(例如,`my_file.md` → `#file-my_file-md`;下划线保持不变)。 #### 设置 1. 在 [gist.github.com](https://gist.github.com) **创建一个 GitHub Gist**,包含任意初始文件(例如内容为 `{}` 的 `init.txt`)。从 URL 复制 Gist ID。 2. 在 [GitHub Settings → Developer settings → Personal access tokens](https://github.com/settings/tokens) **创建一个 Personal Access Token**,需具有 `gist` scope。 3. 向您的 repository **添加 secrets/variables**: - Secret `GIST_TOKEN` — 步骤 2 中的 PAT - Variable `GRYPE_BADGE_GIST_ID` — 步骤 1 中的 gist ID ## 输入 ### 扫描目标(互斥) | 输入 | 描述 | 默认值 | |-------|-------------|---------| | `scan` | Repository 扫描:`latest_release`、`head` 或标签/分支 | `latest_release` | | `image` | 要扫描的 Container image(例如 `alpine:latest`) | – | | `image-source` | `image` 扫描的来源:`auto`, `registry`, `docker`, `podman`, `containerd` | `auto` | | `path` | 要扫描的目录或文件 | – | | `sbom` | SBOM 文件 (Syft, CycloneDX, SPDX) | – | ### 选项 | 输入 | 描述 | 默认值 | |-------|-------------|---------| | `fail-build` | 如果漏洞 ≥ `severity-cutoff` 则失败 | `false` | | `severity-cutoff` | 阈值:`negligible`, `low`, `medium`, `high`, `critical` | `medium` | | `output-file` | 将结果保存到 JSON 文件 | – | | `only-fixed` | 仅报告有可用修复方案的漏洞 | `false` | | `db-update` | 扫描前更新数据库(参见[性能](#performance)) | `false` | | `strict-privilege-drop` | 如果在 UID/GID 丢弃之前无法预打开 `GITHUB_OUTPUT`,则失败而不是回退到 root | `false` | | `description` | 可选的自由文本(支持 Markdown/换行),逐字复制到报告 `.md` 的 `Description:` 下 | – | ### Gist 集成 | 输入 | 描述 | 默认值 | |-------|-------------|---------| | `gist-token` | 具有 `gist` scope 的 GitHub PAT(存储为 secret) | – | | `gist-id` | 要更新的 gist 的 ID | – | | `gist-filename` | gist 文件的基础文件名(例如 `my-project`) | 根据扫描模式自动生成 |
高级输入 | 输入 | 描述 | 默认值 | |-------|-------------|---------| | `debug` | 打印环境变量(可能会暴露 secrets) | `false` |
## 输出 | 输出 | 描述 | |--------|-------------| | `cve-count` | 发现的漏洞总数 | | `critical` / `high` / `medium` / `low` | 按严重程度统计的数量 | | `grype-version` | 使用的 Grype 版本 | | `db-version` | 漏洞数据库版本 | | `json-output` | 输出文件的路径(如果设置了 `output-file`) | | `badge-url` | shields.io 徽章 URL(配置 gist 时为动态 endpoint,否则为静态) | | `report-url` | 渲染后的 gist 报告部分的 URL(`gist.github.com/...#file-...`;保留下划线) | | `runtime-privilege` | 有效的权限模式:`already-non-root`, `dropped` 或 `root-fallback` | | `runtime-privilege-detail` | 当权限降级无法执行时的回退/严格失败原因诊断 | ### 权限降级故障排除 容器以 root 身份启动,并在降级到 UID 10001 之前预打开 `GITHUB_OUTPUT`。继承的文件描述符在 `setuid`/`setgid` 之后仍然有效(标准 Unix 行为),因此可以在不修改挂载所有权的情况下写入步骤输出。如果预打开失败,action 将: - 回退到 root(默认,`strict-privilege-drop: false`)并报告 `runtime-privilege=root-fallback` - 快速失败(`strict-privilege-drop: true`) 使用 `runtime-privilege` 和 `runtime-privilege-detail` 输出以及警告日志来检测这种情况。 ## 性能 Action 镜像每天使用最新的 Grype 和漏洞数据库**重建**。这消除了约 200 MB 的数据库下载,使扫描速度比在 GitHub Actions workflow 中手动运行 Grype **快约 2 倍**。 | 场景 | 建议 | |----------|----------------| | 夜间扫描 | 使用预置数据库(默认)——快速且足够新 | | 发布前的安全门 | 考虑使用 `db-update: true` 以确保绝对最新 | ``` - uses: TomTonic/grype_me@v1 with: scan: 'latest_release' db-update: true # Download latest DB before scanning ``` ### 每日标签更新 发布的 container image 每天重建,以始终包含最新的 Grype release 和最新的漏洞数据库。因此,移动标签每天都会转移到新镜像:`latest`、`v1`、`v1.2` 和 `v1.2.3`。根据设计,补丁级别仅指此 action 的补丁级别,不包括漏洞数据库。 只有以下标签保持不可变且稳定: - `v1.2.3-release` - `v1.2.3_grype-0.xyz.0_db-YYYY-MM-DDThh-mm-ssZ` 此行为是有意为之,但如果您尝试在 CI 或其他自动化中固定到补丁级别标签,可能会令人惊讶。如果您需要不变的镜像,请固定到其中一个不可变标签(例如特定数据库的 `..._grype-..._db-...` 标签或 `-release` 标签)。 ## 徽章 此 action 生成一个动态的 [shields.io](https://shields.io) 徽章,通过颜色编码显示漏洞数量: | 颜色 | 含义 | |-------|---------| | ![brightgreen](https://img.shields.io/badge/vulnerabilities-none-brightgreen) | 无漏洞 | | ![yellowgreen](https://img.shields.io/badge/vulnerabilities-2%20low-yellowgreen) | 仅低严重性 | | ![yellow](https://img.shields.io/badge/vulnerabilities-3%20medium-yellow) | 中严重性 | | ![orange](https://img.shields.io/badge/vulnerabilities-1%20high-orange) | 高严重性 | | ![critical](https://img.shields.io/badge/vulnerabilities-2%20critical-critical) | 严重 严重性 | 配置 gist 集成后,徽章是一个会自动更新的 [shields.io endpoint badge](https://shields.io/badges/endpoint-badge)。点击徽章会打开详细的 Markdown 报告,显示每个 CVE 的 package、version、fix status 和 description。 如果没有 gist 集成,`badge-url` 输出将包含一个静态的 shields.io URL,可以显示在 workflow 摘要中: ``` - uses: TomTonic/grype_me@v1 id: grype with: { scan: 'latest_release' } - run: | echo "![Badge](${{ steps.grype.outputs.badge-url }})" >> $GITHUB_STEP_SUMMARY ``` ## 告警示例 ### 创建 GitHub Issue ``` - uses: TomTonic/grype_me@v1 id: grype with: { scan: 'latest_release' } - if: steps.grype.outputs.critical > 0 uses: actions/github-script@v7 with: script: | await github.rest.issues.create({ owner: context.repo.owner, repo: context.repo.repo, title: '🚨 Critical vulnerabilities detected', body: `Found ${{ steps.grype.outputs.critical }} critical CVEs.\n\n[View report](${{ steps.grype.outputs.report-url }})`, labels: ['security', 'critical'] }); ``` ### Slack 通知 ``` - uses: TomTonic/grype_me@v1 id: grype with: { scan: 'latest_release' } - if: steps.grype.outputs.cve-count > 0 uses: slackapi/slack-github-action@v1 with: payload: | { "text": "🔒 Scan: ${{ steps.grype.outputs.critical }} critical, ${{ steps.grype.outputs.high }} high CVEs" } env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} ``` ## 许可证 BSD 3-Clause License – 详见 [LICENSE](LICENSE)。
标签:AI应用开发, Anchore, Angular, Claude, CVE检测, DevSecOps, Docker, EVTX分析, Gist, GitHub Action, Grype, Markdown报告, SBOM, Web截图, 上游代理, 云安全监控, 代码安全, 安全徽章, 安全防御评估, 容器安全, 工作流, 测试覆盖率, 漏洞枚举, 硬件无关, 结构化查询, 自动化安全, 请求拦截, 静态分析