boredchilada/piptastic
GitHub: boredchilada/piptastic
Python 项目依赖审计工具,检测版本漂移和已知 CVE,并支持感知漏洞的安全版本重写。
Stars: 6 | Forks: 1
# piptastic
一个用于 Python 项目的依赖审计工具。它会遍历目录树,找到每一个声明了
依赖的项目,并针对每个版本锁定回答两个问题:*它过时了多久*
以及 *它是否存在漏洞*。它还可以选择将 `requirements.txt` 重写为
最新兼容版本,同时遵循来自
[pip-audit](https://github.com/pypa/pip-audit) 的 CVE 修复版本数据。
[](LICENSE)
[](pyproject.toml)
[](https://github.com/boredchilada/piptastic/actions/workflows/test.yml)
[](#json-schema)
一次性 CLI。没有守护进程、没有服务器、没有共享状态。可用于运行
单个项目或包含数百个项目的目录树。
## 目录
- [安装](#install)
- [快速开始](#quickstart)
- [设计说明](#design-notes)
- [命令](#commands)
- [工作流](#workflows)
- [接受已知 CVE(抑制规则)](#accepting-known-cves-suppressions)
- [参考](#reference) — 发现、解析、偏移、锁定姿态、 JSON
schema、缓存、日志记录、退出代码
- [路线图](#roadmap)
- [发布说明](#release-notes)
- [许可证](#license)
- [贡献](#contributing)
- [致谢](#acknowledgements)
## 安装
```
pip install git+https://github.com/boredchilada/piptastic
# 或者,使用 PATH 上的 CLI 进行隔离安装:
pipx install git+https://github.com/boredchilada/piptastic
```
会安装两个入口点:`piptastic` 和 `ptc`(短别名)。如果不
安装,可以直接运行该包:`python -m piptastic`。
运行时要求:Python 3.10+,`packaging`,`rich`,`pip-audit`。在 Python < 3.11 上会自动引入 `tomli`。
`pip-audit` 会在底层作为
`python -m pip_audit` 被调用,因此在 Windows 上不需要 PATH 垫片。
## 快速开始
审计单个项目:
```
piptastic audit .
```
示例输出(表格视图,单项目的默认视图):
```
+-----------------------------------------------------------------------------------------+
| Project | Package | Current | Latest | Age | Min safe | Drift | Pin | Vulns
|---------------+------------+----------+--------+------+----------+-------+-------+------
| my-flask-app | flask | 2.0.0 | 3.1.3 | 2mo | 3.1.0 | major | pinned| 2
| my-flask-app | requests | 2.31.0 | 2.34.2 | 1mo | 2.32.4 | minor | pinned| 1
| my-flask-app | sqlalchemy | 2.0.30 | 2.0.43 | 3mo | - | patch | pinned| -
+-----------------------------------------------------------------------------------------+
```
审计整个目录树:
```
piptastic audit ~/code --summary
```
```
+-----------------------------------------------------------------------------------------+
| Project | Py | Pin score | Major | Minor | Patch | Other | Yanked | Vulns | Deps
|----------------+------+-----------+-------+-------+-------+-------+--------+-------+-----
| my-flask-app | 3.11 | 100% | 1 | 1 | 1 | 0 | 0 | 3 | 3
| ingestion-svc | 3.12 | 60% | 0 | 2 | 5 | 0 | 1 | 0 | 12
| legacy-cron | 3.10 | 0% | 8 | 3 | 1 | 1 | 2 | 27 | 14
+-----------------------------------------------------------------------------------------+
3 projects | 29 deps | 27 CVEs across 1 project(s) | 3 yanked
```
对一个项目的 `requirements.txt` 应用感知 CVE 的版本提升:
```
piptastic update ~/code/legacy-cron
# 7 个已升级,2 个由 CVE 驱动
```
预览而不写入:
```
piptastic update ~/code/legacy-cron --dry-run
```
## 设计说明
代码库的结构反映了几个明确的选择:
- **标准库 `urllib` 用于 PyPI,而不是 `requests`。** 少了一个运行时依赖。
PyPI 的 JSON endpoint 足够稳定,不需要重量级的客户端。
- **通过 subprocess 调用 `pip-audit`,而不是在 Python 中 import。** 该库的公共
接口就是 CLI。导入其内部实现会将 piptastic 耦合到一个
不断变化的目标上。
- **到处使用 Frozen dataclass。** `Dep`、`DepAudit`、`ProjectAudit`、
`Vulnerability` 全部是不可变的。通过重建进行修改;新字段会带有
默认值,因此旧的调用处仍能正常工作。领域逻辑存在于
`analysis.py` 中,而不是 dataclass 上。
- **按源文件缓存。** PyPI 元数据按发行版名称缓存;
pip-audit 结果按 `(name, version)` 对缓存。空漏洞结果也
会被缓存——干净的版本锁定不会在后续运行中重新调用 subprocess。
- **优雅降级,绝不静默。** PyPI 缺失会变成 `drift=unknown`
并显示在 `pypi_unreachable` 中。pip-audit 缺失会显示在
`vuln_unreachable` 中(不会被静默报告为干净)。单个项目的失败
不会终止整个目录树的扫描。
- **严格的退出代码约定。** `0` 干净,`1` 操作错误,`2`
重写已回滚,`3` 触发策略门禁。CI 可以区分“你
配置错了”和“门禁生效了”。
- **带版本控制的单一输出 schema。** JSON 输出会声明
`schema_version`。新增更改不会提升版本;字段重命名/删除
则会提升版本。文档记录在 [schema 版本历史](#schema-version-history)中。
## 命令
### `audit `
只读。发现 `` 下的 Python 项目,并报告每个
依赖的锁定姿态、相对于 PyPI 的偏移以及已知 CVE。
| Flag | 效果 |
| --- | --- |
| `--table` | 平铺表格视图(单项目的默认视图)。 |
| `--summary` | 每个项目一行:偏移直方图(Major / Minor / Patch,加上折叠了构建和 epoch 偏移的 `Other` 列)+ 锁定分数 + CVE 汇总。 |
| `--json` | 输出到 stdout 的机器可读 JSON。参见 [JSON schema](#json-schema)。 |
| `--sarif` | 用于 GitHub Code Scanning 的 SARIF 2.1.0 输出。与 `--json` 互斥。 |
| `--include-prereleases` | 将预发布版本视为“最新”的候选。 |
| `--exclude PATTERN` | 与目录基名匹配的 Glob。可重复使用。叠加在内置跳过列表之上。 |
| `--no-cache` | 本次运行跳过磁盘上的 PyPI 缓存。 |
| `--refresh-cache` | 强制重新获取并重写缓存。 |
| `--cache-ttl SECONDS` | 覆盖默认 TTL(3600)。 |
| `--concurrency N` | PyPI 获取线程池大小。 |
| `--no-vulns` | 完全跳过 pip-audit CVE 扫描。与 `--fail-on-vuln` 互斥。 |
| `--vulnerable-only` | 仅显示带有非抑制 CVE 的依赖。匹配数为零的项目将被丢弃。 |
| `--drift-min {build,patch,minor,major,epoch}` | 仅显示偏移 ≥ 此级别的依赖。 |
| `--direct-only` | 从输出中隐藏传递性 lockfile 依赖。仅用于显示——门禁仍会评估完整的解析图。 |
| `--fail-on-drift {build,patch,minor,major,epoch}` | 当任何依赖的偏移 ≥ 此级别时退出代码为 `3`。 |
| `--fail-on-age DAYS` | 当任何依赖的最新发布时间超过 `DAYS` 时退出代码为 `3`。发布日期未知的依赖(PyPI 缺失)永远不会触发它。 |
| `--fail-on-vuln any\|N` | 当任何依赖具有非抑制 CVE(`any`)或整个目录树的 CVE 计数 ≥ N 时退出代码为 `3`。 |
| `--strict-vuln-gate` | 设置了 `--fail-on-vuln` 时,也会对 `vuln_unreachable` 的包触发。默认值为 fail-open 并给出警告。 |
默认视图:对于多项目路径显示树形结构(项目 → 文件 → 依赖),对于
单个项目显示表格。当展示多个项目时,终端输出会以
单行统计结束——包含项目和依赖数量,以及不为零时的 CVE 和 yanked
总数。
### `update [packages ...]`
就地修改 `requirements.txt`。将每个锁定的依赖解析为最新
兼容的发行版(`~=` 仍保持兼容发行版,`>=` 底线仍保持为
底线),写入备份,在临时的 venv 中运行测试安装,如果
安装失败则回滚。
默认情况下,针对每个 `==` 锁定查询 pip-audit,如果当前锁定被未决的咨询覆盖,
则将提升目标提升至最低安全版本。
受 CVE 驱动的提升会在输出中注明:
```
flask: 2.0.0 -> 2.2.5 (CVE floor: PYSEC-2023-62)
```
| Flag | 效果 |
| --- | --- |
| `--dry-run` | 计算可能发生的更改;不写入文件、创建备份或运行测试安装。仍会进行 CVE 底线查找,因此预览结果是准确的。 |
| `--no-test` | 跳过测试安装步骤。 |
| `--refresh` | 绕过 PyPI 和漏洞缓存(等同于 `audit` 中的 `--refresh-cache`)。 |
| `--temp-test-env` | 将临时测试安装 venv 放在 OS 临时目录下,而不是项目旁边的 `.piptastic_test_/` 中。 |
| `--no-apply-cce-floor` | 禁用感知 CVE 的底线;照常选择最新未被 yanked 的发行版。 |
位置参数 `packages` 会将更新限制在这些发行版中。仅
会修改 `requirements*.txt` 家族文件;`pyproject.toml` 和 `Pipfile`
重写尚未实现。
### `stats `
基于同一审计流水线的跨项目汇总。终端输出会显示
被依赖最多的包、跨目录树的版本碎片化、yanked
锁定、未锁定的项目,以及全目录树的偏移 / 锁定姿态直方图。
| Flag | 效果 |
| --- | --- |
| `--top N` | Top-N 包列表大小(默认为 20)。 |
| `--json` | 输出到 stdout 的机器可读 JSON。 |
| `--exclude`, `--no-cache`, `--refresh-cache`, `--cache-ttl`, `--concurrency` | 与 `audit` 相同。 |
### `bootstrap `
根据项目 venv 中安装的包生成 `requirements.txt`。
输出为排序后的 `name==X.Y.Z` 行,venv 自带的基础包(`pip`、`setuptools`、
`wheel`、`pkg_resources`、`distlib`、`_distutils_hack`)以及任何可编辑的
项目自安装都会被过滤掉。
| Flag | 效果 |
| --- | --- |
| `--venv PATH` | 显式指定 venv 目录。当存在多个 venv 并且你想要明确指定时是必填项。 |
| `--force` | 覆盖现有的 `requirements.txt`。之前的文件会先被复制到 `.requirements_backups/requirements__.txt`。 |
| `--dry-run` | 打印到 stdout;不进行任何写入。 |
自动发现会探测 `.venv`、`venv`、`env`、`.env` 中的 `pyvenv.cfg`,然后
回退到扫描项目的顶层子目录。如果找到零个或
多个候选者,且未提供 `--venv`,该命令将在不写入的情况下退出。
## 工作流
### 查找过时的内容
```
piptastic audit . # full table for one project
piptastic audit ~/code --summary # one row per project across a tree
```
偏移列告诉你 `X.Y.Z` 的哪一部分发生了变动。`Age` 列
会显示那些即使偏移为 `none`,但也已经好几年没有发布过的包。
### 将锁定提升到最新兼容版本
```
piptastic update .
piptastic update . flask requests # limit to specific packages
piptastic update . --no-test # skip the test install
piptastic update . --dry-run # preview without writing
piptastic update . --refresh # bypass caches for a fresh fetch
```
对于每个 `==` 锁定,会选择现有说明符允许的、最新未被 yanked 的稳定发行版,
如果 pip-audit 报告
所选版本仍处于易受攻击的范围内,则会进一步提升。
### 查找已知存在 CVE 的项目
```
piptastic audit ~/code --summary --vulnerable-only
```
汇总中的 Vulns 列会汇总每个项目的咨询信息。深入了解某个项目:
```
piptastic audit ~/code/legacy-cron --table --vulnerable-only
```
Min safe(最低安全)列给出了解决影响当前锁定的所有咨询
的最低版本。应用方法:
```
piptastic update ~/code/legacy-cron
```
CVE 底线默认开启;传递 `--no-apply-cve-floor` 可将其禁用。
为了便于流水线消费,JSON 输出包含了每个依赖的完整
`vulnerabilities[]` 数组:
```
piptastic audit ~/code --json | jq '
.projects[]
| {name, vuln_count,
vulnerable_deps: [.deps[] | select(.vulnerabilities | length > 0)
| {name, current, min_safe_version, vulns: [.vulnerabilities[].id]}]}'
```
### 在 CI 中阻止过时或带有漏洞的 PR
```
piptastic audit . --fail-on-drift minor --fail-on-vuln any
```
如果任何依赖的偏移量达到或超过 `minor`,或者任何依赖有
非抑制的 CVE,则退出代码为 `3`。退出代码 `1` 保留用于操作错误;退出代码 `0`
表示干净。
GitHub Actions:
```
- name: Audit dependencies
run: |
pip install git+https://github.com/boredchilada/piptastic
piptastic audit . --fail-on-drift minor --fail-on-vuln any
```
或者上传 SARIF,以便在 Security 选项卡中渲染发现结果:
```
- name: Audit dependencies (SARIF)
run: |
pip install git+https://github.com/boredchilada/piptastic
piptastic audit . --sarif > piptastic.sarif
- uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: piptastic.sarif
```
### 从 venv 恢复丢失的 requirements.txt
```
piptastic bootstrap . --dry-run # preview
piptastic bootstrap . # write requirements.txt
piptastic bootstrap . --force # overwrite (existing file is backed up)
piptastic bootstrap . --venv .venv # disambiguate when multiple venvs exist
```
### 调查整个代码文件夹的依赖健康度
```
piptastic stats ~/code
piptastic stats ~/code --json > stats.json
```
显示被依赖最多的包、版本碎片化的包(在不同
项目中锁定不同版本的同名包)、仍在发布的 yanked 锁定,
以及整个目录树的直方图。
### 在依赖之前评估第三方项目
```
piptastic audit /path/to/their/repo --summary
```
锁定分数、偏移计数器、漏洞计数以及最新发行版存在时间列
可以让你快速了解项目的维护姿态。
## 接受已知 CVE(抑制规则)
当某个咨询仅在名义上影响你——未执行易受攻击的代码路径、
在更高层已经实施了缓解措施、修复程序尚不可用——可以在项目的 `pyproject.toml` 中添加抑制规则:
```
[tool.piptastic]
[[tool.piptastic.suppressions]]
package = "flask"
cve = "PYSEC-2023-62" # also matches the advisory's aliases
reason = "we do not use sessions"
expires = "2026-12-31" # required; past-expiry rules are ignored
```
这四个字段都是必填的。过期的规则会被忽略并记录在日志中,这样
它们就不会存在。在接下来的 30 天内即将过期的规则会
在其仍处于活动状态时发出提醒警告,从而确保被接受的 CVE 不会在到期之日
静默重新激活(并触发 `--fail-on-vuln`)。每条规则都会匹配规范咨询 id
或 pip-audit 报告的任何别名(GHSA / CVE / PYSEC)。`package = "*"`
会抑制项目中所有包的 CVE。
没有 `pyproject.toml` 的项目可以在根目录使用同级的 `.piptastic.toml` 配置规则:
```
[[suppressions]]
package = "requests"
cve = "CVE-2024-1234"
reason = "patched at the proxy"
expires = "2099-01-01"
```
效果:
- `vuln_count` 和 `--fail-on-vuln` 仅计算非抑制的咨询。
- `min_safe_version` 仅根据非抑制的咨询计算;`update`
不会针对已接受的 CVE 提升锁定。
- 完整的咨询仍会输出在 JSON(`suppressed: true` 加上
`suppression` 块)和 SARIF(`suppressions: [{kind: "external"}]`)中,因此
外部审计员可以看到它。
## 参考
### 漏洞查找
每次 `audit` 运行都会在获取 PyPI 元数据的同时查询 pip-audit。pip-audit
会针对 piptastic 已经解析好的 `(name, version)` 对作为
`python -m pip_audit -r --format json --no-deps
--disable-pip` 被调用,因此没有单独的
依赖解析步骤。
每个依赖的结果:
- `vulnerabilities` — 咨询列表:GHSA / PYSEC / CVE id、别名、
修复版本、上游描述。
- `min_safe_version` — 比已安装锁定更新的、每个咨询最低修复版本中的
最大值。升级到此版本可解决所有已知
咨询。当没有适用的咨询,或者没有比当前锁定更新的已知修复时,为 `null`。
每个项目的汇总:
- `vuln_count` — 所有依赖中非抑制咨询的计数,
按咨询 id 去重(pip-audit 可能会针对每个受影响版本范围报告一次相同的咨询;
这些会被合并,因此计数不会膨胀)。
- `vuln_unreachable` — pip-audit 未能返回状态的包。
显示为“unknown”,绝不会被静默视为干净。
- `suppressed_count` — 接受风险的咨询,来自
`[tool.piptastic.suppressions]`。
### 项目发现
如果一个目录包含以下任何内容,则它是一个 Python 项目:
- `requirements*.txt`(包括 `requirements-dev.txt` 等)
- 带有 `[project]` 或 `[tool.poetry]` 表的 `pyproject.toml`
- `Pipfile`
- `uv.lock`、`poetry.lock` 或 `pdm.lock`
遍历会跳过 `.git`、`.venv`、`venv`、`env`、`.env`、`node_modules`、
`__pycache__`、`site-packages`、`build`、`dist`、`.tox`、`.nox`、
`.mypy_cache`、`.pytest_cache`、`.ruff_cache`,以及任何包含
`pyvenv.cfg` 的目录。`--exclude PATTERN` 会添加到此列表中,并接受
与目录基名匹配的 glob 语法。
需求文件内部的 `-r other.txt` / `-c constraints.txt` 包含内容会
在带有循环检测的情况下被跟踪。每个依赖都归因于最初
声明它的文件,而不是包含它的文件。
### 依赖解析
| 来源 | 读取内容 |
| --- | --- |
| `requirements*.txt` 家族 | PEP 508 说明符;带循环检测的 `-r` / `-c` 包含;遵循环境标记;URL / VCS / 本地路径要求显示为 `URL` 姿态。没有 `#egg=name` 的纯 `git+https://…` 行会根据 repo 路径命名,因此它仍然会被显示。 |
| `pyproject.toml` (PEP 621) | `[project].dependencies` 以及 `[project.optional-dependencies]` 下的每个列表。 |
| `pyproject.toml` (Poetry) | `[tool.poetry.dependencies]` 和 `[tool.poetry.group..dependencies]`。插入符号(`^1.2.3`)和波浪号(`~1.2.3`)简写会被展开为 PEP 440 范围。`python` 会被排除。多重约束依赖(一个用于特定平台锁定的 `{version, markers}` 表列表)会变成每个条目一个依赖,各自带有自己的说明符和标记。 |
| `Pipfile` | `[packages]` 和 `[dev-packages]`。 |
| `Pipfile.lock` | 来自 `default` 和 `develop` 部分的带哈希锁定行。 |
| `uv.lock` / `poetry.lock` / `pdm.lock` | 完整的解析图——每个 `[[package]]` 条目作为一个精确锁定(直接**和**传递)。存在 lockfile 时,它会取代其清单(匹配的 `pyproject.toml` 源会被跳过以避免重复计算);仍会读取清单以标记哪些条目是直接依赖。传递条目会在输出中标记,并在 JSON 中标记为 `direct: false`。项目自己的可编辑/虚拟条目会被跳过。 |
`requirements*.txt` 文件会被解码为 UTF-8(允许 UTF-8 BOM)。如果检测到
UTF-16 或 UTF-32 字节顺序标记,则会相应地解码,因此由 PowerShell 的
`pip freeze > requirements.txt`(在 Windows 上为 UTF-16-LE)编写的文件
会被正确解析,而不是被静默丢弃。
### 偏移分类
对于每个具有可比较的声明/最新版本的依赖,偏移会根据
声明版本与最新匹配的 PyPI 发行版之间变动的片段
进行分类:
| 层级 | 含义 |
| --- | --- |
| `NONE` | 声明版本等于最新版本。 |
| `BUILD` | 仅第 4 段及以后的片段发生变动。 |
| `PATCH` | 第 3 段(`X.Y.Z` 中的 `Z`)。 |
| `MINOR` | 第 2 段。 |
| `MAJOR` | 第 1 段。 |
| `EPOCH` | PEP 440 epoch(`N!X.Y.Z`)发生变动。罕见。 |
### 锁定姿态
说明符的*形状*(而不是版本值)决定了姿态:
| 姿态 | 示例 |
| --- | --- |
| `PINNED` | `flask==2.3.0`, `flask===2.3.0` |
| `COMPATIBLE` | `flask~=2.3.0`(PEP 440 兼容发行版) |
| `RANGE` | `flask>=2.0,<3.0` |
| `FLOOR` | `flask>=2.0`(开放上限) |
| `UNPINNED` | `flask`(无说明符) |
| `URL` | `flask @ git+https://...`,本地路径,直接 URL |
**Pin score** 是项目中处于 `PINNED`
或 `COMPATIBLE` 状态的非 URL 依赖的百分比。所有依赖都是 `URL` 的项目显示为 `n/a`——URL 锁定取决于 URL 是否锁定了一个引用,而审计器无法
可靠地判断这一点。
### JSON schema
`audit --json` 和 `stats --json` 都会生成 `schema_version: 3`。破坏性更改会提升版本;
附加更改则不会。顶层的鉴别器是
`kind`:`audit --json` 对应 `"audit"`,`stats --json` 对应 `"stats"`。
每个依赖的字段(audit):
```
{
"name": "flask",
"current": "2.0.0",
"latest": "3.0.4",
"drift": "major",
"pin_status": "pinned",
"yanked": false,
"vulnerabilities": [
{
"id": "PYSEC-2023-62",
"aliases": ["CVE-2023-30861", "GHSA-m2qf-hxjv-5gpq"],
"fix_versions": ["2.2.5", "2.3.2"],
"description": "Flask session cookie issue ...",
"suppressed": false,
"suppression": null
}
],
"min_safe_version": "2.2.5",
"latest_release_date": "2024-09-10T00:00:00+00:00",
"latest_release_age_days": 261,
"warnings": ["1 vulnerability(ies): PYSEC-2023-62"]
}
```
每个项目的字段(audit):`pinning_score`、`drift_summary`、`yanked_count`、
`pypi_unreachable`、`vuln_count`、`vuln_unreachable`、`suppressed_count`。
#### Schema 版本历史
| 版本 | 发布 | 更改 |
| --- | --- | --- |
| `1` | v0.2.0 | 初始公开 schema。 |
| `2` | v0.3.0 | 每个依赖增加了 `vulnerabilities[]` 和 `min_safe_version`;每个项目增加了 `vuln_count` 和 `vuln_unreachable`。 |
| `3` | v0.4.0 | 每个依赖增加了 `latest_release_date` 和 `latest_release_age_days`;每个漏洞增加了 `suppressed` 和可选的 `suppression` 块;每个项目增加了 `suppressed_count`。全部为附加更改。 |
自 v3 以来的附加更改(无版本提升):每个依赖的 `direct` 布尔值(对于
传递性 lockfile 条目为 false),添加于 v0.6.0。
### 缓存
PyPI 元数据和 pip-audit 结果会分别缓存在磁盘上独立的
目录中。
| 来源 | POSIX 默认值 | Windows 默认值 |
| --- | --- | --- |
| PyPI 元数据 | `$XDG_CACHE_HOME/piptastic/pypi/` → `~/.cache/piptastic/pypi/` | `%USERPROFILE%\.cache\piptastic\pypi\` |
| pip-audit 结果 | `$XDG_CACHE_HOME/piptastic/vulns/` → `~/.cache/piptastic/vulns/` | `%USERPROFILE%\.cache\piptastic\vulns\` |
使用 `PIPTASTIC_CACHE_DIR=` 覆盖父目录。两者的默认 TTL 均为
3600s(1 小时)。PyPI 条目是按发行版的 JSON;漏洞条目是按
`(name, version)` 的 JSON,包括干净锁定的空结果。随时
可以安全地删除这两个目录。
### 日志
`-v` / `--verbose` 将根 logger 设置为 INFO。`-q` / `--quiet` 会静默
ERROR 以下的所有内容。`--log-file PATH` 会将日志记录镜像到文件中,而
stderr 流保持不变。默认值为输出到 stderr 的 WARNING。
### 退出代码
| 代码 | 含义 |
| --- | --- |
| `0` | 审计完成;未触发门禁。过时或易受攻击的依赖本身不会改变退出代码。 |
| `1` | 操作失败:路径不存在、未找到 Python 项目、输入格式错误、内部崩溃。PyPI / pip-audit 不可达不会提升此代码——两者都会优雅降级。 |
| `2` | `update` 测试安装失败;requirements 文件已从备份回滚。 |
| `3` | 触发策略门禁:`--fail-on-drift`、`--fail-on-vuln` 和/或 `--fail-on-age`。审计本身已成功执行。 |
以前检查 `==1` 来判断是否触发门禁的 CI 消费者应切换到
`==3`(v0.4 约定更改)。
## 路线图
推迟到未来版本发布。顺序大致按优先级排列,并非发布计划:
- Lockfile 偏移检测(`Pipfile` ↔ `Pipfile.lock`、`poetry.lock`、
`uv.lock`)。
- 针对 `pyproject.toml` 和 `Pipfile` 执行 `update`。
- `setup.py` / `setup.cfg` 解析。
- HTML 报告输出。
- 监视 / 守护进程模式。
- 发布到 PyPI(目前需从源码 / git 安装)。
## 发布说明
[CHANGELOG.md](CHANGELOG.md) 记录了每次发布。Schema 提升和破坏性
flag 更改会列在“Breaking”标题下。
## 许可证
AGPL-3.0-or-later。完整文本请见 [LICENSE](LICENSE)。
AGPL 的网络服务条款适用:如果你将修改后的
piptastic 版本作为网络服务提供,你必须向该版本
的用户提供其源代码。对于不适合使用 AGPL 的商业部署,
请联系维护者洽谈商业许可。
## 贡献
欢迎提交 Issue 和 PR。提交贡献即表示你同意将其
在项目的许可下(AGPL-3.0-or-later)分发。
工程约定(frozen dataclass、I/O 边界、JSON-schema
版本控制规则、跨平台限制)记录在
[CLAUDE.md](CLAUDE.md) 中。在开启重要的 PR 之前请阅读它;无论
贡献者是人类还是 AI 代理,都适用相同的约定。
## 致谢
piptastic 构建于几个维护良好的库之上:
- [packaging](https://github.com/pypa/packaging) (PyPA) — PEP 440 版本、
说明符和标记解析。偏移和锁定姿态模型基于
其 `Version` 和 `SpecifierSet` 构建。
- [rich](https://github.com/Textualize/rich) — 终端表格、树状结构
和进度条。
- [pip-audithttps://github.com/pypa/pip-audit) (PyPA) — CVE 扫描。
piptastic 将其作为 subprocess 调用,而不是重新实现咨询
匹配。
- [tomli](https://github.com/hukkin/tomli) — Python 3.10 上的 TOML 解析
(3.11+ 使用标准库 `tomllib`)。
- [hatchling](https://github.com/pypa/hatch) — 构建后端。
- [pytest](https://github.com/pytest-dev/pytest) — 测试套件。
审计中显示的漏洞咨询来自 pip-audit 的数据
源——主要是
[PyPI Advisory Database](https://github.com/pypa/advisory-database) 和
[OSV](https://osv.dev/)——而包的元数据来自
[PyPI JSON API](https://warehouse.pypa.io/api-reference/json.html)。感谢上述所有项目
的维护者。
标签:CISA项目, Python, SOC Prime, 依赖管理, 域名收集, 开发工具, 无后门, 逆向工具