@yss123/cage-lint 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +64 -9
- package/dependency-cruiser.cjs +7 -2
- package/dist/index.d.ts +6 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -1
- package/dist/rules/no-manual-routes.d.ts +9 -0
- package/dist/rules/no-manual-routes.js +7 -0
- package/dist/rules/no-manual-routes.js.map +1 -1
- package/dist/rules/no-secret-literal.d.ts +9 -0
- package/dist/rules/no-secret-literal.js +10 -0
- package/dist/rules/no-secret-literal.js.map +1 -1
- package/dist/rules/no-sql-concat.d.ts +9 -0
- package/dist/rules/no-sql-concat.js +8 -0
- package/dist/rules/no-sql-concat.js.map +1 -1
- package/dist/rules/unsafe-needs-reason.d.ts +9 -0
- package/dist/rules/unsafe-needs-reason.js +4 -0
- package/dist/rules/unsafe-needs-reason.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,19 +1,74 @@
|
|
|
1
1
|
# @yss123/cage-lint
|
|
2
2
|
|
|
3
|
-
dependency-cruiser
|
|
3
|
+
Cage 的静态边界检查包。ESLint 规则检查手写业务路由、SQL 拼接、疑似密钥和缺少说明的 unsafe;dependency-cruiser 配置约束 domain、contracts、Web 与服务端的依赖方向。用于开发与 CI,不参与运行时授权。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## 安装
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
需要 Node.js 24+、ESLint 9;在应用根目录安装为开发依赖:
|
|
8
8
|
|
|
9
9
|
```powershell
|
|
10
|
-
pnpm add -D @yss123/cage-lint
|
|
10
|
+
pnpm add -D @yss123/cage-lint eslint@^9 dependency-cruiser
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
脚手架项目已经包含对应依赖与检查配置,升级时保留应用现有扩展规则。
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
- [框架源码与范例](https://github.com/shunshunyue/cage)
|
|
17
|
-
- [问题反馈](https://github.com/shunshunyue/cage/issues)
|
|
15
|
+
## 接入 ESLint
|
|
18
16
|
|
|
19
|
-
|
|
17
|
+
在 ESM 项目的 `eslint.config.js` 中使用 flat config:
|
|
18
|
+
|
|
19
|
+
```js
|
|
20
|
+
/** 使用 Cage 推荐规则;后续可追加应用规则,不能为绕过门禁关闭边界检查。 */
|
|
21
|
+
import cage from '@yss123/cage-lint';
|
|
22
|
+
|
|
23
|
+
export default [...cage.configs.recommended];
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
执行:
|
|
27
|
+
|
|
28
|
+
```powershell
|
|
29
|
+
pnpm exec eslint packages apps
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
推荐配置包括 TypeScript/TSX 解析器,并排除依赖、构建产物、生成契约和 `.cage`。应从项目根目录运行,使相对路径规则与模板结构一致。
|
|
33
|
+
|
|
34
|
+
## 接入依赖方向检查
|
|
35
|
+
|
|
36
|
+
在项目根目录 `.dependency-cruiser.cjs` 中导出框架规则:
|
|
37
|
+
|
|
38
|
+
```js
|
|
39
|
+
/** 沿用框架的模块边界;本文件只配置静态依赖分析,不改变运行权限。 */
|
|
40
|
+
module.exports = require('@yss123/cage-lint/dependency-cruiser.cjs');
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
执行:
|
|
44
|
+
|
|
45
|
+
```powershell
|
|
46
|
+
pnpm exec depcruise packages apps --config .dependency-cruiser.cjs
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
也可在完整脚手架中运行 `pnpm exec cage check`,结合声明、目录与图规则检查定位问题。
|
|
50
|
+
|
|
51
|
+
## 包含哪些规则
|
|
52
|
+
|
|
53
|
+
| 规则/边界 | 目的 |
|
|
54
|
+
| --- | --- |
|
|
55
|
+
| `cage/no-manual-routes` | 普通业务通过声明生成路由,避免另写接口绕过统一流水线 |
|
|
56
|
+
| `cage/no-sql-concat` | 拒绝可识别的 SQL 字符串拼接,使用参数化安全查询 |
|
|
57
|
+
| `cage/no-secret-literal` | 检查疑似密钥字面量,真实值通过部署配置注入 |
|
|
58
|
+
| `cage/unsafe-needs-reason` | unsafe 需记录原因与责任,供审查和预算追踪 |
|
|
59
|
+
| domain 不直接 IO | 不导入文件/网络/数据库或 HTTP/文件服务实现 |
|
|
60
|
+
| Web 不导入服务端 | 前端消费 contracts、client 和浏览器安全协议 |
|
|
61
|
+
| domain 不反向依赖 contracts | 避免声明与生成契约形成依赖循环 |
|
|
62
|
+
| 适配器不直接写库 | 外部结果仍回到领域命令 |
|
|
63
|
+
|
|
64
|
+
本包默认导出插件与 `configs.recommended`,另有命名导出 `rules`;依赖规则通过公开子路径 `@yss123/cage-lint/dependency-cruiser.cjs` 获取。
|
|
65
|
+
|
|
66
|
+
检查基于语法与约定目录,不能证明任意代码不存在漏洞、SQL 注入或秘密,也不能替代后端授权与数据库回归。出现诊断时阅读 `code/at/reason/fix` 并修正职责归属,不通过删除约束或禁用 lint 消除报错。
|
|
67
|
+
|
|
68
|
+
## 文档
|
|
69
|
+
|
|
70
|
+
- [工程目录与模块组织](https://github.com/shunshunyue/cage/blob/main/docs/ai/project-structure.md)
|
|
71
|
+
- [开发流程](https://github.com/shunshunyue/cage/blob/main/docs/ai/workflow.md)
|
|
72
|
+
- [错误码册](https://github.com/shunshunyue/cage/blob/main/docs/errors/README.md)
|
|
73
|
+
|
|
74
|
+
源码与反馈:[GitHub](https://github.com/shunshunyue/cage)。许可证:[MIT](https://github.com/shunshunyue/cage/blob/main/LICENSE)。
|
package/dependency-cruiser.cjs
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 为业务项目声明模块依赖的禁止方向:domain 不直接 IO,适配器不直接写库,Web 不加载服务端运行时。
|
|
3
|
+
* 生成契约和 generated 目录不能反向进入 domain,避免生成循环和职责倒置。
|
|
4
|
+
* 路径正则面向脚手架目录布局,测试文件对 domain IO 规则有明确例外;配置只分析依赖,不改变打包或运行时权限。
|
|
5
|
+
*/
|
|
1
6
|
// 依赖规则(框架提供):管「谁不能导入谁」。项目里的 .dependency-cruiser.cjs 只需要一行:
|
|
2
7
|
// module.exports = require('@yss123/cage-lint/dependency-cruiser.cjs');
|
|
3
8
|
module.exports = {
|
|
@@ -8,7 +13,7 @@ module.exports = {
|
|
|
8
13
|
comment: '[CAGE-DEP-001] 声明和 handler 不能直接做 IO',
|
|
9
14
|
from: { path: '^packages/domain', pathNot: '\\.(test|spec)\\.' },
|
|
10
15
|
to: {
|
|
11
|
-
path: '^(node:)?(fs|net|http|https|http2|child_process|dgram|tls|worker_threads|cluster)$|node_modules/(pg|kysely|axios|undici|node-fetch|got)/|node_modules/@yss123/cage-http/',
|
|
16
|
+
path: '^(node:)?(fs|net|http|https|http2|child_process|dgram|tls|worker_threads|cluster)$|node_modules/(pg|kysely|axios|undici|node-fetch|got)/|node_modules/@yss123/cage-(http|files)/',
|
|
12
17
|
},
|
|
13
18
|
},
|
|
14
19
|
{
|
|
@@ -23,7 +28,7 @@ module.exports = {
|
|
|
23
28
|
severity: 'error',
|
|
24
29
|
comment: '[CAGE-DEP-003] 前端只能依赖 @app/contracts',
|
|
25
30
|
from: { path: '^apps/web' },
|
|
26
|
-
to: { path: '^packages/domain|node_modules/@yss123/cage-(kernel|http|admin|connectors|approval|testkit)/' },
|
|
31
|
+
to: { path: '^packages/domain|node_modules/@yss123/cage-(kernel|http|files|admin|connectors|approval|testkit|ai|ontology)/' },
|
|
27
32
|
},
|
|
28
33
|
{
|
|
29
34
|
name: 'no-generated-imports-from-domain',
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import type { ESLint, Linter } from 'eslint';
|
|
2
|
+
/**
|
|
3
|
+
* 公开规则表,键名供 cage/规则名 配置引用;统一实现由下方插件与推荐配置复用。
|
|
4
|
+
*/
|
|
2
5
|
export declare const rules: {
|
|
3
6
|
'unsafe-needs-reason': import("eslint").Rule.RuleModule;
|
|
4
7
|
'no-sql-concat': import("eslint").Rule.RuleModule;
|
|
5
8
|
'no-secret-literal': import("eslint").Rule.RuleModule;
|
|
6
9
|
'no-manual-routes': import("eslint").Rule.RuleModule;
|
|
7
10
|
};
|
|
11
|
+
/**
|
|
12
|
+
* ESLint 插件对象先创建再填充 recommended,避免配置复制出另一套规则实例。
|
|
13
|
+
*/
|
|
8
14
|
declare const plugin: ESLint.Plugin & {
|
|
9
15
|
configs: Record<string, Linter.Config[]>;
|
|
10
16
|
};
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 导出 Cage ESLint 插件及面向业务项目的推荐规则。
|
|
3
|
+
* 规则覆盖手写路由、SQL 拼接、疑似密钥和 unsafe 说明;依赖方向另由 dependency-cruiser 检查。
|
|
4
|
+
* 推荐配置排除依赖、构建产物和生成契约,只做静态语法检查,不能替代运行时授权或业务测试。
|
|
5
|
+
*/
|
|
1
6
|
// @yss123/cage-lint:ESLint 插件与推荐配置。项目里的 eslint.config.js:
|
|
2
7
|
// import cage from '@yss123/cage-lint';
|
|
3
8
|
// export default [...cage.configs.recommended];
|
|
@@ -6,12 +11,18 @@ import noManualRoutes from './rules/no-manual-routes.js';
|
|
|
6
11
|
import noSecretLiteral from './rules/no-secret-literal.js';
|
|
7
12
|
import noSqlConcat from './rules/no-sql-concat.js';
|
|
8
13
|
import unsafeNeedsReason from './rules/unsafe-needs-reason.js';
|
|
14
|
+
/**
|
|
15
|
+
* 公开规则表,键名供 cage/规则名 配置引用;统一实现由下方插件与推荐配置复用。
|
|
16
|
+
*/
|
|
9
17
|
export const rules = {
|
|
10
18
|
'unsafe-needs-reason': unsafeNeedsReason,
|
|
11
19
|
'no-sql-concat': noSqlConcat,
|
|
12
20
|
'no-secret-literal': noSecretLiteral,
|
|
13
21
|
'no-manual-routes': noManualRoutes,
|
|
14
22
|
};
|
|
23
|
+
/**
|
|
24
|
+
* ESLint 插件对象先创建再填充 recommended,避免配置复制出另一套规则实例。
|
|
25
|
+
*/
|
|
15
26
|
const plugin = {
|
|
16
27
|
meta: { name: '@yss123/cage-lint', version: '0.1.0' },
|
|
17
28
|
rules: rules,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAC1D,0CAA0C;AAC1C,kDAAkD;AAClD,OAAO,QAAQ,MAAM,2BAA2B,CAAC;AAEjD,OAAO,cAAc,MAAM,6BAA6B,CAAC;AACzD,OAAO,eAAe,MAAM,8BAA8B,CAAC;AAC3D,OAAO,WAAW,MAAM,0BAA0B,CAAC;AACnD,OAAO,iBAAiB,MAAM,gCAAgC,CAAC;AAE/D,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,qBAAqB,EAAE,iBAAiB;IACxC,eAAe,EAAE,WAAW;IAC5B,mBAAmB,EAAE,eAAe;IACpC,kBAAkB,EAAE,cAAc;CACnC,CAAC;AAEF,MAAM,MAAM,GAAiE;IAC3E,IAAI,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,OAAO,EAAE;IACrD,KAAK,EAAE,KAAY;IACnB,OAAO,EAAE,EAAE;CACZ,CAAC;AAEF,MAAM,CAAC,OAAO,CAAC,WAAW,GAAG;IAC3B,EAAE,OAAO,EAAE,CAAC,oBAAoB,EAAE,YAAY,EAAE,cAAc,EAAE,uBAAuB,EAAE,UAAU,CAAC,EAAE;IACtG;QACE,KAAK,EAAE,CAAC,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,CAAC;QACrD,eAAe,EAAE;YACf,MAAM,EAAE,QAAe;YACvB,aAAa,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;SAC5F;QACD,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;QACzB,KAAK,EAAE;YACL,0BAA0B,EAAE,OAAO;YACnC,oBAAoB,EAAE,OAAO;YAC7B,wBAAwB,EAAE,OAAO;YACjC,uBAAuB,EAAE,OAAO;SACjC;KACF;CACF,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,0DAA0D;AAC1D,0CAA0C;AAC1C,kDAAkD;AAClD,OAAO,QAAQ,MAAM,2BAA2B,CAAC;AAEjD,OAAO,cAAc,MAAM,6BAA6B,CAAC;AACzD,OAAO,eAAe,MAAM,8BAA8B,CAAC;AAC3D,OAAO,WAAW,MAAM,0BAA0B,CAAC;AACnD,OAAO,iBAAiB,MAAM,gCAAgC,CAAC;AAE/D;;GAEG;AACH,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,qBAAqB,EAAE,iBAAiB;IACxC,eAAe,EAAE,WAAW;IAC5B,mBAAmB,EAAE,eAAe;IACpC,kBAAkB,EAAE,cAAc;CACnC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,GAAiE;IAC3E,IAAI,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,OAAO,EAAE;IACrD,KAAK,EAAE,KAAY;IACnB,OAAO,EAAE,EAAE;CACZ,CAAC;AAEF,MAAM,CAAC,OAAO,CAAC,WAAW,GAAG;IAC3B,EAAE,OAAO,EAAE,CAAC,oBAAoB,EAAE,YAAY,EAAE,cAAc,EAAE,uBAAuB,EAAE,UAAU,CAAC,EAAE;IACtG;QACE,KAAK,EAAE,CAAC,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,CAAC;QACrD,eAAe,EAAE;YACf,MAAM,EAAE,QAAe;YACvB,aAAa,EAAE,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE;SAC5F;QACD,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;QACzB,KAAK,EAAE;YACL,0BAA0B,EAAE,OAAO;YACnC,oBAAoB,EAAE,OAAO;YAC7B,wBAAwB,EAAE,OAAO;YACjC,uBAAuB,EAAE,OAAO;SACjC;KACF;CACF,CAAC;AAEF,eAAe,MAAM,CAAC"}
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 检查业务代码是否绕过声明直接注册 HTTP 路由。
|
|
3
|
+
* 通过常见接收器名、HTTP 方法和路径形状识别调用,命中返回 CAGE-ROUTE-001。
|
|
4
|
+
* 这是有界语法检查,不解析任意变量别名或运行时动态路由;框架自己的 HTTP 实现由其维护边界管理。
|
|
5
|
+
*/
|
|
1
6
|
import type { Rule } from 'eslint';
|
|
7
|
+
/**
|
|
8
|
+
* ESLint 规则定义,每个文件由 create 建立 CallExpression 访问器。
|
|
9
|
+
* 支持字符串路径、模板路径及含 url 属性的路由对象;不执行任何被检查的代码。
|
|
10
|
+
*/
|
|
2
11
|
declare const rule: Rule.RuleModule;
|
|
3
12
|
export default rule;
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 常见路由注册方法集合;只有同时匹配接收器和路径形状才报告,避免把普通对象 get 操作当路由。
|
|
3
|
+
*/
|
|
1
4
|
const METHODS = new Set(['get', 'post', 'put', 'patch', 'delete', 'route', 'all', 'head', 'options']);
|
|
2
5
|
const RECEIVERS = /^(app|server|fastify|router|api|instance)$/i;
|
|
6
|
+
/**
|
|
7
|
+
* ESLint 规则定义,每个文件由 create 建立 CallExpression 访问器。
|
|
8
|
+
* 支持字符串路径、模板路径及含 url 属性的路由对象;不执行任何被检查的代码。
|
|
9
|
+
*/
|
|
3
10
|
const rule = {
|
|
4
11
|
meta: {
|
|
5
12
|
type: 'problem',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-manual-routes.js","sourceRoot":"","sources":["../../src/rules/no-manual-routes.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"no-manual-routes.js","sourceRoot":"","sources":["../../src/rules/no-manual-routes.ts"],"names":[],"mappings":"AAQA;;GAEG;AACH,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;AACtG,MAAM,SAAS,GAAG,6CAA6C,CAAC;AAEhE;;;GAGG;AACH,MAAM,IAAI,GAAoB;IAC5B,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,EAAE,WAAW,EAAE,oBAAoB,EAAE;QAC3C,QAAQ,EAAE,EAAE,KAAK,EAAE,4DAA4D,EAAE;QACjF,MAAM,EAAE,EAAE;KACX;IACD,MAAM,CAAC,OAAO;QACZ,OAAO;YACL,cAAc,CAAC,IAAS;gBACtB,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;gBACtB,IAAI,CAAC,CAAC,IAAI,KAAK,kBAAkB,IAAI,CAAC,CAAC,QAAQ,EAAE,IAAI,KAAK,YAAY,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;oBAAE,OAAO;gBAChH,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,KAAK,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpI,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;gBAChC,MAAM,MAAM,GACV,CAAC,KAAK,EAAE,IAAI,KAAK,SAAS,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;oBAC7F,CAAC,KAAK,EAAE,IAAI,KAAK,iBAAiB,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;oBAChG,CAAC,KAAK,EAAE,IAAI,KAAK,kBAAkB,IAAI,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC;gBACrH,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,IAAI,MAAM;oBAAE,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC,CAAC;YACzI,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AACF,eAAe,IAAI,CAAC"}
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 扫描字符串字面量中的常见凭据格式与疑似密钥赋值。
|
|
3
|
+
* 已知供应商格式先匹配,再依据变量/属性名、长度及字符形状作启发式判断。
|
|
4
|
+
* 环境变量名称允许作为引用;检查并不覆盖任意编码、拼接或运行时构造的秘密,不应把未报错当作绝对无泄漏。
|
|
5
|
+
*/
|
|
1
6
|
import type { Rule } from 'eslint';
|
|
7
|
+
/**
|
|
8
|
+
* 检查 Literal 的字符串值,并从父节点提取变量名、属性名或赋值目标名。
|
|
9
|
+
* 同一值命中已知格式后立即报告并结束该值检查,避免重复提示。
|
|
10
|
+
*/
|
|
2
11
|
declare const rule: Rule.RuleModule;
|
|
3
12
|
export default rule;
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 已知凭据外形及面向开发者的分类名称;这里只存模式,不包含真实密钥样本。
|
|
3
|
+
*/
|
|
1
4
|
const PATTERNS = [
|
|
2
5
|
[/AKIA[0-9A-Z]{16}/, 'AWS 访问密钥'],
|
|
3
6
|
[/-----BEGIN (RSA |EC |OPENSSH )?PRIVATE KEY-----/, '私钥'],
|
|
@@ -7,7 +10,14 @@ const PATTERNS = [
|
|
|
7
10
|
[/\bxox[baprs]-[A-Za-z0-9-]{10,}/, 'Slack 令牌'],
|
|
8
11
|
[/eyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/, 'JWT'],
|
|
9
12
|
];
|
|
13
|
+
/**
|
|
14
|
+
* 对变量或属性名的末尾做密钥语义匹配,供第二阶段启发式判断使用。
|
|
15
|
+
*/
|
|
10
16
|
const NAME_RE = /(password|passwd|secret|token|api[_-]?key|access[_-]?key|private[_-]?key)$/i;
|
|
17
|
+
/**
|
|
18
|
+
* 检查 Literal 的字符串值,并从父节点提取变量名、属性名或赋值目标名。
|
|
19
|
+
* 同一值命中已知格式后立即报告并结束该值检查,避免重复提示。
|
|
20
|
+
*/
|
|
11
21
|
const rule = {
|
|
12
22
|
meta: {
|
|
13
23
|
type: 'problem',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-secret-literal.js","sourceRoot":"","sources":["../../src/rules/no-secret-literal.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"no-secret-literal.js","sourceRoot":"","sources":["../../src/rules/no-secret-literal.ts"],"names":[],"mappings":"AAQA;;GAEG;AACH,MAAM,QAAQ,GAAuB;IACnC,CAAC,kBAAkB,EAAE,UAAU,CAAC;IAChC,CAAC,iDAAiD,EAAE,IAAI,CAAC;IACzD,CAAC,2CAA2C,EAAE,QAAQ,CAAC;IACvD,CAAC,yBAAyB,EAAE,QAAQ,CAAC;IACrC,CAAC,8BAA8B,EAAE,WAAW,CAAC;IAC7C,CAAC,gCAAgC,EAAE,UAAU,CAAC;IAC9C,CAAC,kEAAkE,EAAE,KAAK,CAAC;CAC5E,CAAC;AACF;;GAEG;AACH,MAAM,OAAO,GAAG,6EAA6E,CAAC;AAE9F;;;GAGG;AACH,MAAM,IAAI,GAAoB;IAC5B,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE;QAChC,QAAQ,EAAE,EAAE,MAAM,EAAE,sDAAsD,EAAE;QAC5E,MAAM,EAAE,EAAE;KACX;IACD,MAAM,CAAC,OAAO;QACZ,MAAM,KAAK,GAAG,CAAC,IAAS,EAAE,KAAa,EAAE,IAAa,EAAE,EAAE;YACxD,KAAK,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,QAAQ,EAAE,CAAC;gBAClC,IAAI,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;oBACnB,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;oBAC9D,OAAO;gBACT,CAAC;YACH,CAAC;YACD,+BAA+B;YAC/B,IAAI,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,MAAM,IAAI,EAAE,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC9G,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;YACtE,CAAC;QACH,CAAC,CAAC;QACF,OAAO;YACL,OAAO,CAAC,IAAS;gBACf,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ;oBAAE,OAAO;gBAC3C,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;gBACtB,MAAM,IAAI,GACR,CAAC,EAAE,IAAI,KAAK,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI;oBAC3C,CAAC,CAAC,CAAC,EAAE,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC;wBACtD,CAAC,CAAC,CAAC,EAAE,IAAI,KAAK,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI;4BAC3D,CAAC,CAAC,SAAS,CAAC;gBACpB,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YAChC,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AACF,eAAe,IAAI,CAAC"}
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 检查业务源码中的动态 SQL 文本拼接以及非字面量 sql.raw 调用。
|
|
3
|
+
* 推荐参数化标签模板或查询构建器;检测通过 AST 形状与 SQL 关键词完成,不连接数据库。
|
|
4
|
+
* 任意标签模板会被跳过,这是当前检查器的语法边界,不能据此证明所有被跳过标签都安全。
|
|
5
|
+
*/
|
|
1
6
|
import type { Rule } from 'eslint';
|
|
7
|
+
/**
|
|
8
|
+
* 为插值模板、最外层加法表达式和 sql.raw 调用分别报告诊断。
|
|
9
|
+
* 跳过嵌套加法节点避免重复报同一拼接;raw 仅允许普通字面量或无插值模板。
|
|
10
|
+
*/
|
|
2
11
|
declare const rule: Rule.RuleModule;
|
|
3
12
|
export default rule;
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
const SQL_RE = /\b(select|insert|update|delete)\b[\s\S]*\b(from|into|set|where)\b/i;
|
|
2
|
+
/**
|
|
3
|
+
* 递归判断字面量、模板静态片段或二元表达式中是否具有 SQL 语句外形。
|
|
4
|
+
* 未知节点返回 false;该函数不追踪变量来源,也不把识别结果当成完整 SQL 解析。
|
|
5
|
+
*/
|
|
2
6
|
function isSqlish(node) {
|
|
3
7
|
if (!node)
|
|
4
8
|
return false;
|
|
@@ -10,6 +14,10 @@ function isSqlish(node) {
|
|
|
10
14
|
return isSqlish(node.left) || isSqlish(node.right);
|
|
11
15
|
return false;
|
|
12
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* 为插值模板、最外层加法表达式和 sql.raw 调用分别报告诊断。
|
|
19
|
+
* 跳过嵌套加法节点避免重复报同一拼接;raw 仅允许普通字面量或无插值模板。
|
|
20
|
+
*/
|
|
13
21
|
const rule = {
|
|
14
22
|
meta: {
|
|
15
23
|
type: 'problem',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-sql-concat.js","sourceRoot":"","sources":["../../src/rules/no-sql-concat.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"no-sql-concat.js","sourceRoot":"","sources":["../../src/rules/no-sql-concat.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,GAAG,oEAAoE,CAAC;AAEpF;;;GAGG;AACH,SAAS,QAAQ,CAAC,IAAS;IACzB,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IACxB,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC9F,IAAI,IAAI,CAAC,IAAI,KAAK,iBAAiB;QAAE,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;IACnG,IAAI,IAAI,CAAC,IAAI,KAAK,kBAAkB;QAAE,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACzF,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,IAAI,GAAoB;IAC5B,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,EAAE,WAAW,EAAE,aAAa,EAAE;QACpC,QAAQ,EAAE;YACR,MAAM,EAAE,wDAAwD;YAChE,GAAG,EAAE,kCAAkC;SACxC;QACD,MAAM,EAAE,EAAE;KACX;IACD,MAAM,CAAC,OAAO;QACZ,OAAO;YACL,eAAe,CAAC,IAAS;gBACvB,IAAI,IAAI,CAAC,MAAM,EAAE,IAAI,KAAK,0BAA0B;oBAAE,OAAO,CAAC,gBAAgB;gBAC9E,IAAI,IAAI,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC;oBAAE,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC;YACnG,CAAC;YACD,gBAAgB,CAAC,IAAS;gBACxB,IAAI,IAAI,CAAC,QAAQ,KAAK,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE,IAAI,KAAK,kBAAkB;oBAAE,OAAO;gBAC9E,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC;oBAAE,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC;YACvI,CAAC;YACD,cAAc,CAAC,IAAS;gBACtB,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;gBACtB,IAAI,CAAC,CAAC,IAAI,KAAK,kBAAkB,IAAI,CAAC,CAAC,MAAM,EAAE,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,QAAQ,EAAE,IAAI,KAAK,KAAK,EAAE,CAAC;oBAC5F,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;oBAC5B,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK,iBAAiB,IAAI,CAAC,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;oBAC5G,IAAI,CAAC,OAAO;wBAAE,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;gBAC3D,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AACF,eAAe,IAAI,CAAC"}
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 检查显式 unsafe 调用是否给出 reason 与 owner,以便越界方案可被追踪和评审。
|
|
3
|
+
* 只识别名为 unsafe 的直接调用及其对象字面量参数;不会推断任意别名,也不会判断文字理由是否充分。
|
|
4
|
+
* 存在且不是空白字面量即通过本语法检查,最终越界必要性仍需源码审查。
|
|
5
|
+
*/
|
|
1
6
|
import type { Rule } from 'eslint';
|
|
7
|
+
/**
|
|
8
|
+
* 静态检查首个对象参数的两个说明字段;缺失时返回 CAGE-UNSAFE-001。
|
|
9
|
+
* 规则不放宽业务依赖边界,也不执行 unsafe 所描述的操作。
|
|
10
|
+
*/
|
|
2
11
|
declare const rule: Rule.RuleModule;
|
|
3
12
|
export default rule;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unsafe-needs-reason.js","sourceRoot":"","sources":["../../src/rules/unsafe-needs-reason.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"unsafe-needs-reason.js","sourceRoot":"","sources":["../../src/rules/unsafe-needs-reason.ts"],"names":[],"mappings":"AAQA;;;GAGG;AACH,MAAM,IAAI,GAAoB;IAC5B,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,EAAE,WAAW,EAAE,iCAAiC,EAAE;QACxD,QAAQ,EAAE,EAAE,OAAO,EAAE,iFAAiF,EAAE;QACxG,MAAM,EAAE,EAAE;KACX;IACD,MAAM,CAAC,OAAO;QACZ,OAAO;YACL,cAAc,CAAC,IAAS;gBACtB,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,YAAY,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,QAAQ;oBAAE,OAAO;gBAC/E,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;gBAC9B,MAAM,KAAK,GAAU,GAAG,EAAE,IAAI,KAAK,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC5E,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC;gBACzF,MAAM,MAAM,GAAG,CAAC,CAAS,EAAE,EAAE;oBAC3B,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;oBACjB,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;gBACzE,CAAC,CAAC;gBACF,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC;oBAAE,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC;YAC5F,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC;AACF,eAAe,IAAI,CAAC"}
|