progmune-runtime 3.7.22 → 3.7.24

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.
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ /**
37
+ * policy/engine.test.ts — 策略引擎 fail-closed 回归(审计修复 2026-09-06)
38
+ *
39
+ * 锁定 Kimi 审计的三条修复:
40
+ * 1. risk 规则不再伪造 ["SSL_CTX_new","SSL_connect"] 输入——无真实调用
41
+ * 数据时按 fail-closed 计违规
42
+ * 2. 配置解析失败显式携带 configError(不再静默回退默认)
43
+ * 3. execute 写盘策略门:项目 opt-in(.progmune-policy.json)时 BLOCK
44
+ * 回滚写盘;未配置时无操作
45
+ */
46
+ const vitest_1 = require("vitest");
47
+ const fs = __importStar(require("fs"));
48
+ const os = __importStar(require("os"));
49
+ const path = __importStar(require("path"));
50
+ const engine_1 = require("./engine");
51
+ const execute_1 = require("../execute");
52
+ let dir;
53
+ (0, vitest_1.beforeEach)(() => { dir = fs.mkdtempSync(path.join(os.tmpdir(), "pm-policy-")); });
54
+ (0, vitest_1.afterEach)(() => { fs.rmSync(dir, { recursive: true, force: true }); });
55
+ function baseCtx(file) {
56
+ return {
57
+ certificate: {
58
+ validated: true,
59
+ confidence: "high",
60
+ provenanceIntact: true,
61
+ fingerprint: "test-fp",
62
+ violations: 0,
63
+ plsbCoverage: "10/13",
64
+ plsbRecall: 1,
65
+ degraded: false,
66
+ sessionId: "test-session",
67
+ file,
68
+ timestamp: new Date().toISOString(),
69
+ },
70
+ accountability: {
71
+ humanEvents: 1,
72
+ aiEvents: 1,
73
+ automatedEvents: 0,
74
+ custodyGap: false,
75
+ },
76
+ };
77
+ }
78
+ (0, vitest_1.describe)("policy engine(fail-closed 回归)", () => {
79
+ (0, vitest_1.it)("risk 规则:无可提取调用数据 → 显式违规(fail-closed,不再伪造输入)", () => {
80
+ const f = path.join(dir, "empty.ts");
81
+ fs.writeFileSync(f, "");
82
+ const result = (0, engine_1.evaluatePolicy)(baseCtx(f));
83
+ const riskViolations = result.violations.filter((v) => v.rule.type === "risk");
84
+ (0, vitest_1.expect)(riskViolations.length).toBeGreaterThanOrEqual(1);
85
+ (0, vitest_1.expect)(riskViolations[0].detail).toContain("fail-closed");
86
+ });
87
+ (0, vitest_1.it)("risk 规则:真实调用提取后良性代码不产生风险违规", () => {
88
+ const f = path.join(dir, "benign.ts");
89
+ fs.writeFileSync(f, "function hello() { console.log('x'); return computeSum(a, b); }");
90
+ const result = (0, engine_1.evaluatePolicy)(baseCtx(f));
91
+ const riskViolations = result.violations.filter((v) => v.rule.type === "risk");
92
+ (0, vitest_1.expect)(riskViolations).toHaveLength(0);
93
+ });
94
+ (0, vitest_1.it)("loadPolicyConfig:JSON 解析失败显式携带 configError(不再静默回退)", () => {
95
+ fs.writeFileSync(path.join(dir, ".progmune-policy.json"), "{ broken json !!!");
96
+ const res = (0, engine_1.loadPolicyConfig)(dir);
97
+ (0, vitest_1.expect)(res.configError).toBeDefined();
98
+ (0, vitest_1.expect)(res.configError).toContain("Failed to parse");
99
+ });
100
+ (0, vitest_1.it)("空规则集 fail-closed:[] 是 truthy 但必须拒绝(BLOCK,非 ALLOW)", () => {
101
+ const f = path.join(dir, "empty.ts");
102
+ fs.writeFileSync(f, "");
103
+ const result = (0, engine_1.evaluatePolicy)(baseCtx(f), []);
104
+ (0, vitest_1.expect)(result.passed).toBe(false);
105
+ (0, vitest_1.expect)(result.verdict).toBe("BLOCK");
106
+ (0, vitest_1.expect)(result.violations.some((v) => v.rule.type === "policy_config")).toBe(true);
107
+ });
108
+ });
109
+ (0, vitest_1.describe)("execute 写盘策略门(opt-in)", () => {
110
+ const MARKED = `// @progmune-generated session=s1 timestamp=2026-09-06T00:00:00.000Z
111
+ function doThing() { return 1; }
112
+ `;
113
+ (0, vitest_1.it)("未配置 .progmune-policy.json → 无操作(旧行为)", () => {
114
+ const f = path.join(dir, "out.ts");
115
+ fs.writeFileSync(f, MARKED);
116
+ const gate = (0, execute_1.applyPolicyGateAfterWrite)(dir, f);
117
+ (0, vitest_1.expect)(gate.blocked).toBe(false);
118
+ (0, vitest_1.expect)(fs.existsSync(f)).toBe(true);
119
+ });
120
+ (0, vitest_1.it)("配置阻断规则 → BLOCK 回滚(新文件删除)", () => {
121
+ fs.writeFileSync(path.join(dir, ".progmune-policy.json"), JSON.stringify({
122
+ inherit: false,
123
+ rules: [{ type: "confidence", severity: "block", threshold: 2 }],
124
+ }));
125
+ const f = path.join(dir, "out.ts");
126
+ fs.writeFileSync(f, MARKED);
127
+ const gate = (0, execute_1.applyPolicyGateAfterWrite)(dir, f);
128
+ (0, vitest_1.expect)(gate.blocked).toBe(true);
129
+ (0, vitest_1.expect)(gate.decision).toBe("BLOCK");
130
+ (0, vitest_1.expect)(fs.existsSync(f)).toBe(false); // 回滚 = 删除新文件
131
+ });
132
+ (0, vitest_1.it)("配置阻断规则 → BLOCK 回滚(已有文件恢复原内容)", () => {
133
+ fs.writeFileSync(path.join(dir, ".progmune-policy.json"), JSON.stringify({
134
+ inherit: false,
135
+ rules: [{ type: "confidence", severity: "block", threshold: 2 }],
136
+ }));
137
+ const f = path.join(dir, "out.ts");
138
+ const prev = "// original content\n";
139
+ const gate = (0, execute_1.applyPolicyGateAfterWrite)(dir, f, prev);
140
+ (0, vitest_1.expect)(gate.blocked).toBe(true);
141
+ (0, vitest_1.expect)(fs.readFileSync(f, "utf-8")).toBe(prev); // 恢复原内容
142
+ });
143
+ });
package/dist/sdk.js CHANGED
@@ -20,7 +20,7 @@ const risk_model_1 = require("./risk-model");
20
20
  const protocol_knowledge_1 = require("./protocol-knowledge");
