toshtag/fairux-linter
GitHub: toshtag/fairux-linter
FairUX Linter 是一款基于规则的可解释静态分析工具,用于检测界面中的暗黑模式和不公平 UX 设计,覆盖静态源码、实时 DOM 和 CI 流水线。
Stars: 0 | Forks: 0
# FairUX Linter
FairUX 专门标记可能会向用户施压或误导用户的界面模式 —— **暗黑模式 (dark patterns)、误导性的订阅流程、隐藏费用、不公平的同意 UI、取消阻碍以及稀缺性施压**。它是**基于规则且可解释的**:每一项检测结果都会说明发现了什么、为什么重要以及如何修复 —— 不依赖 AI,无需猜测,完全在你的本地机器上运行。相同的规则可运行于**静态 HTML、实时页面 (浏览器) 以及 JSX/TSX 源码**,支持通过 **CLI**、**CI** (SARIF)、**浏览器扩展**和 **VS Code 扩展**调用。
## 当前状态
FairUX 是本仓库中一个处于工作阶段的 beta 期引擎和工具链。SDK 和 CLI 软件包已准备好发布预览版,但尚未作为公开的 npm 版本进行验证。请参阅 [docs/status.md](docs/status.md) 了解当前的实现和路线图状态。
## 快速开始
要求 **Node.js `^22.18.0 || >=24.11.0`**。仓库默认版本记录在 [`.node-version`](.node-version) 中。
```
pnpm install
pnpm build
pnpm fairux scan examples/free-trial.html # Markdown (default)
pnpm fairux scan examples/PricingCard.tsx # also scans JSX/TSX
pnpm fairux scan examples/checkout.html --format json
```
### npm 发布状态
`fairux@0.1.0-beta.1` 和 `@fairux/sdk@0.1.0-beta.1` 已配置好发布,但本仓库尚未完成公开的 npm beta 发布以及干净的注册表安装验证。在该版本发布之前,请使用上述的 workspace 命令,或使用从发布工作流中提取的受控打包 tarball。
外部 RulePack 作者可以基于 beta 创作工具包开始工作:
[RulePack 创作](docs/rule-pack-authoring.md)、[RulePack 测试](docs/rule-pack-testing.md)、
[分类法迁移说明](docs/migrations/rule-pack-taxonomy-beta.1.md) 以及可复制的
[外部作者示例](examples/rule-pack-author)。第三方 RulePack 是受信任的可执行 JavaScript,而不是沙箱化的插件。
CLI 可以扫描**单个文件、目录、glob 模式和 stdin**。
传入 `--format sarif` 以供 CI 使用,传入 `--format json` 用于编程调用。
检测结果如下所示:
```
## 高
### 预选中的同意复选框
- **Rule:** `consent/checked-checkbox`
- **Severity:** high **Confidence:** high
- **What:** A checkbox is checked by default: "Email me product offers and promotions".
- **Why it matters:** Pre-checked boxes opt users in without an active, informed choice.
- **Recommendation:** Leave consent and marketing checkboxes unchecked so users opt in deliberately.
- **Evidence:**
- `#newsletter` — "Email me product offers and promotions" (free-trial.html:16)
```
输出格式:**Markdown**(默认)、**JSON**(稳定且有文档说明的包装格式)和 **SARIF 2.1.0**(用于 GitHub 代码扫描)。`--include-experimental` 可开启启发式规则。
## 检测范围
目前有 13 条规则(默认启用 11 条,2 条实验性)。所有规则均可解释;经过调优以保持低误报率(支持英语和日语短语):
| 类别 | 规则 |
| ---------------- | -------------------------------------------------------------------------------------- |
| **同意 (Consent)** | 预选中的同意框 · 仅有同意而无明确拒绝选项 · 捆绑式(非颗粒度)同意 |
| **订阅 (Subscription)** | 未披露续费信息的免费试用 CTA · 未包含取消条款的订阅 CTA |
| **取消 (Cancellation)** | 没有取消途径的订阅/账户页面 |
| **稀缺性 (Scarcity)** | 稀缺性 / 紧迫性短语 · 倒计时计时器 |
| **隐藏费用 (Hidden cost)** | 显示价格时未披露税/运费/手续费(结账页面) |
| **阻碍 (Obstruction)** | 没有关闭控件的模态框 · 强加负罪感(利用愧疚感诱导拒绝选项) |
| **实验性 (Experimental)** | 接受/拒绝视觉不平衡 · 难以察觉的模态框关闭按钮(启发式,默认关闭) |
规则可针对特定项目进行调优或静默 —— 请参阅 [配置](#configuration)。
## 在你的工作环境中使用
本仓库中已实现这些功能界面。公开包的安装取决于首次 npm beta 版本的发布。
### CLI
```
pnpm fairux scan # .html → HTML; .tsx/.jsx/.ts/.js → JSX/TSX
pnpm fairux scan --format json|sarif
pnpm fairux scan --include-experimental
```
适配器根据文件扩展名进行选择。JSX/TSX 扫描**仅限静态分析**:仅分析静态编写的直接 JSX 元素。JSX 表达式子节点
(`{cond && }`)会被丢弃(视为未知,绝不断言),并且自定义组件会被视为原生标签。动态值(`checked={x}`, `{label}`)被视为未知(绝不断言),这些检测结果的置信度上限为 `medium`。
(`node apps/cli/dist/index.js scan …` 是底层命令;`pnpm fairux …` 是简短的别名。)
### CI (SARIF → GitHub 代码扫描)
`--format sarif` 输出 **SARIF 2.1.0**。严重性映射为 `high → error`、`medium → warning`、
`low | info → note`,因此 `high` 级别的检测结果可以阻止 PR 合并。检测结果携带稳定的指纹
(`fairuxV1`),因此基准在不同运行和运行时环境中能够保持持久。建议初始阶段设为非阻塞,之后再针对 `high` 级别设置门禁 —— 请参阅 **[GitHub Actions 指南](docs/github-actions.md)**。
### 浏览器扩展
这是一个 Manifest V3 外壳程序,可在实时页面上运行**相同的规则** —— 完全在本地运行(无网络请求,无 AI)。它仅使用 `activeTab` + `scripting`,并且**默认不运行任何内容脚本**:点击 **Scan this page** 会按需将扫描程序注入到该特定标签页中,因此它绝不会触及你未要求扫描的页面:
```
pnpm --filter @fairux/chrome-extension build
# Chrome → chrome://extensions → 启用 Developer mode → “Load unpacked” → apps/chrome-extension/dist
```
打开任意页面,点击工具栏图标,**Scan this page** → 检测结果按严重性分组;点击其中一个即可高亮显示该元素。实时 DOM 适配器可以捕捉到静态扫描无法检测到的状态(例如用户刚刚勾选的复选框)。
该扩展目前仅扫描主文档;不扫描嵌入式框架。
### VS Code 扩展
在“问题 (Problems)”面板中为 **HTML 和 JSX/TSX** 提供内联诊断 —— 在进程内运行,不依赖 AI:
```
pnpm --filter fairux-vscode build
# VS Code → Run → Start Debugging (Extension Development Host) 在 apps/vscode-extension 上
```
该扩展运行**默认规则集**(关闭实验性规则),并从文档所在目录向上自动发现 `fairux.config.json` —— 因此按项目设定的严重性/禁用/实验性覆盖配置也会在编辑器中生效。可执行配置(`.ts/.mjs/.js/.cjs`)不会在编辑器中自动执行;请使用 `fairux.config.json` 进行编辑器设置。
## 配置
在你的项目附近放置一个 `fairux.config.json` —— 它会从扫描目标向上(直到仓库根目录)被**自动发现**。可执行配置(`fairux.config.{ts,mjs,js,cjs}`)是**受信任的代码**,且_不会_被自动发现;需使用 `--config ` 显式加载(你将收到一行 stderr 警告,因为它将以你的权限运行)。对于类型化的配置,通过 `--config` 传入的 `.ts` 文件如下所示:
```
import type { FairuxConfig } from "@fairux/sdk";
const config: FairuxConfig = {
rules: {
"consent/missing-reject-option": false, // silence a rule
"consent/checked-checkbox": { severity: "low" }, // re-grade severity
"obstruction/modal-close-visibility": { enabled: true }, // force-enable an experimental rule
},
};
export default config;
```
严重性覆盖**不会**改变检测结果指纹,因此当你重新评级时,CI 基准依然保持稳定。`confidence`(置信度)是有意设为不可覆盖的(它反映了检测的确定性,而非策略)。使用 `--ignore-config` 可跳过自动发现。完整的字段参考:请参阅上方的 [配置](#configuration) 部分。程序化调用方应从 `@fairux/sdk` 导入公共类型;该类型导入要求在首次 SDK 发布后安装 `@fairux/sdk`,或从本 workspace 链接。内部包不构成公共兼容性契约。
### 程序化 SDK(准备发布的预览版)
`@fairux/sdk` 是一个准备发布的预览版,尚未发布到 npm。在首次 SDK 版本可用之前,请从本 workspace 或受控的打包 tarball 中使用它。它适用于需要确定性的 FairUX 检测结果而无需调用 CLI 的产品:
SDK 遵循与 CLI 相同的 Node.js 支持合约:
**`^22.18.0 || >=24.11.0`**。
```
import { scanHtml } from "@fairux/sdk/html";
const report = scanHtml(`
`);
```
对于重复扫描,只需创建一次可复用的扫描程序,并在扫描时传入针对特定输入的解析选项:
```
import { createHtmlScanner } from "@fairux/sdk/html";
const scanner = createHtmlScanner({
ruleOverrides: {
"consent/checked-checkbox": false,
"obstruction/modal-close-visibility": { enabled: true },
},
});
const report = scanner.scan(html, { file: "checkout.html" });
```
自定义规则包可与内置包组合使用:
```
import { fairuxBuiltinRulePack } from "@fairux/sdk";
import { scanHtml } from "@fairux/sdk/html";
const report = scanHtml(html, {
rulePacks: [fairuxBuiltinRulePack, purchaseGuardRulePack],
ruleOverrides: {
"purchase-guard/missing-return-policy": { severity: "medium" },
},
});
```
要构建自定义 RulePack,请使用 [RulePack 创作指南](docs/rule-pack-authoring.md)、
[测试指南](docs/rule-pack-testing.md)、
[分类法 beta 迁移指南](docs/migrations/rule-pack-taxonomy-beta.1.md) 以及
[外部作者示例](examples/rule-pack-author)。beta API 的范围被有意收窄:仅使用
`@fairux/sdk`、`@fairux/sdk/html` 和 `@fairux/sdk/dom`。内部包并非公开 API。
一次性 HTML/DOM API 和可复用的 HTML/DOM 扫描程序共享相同的策略选项:
`rulePacks`、`includeExperimental`、`ruleOverrides`、`severityOverrides`、`locale`、`toolVersion` 和 `now`。扫描程序策略和规则包来源会在创建扫描程序时进行快照,因此随后对源选项对象或规则包元数据的修改不会影响未来的扫描。
`severityOverrides` 仅更改严重性;它永远不会启用或禁用规则。当 `ruleOverrides` 和 `severityOverrides` 同时指向同一规则时,`ruleOverrides` 控制启用状态,而 `severityOverrides` 提供最终的严重性级别。
规则覆盖 ID 会根据已配置规则包提供的规则进行验证。未知的 ID 会导致扫描程序构建失败,这可以防止拼写错误的规则 ID 在不被察觉的情况下导致规则保持启用或未更改状态。自定义规则 ID 只有在将其 RulePack 包含在 `rulePacks` 中之后才能被覆盖。
`composeRulePacks()` 仅接受布尔值作为 `includeExperimental`。
扫描程序选项是严格的:未知的选项名称、非纯对象、symbol 键、无效的 `null` 值以及不支持的规则 ID 都会导致扫描程序构建失败。只有 `undefined` 会触发 SDK 默认值。`null` 被视为无效输入,绝不转换为默认值。
RulePack 字典组名称是存储在无原型 map 中的任意字符串。诸如 `constructor`、`toString` 和 `__proto__` 之类的名称是普通的字典键,而非保留字。
RulePack 数组必须是紧密的:稀疏的 `rules`、元数据数组和字典模式数组会导致组合失败并抛出 `RulePackError`。只有 `undefined` 表示 RulePack 字典不存在;`null`、布尔值、数字、字符串和数组是无效的字典值。
RulePack 对象、包元数据、规则和规则元数据是严格的自有普通属性对象:未知字段、symbol 字段、继承字段和类实例都会导致组合失败。规则执行输出也会在运行时进行验证并标准化为新的数据快照,因此 getter 或后续对检测结果、证据、定位器、源或引用对象的修改都无法更改公开报告。每个自定义规则结果属性在标准化过程中最多读取一次;从该读取中获得的值将同时用于验证和 FairUX 拥有的快照。访问器属性无法向验证器呈现一个值而向报告呈现另一个值,并且访问器失败会在指纹识别、摘要聚合或 JSON 序列化之前被转换为 `RulePackError`。
自定义检测结果必须保持 `ruleId` 和 `category` 与其规则元数据一致,并且检测结果的 ID 在报告内必须唯一。格式错误的自定义检测结果会抛出 `RulePackError` 失败,以免破坏严重性摘要或公开报告 schema。
FairUX 引擎和内置规则包是确定性的且仅限于本地运行:它们不会对相同的标准化输入发出网络请求或进行 AI 调用。第三方规则包是受信任的可执行 JavaScript,且不受 FairUX 沙箱化限制。请固定版本、审查源码、保持 lockfile 完整性,并且不要动态下载未知的包,或将任意包代码注入到浏览器扩展中。
SDK 不添加评分、基准、抑制或自动修复功能。
### 外部产品
Purchase Guard 风格的产品是独立的产品,而不是 FairUX 的模式。它们可以复用
`@fairux/sdk`、标准化的 UI 模型、确定性的检测结果以及 RulePack 组合。URL、TLS、
域名、重定向、信誉度以及其他网站/安全信号必须保留在应用层命名空间中,而不是混入 FairUX 的检测结果中。
## 包
FairUX 是一个 pnpm monorepo。引擎和规则是**浏览器安全的**(无 Node,无 DOM),因此完全相同的规则可以在每个功能界面上运行。
| 包 | 角色 |
| -------------------------- | --------------------------------------------------------------- |
| `fairux` | 公共 CLI 包 |
| `@fairux/sdk` | 公共程序化 API 外观:规则包、HTML 扫描、DOM 扫描 |
| `@fairux/core` | 内部引擎实现细节 |
| `@fairux/rules` | 内部内置规则实现细节 |
| `@fairux/html` | 内部静态 HTML 适配器实现细节 |
|@fairux/dom` | 内部实时 DOM 适配器实现细节 |
| `@fairux/ast` | 内部 JSX/TSX 适配器实现细节 |
| `@fairux/report` | 内部 JSON + Markdown + SARIF 报告器实现细节 |
| `@fairux/chrome-extension` | Manifest V3 外壳程序 |
| `fairux-vscode` | VS Code 扩展 |
## 许可证
基于 **[Apache License 2.0](LICENSE)** 授权(参见 [`NOTICE`](NOTICE))。
FairUX 是**开放核心 (open core)** 模式:本仓库 —— 包括规则引擎、适配器、报告器、CLI 以及浏览器 / VS Code 界面 —— 均为开源。未来任何高级功能(托管仪表板、团队/企业级功能、AI 辅助解释)都将放在独立的产品中,而不是此处。
标签:Apache Flink, IPv6支持, MITM代理, 云安全监控, 代码规范检查, 内核驱动漏洞利用, 前端工程, 合规审查, 用户体验, 自动化攻击, 静态分析