mockingbird777/specsentinel

GitHub: mockingbird777/specsentinel

SpecSentinel 是一款具备安全感知的 OpenAPI 破坏性变更检测工具,用于在本地或 CI 中对比两份契约文档并阻止不兼容变更发布到生产环境。

Stars: 0 | Forks: 1

SpecSentinel — OpenAPI contract intelligence

具备安全感知的 OpenAPI 破坏性变更检测工具,既易于人类阅读,又能在 CI 中强制执行。

CI Live report MIT license Node 20+ OpenAPI 3.x

SpecSentinel 会对比两份 OpenAPI 3.x 文档,并在不兼容问题影响到 SDK 或生产环境消费者之前,标记出客户端契约的不兼容之处。它能够理解操作、参数、递归的请求与响应 schema、本地 `$ref` 组件以及 OpenAPI 安全备选方案。其报告可在终端、Pull Request、GitHub Code Scanning 工作流或独立的 HTML 文件中使用。

浏览实时的契约对比报告 · 运行零配置演示 · 提出规则建议

## 为什么选择 SpecSentinel - **有价值的信号,而非文本噪音。** 它比较的是 API 语义,而不是单纯对比 YAML 文本行。 - **具备安全感知。** 它会标记出新增加的必需凭证、被移除的认证备选方案以及新增的 OAuth scope。 - **为 CI 原生设计。** 内置严重性阈值、稳定的规则 ID、限定范围的抑制规则、SARIF 支持以及确定性的退出代码。 - **跨平台便携。** 支持 JSON 和 YAML 输入,提供五种报告格式,支持 Node.js 20+,仅有一个轻量级的运行时依赖。 - **可嵌入式。** 可以直接使用 CLI,或将带有类型的 diff 引擎导入到你的治理工具中。 | 对比对象 | SpecSentinel 的侧重点 | | --- | --- | | 逐行对比的 YAML diff | OpenAPI 语义与客户端兼容性 | | 通用的 schema 验证器 | 两份有效契约之间的变更 | | 仅有破坏性变更列表 | 安全备选方案、OAuth scope、稳定的规则 ID 以及可操作的定位信息 | | 仅限 CI 的服务 | 相同的确定性引擎,可在本地、Actions 中或作为库使用 | ## 30秒演示 唯一的先决条件是 Node.js 20+。此演示会分析两个已打包的 OpenAPI 契约,因此无需下载或配置任何文件: ``` npx --yes github:mockingbird777/specsentinel demo ``` 精简后的输出: ``` SpecSentinel 0.2.0 Comparing demo/baseline.yaml → demo/candidate.yaml [CRITICAL] PATH_REMOVED #/paths/~1legacy Path '/legacy' was removed. [HIGH] SECURITY_STRENGTHENED #/paths/~1pets/get/security Security requirements became stricter for previously valid requests. … 16 incompatible changes (2 critical, 14 high) ``` 演示过程会成功退出,因此你可以放心地将其粘贴到 shell 中运行。添加 `--fail-on high` 即可激活 CI 门禁,并在触发时收到退出代码 `1`。 ## 检查你的 API 将已提交或已发布的契约与你的分支生成的候选版本进行对比: ``` npx --yes github:mockingbird777/specsentinel \ api/openapi.baseline.yaml api/openapi.yaml \ --fail-on high ``` 对于固定的项目依赖: ``` npm install --save-dev github:mockingbird777/specsentinel#v0.2.0 npx specsentinel api/openapi.baseline.yaml api/openapi.yaml --fail-on high ``` 生成可审查的构建产物,而不会改变门禁行为: ``` npx specsentinel old.yaml new.yaml --format html --output contract-report.html ``` ## 规则矩阵 | 规则 ID | 默认级别 | 捕获内容 | | --- | --- | --- | | `PATH_REMOVED` | critical | 基线路径消失 | | `OPERATION_REMOVED` | critical | 某个 GET、POST、PUT、PATCH、DELETE、HEAD、OPTIONS 或 TRACE 操作消失 | | `PARAM_REQUIRED_ADDED` | high | 添加了必需的参数,或原有参数变为必需 | | `PARAM_TYPE_CHANGED` | high | 原有参数的类型发生改变 | | `PARAM_ENUM_NARROWED` | high | 移除了可接受的参数值,或不受限制的参数增加了 enum | | `REQUEST_BODY_REQUIRED` | high | request body 变为必填 | | `REQUEST_CONTENT_REMOVED` | high | 原本接受的 request media type 消失 | | `REQUEST_PROPERTY_REQUIRED` | high | request property 变为必填,包括通过本地 `$ref` schema 引入的情况 | | `REQUEST_TYPE_CHANGED` | high | request schema 类型发生递归改变 | | `RESPONSE_REMOVED` | high | 文档中记录的状态响应消失 | | `RESPONSE_CONTENT_REMOVED` | high | response media type 或 schema 消失 | | `RESPONSE_PROPERTY_REMOVED` | high | response property 递归消失 | | `RESPONSE_TYPE_CHANGED` | high | response schema 类型发生递归改变 | | `SECURITY_STRENGTHENED` | high | 匿名访问/认证备选方案被移除、新增了安全 scheme,或 OAuth scope 变得更严格 | 每项发现结果都包含 `ruleId`、`severity`、符合 RFC 6901 样式的 OpenAPI 定位路径、纯文本消息,以及在适用时提供的结构化 `before` / `after` 值。 ## 报告 ``` # Human-friendly terminal(默认) specsentinel old.yaml new.yaml # 稳定的 automation payload specsentinel old.yaml new.yaml --format json --output report.json # 在 CI 中 pipe report('-' 写入到 stdout) specsentinel old.yaml new.yaml --format json --output - | jq .summary # Pull-request 摘要 specsentinel old.yaml new.yaml --format markdown --output report.md # GitHub Code Scanning / security tooling specsentinel old.yaml new.yaml --format sarif --output report.sarif # 无需 server 或 assets 的可移植 styled report specsentinel old.yaml new.yaml --format html --output report.html ``` ## 配置与有意变更 使用 `--config` 传入 YAML 或 JSON 配置文件。抑制规则应尽可能做到范围精确、经过审查且仅作临时使用。 ``` failOn: high format: terminal # Whole-rule suppression ignoreRules: - RESPONSE_REMOVED # Location-scoped suppression;`*` 是通配符 ignores: - rule: RESPONSE_PROPERTY_REMOVED location: '#/paths/~1internal/*' ``` 命令行抑制规则适用于一次性的调查场景: ``` specsentinel old.yaml new.yaml --ignore RESPONSE_REMOVED --ignore SECURITY_STRENGTHENED ``` ## GitHub Actions 该仓库提供了一个 Node 20 action,其依赖项已被打包进 `dist/action.cjs`: ``` name: API compatibility on: [pull_request] jobs: contract: runs-on: ubuntu-latest permissions: contents: read steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Materialize baseline from the target branch run: git show "origin/${{ github.base_ref }}:api/openapi.yaml" > /tmp/openapi.baseline.yaml - name: Guard the contract uses: mockingbird777/specsentinel@v0.2.0 with: baseline: /tmp/openapi.baseline.yaml candidate: api/openapi.yaml fail-on: high format: terminal ``` 对于 Code Scanning,可使用 CLI 生成 SARIF 并进行上传,即使存在发现结果也能正常上传: ``` - uses: actions/setup-node@v4 with: { node-version: 20 } - name: Create SARIF continue-on-error: true run: npx --yes github:mockingbird777/specsentinel old.yaml new.yaml --format sarif --output specsentinel.sarif - uses: github/codeql-action/upload-sarif@v3 with: { sarif_file: specsentinel.sarif } ``` ## 退出代码 | 代码 | 含义 | | --- | --- | | `0` | 没有未被抑制的发现结果达到 `--fail-on` 阈值 | | `1` | 至少有一项发现结果达到了严重性阈值 | | `2` | CLI 用法无效、输入无法读取、配置格式错误、不支持的外部 `$ref`,或无效的 OpenAPI 文档 | 默认阈值为 `high`。可从 `info`、`low`、`medium`、`high` 或 `critical` 中进行选择。 ## 库 API ``` import { diffOpenApi, parseOpenApi } from 'specsentinel'; const baseline = parseOpenApi(baselineSource, 'baseline.yaml'); const candidate = parseOpenApi(candidateSource, 'candidate.yaml'); const result = diffOpenApi({ baseline, candidate }); for (const change of result.changes) { console.log(change.ruleId, change.location, change.message); } ``` ## 支持的引用 SpecSentinel 会解析如 `#/components/schemas/Pet` 这样的内部 JSON Pointer 引用,并保留 OpenAPI 3.1 的 `$ref` 同级字段。外部文件和 URL 引用会特意以退出代码 2 报错失败,而不是静默地生成不完整的分析结果。 ## 路线图 - 具有明确信任策略的外部多文件及 URL 引用图 - Discriminator、组合(`allOf` / `oneOf` / `anyOf`)、数值边界以及可为空类型的兼容性规则 - 从 Git 标签和制品库中获取基线 - 带有过期日期和所有权的内联抑制元数据 - 策略包和自定义规则插件 ## 项目元数据 推荐的 GitHub 描述:**在发布前捕获 OpenAPI 破坏性变更和安全回退问题。** 推荐的 topics:`openapi`、`api-governance`、`contract-testing`、`breaking-changes`、`devsecops`、`sarif`、`github-actions`、`typescript`。机器可读的值保存在 [`REPO_META.json`](REPO_META.json) 中。 ## 贡献与安全 最有价值的初步贡献包括:为缺失的兼容性边缘情况提供最小化的基线/候选契约对、提供带有反例的误报报告,或针对性的报告器改进。请从 [CONTRIBUTING.md](CONTRIBUTING.md) 开始,或[提出规则建议](https://github.com/mockingbird777/specsentinel/issues/new/choose)。请阅读[行为准则](CODE_OF_CONDUCT.md),对于漏洞问题,请使用 [SECURITY.md](SECURITY.md) 中的私密流程进行处理。 如果 SpecSentinel 帮助你在真实的 API 中避免了破坏客户端的变更,请在 GitHub 上点个 Star,以帮助其他 API 团队发现它。 基于 [MIT License](LICENSE) 发布。
标签:API契约, GNU通用公共许可证, LNA, MITM代理, Node.js, OpenAPI, 代码质量审查, 破坏性变更检测, 聊天机器人, 自动化攻击