dsh-rule-engine 0.5.17 → 0.6.1
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 +268 -236
- package/lib/core/authorization.js +68 -13
- package/lib/core/contract.js +1 -1
- package/lib/core/guard-core.js +46 -22
- package/lib/core/intent.js +322 -322
- package/lib/core/mount-signature.js +87 -87
- package/lib/core/patterns.js +744 -730
- package/lib/core/state.js +2 -1
- package/lib/core/text-detect.js +24 -4
- package/lib/core/tool-catalog.js +3 -0
- package/lib/index.js +101 -13
- package/lib/service.js +5 -2
- package/package.json +60 -58
- package/scripts/audit-mount-consistency.mjs +198 -198
- package/scripts/check-tool-coverage.mjs +63 -41
- package/scripts/lib/pnpm-exempt.mjs +56 -0
- package/scripts/local-residue-scan.mjs +40 -0
- package/scripts/publish-aptitude-check.mjs +102 -144
- package/scripts/readme-version-check.mjs +41 -0
- package/scripts/release-plugin.mjs +371 -329
- package/scripts/verify-all.mjs +85 -2
package/scripts/verify-all.mjs
CHANGED
|
@@ -12,9 +12,10 @@
|
|
|
12
12
|
// 任一 ❌ → exit 1;⚠️(WARN)不阻塞但必须明示。
|
|
13
13
|
// 注意:子进程输出捕获需完整权限运行(受限模式 EPERM)。
|
|
14
14
|
import { execFileSync } from "node:child_process";
|
|
15
|
-
import { readdirSync, statSync, readFileSync } from "node:fs";
|
|
15
|
+
import { readdirSync, statSync, readFileSync, existsSync } from "node:fs";
|
|
16
16
|
import { dirname, join } from "node:path";
|
|
17
17
|
import { fileURLToPath } from "node:url";
|
|
18
|
+
import { exemptPkg } from "./lib/pnpm-exempt.mjs";
|
|
18
19
|
|
|
19
20
|
const root = join(dirname(fileURLToPath(import.meta.url)), "..");
|
|
20
21
|
const lines = [];
|
|
@@ -58,7 +59,8 @@ step("单元(test/run-all.mjs)", process.execPath, [join(root, "test", "run-
|
|
|
58
59
|
// ── ③ 组合冒烟 ──
|
|
59
60
|
step("组合冒烟(loader-smoke,真实接线+外部世界断言)", process.execPath, [join(root, "test", "loader-smoke.e2e.mjs")]);
|
|
60
61
|
|
|
61
|
-
// ── ⑤ 工具箱覆盖(0.5.9
|
|
62
|
+
// ── ⑤ 工具箱覆盖(0.5.9 门禁;0.6.0 B2′:素材经 CHECK_TOOL_CATALOG/--catalog 提供,缺素材=FAIL 含获取方式——
|
|
63
|
+
// 本机运行请设 CHECK_TOOL_CATALOG=D:\...\docs\docs-site-text\...;发布物内不硬编码任何本机路径) ──
|
|
62
64
|
step("工具箱覆盖(官方 tool-catalog vs 分类表,缺失即红)", process.execPath, [join(root, "scripts", "check-tool-coverage.mjs")]);
|
|
63
65
|
|
|
64
66
|
// ── ⑥ 变更工具守卫链覆盖(0.5.11 规则 24④ 跨工具一致性门禁) ──
|
|
@@ -123,6 +125,87 @@ if (judgeReal > 0) {
|
|
|
123
125
|
// 无 AGENTS.md 冷启动 / 空白规则静默 / 任意编号规则声明式绑定 / 格式契约冒烟 / 个人标识扫描
|
|
124
126
|
step("发布适用性门禁(无 AGENTS.md 冷启动 / 空白规则 / 任意编号 / 个人标识扫描)", process.execPath, [join(root, "scripts", "publish-aptitude-check.mjs")]);
|
|
125
127
|
|
|
128
|
+
// ── ⑨ 发布门禁 B1(阶段 B,2026-09-04:README 版本四性一致性)──
|
|
129
|
+
step("发布门禁 B1(README 版本四性一致性:package.json/徽章/正文/历史表/固定源)", process.execPath, [join(root, "scripts", "readme-version-check.mjs")]);
|
|
130
|
+
|
|
131
|
+
// ── ⑩ 发布门禁 B2(阶段 B,2026-09-04:lib/ 本机痕迹扫描,词表唯一源)──
|
|
132
|
+
step("发布门禁 B2(lib/ 本机痕迹扫描——词表唯一源,命中即红)", process.execPath, [join(root, "scripts", "local-residue-scan.mjs")]);
|
|
133
|
+
|
|
134
|
+
// ── ⑪ 存在性扫描(泄露预防,2026-09-05:真实路径判据——REAL_PATHS_SCAN 指向扫描器,0 命中才算过;
|
|
135
|
+
// 未设置=WARN(本机增强门禁,通用环境无此工具)──
|
|
136
|
+
{
|
|
137
|
+
const scanReal = process.env.REAL_PATHS_SCAN;
|
|
138
|
+
if (scanReal) {
|
|
139
|
+
step("存在性扫描(真实路径判据,0 命中红线)", process.execPath, [scanReal, "--root", root]);
|
|
140
|
+
} else {
|
|
141
|
+
lines.push("⚠️ 存在性扫描:未设置 REAL_PATHS_SCAN(本机增强门禁;发布流水线建议设置)");
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// ── ⑫ 判据库回归(窗口 B 接入,2026-09-06:净化判据 L1 敏感串全集全历史 0 非白名单 + L2 根段未覆盖 0
|
|
146
|
+
// 红线——JUDGE_SCAN 指向本机判定门禁(stage1 判据库扫描器包装),未设置=WARN(本机增强门禁)──
|
|
147
|
+
{
|
|
148
|
+
const judgeScan = process.env.JUDGE_SCAN;
|
|
149
|
+
if (judgeScan) {
|
|
150
|
+
step("判据库回归(净化判据全历史 0 非白名单 + L2 未覆盖 0 红线)", process.execPath, [judgeScan, "--root", root]);
|
|
151
|
+
} else {
|
|
152
|
+
lines.push("⚠️ 判据库回归:未设置 JUDGE_SCAN(本机增强门禁;发布流水线建议设置)");
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ── ⑬ pnpm 豁免校验(批次四 04 1.1 B1 口径;E-56 修活后为真跑校验:npm 已发布 latest 必须 ∈ minimumReleaseAgeExclude;
|
|
157
|
+
// 绝对口径(12.4/13.2 裁定):**link 装配不豁免**——四包 npm latest 必须 ∈ 豁免名单(防未来转非 link 装配踩坑 18)──
|
|
158
|
+
{
|
|
159
|
+
try {
|
|
160
|
+
const dshHome = process.env.DSH_HOME || join(process.env.USERPROFILE || "", ".dsh");
|
|
161
|
+
const wsYaml = readFileSync(join(dshHome, "profiles", "web", "pnpm-workspace.yaml"), "utf8");
|
|
162
|
+
const profPkg = JSON.parse(readFileSync(join(dshHome, "profiles", "web", "package.json"), "utf8"));
|
|
163
|
+
const pkgVerLocal = (p) => { try { return JSON.parse(readFileSync(join(dshHome, "profiles", "web", "node_modules", p, "package.json"), "utf8")).version; } catch { return null; } };
|
|
164
|
+
const fourPkgs = ["dsh-rule-engine", "dsh-rules-manager", "dsh-rules-manager-client", "dsh-rule-engine-client"];
|
|
165
|
+
const misses = [];
|
|
166
|
+
const viewFails = [];
|
|
167
|
+
// 豁免判定(单源:scripts/lib/pnpm-exempt.mjs——与 release-plugin 预插共享;一致性测试锁)
|
|
168
|
+
const exempt = (p, v) => exemptPkg(wsYaml, p, v);
|
|
169
|
+
for (const p of fourPkgs) {
|
|
170
|
+
const spec = profPkg.dependencies?.[p];
|
|
171
|
+
if (!spec) continue;
|
|
172
|
+
const isLink = typeof spec === "string" && spec.startsWith("link:");
|
|
173
|
+
const esc = p.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
174
|
+
// ⑬ 强校验(12.4 修法绝对口径):npm 已发布 latest 必须 ∈ 豁免名单——**不因 link 装配豁免**
|
|
175
|
+
//(link 包其 npm 已发布版本仍须豁免——防未来转非 link 装配时踩坑 18);本机版校验仅非 link 执行
|
|
176
|
+
let latest = null;
|
|
177
|
+
try {
|
|
178
|
+
const npmCli = join(dirname(process.execPath), "node_modules", "npm", "bin", "npm-cli.js");
|
|
179
|
+
latest = (process.platform === "win32" && existsSync(npmCli))
|
|
180
|
+
? execFileSync(process.execPath, [npmCli, "view", p, "version"], { encoding: "utf8", stdio: "pipe" }).trim()
|
|
181
|
+
: execFileSync("npm", ["view", p, "version"], { encoding: "utf8", stdio: "pipe" }).trim();
|
|
182
|
+
} catch { latest = null; viewFails.push(p); }
|
|
183
|
+
if (latest && !exempt(p, latest)) {
|
|
184
|
+
misses.push(`${p}@${latest}(npm latest 未豁免)`);
|
|
185
|
+
}
|
|
186
|
+
if (!isLink) {
|
|
187
|
+
const ver = pkgVerLocal(p);
|
|
188
|
+
if (ver && !exempt(p, ver)) misses.push(`${p}@${ver}(本机版未豁免)`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
if (process.env.VERIFY_ALL_TESTMODE === "1") { misses.push("TESTMODE 合成 miss(门禁活性自证——必须转红)"); viewFails.push("TESTMODE-合成"); }
|
|
192
|
+
if (viewFails.length) {
|
|
193
|
+
// E2:发布语境(VERIFY_ALL_STRICT=1,release-plugin 3.7 设置)viewFails>0 计 ❌(fail-closed);本地默认 ⚠️ 可见+抑制 ✅
|
|
194
|
+
const strictFail = process.env.VERIFY_ALL_STRICT === "1";
|
|
195
|
+
lines.push(strictFail
|
|
196
|
+
? `❌ pnpm 豁免校验:npm view 执行失败 ${viewFails.length} 包(${viewFails.join("、")})——发布语境 fail-closed(latest 未获取即阻断)`
|
|
197
|
+
: `⚠️ pnpm 豁免校验:npm view 执行失败 ${viewFails.length} 包(${viewFails.join("、")})——latest 未获取(fail-closed:未完成≠通过)`);
|
|
198
|
+
}
|
|
199
|
+
if (misses.length) {
|
|
200
|
+
lines.push(`❌ pnpm 豁免校验:${misses.join("、")} 不在 minimumReleaseAgeExclude(发布后首装会被静默跳过——见踩坑 18)`);
|
|
201
|
+
} else if (!viewFails.length) {
|
|
202
|
+
lines.push("✅ pnpm 豁免校验(四包 npm latest 均已豁免)");
|
|
203
|
+
}
|
|
204
|
+
} catch (e) {
|
|
205
|
+
lines.push("⚠️ pnpm 豁免校验:读取失败(本机 profile 缺失时跳过)");
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
126
209
|
console.log(lines.join("\n"));
|
|
127
210
|
const failed = lines.filter((l) => l.startsWith("❌"));
|
|
128
211
|
if (failed.length) {
|