21
21
  const evidence_repository_1 = require("./evidence-repository");
22
22
  /** Runtime version — stable public identifier. Internal layers evolve underneath. */
23
- exports.RUNTIME_VERSION = "3.7.22";
23
+ exports.RUNTIME_VERSION = "3.7.24";
24
24
  function verify(filePath) {
25
25
  const cert = (0, certify_1.certify)(filePath);
26
26
  const kb = (0, protocol_knowledge_1.buildKnowledgeBase)();
@@ -759,6 +759,9 @@ function rejectionToJSON(rejection) {
759
759
  function parseProtocolsFromJSON(protocolDef) {
760
760
  const protocols = [];
761
761
  for (const [funcName, rule] of Object.entries(protocolDef.rules)) {
762
+ // 未人工确认的提案规则不加载——AI 只提案,人不签字不生效
763
+ if (rule.status && rule.status !== "confirmed")
764
+ continue;
762
765
  protocols.push({
763
766
  function: funcName,
764
767
  protocol: {
@@ -1192,6 +1192,11 @@ async function collectProtocolViolations(ctx, callGraph) {
1192
1192
  let ssgTotalCalls = 0;
1193
1193
  let ssgMatchedCalls = 0;
1194
1194
  let ssgViolationCount = 0;
1195
+ // 截断序列计数(预算耗尽——尾部调用未验证,覆盖率降级信号)
1196
+ let truncatedSeqCount = 0;
1197
+ // Oracle 隔离政策(docs/ORACLE_ISOLATION_POLICY.md):注解合并注册的
1198
+ // 绑定与代码作者同源——单独统计并在报告中披露(独立度指标)
1199
+ const annotationRuleNames = new Set();
1195
1200
  // C 注解建议(函数级作用域——返回值在 try 外组装)
1196
1201
  let annotationSuggestions;
1197
1202
  try {
@@ -1274,9 +1279,11 @@ async function collectProtocolViolations(ctx, callGraph) {
1274
1279
  const nameUnique = (nameCounts.get(fname) || 0) === 1;
1275
1280
  if (qualified) {
1276
1281
  protocolRulesData.rules.set(qualified, protocol);
1282
+ annotationRuleNames.add(qualified);
1277
1283
  }
1278
1284
  if (!f.className || nameUnique) {
1279
1285
  protocolRulesData.rules.set(fname, protocol);
1286
+ annotationRuleNames.add(fname);
1280
1287
  }
1281
1288
  // CamelCase 真实命名(C 代码普遍,如 ACLCheckAllPerm)注册的规则
1282
1289
  // 原样无法被任何匹配策略触达(normalize 只作用于调用名;词段匹配
@@ -1285,6 +1292,7 @@ async function collectProtocolViolations(ctx, callGraph) {
1285
1292
  const normalized = (0, ssg_bridge_1.normalizeName)(fname);
1286
1293
  if (normalized !== fname && (!f.className || nameUnique)) {
1287
1294
  protocolRulesData.rules.set(normalized, protocol);
1295
+ annotationRuleNames.add(normalized);
1288
1296
  }
1289
1297
  }
1290
1298
  }
@@ -1335,6 +1343,8 @@ async function collectProtocolViolations(ctx, callGraph) {
1335
1343
  }
1336
1344
  catch { /* best-effort */ }
1337
1345
  for (const seq of callSequences) {
1346
+ if (seq.truncated)
1347
+ truncatedSeqCount++;
1338
1348
  try {
1339
1349
  const semantic = await (0, api_semantic_mapper_1.mapSequenceToSemanticWithLLM)(seq.calls);
1340
1350
  // ── Phase 5: Cross-function propagation ──
@@ -1481,9 +1491,22 @@ async function collectProtocolViolations(ctx, callGraph) {
1481
1491
  totalCalls: ssgTotalCalls,
1482
1492
  matchedCalls: ssgMatchedCalls,
1483
1493
  ssgViolations: ssgViolationCount,
1484
- summary: (0, ssg_bridge_1.summarizeSSGCoverage)(ssgResults),
1494
+ // 截断序列显式上报(审计修复 2026-09-06):预算耗尽时尾部调用
1495
+ // (close_file 类释放操作)不可见——覆盖率降级信号,不再静默
1496
+ truncatedSequences: truncatedSeqCount,
1497
+ summary: (0, ssg_bridge_1.summarizeSSGCoverage)(ssgResults) +
1498
+ (truncatedSeqCount > 0
1499
+ ? ` (${truncatedSeqCount} sequence(s) truncated — tail calls unverified)`
1500
+ : ""),
1485
1501
  aliasWarnings: protocolRulesData.aliasWarnings?.length
1486
1502
  ? protocolRulesData.aliasWarnings : undefined,
1503
+ // Oracle 独立度(docs/ORACLE_ISOLATION_POLICY.md):规则/别名均为
1504
+ // 人工确认(加载端过滤);项目注解与代码作者同源,单独披露
1505
+ oracleIndependence: {
1506
+ confirmedRules: protocolRulesData.rules.size - annotationRuleNames.size,
1507
+ sameSourceAnnotations: annotationRuleNames.size,
1508
+ confirmedAliases: protocolRulesData.aliasIndex.size,
1509
+ },
1487
1510
  } : undefined,
1488
1511
  annotationSuggestions,
1489
1512
  };
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ /**
37
+ * protocol-rules-liveness.test.ts — 协议规则活性守卫(2026-09-06)
38
+ *
39
+ * Kimi 源码审计发现:SSG 验证器按命名空间隔离状态(stateMap 以
40
+ * namespace 为键),而 protocols.json 中多条规则的 pre_states 引用
41
+ * 其他命名空间建立的状态(如 session_fixation 的规则 pre SESSION_ACTIVE,
42
+ * SESSION_ACTIVE 由 auth 的 create_session 建立)——规则在本命名空间
43
+ * 永远无法满足前置,实际永不触发(G5 同族:2026-08-28 data_integrity
44
+ * 的 check_resource_ownership pre AUTHENTICATED 已发现一次个案)。
45
+ *
46
+ * 本测试把该现象固化为硬性校验:每条规则的 pre_states 必须能在其
47
+ * 命名空间内到达(初始状态 + 本命名空间规则的 post_states 闭包)。
48
+ * 例外(printlab 业务链跨命名空间依赖)显式列入 KNOWN_CROSS_NS,
49
+ * 待跨命名空间状态引用特性实现后移除。
50
+ */
51
+ const vitest_1 = require("vitest");
52
+ const fs = __importStar(require("fs"));
53
+ const path = __importStar(require("path"));
54
+ function loadProtocols() {
55
+ const p = path.join(__dirname, "..", "..", "protocols.json");
56
+ return JSON.parse(fs.readFileSync(p, "utf-8"));
57
+ }
58
+ /** 命名空间内可到达状态:初始状态 + post_states 闭包(同验证器语义) */
59
+ function reachableStates(ns, rules, nsInit) {
60
+ const states = new Set([nsInit[ns] ?? "INIT"]);
61
+ let changed = true;
62
+ while (changed) {
63
+ changed = false;
64
+ for (const r of Object.values(rules)) {
65
+ if ((r.namespace ?? "_global") !== ns)
66
+ continue;
67
+ const pre = new Set(r.pre_states ?? []);
68
+ if (![...pre].every((s) => states.has(s)))
69
+ continue;
70
+ for (const p of r.post_states ?? []) {
71
+ if (!states.has(p)) {
72
+ states.add(p);
73
+ changed = true;
74
+ }
75
+ }
76
+ }
77
+ }
78
+ return states;
79
+ }
80
+ (0, vitest_1.describe)("protocol rules liveness(跨命名空间死规则守卫)", () => {
81
+ (0, vitest_1.it)("每条 confirmed 规则的 pre_states 在其命名空间内可达(跨命名空间引用为显式例外)", () => {
82
+ const { rules, namespaceInitialStates } = loadProtocols();
83
+ const nsInit = namespaceInitialStates ?? {};
84
+ // Oracle 隔离政策:proposed 规则不参与判定,也不做活性断言
85
+ // (在人工确认时由 rule-propose 流程检查)
86
+ const activeRules = {};
87
+ for (const [name, r] of Object.entries(rules)) {
88
+ if (!r.status || r.status === "confirmed")
89
+ activeRules[name] = r;
90
+ }
91
+ // 文档化例外:printlab 业务链(printlab_order ↔ printlab_print 跨
92
+ // 命名空间依赖:queue_order → start_print、upload_stl pre AUTHENTICATED
93
+ // 等)——待跨命名空间状态引用特性后移除
94
+ const KNOWN_CROSS_NS = new Set([
95
+ "upload_stl", "slice_model", "generate_gcode", "estimate_cost",
96
+ "queue_order", "start_print", "complete_print", "ship_order",
97
+ "deliver_order", "fail_print",
98
+ ]);
99
+ const dead = [];
100
+ for (const [name, r] of Object.entries(activeRules)) {
101
+ const ns = r.namespace ?? "_global";
102
+ const reach = reachableStates(ns, activeRules, nsInit);
103
+ for (const s of r.pre_states ?? []) {
104
+ if (!reach.has(s)) {
105
+ dead.push(`${name} (ns=${ns}, pre=${s} 不可达)`);
106
+ }
107
+ }
108
+ }
109
+ (0, vitest_1.expect)(dead.filter((d) => !KNOWN_CROSS_NS.has(d.split(" ")[0]))).toEqual([]);
110
+ // 例外清单必须与实际死规则一致(防止例外清单腐化)
111
+ (0, vitest_1.expect)(dead.map((d) => d.split(" ")[0]).sort())
112
+ .toEqual([...KNOWN_CROSS_NS].sort());
113
+ });
114
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "progmune-runtime",
3
- "version": "3.7.22",
3
+ "version": "3.7.24",
4
4
  "description": "Progmune — AI Trust Decision Engine. Verify AI-generated code before it reaches production. Outputs APPROVED / NEEDS_REVIEW / BLOCKED with evidence.",
5
5
  "files": [
6
6
  "dist/",
@@ -12,11 +12,14 @@
12
12
  "tools/extract_ir.py",
13
13
  "tools/extract_framework_py.py",
14
14
  "tools/extract_framework_django.py",
15
- "tools/extract_framework_flask.py"
15
+ "tools/extract_framework_flask.py",
16
+ "scripts/init-policy.js",
17
+ "templates/"
16
18
  ],
17
19
  "main": "dist/mcp-server.mjs",
18
20
  "bin": {
19
- "progmune-runtime": "dist/mcp-server.mjs"
21
+ "progmune-runtime": "dist/mcp-server.mjs",
22
+ "progmune-init-policy": "scripts/init-policy.js"
20
23
  },
21
24
  "scripts": {
22
25
  "prepare": "npm run build",