i-afaqrashid/cms-lab

GitHub: i-afaqrashid/cms-lab

部署前CMS漏洞扫描工具

Stars: 2 | Forks: 0

# CMS 实验室 在部署前捕捉 CMS 缺陷。 [![npm](https://img.shields.io/npm/v/@cms-lab/cli)](https://www.npmjs.com/package/@cms-lab/cli) [![CI](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/3ecc211965032833.svg)](https://github.com/i-afaqrashid/cms-lab/actions/workflows/ci.yml) [![license: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE) `cms-lab` 捕捉当你的无头 CMS 和你的 Next.js 路由分离时出现的缺陷 - 破损的路由、重复的 slug、指向未发布内容的链接、缺失 SEO/OG/canonical/JSON-LD、图像 alt 和尺寸、地区差异 - 并在它们达到生产环境之前使 CI 失败。与 Prismic、Strapi、Directus、WordPress、Contentful、Sanity 和 Payload 兼容。 无需安装即可运行: ``` npx @cms-lab/cli scan ``` 它读取您的配置,获取 CMS 条目,探测您的运行站点,并写入终端、JSON、Markdown、JUnit、Slack 和 HTML 报告输出。没有托管 cms-lab 服务。CLI 在您的项目中运行,并直接与您配置的 CMS 端点通信。 ![cms-lab HTML 报告显示来自破损的 Prismic 示例的路由错误、字段警告、SEO 警告和图像 alt 文本警告](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/8f063c5ac0032833.png) ## 安装 ``` pnpm add -D @cms-lab/cli @cms-lab/core ``` 您也可以不将其添加到项目中运行: ``` npx @cms-lab/cli scan ``` ## 在 StackBlitz 中试用 在将 cms-lab 集成到您自己的 CMS 之前,先打开一个公开示例: - [在 StackBlitz 中运行破损的 Prismic 示例](https://stackblitz.com/fork/github/i-afaqrashid/cms-lab/tree/main/examples/broken-prismic-demo?title=cms-lab%20Broken%20Prismic%20demo) - [在 StackBlitz 中运行 Next Prismic 配置参考](https://stackblitz.com/fork/github/i-afaqrashid/cms-lab/tree/main/examples/next-prismic?title=cms-lab%20Next%20Prismic%20config) 默认浏览器启动器也可在以下位置找到: https://cmslab.afaqrashid.com/new. ## 快速开始 在 Next.js 项目中创建 `cms-lab.config.ts`: ``` import { defineConfig } from "@cms-lab/core"; export default defineConfig({ site: { url: "http://localhost:3000" }, framework: { type: "next", router: "app" }, cms: { provider: "prismic", repositoryName: "my-repo", accessToken: process.env.PRISMIC_ACCESS_TOKEN, }, routes: [ { type: "page", pattern: "/:uid", getPath: (doc) => `/${doc.uid}` }, { type: "blog_post", pattern: "/blog/:uid", getPath: (doc) => `/blog/${doc.uid}`, }, ], checks: { fields: { required: [ { type: "page", path: "headline" }, { type: "blog_post", path: "author.name", severity: "warning" }, ], }, relationships: [ { from: "blog_post", to: "author", where: { fromField: "author.id", toField: "id" }, min: 1, severity: "warning", }, ], }, }); ``` 对于本地化应用程序,其中 `/` 不是您想要首先探测的页面,请将路由相对于 `site.url` 保持相对,并单独设置健康路由: ``` site: { url: "http://localhost:3000", healthPath: "/en", } ``` 运行您的 Next.js 应用程序,然后扫描它: ``` pnpm next dev pnpm cms-lab scan ``` 对于 CI: ``` pnpm cms-lab scan --ci --report --markdown --junit ``` 或使用 GitHub Action: ``` - uses: i-afaqrashid/cms-lab@v1 with: config: cms-lab.config.ts report: true # node-version: "20" # default; override to "22" or "24" if you need ``` 该操作默认安装 Node 20 以匹配 `@cms-lab/cli` 的 `engines.node >= 20.10`。如果您的流程运行在较新的 Node 版本上,请使用 `node-version` 覆盖。 ## CMS 适配器 Prismic: ``` cms: { provider: "prismic", repositoryName: "my-repo", accessToken: process.env.PRISMIC_ACCESS_TOKEN, } ``` Strapi: ``` import { strapiRelationSlug } from "@cms-lab/core"; cms: { provider: "strapi", url: "http://localhost:1337", token: process.env.STRAPI_TOKEN, locale: "en", collections: [ { type: "page", endpoint: "pages", uidField: "routing.slug", urlField: "routing.url", }, ], singleTypes: [ { type: "navbar", endpoint: "navbar", }, ], }, routes: [ { type: "page", pattern: "/:slug", getPath: (doc) => `/${doc.uid}` }, { type: "article", pattern: "/blog/:topic/:slug", getPath: (doc) => { const topic = strapiRelationSlug(doc.data, "topic") ?? "uncategorized"; return `/blog/${topic}/${doc.uid}`; }, }, ] ``` Directus: ``` cms: { provider: "directus", url: "http://localhost:8055", token: process.env.DIRECTUS_TOKEN, collections: [ { type: "page", collection: "pages", uidField: "routing.slug", urlField: "routing.url", }, ], } ``` WordPress: ``` cms: { provider: "wordpress", url: "http://localhost:8080", contentTypes: [ { type: "page", endpoint: "pages" }, { type: "post", endpoint: "posts", uidField: "acf.handle", urlField: "acf.permalink", }, ], } ``` Contentful: ``` cms: { provider: "contentful", spaceId: "my-space", environment: "master", accessToken: process.env.CONTENTFUL_DELIVERY_TOKEN, contentTypes: [ { type: "page", contentType: "page", uidField: "routing.slug", urlField: "routing.url", }, ], } ``` Sanity: ``` cms: { provider: "sanity", projectId: "my-project", dataset: "production", apiVersion: "2025-02-19", token: process.env.SANITY_READ_TOKEN, contentTypes: [ { type: "page", documentType: "page", uidField: "slug.current", urlField: "seo.canonical", }, ], } ``` Payload: ``` cms: { provider: "payload", url: "http://localhost:3000", apiPath: "/api", token: process.env.PAYLOAD_TOKEN, collections: [ { type: "page", collection: "pages", uidField: "slug" }, { type: "post", collection: "posts", uidField: "slug" }, ], } ``` 所有适配器将内容标准化为相同的扫描模型,因此路由检查、字段检查、SEO 检查、报告输出和 CI 行为保持一致。当您的 CMS 不公开纯 `uid` 或 `slug` 字段时,请使用 `uidField`。当 CMS 已经存储公共永久链接时,请使用 `urlField`。这两个字段都从 `document.data` 读取点分隔路径。 ## 命令 ``` cms-lab init cms-lab init --cms strapi --router pages cms-lab init --cms directus --router pages cms-lab init --cms payload cms-lab init --cms wordpress cms-lab init --cms contentful --space-id my-space cms-lab init --cms sanity --project-id my-project cms-lab doctor cms-lab scan cms-lab agent-context cms-lab explain CMS-ROUTE-404 ``` 有用的扫描选项: ``` cms-lab scan --url https://staging.example.com cms-lab scan --config ./cms-lab.config.ts cms-lab scan --json cms-lab scan --ci cms-lab scan --report cms-lab scan --report --share-report cms-lab scan --markdown cms-lab scan --junit cms-lab scan --slack-webhook "$CMS_LAB_SLACK_WEBHOOK" cms-lab scan --type page cms-lab scan --only routes cms-lab scan --only relationships cms-lab scan --skip seo --skip a11y cms-lab scan --fail-on warning cms-lab scan --max-warnings 0 cms-lab scan --strict cms-lab scan --timeout 10000 cms-lab scan --concurrency 4 cms-lab scan --retries 2 cms-lab scan --debug --verbose 2 ``` 为编码代理生成上下文文件: ``` cms-lab agent-context cms-lab agent-context --preset all cms-lab agent-context --preset claude cms-lab agent-context --preset gemini cms-lab agent-context --preset copilot cms-lab agent-context --force cms-lab agent-context --no-agents-md cms-lab agent-context --out .cms-lab ``` 默认预设写入 `AGENTS.md`、`.cms-lab/agent-context.md` 和 `.cms-lab/agent-prompt.md`。工具特定的预设也可以写入 `CLAUDE.md`、`GEMINI.md`、`.github/copilot-instructions.md` 和 `.github/prompts/cms-lab-fix.prompt.md`。 生成的文件将代理指向 cms-lab GitHub 仓库、npm 包、文档、本地命令示例、配置的路由模式以及安全的项目事实,而不包括令牌、原始 CMS 有效负载、私有 URL、webhook URL 或本地绝对路径。 ## 测试与 公共测试矩阵位于 [`/docs/tested-with`](https://cmslab.afaqrashid.com/docs/tested-with)。它列出了 仅由 fixture、适配器测试、公共演示或可重复的烟雾测试覆盖的路径,并明确标记适配器成熟度限制。 当前覆盖率包括 Prismic 与 Next.js App Router、Strapi v4 与 Next.js Pages Router、Strapi 单个类型,以及 Directus、WordPress、Contentful、Sanity 和 Payload 的适配器 fixture 检查。 有关 cms-lab 建造来捕捉的普通 CMS 失败,请参阅 [`/docs/bug-examples`](https://cmslab.afaqrashid.com/docs/bug-examples)。 有关 cms-lab 如何与链接检查器、Playwright、Lighthouse CI 和自定义路由爬取配合使用,请参阅 [`/docs/comparison`](https://cmslab.afaqrashid.com/docs/comparison)。 有关常见首次运行失败和修复方法,请参阅 [`/docs/troubleshooting`](https://cmslab.afaqrashid.com/docs/troubleshooting)。 有关较大 CMS 库的基线、过滤和并发指南,请参阅 [`/docs/large-catalogs`](https://cmslab.afaqrashid.com/docs/large-catalogs)。 有关 Prismic、Strapi、Directus、WordPress、Contentful 和 Sanity 的提供者特定设置说明,请参阅 [`/docs/providers`](https://cmslab.afaqrashid.com/docs/providers)。 有关通用 Directus 餐厅/目录配置,请参阅 [`/docs/examples/directus-restaurant`](https://cmslab.afaqrashid.com/docs/examples/directus-restaurant). ## 检查 cms-lab 当前检查: - 无法生成配置路由的 CMS 文档 - 返回 `404` 的预期 CMS 路由 - 返回 `5xx` 的预期 CMS 路由 - 站点可达后失败的路线探测 - 缺失 SEO 标题和描述 - 缺失或占位符图像 alt 文本 - 在 `checks.fields.required` 中声明的自定义必需字段 - 在 `checks.relationships` 中声明的跨文档关系最小值 扫描器保留原始 CMS 有效负载在 `document.data` 中,当 CMS 公开时保留公共永久链接,在可用时使用类似 slug 的字段作为 `uid`,并将非公开条目(如草稿、存档内容和计划中的 WordPress 帖子)视为 `draft`。 ## 输出和隐私 默认情况下,`--json` 会删除原始 CMS 文档数据、文档 URL、文档 UIDs 和绝对项目路径。仅在使用需要完整有效负载的私有自动化时使用 `--include-sensitive-output`。 报告输出: - `--report` 写入 `.cms-lab/report.html` - `--share-report` 从 HTML 报告中删除 CMS 源 ID 和本地项目路径,同时保留诊断代码、严重性、路由路径和字段路径可见 - `--markdown` 写入 `.cms-lab/summary.md` - `--junit` 写入 `.cms-lab/junit.xml` - `--slack-webhook` 发送紧凑的删除 Slack 摘要 终端、JSON、Markdown 和 HTML 报告包括当相同的内容类型/模板多次产生相同的诊断时,重复发现的摘要。 原始行级诊断始终可用于调试。 Slack 摘要包括计数和诊断代码。它们不包括 CMS 令牌、webhook URL、原始 CMS 有效负载、本地项目路径或完整的 JSON 输出。 ## 退出行为 `cms-lab scan` 退出: - `0` 当扫描在配置的失败阈值以下完成时 - `1` 当诊断超过阈值时 - `2` 对于配置、加载或验证错误 - `3` 当 CMS 不可达或认证失败时 - `4` 当站点不可达时 - `130` 当被中断时 当您想要没有失败的工件时,请使用 `--fail-on never`。当警告和 info 诊断应该使 CI 失败时,请使用 `--strict`。 ## 开发 ``` pnpm install pnpm test pnpm bench pnpm typecheck pnpm build pnpm site:build pnpm lint pnpm verify pnpm smoke:pack ``` 在本地运行文档站点: ``` pnpm site:dev ``` 运行公共 Prismic 烟雾 fixture: ``` pnpm build pnpm live:doctor pnpm live:scan pnpm smoke:pack:live ``` `pnpm smoke:pack` 打包可发布的包,将它们安装到干净临时应用程序中,并运行安装的 `cms-lab` 二进制文件。`pnpm smoke:pack:live` 执行相同的包烟雾测试,然后扫描公共 Prismic fixture。 ## 仓库 ``` packages/core config, types, diagnostics, checks packages/cli cms-lab binary and output packages/next Next.js project detection packages/prismic Prismic adapter packages/strapi Strapi adapter packages/directus Directus adapter packages/wordpress WordPress adapter packages/contentful Contentful adapter packages/sanity Sanity adapter packages/payload Payload adapter packages/reporter local HTML report renderer apps/site marketing site and docs test-fixtures/ public Prismic fixture ``` ## 社区 - [讨论](https://github.com/i-afaqrashid/cms-lab/discussions) 用于 问题、新检查的想法和展示。 - [路线图](https://cmslab.afaqrashid.com/roadmap) 用于已发布、计划和 正在研究的内容。 - [问题](https://github.com/i-afaqrashid/cms-lab/issues) 用于错误和具体的 功能请求。 贡献或审查?请参阅 [CONTRIBUTING.md](./CONTRIBUTING.md) 和 [.github/CODEOWNERS](./.github/CODEOWNERS) 以了解所有权和审查路径。 ## 发布和维护 阅读 [CHANGELOG.md](./CHANGELOG.md) 和 [GitHub Releases](https://github.com/i-afaqrashid/cms-lab/releases) 了解 按版本发布的发布历史。 在使用 cms-lab 作为生产项目中严格的部署门之前,请阅读 [版本和稳定性策略](https://cmslab.afaqrashid.com/docs/versioning) 阅读 [LAUNCH.md](./LAUNCH.md) 了解发布清单、npm 发布流程、发布后验证和发布日笔记。 阅读 [TESTING.md](./TESTING.md) 了解本地测试者工作流程。在打开公共问题或 PR 之前,请阅读 [CONTRIBUTING.md](./CONTRIBUTING.md)、[SECURITY.md](./SECURITY.md)、[SUPPORT.md](./SUPPORT.md)、[CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md)。 cms-lab 是 MIT 许可。请参阅 [LICENSE](./LICENSE).
标签:CMS, Contentful, Directus, MITM代理, Payload, Prismic, Sanity, SEO, Strapi, WordPress, 代码审查, 内容管理系统, 安全可观测性, 版本控制, 自动化攻击, 错误报告