@yss123/cage-cli 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +18 -2
- package/bin/cage.js +6 -0
- package/bin/create-cage-app.js +6 -0
- package/dist/analyze.d.ts +18 -0
- package/dist/analyze.js +26 -0
- package/dist/analyze.js.map +1 -0
- package/dist/baseline.d.ts +5 -0
- package/dist/baseline.js +50 -0
- package/dist/baseline.js.map +1 -0
- package/dist/budget.d.ts +7 -0
- package/dist/budget.js +52 -0
- package/dist/budget.js.map +1 -0
- package/dist/config.d.ts +30 -0
- package/dist/config.js +47 -0
- package/dist/config.js.map +1 -0
- package/dist/create.d.ts +1 -0
- package/dist/create.js +47 -0
- package/dist/create.js.map +1 -0
- package/dist/database.d.ts +5 -0
- package/dist/database.js +70 -0
- package/dist/database.js.map +1 -0
- package/dist/derive.d.ts +14 -0
- package/dist/derive.js +163 -0
- package/dist/derive.js.map +1 -0
- package/dist/dev.d.ts +2 -0
- package/dist/dev.js +155 -0
- package/dist/dev.js.map +1 -0
- package/dist/env.d.ts +1 -0
- package/dist/env.js +15 -0
- package/dist/env.js.map +1 -0
- package/dist/findings.d.ts +11 -0
- package/dist/findings.js +13 -0
- package/dist/findings.js.map +1 -0
- package/dist/gen/contracts.d.ts +6 -0
- package/dist/gen/contracts.js +167 -0
- package/dist/gen/contracts.js.map +1 -0
- package/dist/gen/index.d.ts +19 -0
- package/dist/gen/index.js +137 -0
- package/dist/gen/index.js.map +1 -0
- package/dist/gen/zod-code.d.ts +7 -0
- package/dist/gen/zod-code.js +161 -0
- package/dist/gen/zod-code.js.map +1 -0
- package/dist/graph-snapshot.d.ts +13 -0
- package/dist/graph-snapshot.js +46 -0
- package/dist/graph-snapshot.js.map +1 -0
- package/dist/graph.d.ts +11 -0
- package/dist/graph.js +87 -0
- package/dist/graph.js.map +1 -0
- package/dist/impact.d.ts +28 -0
- package/dist/impact.js +223 -0
- package/dist/impact.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/load.d.ts +6 -0
- package/dist/load.js +17 -0
- package/dist/load.js.map +1 -0
- package/dist/main.d.ts +1 -0
- package/dist/main.js +176 -0
- package/dist/main.js.map +1 -0
- package/dist/migrate.d.ts +7 -0
- package/dist/migrate.js +69 -0
- package/dist/migrate.js.map +1 -0
- package/dist/ontology.d.ts +41 -0
- package/dist/ontology.js +270 -0
- package/dist/ontology.js.map +1 -0
- package/dist/process.d.ts +6 -0
- package/dist/process.js +39 -0
- package/dist/process.js.map +1 -0
- package/dist/rules.d.ts +23 -0
- package/dist/rules.js +251 -0
- package/dist/rules.js.map +1 -0
- package/dist/static-check.d.ts +23 -0
- package/dist/static-check.js +225 -0
- package/dist/static-check.js.map +1 -0
- package/dist/sync.d.ts +5 -0
- package/dist/sync.js +46 -0
- package/dist/sync.js.map +1 -0
- package/dist/upgrade.d.ts +10 -0
- package/dist/upgrade.js +81 -0
- package/dist/upgrade.js.map +1 -0
- package/dist/verify.d.ts +7 -0
- package/dist/verify.js +88 -0
- package/dist/verify.js.map +1 -0
- package/dist/version.d.ts +4 -0
- package/dist/version.js +6 -0
- package/dist/version.js.map +1 -0
- package/graph-ui/app.js +1065 -0
- package/graph-ui/index.html +197 -0
- package/graph-ui/model.js +141 -0
- package/graph-ui/relations.js +125 -0
- package/graph-ui/structure.js +74 -0
- package/graph-ui/style.css +1698 -0
- package/managed/errors/CAGE-APPR-001.md +32 -0
- package/managed/errors/CAGE-APPR-002.md +32 -0
- package/managed/errors/CAGE-APPR-003.md +32 -0
- package/managed/errors/CAGE-APPR-004.md +32 -0
- package/managed/errors/CAGE-APPR-005.md +32 -0
- package/managed/errors/CAGE-APPR-006.md +32 -0
- package/managed/errors/CAGE-APPR-007.md +32 -0
- package/managed/errors/CAGE-APPR-010.md +32 -0
- package/managed/errors/CAGE-AUTH-001.md +32 -0
- package/managed/errors/CAGE-BUDGET-001.md +32 -0
- package/managed/errors/CAGE-BUDGET-002.md +32 -0
- package/managed/errors/CAGE-BUDGET-003.md +32 -0
- package/managed/errors/CAGE-CMD-002.md +32 -0
- package/managed/errors/CAGE-CMD-003.md +34 -0
- package/managed/errors/CAGE-CONN-001.md +32 -0
- package/managed/errors/CAGE-CONN-002.md +32 -0
- package/managed/errors/CAGE-CONN-003.md +32 -0
- package/managed/errors/CAGE-CONN-004.md +32 -0
- package/managed/errors/CAGE-CONN-005.md +32 -0
- package/managed/errors/CAGE-CONN-006.md +32 -0
- package/managed/errors/CAGE-CONN-007.md +32 -0
- package/managed/errors/CAGE-CONN-008.md +32 -0
- package/managed/errors/CAGE-CONN-009.md +32 -0
- package/managed/errors/CAGE-CONN-010.md +32 -0
- package/managed/errors/CAGE-CONN-011.md +32 -0
- package/managed/errors/CAGE-CONN-012.md +32 -0
- package/managed/errors/CAGE-CREATE-001.md +32 -0
- package/managed/errors/CAGE-DECL-001.md +34 -0
- package/managed/errors/CAGE-DECL-002.md +34 -0
- package/managed/errors/CAGE-DECL-003.md +34 -0
- package/managed/errors/CAGE-DECL-004.md +34 -0
- package/managed/errors/CAGE-DEP-001.md +34 -0
- package/managed/errors/CAGE-DEP-002.md +34 -0
- package/managed/errors/CAGE-DEP-003.md +34 -0
- package/managed/errors/CAGE-DEP-004.md +34 -0
- package/managed/errors/CAGE-DEP-005.md +34 -0
- package/managed/errors/CAGE-DLQ-001.md +32 -0
- package/managed/errors/CAGE-ENV-001.md +32 -0
- package/managed/errors/CAGE-EVENT-001.md +32 -0
- package/managed/errors/CAGE-EVENT-002.md +32 -0
- package/managed/errors/CAGE-FIELD-001.md +32 -0
- package/managed/errors/CAGE-FIELD-002.md +32 -0
- package/managed/errors/CAGE-FIELD-003.md +32 -0
- package/managed/errors/CAGE-FIELD-004.md +32 -0
- package/managed/errors/CAGE-GEN-001.md +33 -0
- package/managed/errors/CAGE-GEN-002.md +33 -0
- package/managed/errors/CAGE-GRANT-001.md +32 -0
- package/managed/errors/CAGE-GRANT-002.md +32 -0
- package/managed/errors/CAGE-GRANT-003.md +32 -0
- package/managed/errors/CAGE-IMPACT-001.md +32 -0
- package/managed/errors/CAGE-JOB-001.md +32 -0
- package/managed/errors/CAGE-JOB-002.md +32 -0
- package/managed/errors/CAGE-JOB-003.md +32 -0
- package/managed/errors/CAGE-LINT-001.md +32 -0
- package/managed/errors/CAGE-MIG-001.md +32 -0
- package/managed/errors/CAGE-MIG-002.md +32 -0
- package/managed/errors/CAGE-MIG-003.md +32 -0
- package/managed/errors/CAGE-MIG-004.md +32 -0
- package/managed/errors/CAGE-MIG-005.md +32 -0
- package/managed/errors/CAGE-NAME-001.md +32 -0
- package/managed/errors/CAGE-NAME-002.md +32 -0
- package/managed/errors/CAGE-NAME-003.md +32 -0
- package/managed/errors/CAGE-NAME-004.md +32 -0
- package/managed/errors/CAGE-NAME-005.md +32 -0
- package/managed/errors/CAGE-NAME-006.md +32 -0
- package/managed/errors/CAGE-ORG-001.md +32 -0
- package/managed/errors/CAGE-PAIR-002.md +33 -0
- package/managed/errors/CAGE-QUERY-001.md +32 -0
- package/managed/errors/CAGE-QUERY-002.md +32 -0
- package/managed/errors/CAGE-QUERY-003.md +32 -0
- package/managed/errors/CAGE-REACT-001.md +32 -0
- package/managed/errors/CAGE-REACT-002.md +32 -0
- package/managed/errors/CAGE-READS-001.md +32 -0
- package/managed/errors/CAGE-REG-001.md +32 -0
- package/managed/errors/CAGE-REG-002.md +32 -0
- package/managed/errors/CAGE-REG-003.md +32 -0
- package/managed/errors/CAGE-ROUTE-001.md +32 -0
- package/managed/errors/CAGE-SCOPE-001.md +32 -0
- package/managed/errors/CAGE-SCOPE-002.md +32 -0
- package/managed/errors/CAGE-SECRET-001.md +32 -0
- package/managed/errors/CAGE-SECRET-002.md +32 -0
- package/managed/errors/CAGE-SENS-001.md +32 -0
- package/managed/errors/CAGE-SQL-001.md +32 -0
- package/managed/errors/CAGE-SQL-002.md +32 -0
- package/managed/errors/CAGE-STATE-001.md +32 -0
- package/managed/errors/CAGE-STATE-002.md +32 -0
- package/managed/errors/CAGE-STATE-003.md +32 -0
- package/managed/errors/CAGE-STATE-004.md +32 -0
- package/managed/errors/CAGE-STATE-005.md +32 -0
- package/managed/errors/CAGE-STATE-010.md +32 -0
- package/managed/errors/CAGE-STATE-011.md +32 -0
- package/managed/errors/CAGE-SYNC-001.md +35 -0
- package/managed/errors/CAGE-TEST-001.md +33 -0
- package/managed/errors/CAGE-UNSAFE-001.md +32 -0
- package/managed/errors/CAGE-UPGRADE-001.md +32 -0
- package/managed/errors/README.md +99 -0
- package/package.json +60 -3
- package/templates/app/.dockerignore +10 -0
- package/templates/app/.env.example +17 -0
- package/templates/app/.github/workflows/cage.yml +44 -0
- package/templates/app/AGENTS.md +13 -0
- package/templates/app/Dockerfile +23 -0
- package/templates/app/README.md +58 -0
- package/templates/app/apps/api/package.json +16 -0
- package/templates/app/apps/api/src/main.ts +10 -0
- package/templates/app/apps/api/src/worker.ts +14 -0
- package/templates/app/apps/api/tsconfig.json +5 -0
- package/templates/app/apps/web/index.html +13 -0
- package/templates/app/apps/web/package.json +22 -0
- package/templates/app/apps/web/src/main.tsx +552 -0
- package/templates/app/apps/web/src/style.css +663 -0
- package/templates/app/apps/web/tsconfig.json +11 -0
- package/templates/app/apps/web/vite.config.ts +16 -0
- package/templates/app/cage.config.json +114 -0
- package/templates/app/compose.yaml +39 -0
- package/templates/app/db/migrations/0001_init.sql +112 -0
- package/templates/app/package.json +25 -0
- package/templates/app/packages/contracts/package.json +16 -0
- package/templates/app/packages/contracts/src/dept.ts +74 -0
- package/templates/app/packages/contracts/src/index.ts +81 -0
- package/templates/app/packages/contracts/src/inventory-lock.ts +52 -0
- package/templates/app/packages/contracts/src/inventory.ts +57 -0
- package/templates/app/packages/contracts/src/purchase-order.ts +72 -0
- package/templates/app/packages/contracts/src/queries.ts +17 -0
- package/templates/app/packages/contracts/src/role.ts +85 -0
- package/templates/app/packages/contracts/src/user.ts +89 -0
- package/templates/app/packages/contracts/tsconfig.json +5 -0
- package/templates/app/packages/domain/package.json +23 -0
- package/templates/app/packages/domain/src/approvals.ts +18 -0
- package/templates/app/packages/domain/src/erp.ts +36 -0
- package/templates/app/packages/domain/src/index.ts +9 -0
- package/templates/app/packages/domain/src/inventory.ts +43 -0
- package/templates/app/packages/domain/src/jobs.ts +13 -0
- package/templates/app/packages/domain/src/purchase-order.test.ts +137 -0
- package/templates/app/packages/domain/src/purchase-order.ts +122 -0
- package/templates/app/packages/domain/src/queries.ts +10 -0
- package/templates/app/packages/domain/src/reactions.ts +24 -0
- package/templates/app/packages/domain/tsconfig.json +5 -0
- package/templates/app/pnpm-workspace.yaml +10 -0
- package/templates/app/renovate.json +5 -0
- package/templates/app/tsconfig.base.json +8 -0
package/dist/ontology.js
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
// 抽取器:把声明变成一张本体图(节点 + 边),写到 .cage/ontology.json。规则检查、影响分析、测试生成都读这张图。
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
import { snake, stableStringify } from '@yss123/cage-kernel';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
const h = (v) => createHash('sha256').update(stableStringify(v)).digest('hex').slice(0, 12);
|
|
6
|
+
function jsonSchema(s) {
|
|
7
|
+
try {
|
|
8
|
+
return z.toJSONSchema(s, { unrepresentable: 'any', io: 'input' });
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function fieldAttrs(f) {
|
|
15
|
+
return {
|
|
16
|
+
kind: f.kind,
|
|
17
|
+
sql: f.sql,
|
|
18
|
+
optional: f.isOptional,
|
|
19
|
+
sensitive: f.sensitiveKind ?? null,
|
|
20
|
+
ref: f.ref ?? null,
|
|
21
|
+
unique: !!f.isUnique,
|
|
22
|
+
hidden: !!f.isHidden,
|
|
23
|
+
description: f.description ?? null,
|
|
24
|
+
values: f.values ?? null,
|
|
25
|
+
shape: f.shape
|
|
26
|
+
? Object.fromEntries(Object.entries(f.shape).map(([k, sf]) => [
|
|
27
|
+
k,
|
|
28
|
+
{ kind: sf.kind, optional: sf.isOptional },
|
|
29
|
+
]))
|
|
30
|
+
: null,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export function extract(reg, sites = [], unsafeCount = 0) {
|
|
34
|
+
const nodes = [];
|
|
35
|
+
const edges = [];
|
|
36
|
+
const siteOf = new Map(sites.map((s) => [s.exportName, s]));
|
|
37
|
+
const where = (v) => {
|
|
38
|
+
const n = reg.nameOf(v);
|
|
39
|
+
const s = n ? siteOf.get(n) : undefined;
|
|
40
|
+
return s ? { file: s.file, line: s.line } : {};
|
|
41
|
+
};
|
|
42
|
+
const textHash = (v) => {
|
|
43
|
+
const n = reg.nameOf(v);
|
|
44
|
+
const s = n ? siteOf.get(n) : undefined;
|
|
45
|
+
// Git 的 autocrlf 会改变检出文件的换行。源码哈希统一换行,避免没有业务改动
|
|
46
|
+
// 却把整张命令图都报成变化;字符串字面量的转义内容仍保留原样。
|
|
47
|
+
return s ? h(s.text.replace(/\r\n/g, '\n')) : null;
|
|
48
|
+
};
|
|
49
|
+
const push = (kind, id, attrs, at = {}) => nodes.push({ kind, id, hash: h({ kind, id, attrs }), ...at, attrs });
|
|
50
|
+
const aggOfField = new Map();
|
|
51
|
+
for (const a of reg.aggregates) {
|
|
52
|
+
push('aggregate', a.name, {
|
|
53
|
+
table: `${a.table.schema}.${a.table.name}`,
|
|
54
|
+
scope: { dept: a.scope.deptField ?? null, owner: a.scope.ownerField ?? null },
|
|
55
|
+
invariants: Object.keys(a.invariants),
|
|
56
|
+
invariantSrc: Object.fromEntries(Object.entries(a.invariants).map(([k, fn]) => [k, h(String(fn))])),
|
|
57
|
+
description: a.description ?? null,
|
|
58
|
+
defaultStates: a.states.values.join() === 'active,deleted',
|
|
59
|
+
}, where(a));
|
|
60
|
+
for (const [k, f] of Object.entries(a.fields)) {
|
|
61
|
+
push('field', `${a.name}.${k}`, fieldAttrs(f));
|
|
62
|
+
edges.push({ kind: 'field', from: a.name, to: `${a.name}.${k}` });
|
|
63
|
+
aggOfField.set(`${a.name}.${k}`, a);
|
|
64
|
+
if (f.ref)
|
|
65
|
+
edges.push({ kind: 'refs', from: `${a.name}.${k}`, to: f.ref });
|
|
66
|
+
}
|
|
67
|
+
for (const s of a.states.values) {
|
|
68
|
+
push('state', `${a.name}.${s}`, {
|
|
69
|
+
terminal: a.states.terminal.includes(s),
|
|
70
|
+
initial: a.states.initial === s,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
push('capability', `${a.name}.read`, { kind: 'read' });
|
|
74
|
+
push('capability', `${a.name}.export`, { kind: 'export' });
|
|
75
|
+
}
|
|
76
|
+
for (const e of reg.events) {
|
|
77
|
+
push('event', e.name, { fields: Object.fromEntries(Object.entries(e.fields).map(([k, f]) => [k, fieldAttrs(f)])) }, where(e));
|
|
78
|
+
}
|
|
79
|
+
for (const c of reg.commands) {
|
|
80
|
+
const { cmd, capability } = c;
|
|
81
|
+
const agg = cmd.agg.name;
|
|
82
|
+
push('command', capability, {
|
|
83
|
+
from: cmd.from,
|
|
84
|
+
to: cmd.to,
|
|
85
|
+
invokedBy: cmd.invokedBy,
|
|
86
|
+
input: jsonSchema(cmd.input),
|
|
87
|
+
reads: Object.fromEntries(Object.entries(cmd.reads).map(([k, a]) => [k, a.name])),
|
|
88
|
+
emits: cmd.emits.map((e) => e.event.name),
|
|
89
|
+
customEmit: cmd.emits.filter((e) => e.map).map((e) => e.event.name),
|
|
90
|
+
constraints: cmd.constraints.map((k) => k.name),
|
|
91
|
+
src: textHash(cmd) ?? h(String(cmd.handler)),
|
|
92
|
+
domainCodes: sites.find((s) => s.exportName === c.exportName)?.domainCodes ?? [],
|
|
93
|
+
public: cmd.public,
|
|
94
|
+
}, where(cmd));
|
|
95
|
+
const froms = cmd.from === 'new' ? ['[new]'] : cmd.from;
|
|
96
|
+
for (const f of froms) {
|
|
97
|
+
edges.push({
|
|
98
|
+
kind: 'transition',
|
|
99
|
+
from: f === '[new]' ? `${agg}.[new]` : `${agg}.${f}`,
|
|
100
|
+
// to: null 是各允许起始状态上的自环,不能生成名为 null 的虚假状态。
|
|
101
|
+
to: `${agg}.${cmd.to ?? f}`,
|
|
102
|
+
via: capability,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
for (const [alias, a] of Object.entries(cmd.reads))
|
|
106
|
+
edges.push({ kind: 'reads', from: capability, to: a.name, alias });
|
|
107
|
+
for (const spec of cmd.emits) {
|
|
108
|
+
edges.push({ kind: 'emits', from: capability, to: spec.event.name });
|
|
109
|
+
// 事件载荷用到了聚合的哪些字段(默认映射按同名字段)
|
|
110
|
+
if (!spec.map) {
|
|
111
|
+
for (const k of Object.keys(spec.event.fields)) {
|
|
112
|
+
if (k in cmd.agg.fields)
|
|
113
|
+
edges.push({ kind: 'uses', from: spec.event.name, to: `${agg}.${k}`, as: '事件载荷' });
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
for (const k of cmd.constraints) {
|
|
118
|
+
for (const f of k.fields ?? [])
|
|
119
|
+
edges.push({ kind: 'uses', from: capability, to: `${agg}.${f}`, as: `约束 ${k.name}` });
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
for (const { r, name } of reg.reactions) {
|
|
123
|
+
push('reaction', name, {
|
|
124
|
+
tx: r.tx,
|
|
125
|
+
acquires: r.acquires ?? null,
|
|
126
|
+
releases: r.releases ?? null,
|
|
127
|
+
event: r.event.name,
|
|
128
|
+
command: reg.capabilityOf(r.command),
|
|
129
|
+
src: h(String(r.map)),
|
|
130
|
+
}, where(r));
|
|
131
|
+
edges.push({ kind: 'triggers', from: r.event.name, to: name });
|
|
132
|
+
edges.push({
|
|
133
|
+
kind: 'targets',
|
|
134
|
+
from: name,
|
|
135
|
+
to: reg.capabilityOf(r.command),
|
|
136
|
+
acquires: r.acquires,
|
|
137
|
+
releases: r.releases,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
for (const q of reg.queries) {
|
|
141
|
+
push('query', q.name, {
|
|
142
|
+
reads: q.reads.map((a) => a.name),
|
|
143
|
+
sql: q.sql ? h(q.sql) : null,
|
|
144
|
+
build: q.build ? h(String(q.build)) : null,
|
|
145
|
+
input: jsonSchema(q.input),
|
|
146
|
+
sqlText: q.sql ?? null,
|
|
147
|
+
}, where(q));
|
|
148
|
+
for (const a of q.reads) {
|
|
149
|
+
edges.push({ kind: 'queries', from: q.name, to: a.name });
|
|
150
|
+
const text = (q.sql ?? String(q.build ?? '')).toLowerCase();
|
|
151
|
+
for (const k of Object.keys(a.fields)) {
|
|
152
|
+
if (new RegExp(`\\b(${snake(k)}|${k.toLowerCase()})\\b`).test(text))
|
|
153
|
+
edges.push({ kind: 'uses', from: q.name, to: `${a.name}.${k}`, as: '查询' });
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
for (const { a, name } of reg.approvals) {
|
|
158
|
+
push('approval', name, {
|
|
159
|
+
process: a.process,
|
|
160
|
+
aggregate: a.agg.name,
|
|
161
|
+
start: a.start.name,
|
|
162
|
+
routable: a.routable,
|
|
163
|
+
onApproved: reg.capabilityOf(a.onApproved),
|
|
164
|
+
onRejected: reg.capabilityOf(a.onRejected),
|
|
165
|
+
cancelOn: a.cancelOn.map((e) => e.name),
|
|
166
|
+
}, where(a));
|
|
167
|
+
edges.push({ kind: 'triggers', from: a.start.name, to: name });
|
|
168
|
+
edges.push({ kind: 'binds', from: name, to: reg.capabilityOf(a.onApproved) });
|
|
169
|
+
edges.push({ kind: 'binds', from: name, to: reg.capabilityOf(a.onRejected) });
|
|
170
|
+
for (const f of a.routable)
|
|
171
|
+
edges.push({ kind: 'uses', from: name, to: `${a.agg.name}.${f}`, as: '可路由字段' });
|
|
172
|
+
}
|
|
173
|
+
for (const j of reg.jobs) {
|
|
174
|
+
push('job', j.name, {
|
|
175
|
+
cron: j.cron,
|
|
176
|
+
reads: j.reads.map((a) => a.name),
|
|
177
|
+
calls: j.calls.map((c) => reg.capabilityOf(c)),
|
|
178
|
+
src: h(String(j.run)),
|
|
179
|
+
}, where(j));
|
|
180
|
+
for (const a of j.reads)
|
|
181
|
+
edges.push({ kind: 'queries', from: j.name, to: a.name });
|
|
182
|
+
for (const c of j.calls)
|
|
183
|
+
edges.push({ kind: 'calls', from: j.name, to: reg.capabilityOf(c) });
|
|
184
|
+
}
|
|
185
|
+
for (const e of reg.extensions) {
|
|
186
|
+
const v = e.value;
|
|
187
|
+
if (e.kind === 'ROUTE') {
|
|
188
|
+
const binding = reg.approvalByProcess(v.process);
|
|
189
|
+
push('route', `route:${v.process}`, { process: v.process, nodes: v.nodes }, { ...(siteOf.get(e.name) ? { file: siteOf.get(e.name).file, line: siteOf.get(e.name).line } : {}) });
|
|
190
|
+
if (binding) {
|
|
191
|
+
edges.push({ kind: 'binds', from: `route:${v.process}`, to: binding.name });
|
|
192
|
+
for (const f of v.fieldsUsed)
|
|
193
|
+
edges.push({
|
|
194
|
+
kind: 'uses',
|
|
195
|
+
from: `route:${v.process}`,
|
|
196
|
+
to: `${binding.a.agg.name}.${f}`,
|
|
197
|
+
as: '路由条件',
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
else if (e.kind === 'CONNECTOR') {
|
|
202
|
+
push('connector', `connector:${v.name}`, {
|
|
203
|
+
hosts: v.hosts,
|
|
204
|
+
secret: v.secret ?? null,
|
|
205
|
+
operations: Object.fromEntries(Object.entries(v.operations).map(([k, o]) => [
|
|
206
|
+
k,
|
|
207
|
+
{
|
|
208
|
+
effect: o.effect,
|
|
209
|
+
method: o.method,
|
|
210
|
+
path: o.path,
|
|
211
|
+
request: jsonSchema(o.request),
|
|
212
|
+
response: jsonSchema(o.response),
|
|
213
|
+
},
|
|
214
|
+
])),
|
|
215
|
+
}, siteOf.get(e.name) ? { file: siteOf.get(e.name).file, line: siteOf.get(e.name).line } : {});
|
|
216
|
+
}
|
|
217
|
+
else if (e.kind === 'OUTBOUND') {
|
|
218
|
+
const id = e.name;
|
|
219
|
+
push('outbound', id, {
|
|
220
|
+
event: v.event.name,
|
|
221
|
+
connector: v.op.connector.name,
|
|
222
|
+
operation: v.op.name,
|
|
223
|
+
onSuccess: v.onSuccess ? reg.capabilityOf(v.onSuccess.command) : null,
|
|
224
|
+
src: h(String(v.map)),
|
|
225
|
+
}, siteOf.get(e.name) ? { file: siteOf.get(e.name).file, line: siteOf.get(e.name).line } : {});
|
|
226
|
+
edges.push({ kind: 'triggers', from: v.event.name, to: id });
|
|
227
|
+
edges.push({ kind: 'targets', from: id, to: `connector:${v.op.connector.name}` });
|
|
228
|
+
if (v.onSuccess)
|
|
229
|
+
edges.push({ kind: 'targets', from: id, to: reg.capabilityOf(v.onSuccess.command) });
|
|
230
|
+
// 出站映射用到的事件字段 → 这些字段在聚合里的同名字段
|
|
231
|
+
const emitters = reg.commands.filter((c) => c.cmd.emits.some((s) => s.event === v.event));
|
|
232
|
+
for (const f of v.fields ?? []) {
|
|
233
|
+
for (const c of emitters)
|
|
234
|
+
if (f in c.cmd.agg.fields)
|
|
235
|
+
edges.push({ kind: 'uses', from: id, to: `${c.cmd.agg.name}.${f}`, as: '出站映射' });
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
else if (e.kind === 'INBOUND') {
|
|
239
|
+
const id = e.name;
|
|
240
|
+
push('inbound', id, {
|
|
241
|
+
connector: v.connector.name,
|
|
242
|
+
event: v.event,
|
|
243
|
+
command: reg.capabilityOf(v.command),
|
|
244
|
+
payload: jsonSchema(v.payload),
|
|
245
|
+
}, siteOf.get(e.name) ? { file: siteOf.get(e.name).file, line: siteOf.get(e.name).line } : {});
|
|
246
|
+
edges.push({ kind: 'targets', from: id, to: reg.capabilityOf(v.command) });
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
nodes.sort((a, b) => a.id.localeCompare(b.id) || a.kind.localeCompare(b.kind));
|
|
250
|
+
return { version: 1, nodes, edges, unsafeCount };
|
|
251
|
+
}
|
|
252
|
+
export function diffOntology(base, head) {
|
|
253
|
+
const key = (n) => `${n.kind}:${n.id}`;
|
|
254
|
+
const b = new Map(base.nodes.map((n) => [key(n), n]));
|
|
255
|
+
const hd = new Map(head.nodes.map((n) => [key(n), n]));
|
|
256
|
+
const out = { added: [], removed: [], changed: [] };
|
|
257
|
+
for (const [k, n] of hd) {
|
|
258
|
+
const old = b.get(k);
|
|
259
|
+
if (!old)
|
|
260
|
+
out.added.push(n);
|
|
261
|
+
else if (old.hash !== n.hash)
|
|
262
|
+
out.changed.push({ before: old, after: n });
|
|
263
|
+
}
|
|
264
|
+
for (const [k, n] of b)
|
|
265
|
+
if (!hd.has(k))
|
|
266
|
+
out.removed.push(n);
|
|
267
|
+
return out;
|
|
268
|
+
}
|
|
269
|
+
export const nodeById = (g) => new Map(g.nodes.map((n) => [n.id, n]));
|
|
270
|
+
//# sourceMappingURL=ontology.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ontology.js","sourceRoot":"","sources":["../src/ontology.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type ChildProcess } from 'node:child_process';
|
|
2
|
+
export declare function binPath(pkg: string, bin?: string): string;
|
|
3
|
+
export declare function launch(file: string, args: string[], cwd: string, env?: NodeJS.ProcessEnv): ChildProcess;
|
|
4
|
+
export declare function run(file: string, args: string[], cwd: string, env?: NodeJS.ProcessEnv): Promise<number>;
|
|
5
|
+
/** 升级时安装更新后的清单。这里不接收任意 shell 字符串,参数固定为 install。 */
|
|
6
|
+
export declare function installDependencies(cwd: string): Promise<number>;
|
package/dist/process.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
5
|
+
export function binPath(pkg, bin) {
|
|
6
|
+
// 使用 ESM 解析条件,dependency-cruiser 等纯 ESM 包没有 require 入口。
|
|
7
|
+
let dir = dirname(fileURLToPath(import.meta.resolve(pkg)));
|
|
8
|
+
while (!existsSync(join(dir, 'package.json')) ||
|
|
9
|
+
JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8')).name !== pkg) {
|
|
10
|
+
const parent = dirname(dir);
|
|
11
|
+
if (parent === dir)
|
|
12
|
+
throw new Error(`找不到 ${pkg} 的命令入口`);
|
|
13
|
+
dir = parent;
|
|
14
|
+
}
|
|
15
|
+
const p = JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8'));
|
|
16
|
+
return join(dir, typeof p.bin === 'string' ? p.bin : p.bin[bin ?? Object.keys(p.bin)[0]]);
|
|
17
|
+
}
|
|
18
|
+
export function launch(file, args, cwd, env = process.env) {
|
|
19
|
+
return spawn(process.execPath, [file, ...args], { cwd, env, stdio: 'inherit', windowsHide: true });
|
|
20
|
+
}
|
|
21
|
+
export async function run(file, args, cwd, env = process.env) {
|
|
22
|
+
const child = launch(file, args, cwd, env);
|
|
23
|
+
return new Promise((resolve, reject) => {
|
|
24
|
+
child.once('error', reject);
|
|
25
|
+
child.once('exit', (code) => resolve(code ?? 1));
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
/** 升级时安装更新后的清单。这里不接收任意 shell 字符串,参数固定为 install。 */
|
|
29
|
+
export async function installDependencies(cwd) {
|
|
30
|
+
const pnpm = process.env.npm_execpath;
|
|
31
|
+
if (pnpm && /pnpm/i.test(pnpm))
|
|
32
|
+
return run(pnpm, ['install'], cwd);
|
|
33
|
+
const child = spawn('pnpm', ['install'], { cwd, stdio: 'inherit', windowsHide: true, shell: process.platform === 'win32' });
|
|
34
|
+
return new Promise((resolve, reject) => {
|
|
35
|
+
child.once('error', reject);
|
|
36
|
+
child.once('exit', (code) => resolve(code ?? 1));
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=process.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process.js","sourceRoot":"","sources":["../src/process.ts"],"names":[],"mappings":"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"}
|
package/dist/rules.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Finding } from './findings.js';
|
|
2
|
+
import type { Ontology } from './ontology.js';
|
|
3
|
+
/** 状态 → 进入时获得的资源:命令迁移到 S、发出事件、事件触发标注了 acquires 的反应 */
|
|
4
|
+
export declare function statesHoldingResources(g: Ontology): {
|
|
5
|
+
state: string;
|
|
6
|
+
resource: string;
|
|
7
|
+
via: string;
|
|
8
|
+
}[];
|
|
9
|
+
/** CAGE-PAIR-002:进入某状态时获得了资源,从该状态出发的每一条迁移都必须释放它,或进入一个同样持有它的状态 */
|
|
10
|
+
export declare function checkPairing(g: Ontology): Finding[];
|
|
11
|
+
/** CAGE-STATE-010:每个状态都能从初始状态到达;CAGE-STATE-011:非终态必须有出边 */
|
|
12
|
+
export declare function checkStates(g: Ontology): Finding[];
|
|
13
|
+
/** CAGE-SENS-001:敏感字段不得原样进入事件载荷 */
|
|
14
|
+
export declare function checkSensitiveEvents(g: Ontology): Finding[];
|
|
15
|
+
/** CAGE-APPR-010:invokedBy 为 process 的命令必须有审批绑定或反应调用它,否则没有人能调用 */
|
|
16
|
+
export declare function checkProcessCommands(g: Ontology): Finding[];
|
|
17
|
+
/** CAGE-QUERY-003:手写 SQL 只能引用 reads 里聚合的安全视图 */
|
|
18
|
+
export declare function checkQueries(g: Ontology): Finding[];
|
|
19
|
+
/** CAGE-ORG-001:domain 必须包含框架自带的组织模型 */
|
|
20
|
+
export declare function checkOrg(g: Ontology): Finding[];
|
|
21
|
+
/** CAGE-EVENT-002:事件载荷只允许向后兼容的变更(只能新增可选字段) */
|
|
22
|
+
export declare function checkEventCompat(base: Ontology, head: Ontology): Finding[];
|
|
23
|
+
export declare function runRules(g: Ontology, base?: Ontology | null): Finding[];
|
package/dist/rules.js
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
const at = (n) => (n?.file ? `${n.file}:${n.line ?? 1}` : undefined);
|
|
2
|
+
function index(g) {
|
|
3
|
+
const byId = new Map(g.nodes.map((n) => [`${n.kind}:${n.id}`, n]));
|
|
4
|
+
const get = (kind, id) => byId.get(`${kind}:${id}`);
|
|
5
|
+
const out = (kind, from) => g.edges.filter((e) => e.kind === kind && e.from === from);
|
|
6
|
+
const into = (kind, to) => g.edges.filter((e) => e.kind === kind && e.to === to);
|
|
7
|
+
return { get, out, into };
|
|
8
|
+
}
|
|
9
|
+
/** 状态 → 进入时获得的资源:命令迁移到 S、发出事件、事件触发标注了 acquires 的反应 */
|
|
10
|
+
export function statesHoldingResources(g) {
|
|
11
|
+
const { out } = index(g);
|
|
12
|
+
const held = [];
|
|
13
|
+
for (const t of g.edges.filter((e) => e.kind === 'transition')) {
|
|
14
|
+
for (const ev of out('emits', t.via)) {
|
|
15
|
+
for (const tr of out('triggers', ev.to)) {
|
|
16
|
+
for (const tg of out('targets', tr.to)) {
|
|
17
|
+
if (tg.acquires && !held.some((h) => h.state === t.to && h.resource === tg.acquires))
|
|
18
|
+
held.push({ state: t.to, resource: tg.acquires, via: t.via });
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return held;
|
|
24
|
+
}
|
|
25
|
+
function releasesOnPath(g, via, resource) {
|
|
26
|
+
const { out } = index(g);
|
|
27
|
+
for (const ev of out('emits', via)) {
|
|
28
|
+
for (const tr of out('triggers', ev.to)) {
|
|
29
|
+
if (out('targets', tr.to).some((tg) => tg.releases === resource))
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
/** CAGE-PAIR-002:进入某状态时获得了资源,从该状态出发的每一条迁移都必须释放它,或进入一个同样持有它的状态 */
|
|
36
|
+
export function checkPairing(g) {
|
|
37
|
+
const { get } = index(g);
|
|
38
|
+
const findings = [];
|
|
39
|
+
const held = statesHoldingResources(g);
|
|
40
|
+
const holds = (state, resource) => held.some((h) => h.state === state && h.resource === resource);
|
|
41
|
+
for (const h of held) {
|
|
42
|
+
for (const t of g.edges.filter((e) => e.kind === 'transition' && e.from === h.state && e.to !== h.state)) {
|
|
43
|
+
if (!releasesOnPath(g, t.via, h.resource) && !holds(t.to, h.resource)) {
|
|
44
|
+
findings.push({
|
|
45
|
+
code: 'CAGE-PAIR-002',
|
|
46
|
+
at: at(get('command', t.via)),
|
|
47
|
+
reason: `${t.via} 让单据离开 ${h.state},但没有释放 ${h.resource}`,
|
|
48
|
+
fix: `新增订阅 ${t.via} 所发事件的反应,并标注 releases: '${h.resource}'`,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return findings;
|
|
54
|
+
}
|
|
55
|
+
/** CAGE-STATE-010:每个状态都能从初始状态到达;CAGE-STATE-011:非终态必须有出边 */
|
|
56
|
+
export function checkStates(g) {
|
|
57
|
+
const { get } = index(g);
|
|
58
|
+
const findings = [];
|
|
59
|
+
for (const a of g.nodes.filter((n) => n.kind === 'aggregate')) {
|
|
60
|
+
const states = g.nodes.filter((n) => n.kind === 'state' && n.id.startsWith(`${a.id}.`));
|
|
61
|
+
const trans = g.edges.filter((e) => e.kind === 'transition' && e.to.startsWith(`${a.id}.`));
|
|
62
|
+
const reached = new Set(trans.filter((t) => t.from === `${a.id}.[new]`).map((t) => t.to));
|
|
63
|
+
if (reached.size === 0) {
|
|
64
|
+
const init = states.find((s) => s.attrs.initial);
|
|
65
|
+
if (init)
|
|
66
|
+
reached.add(init.id);
|
|
67
|
+
}
|
|
68
|
+
let grew = true;
|
|
69
|
+
while (grew) {
|
|
70
|
+
grew = false;
|
|
71
|
+
for (const t of trans)
|
|
72
|
+
if (reached.has(t.from) && !reached.has(t.to)) {
|
|
73
|
+
reached.add(t.to);
|
|
74
|
+
grew = true;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const defaults = !!a.attrs.defaultStates;
|
|
78
|
+
for (const s of states) {
|
|
79
|
+
if (defaults && s.id.endsWith('.deleted'))
|
|
80
|
+
continue; // 默认生命周期的 deleted 由框架提供
|
|
81
|
+
if (!reached.has(s.id)) {
|
|
82
|
+
findings.push({
|
|
83
|
+
code: 'CAGE-STATE-010',
|
|
84
|
+
at: at(a),
|
|
85
|
+
reason: `状态 ${s.id} 从初始状态不可达`,
|
|
86
|
+
fix: '增加一个迁移到它的命令,或从 states 里删掉它',
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
const outs = trans.filter((t) => t.from === s.id);
|
|
90
|
+
if (!s.attrs.terminal && outs.length === 0 && !defaults) {
|
|
91
|
+
findings.push({
|
|
92
|
+
code: 'CAGE-STATE-011',
|
|
93
|
+
at: at(a),
|
|
94
|
+
reason: `非终态 ${s.id} 没有任何出边,单据会卡在这里`,
|
|
95
|
+
fix: '增加离开它的命令,或在 states 里把它标记为 terminal',
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
void get;
|
|
101
|
+
return findings;
|
|
102
|
+
}
|
|
103
|
+
/** CAGE-SENS-001:敏感字段不得原样进入事件载荷 */
|
|
104
|
+
export function checkSensitiveEvents(g) {
|
|
105
|
+
const { get, out } = index(g);
|
|
106
|
+
const findings = [];
|
|
107
|
+
for (const c of g.nodes.filter((n) => n.kind === 'command')) {
|
|
108
|
+
const agg = c.id.split('.')[0];
|
|
109
|
+
const custom = new Set(c.attrs.customEmit ?? []);
|
|
110
|
+
for (const e of out('emits', c.id)) {
|
|
111
|
+
const ev = get('event', e.to);
|
|
112
|
+
if (!ev)
|
|
113
|
+
continue;
|
|
114
|
+
for (const [k, f] of Object.entries((ev.attrs.fields ?? {}))) {
|
|
115
|
+
const af = get('field', `${agg}.${k}`);
|
|
116
|
+
if (af?.attrs.sensitive && !f.sensitive) {
|
|
117
|
+
findings.push({
|
|
118
|
+
code: 'CAGE-SENS-001',
|
|
119
|
+
at: at(ev),
|
|
120
|
+
reason: `事件 ${ev.id} 的载荷字段 ${k}${custom.has(ev.id) ? '(自定义映射)' : ''} 对应敏感字段 ${agg}.${k},会原样进入 outbox 和下游系统`,
|
|
121
|
+
fix: `在事件声明里把 ${k} 标成 .sensitive('${af.attrs.sensitive}')(载荷里自动掩码),或从载荷里去掉它`,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return findings;
|
|
128
|
+
}
|
|
129
|
+
/** CAGE-APPR-010:invokedBy 为 process 的命令必须有审批绑定或反应调用它,否则没有人能调用 */
|
|
130
|
+
export function checkProcessCommands(g) {
|
|
131
|
+
const { into } = index(g);
|
|
132
|
+
const findings = [];
|
|
133
|
+
for (const c of g.nodes.filter((n) => n.kind === 'command')) {
|
|
134
|
+
const by = c.attrs.invokedBy;
|
|
135
|
+
const callers = [...into('binds', c.id), ...into('targets', c.id), ...into('calls', c.id)];
|
|
136
|
+
if (by.includes('process') && !by.includes('user') && callers.length === 0) {
|
|
137
|
+
findings.push({
|
|
138
|
+
code: 'CAGE-APPR-010',
|
|
139
|
+
at: at(c),
|
|
140
|
+
reason: `命令 ${c.id} 只接受流程调用,但没有审批绑定或反应调用它`,
|
|
141
|
+
fix: '用 approval(...) 把它绑定为 onApproved/onRejected,或让一个反应调用它;也可能是 invokedBy 写错了',
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
if (by.includes('external') && !by.includes('user') && callers.length === 0) {
|
|
145
|
+
findings.push({
|
|
146
|
+
code: 'CAGE-CONN-012',
|
|
147
|
+
at: at(c),
|
|
148
|
+
reason: `命令 ${c.id} 只接受外部调用,但没有入站回调或出站映射调用它`,
|
|
149
|
+
fix: '用 inbound(...) 或 outbound(..., { onSuccess }) 调用它',
|
|
150
|
+
severity: 'warning',
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return findings;
|
|
155
|
+
}
|
|
156
|
+
/** CAGE-QUERY-003:手写 SQL 只能引用 reads 里聚合的安全视图 */
|
|
157
|
+
export function checkQueries(g) {
|
|
158
|
+
const { get } = index(g);
|
|
159
|
+
const findings = [];
|
|
160
|
+
for (const q of g.nodes.filter((n) => n.kind === 'query')) {
|
|
161
|
+
const text = q.attrs.sqlText;
|
|
162
|
+
if (!text)
|
|
163
|
+
continue;
|
|
164
|
+
const allowed = new Set((q.attrs.reads ?? []).map((a) => String(get('aggregate', a)?.attrs.table ?? '').split('.')[1]));
|
|
165
|
+
for (const m of text.matchAll(/\bsafe\.("?)([a-z_][a-z0-9_]*)\1/gi)) {
|
|
166
|
+
if (!allowed.has(m[2])) {
|
|
167
|
+
findings.push({
|
|
168
|
+
code: 'CAGE-QUERY-003',
|
|
169
|
+
at: at(q),
|
|
170
|
+
reason: `查询 ${q.id} 引用了 safe.${m[2]},但 reads 里没有声明对应的聚合`,
|
|
171
|
+
fix: `在 reads 里加上 safe.${m[2]} 对应的聚合,影响分析才能找到这个查询`,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (/\b(from|join)\s+(?!safe\.|\(|lateral\b|unnest\b|generate_series\b|jsonb_|json_)("?[a-z_][a-z0-9_]*"?)\s*(\.|\b)/i.test(text.replace(/--.*$/gm, ''))) {
|
|
176
|
+
const m = /\b(from|join)\s+(?!safe\.|\(|lateral\b|unnest\b|generate_series\b|jsonb_|json_)("?[a-z_][a-z0-9_.]*"?)/i.exec(text);
|
|
177
|
+
if (m && m[2].includes('.'))
|
|
178
|
+
findings.push({
|
|
179
|
+
code: 'CAGE-QUERY-003',
|
|
180
|
+
at: at(q),
|
|
181
|
+
reason: `查询 ${q.id} 引用了 ${m[2]},只允许引用 safe.* 安全视图`,
|
|
182
|
+
fix: '改为查询对应的安全视图',
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return findings;
|
|
187
|
+
}
|
|
188
|
+
/** CAGE-ORG-001:domain 必须包含框架自带的组织模型 */
|
|
189
|
+
export function checkOrg(g) {
|
|
190
|
+
const has = (id) => g.nodes.some((n) => n.kind === 'aggregate' && n.id === id);
|
|
191
|
+
return has('User') && has('Dept') && has('Role')
|
|
192
|
+
? []
|
|
193
|
+
: [
|
|
194
|
+
{
|
|
195
|
+
code: 'CAGE-ORG-001',
|
|
196
|
+
reason: 'domain 没有导出组织模型(User、Dept、Role)',
|
|
197
|
+
fix: "在 domain 的 index.ts 里加上 export * from '@yss123/cage-admin/domain'",
|
|
198
|
+
},
|
|
199
|
+
];
|
|
200
|
+
}
|
|
201
|
+
/** CAGE-EVENT-002:事件载荷只允许向后兼容的变更(只能新增可选字段) */
|
|
202
|
+
export function checkEventCompat(base, head) {
|
|
203
|
+
const findings = [];
|
|
204
|
+
const b = new Map(base.nodes.filter((n) => n.kind === 'event').map((n) => [n.id, n]));
|
|
205
|
+
for (const ev of head.nodes.filter((n) => n.kind === 'event')) {
|
|
206
|
+
const old = b.get(ev.id);
|
|
207
|
+
if (!old)
|
|
208
|
+
continue;
|
|
209
|
+
const of = (old.attrs.fields ?? {});
|
|
210
|
+
const nf = (ev.attrs.fields ?? {});
|
|
211
|
+
for (const [k, f] of Object.entries(of)) {
|
|
212
|
+
if (!(k in nf))
|
|
213
|
+
findings.push({
|
|
214
|
+
code: 'CAGE-EVENT-002',
|
|
215
|
+
at: at(ev),
|
|
216
|
+
reason: `事件 ${ev.id} 删除了载荷字段 ${k},下游消费者会出错`,
|
|
217
|
+
fix: '保留旧字段(标注废弃),新增字段承载新含义;或新建一个事件',
|
|
218
|
+
});
|
|
219
|
+
else if (nf[k].kind !== f.kind) {
|
|
220
|
+
findings.push({
|
|
221
|
+
code: 'CAGE-EVENT-002',
|
|
222
|
+
at: at(ev),
|
|
223
|
+
reason: `事件 ${ev.id} 的字段 ${k} 类型从 ${f.kind} 变成了 ${nf[k].kind}`,
|
|
224
|
+
fix: '新增一个字段承载新类型,旧字段保留',
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
for (const [k, f] of Object.entries(nf)) {
|
|
229
|
+
if (!(k in of) && !f.optional)
|
|
230
|
+
findings.push({
|
|
231
|
+
code: 'CAGE-EVENT-002',
|
|
232
|
+
at: at(ev),
|
|
233
|
+
reason: `事件 ${ev.id} 新增了必填字段 ${k},已在 outbox 里的旧事件没有它`,
|
|
234
|
+
fix: `把 ${k} 声明为 .optional()`,
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return findings;
|
|
239
|
+
}
|
|
240
|
+
export function runRules(g, base) {
|
|
241
|
+
return [
|
|
242
|
+
...checkOrg(g),
|
|
243
|
+
...checkStates(g),
|
|
244
|
+
...checkPairing(g),
|
|
245
|
+
...checkSensitiveEvents(g),
|
|
246
|
+
...checkProcessCommands(g),
|
|
247
|
+
...checkQueries(g),
|
|
248
|
+
...(base ? checkEventCompat(base, g) : []),
|
|
249
|
+
];
|
|
250
|
+
}
|
|
251
|
+
//# sourceMappingURL=rules.js.map
|