shahzaneer/Pre-CI-Security-Audit-Checks

GitHub: shahzaneer/Pre-CI-Security-Audit-Checks

一套基于 GitHub Actions 的可复用 CI 前安全审计流水线模板,集成了 SAST、SCA、恶意软件检测和包成熟度验证,作为部署前的安全门控机制。

Stars: 1 | Forks: 0

# CI 安全检查 一个可复用、多语言的 **CI 前安全审计** pipeline,作为部署前的门控机制。它执行四个并行安全扫描 — 供应链恶意软件检测、静态分析 (SAST)、软件成分分析 (SCA) 以及包成熟度验证 — 然后将结果聚合到一个统一的通过/失败仪表板中。 通过特定语言的 GitHub Actions 可复用工作流,同时支持 **JavaScript / Node.js 前端** 和 **Python 后端** 项目。 ## 架构 ``` workflow_call / push trigger │ ┌─────────────────┬───────────┼───────────┬─────────────────┐ ▼ ▼ ▼ ▼ ▼ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌──────────┐ │ depx │ │ sast │ │ sca │ │ age │ │ (repo) │ │ malware │ │ semgrep │ │ trivy │ │package │ │ inventory│ │ scan │ │ scan │ │ scan │ │maturity │ │ (lock) │ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ └────┬─────┘ │ │ │ │ │ └────────────────┼────────────┼────────────┘──────────────┘ │ │ ▼ ▼ ┌──────────────────────┐ │ gate job │ │ aggregate + decide │ └──────────┬───────────┘ │ outputs: has_failures (boolean) failure_count (integer) ``` 所有四个扫描任务均**并行**运行。**门控任务**会等待所有任务完成 (`needs: [depx, sast, sca, age]`),下载它们的 Markdown artifact 部分,将它们连接成 `$GITHUB_STEP_SUMMARY` 中的单个仪表板,评估通过/失败状态,并将结果作为 workflow 输出呈现,供下游任务进行条件分支。 ## 目录结构 ``` ci-checks/ ├── .vscode/ │ └── settings.json # VS Code Snyk integration ├── javascript-frontend/ │ ├── security_audit.yaml # Reusable workflow for Node.js / npm projects │ └── verify_package_age.cjs # Standalone npm package-age verifier (Node.js) └── python-backend/ ├── security_audit.yaml # Reusable workflow for Python / PyPI projects └── verify_package_age.py # Standalone PyPI package-age + hash verifier (Python) ``` ## 关于误报 没有任何安全扫描器能达到 100% 的准确率。此 pipeline 中的工具都是各自领域中**顶级的免费开源方案** (depx、Semgrep、Trivy) — 它们被广泛采用、积极维护,并在无需付费许可证的情况下提供最高的信噪比。 为了防止误报阻碍开发,只有置信度最高的信号才会对部署进行门控。较低严重性或较早的发现将作为仪表板警告显示 — 可见且可操作,但不会阻断流程。 ## 四道门控 — 为什么每个步骤都至关重要 ### 1. 供应链恶意软件检测 (`depx`) **工具**: ProjectDiscovery 的 [depx](https://github.com/projectdiscovery/depx) **功能**: 提取 `package.json` 和 `requirements.txt` 中声明的所有依赖项,通过管道传递给 `depx`,后者将每个包与已知恶意包数据库进行交叉比对。匹配结果将被分类为 **recent** (发布 ≤ 30 天) 或 **known** (超过 30 天)。 | | | |---|---| | **数据源** | ProjectDiscovery 精选数据库 (社区报告、安全研究、registry 分析) | - Recent 恶意包将**阻断** pipeline。 - Known 恶意包将作为**信息性警告**显示 (折叠在 `
` 块中)。 **必要性**: 包 registry 是供应链攻击的头号载体。攻击者会发布拼写错误抢注或依赖混淆的包,用于窃取机密、挖掘加密货币或注入后门。`depx` 可以在它们于您的 CI 环境中执行之前捕获它们 — 在最早可能的节点阻断攻击。 **失败条件**: 任何被标记为 **recent** 恶意包的依赖项 (`depx_recent > 0`)。 ### 2. 静态应用安全测试 — SAST (`sast`) **工具**: [Semgrep](https://semgrep.dev) (OSS 引擎) **功能**: 对整个源代码树运行 `semgrep scan --config auto` (排除 `.github/` 和 Kubernetes 清单)。它可以检测已知会导致漏洞的模式 — 硬编码的机密、SQL 注入、路径遍历、不安全的反序列化等。发现结果按严重程度进行分类: | | | |---|---| | **数据源** | Semgrep 社区规则库 (OWASP Top 10, CWE Top 25, 社区贡献) | | 严重程度 | 影响 | |----------|--------| | `ERROR` | **阻断** pipeline | | `WARNING` | 信息性 (仅显示在仪表板) | | `INFO` | 信息性 (仅显示在仪表板) | **必要性**: SAST 通过在开发期间、*在* 代码进入生产环境 *之前* 捕捉漏洞来实现安全左移。与 linter 不同,Semgrep 能理解安全语义 — 它不仅会标记“不良代码风格”,还会标记“此代码模式会导致 RCE”。将其作为 CI 门控运行可以防止已知的高危模式被部署。 **失败条件**: 一个或多个 `ERROR` 严重级别的 Semgrep 发现 (`sast_errors > 0`)。 ### 3. 软件成分分析 — SCA (`sca`) **工具**: Aqua Security 的 [Trivy](https://github.com/aquasecurity/trivy) v0.71.2 **功能**: 根据漏洞数据库扫描代码仓库中的所有第三方依赖项 (lockfile、vendored 包、site-packages)。识别具有已知 CVE 的包,并按严重程度进行评分: | | | |---|---| | **数据源** | NVD, GHSA, GitLab Advisories, Red Hat, Debian, npm, PyPA, RubySec | | 严重程度 | 影响 | |----------|--------| | `CRITICAL` / `HIGH` | **阻断** pipeline | | `MEDIUM` / `LOW` | 信息性 (仅显示在仪表板) | **必要性**: 即使您自己的代码是安全的,您的依赖项也未必安全。Log4Shell (CVE-2021-44228)、`event-stream` 事件以及 `xz` 后门都证明了传递依赖中的漏洞可能是灾难性的。SCA 回答了这个问题:*“我们正在发布已知存在漏洞的代码吗?”* **失败条件**: 任何具有 `CRITICAL` 或 `HIGH` CVE 的依赖项 (`sca_critical > 0`)。 ### 4. 包成熟度验证 (`age`) **工具**: 自定义脚本 — `verify_package_age.cjs` (Node.js) 和 `verify_package_age.py` (Python),以及工作流中的内联 Python 代码。 | | | |---|---| | **数据源** | npm registry (`registry.npmjs.org`) / PyPI JSON API (`pypi.org/pypi`) — 权威的实时 registry 元数据 | **功能**: 为每个锁定的依赖项查询 npm registry 或 PyPI,并检查其**发布日期**。任何发布少于 30 天的包都将被标记。 #### JavaScript (`verify_package_age.cjs`) - 解析 `package-lock.json` (支持 v1、v2 和 v3 lockfile 格式) - 查询 `https://registry.npmjs.org/`,对 scoped 包 (`@types%2Fnode`) 进行正确的 URL 编码 - 使用自定义的 `asyncPool` 辅助函数将并发限制为 25 个同时进行的 HTTP 请求 - 处理速率限制 (HTTP 429) 采用指数退避策略:[1秒, 3秒, 5秒, 10秒, 15秒] - 输出 `.pkg-age-report.json` (结构化 JSON) 和 `.pkg-age-errors.json` (用于 Slack/webhook 集成) - 在工作流中,该脚本会在 `node .github/workflows/verify_package_age.cjs` 被调用 — 这意味着需要将此文件复制到目标代码仓库的 `.github/workflows/` 目录中 #### Python (YAML 内联 + 独立的 `verify_package_age.py`) - **工作流 (内联)**: Python 的 `security_audit.yaml` 完全以内联方式执行年龄检查 — 它读取 `requirements.txt`,通过带有 `ThreadPoolExecutor(max_workers=16)` 的 `urllib` 查询 PyPI 的 JSON API,并直接生成 Markdown 部分。无需外部文件调用。 - **独立脚本** (`verify_package_age.py`): 一个更丰富的实现,额外支持: - 从 `requirements.txt` 解析 `--hash` 行 - **根据 PyPI 发布的摘要验证哈希值**,以检测篡改或镜像被入侵的情况 - 支持换行符 (`\`)、环境标记、extras 符号 (`psycopg[binary]`) - 输出 `package_age_report.json` 和带样式的 `package_age_report.html` **必要性**: 全新的包受到的社区审查要少得多。攻击者利用这一点发布恶意包,希望在这些包被报告和移除之前入侵项目。30 天的最短期限强制执行了一个“冷却期” — 如果一个包是供应链攻击,它很有可能在 30 天内被发现并下架。哈希验证 (Python 独立版) 增加了第二层保护:验证包的哈希值是否与 registry 的官方摘要匹配,可以防范镜像被入侵和中间人替换。 **失败条件**: 任何发布少于 30 天的包 (`age_failures > 0`)。 ## 门控如何聚合结果 `gate` 任务在所有四个并行任务完成后运行。它会: 1. 下载所有四个 `*-section` artifact (来自 depx、sast、sca、age 的 Markdown 片段)。 2. 将它们拼接到 `$GITHUB_STEP_SUMMARY` 中,生成一个统一的仪表板。 3. 读取每个任务的数值输出:`depx_recent`、`sast_errors`、`sca_critical`、`age_failures`。 4. 将它们汇总为总的 `failure_count`。 5. 如果 `force_deploy` 为 `true`,则从总数中减去 `age_failures`,但仍会发出警告。 6. 将 `has_failures` (布尔值) 和 `failure_count` (整数) 设置为 workflow 输出。 下游的部署任务随后可以根据以下条件进行门控: ``` if: needs.security.outputs.has_failures == 'false' ``` ## 工作流差异:JavaScript vs Python | 方面 | JavaScript | Python | |--------|-----------|--------| | Push 触发分支 | `stager` | `security-audit-depx` | | `FORCE_JAVASCRIPT_ACTIONS_TO_NODE24` | 在所有 5 个任务上设置 | 未设置 | | Semgrep `setup-python` 缓存 | 仅 `~/.cache/pip` | `cache: 'pip'` + `~/.cache/pip` | | 年龄检查实现 | 调用外部 `node .github/workflows/verify_package_age.cjs`,然后由内联 Python 渲染 Markdown | 完全使用内联 Python — 无外部脚本 | | 年龄检查并发 | 25 个请求 (Node.js `asyncPool`) | 16 个 workers (Python `ThreadPoolExecutor`) | | `download-artifact` action | `@v7` | `@v8` | | 年龄脚本输出 | `.pkg-age-report.json`, `.pkg-age-errors.json` | 直接输出 `age_section.md` | 尽管存在这些差异,两个工作流都会产生相同的输出 (`has_failures`、`failure_count`),并遵循相同的四道门控架构。 ## 如何使用 ### 从其他工作流调用 (推荐) ``` # 在你的 downstream repo 的 .github/workflows/deploy.yaml jobs: security: name: Pre-CI Security Audit uses: your-org/ci-checks/.github/workflows/javascript-frontend/security_audit.yaml@main with: repo_type: javascript # 'python', 'javascript', or 'both' force_deploy: false # set to 'true' to bypass age check only deploy: needs: security if: needs.security.outputs.has_failures == 'false' runs-on: ubuntu-latest steps: - run: echo "All security checks passed — deploying!" ``` ## 工作流输出 | 输出 | 类型 | 描述 | |--------|------|-------------| | `has_failures` | `boolean` | 如果有任何安全门控失败,则为 `true` (不包括强制部署的年龄检查) | | `failure_count` | `integer` | 所有四项检查中失败项目的总数 | ## 工具与依赖 | 层级 | 工具 | 版本 | 用途 | |-------|------|---------|---------| | CI 运行时 | GitHub Actions | — | 流程编排 | | 供应链 | [depx](https://github.com/projectdiscovery/depx) | latest | 恶意包检测 | | SAST | [Semgrep](https://semgrep.dev) | latest (pip) | 静态漏洞扫描 | | SCA | [Trivy](https://github.com/aquasecurity/trivy) | 0.71.2 | 已知 CVE 检测 | | 年龄检查 — JS | Node.js | ≥ 22 | npm registry 查询 | | 年龄检查 — Python | Python | ≥ 3.12 | PyPI registry 查询 | | 缓存 | `actions/cache` | v6 | depx vendor 数据库、pip 缓存、Trivy 漏洞数据库 | | Artifacts | `actions/upload-artifact@v7` / `actions/download-artifact@v7,v8` | v7 / v8 | 跨任务 Markdown + JSON 数据共享 | | IDE | VS Code + Snyk extension | — | 本地开发者侧扫描 | ## 优势 - **安全左移**: 在漏洞进入生产环境之前 — 而不是之后 — 捕捉它们。 - **深度防御**: 四个独立、互不重叠的安全视角。供应链恶意软件、SAST、SCA 和包成熟度各自能捕捉不同类别的风险。 - **顶级的免费工具**: pipeline 中的每个工具都是开源、免费且被广泛采用的 — 没有供应商锁定,无需付费许可证,而且每一个都代表了其所在领域的黄金标准 (用于恶意软件检测的 depx、用于 SAST 的 Semgrep、用于 SCA 的 Trivy)。 - **感知误报的设计**: 该 pipeline 的构建基于没有扫描器是完美的这一理解。只有最高置信度的信号 (recent 恶意软件、ERROR 级别的 SAST、CRITICAL/HIGH CVE、小于 30 天的包) 才会阻断部署。较低严重性的发现将作为信息性的仪表板警告显示 — 可见且可操作,同时不会中止发布。 - **并行执行**: 所有四个扫描均并发运行,因此总的门控延迟等于*最慢*扫描的持续时间,而不是所有四个扫描时间的总和。 - **设计上即可复用**: 单个工作流文件可以从任意数量的下游代码仓库中调用 — 避免了复制粘贴造成的偏差。 - **紧急覆盖**: `force_deploy 标志允许您发布依赖于一个确实全新的包的热修复,而无需禁用其他三个安全门控。 - **丰富的统一报告**: 每次运行都会在 GitHub Actions 总结界面中生成一个人类可读的 Markdown 仪表板,包含文件路径、行号、CVE ID 和包版本 — 开发者可以一目了然地对发现进行分类,而无需在日志中搜寻。 - **独立验证**: 年龄检查脚本可以在本地或任何 CI 系统中运行,而不仅仅是在 GitHub Actions 中。 - **语言对等性**: JavaScript 和 Python 项目通过一个共享架构获得同等的保护,仅存在极少的、有详细文档说明的特定语言差异。
标签:DevSecOps, GitHub Actions, MITM代理, 上游代理, 自动笔记, 逆向工具, 错误基检测, 静态代码分析