progmune-runtime 3.7.6 → 3.7.7
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/CHANGELOG.md +11 -0
- package/dist/annotation-suggest.js +200 -0
- package/dist/annotation-suggest.test.js +117 -0
- package/dist/sdk.js +1 -1
- package/dist/trust/engine.js +13 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [3.7.7] — 2026-08-28
|
|
4
|
+
|
|
5
|
+
### C 注解采纳体验(采纳生死线工具)
|
|
6
|
+
|
|
7
|
+
- **注解建议引擎**(`src/annotation-suggest.ts`):确定性启发式(无 LLM)——按函数名词汇(3.7.6 金标 5/5 真实注解反推的词表)× 已注解状态,生成原语注解候选(verify/establish/guard/open/close 角色 + 命名空间/状态转移/注释块模板/置信度/命中理由/掩蔽风险标记);已注解、规则名、外部函数自动排除;两遍计算 maskRisk(体内调用规则原语或本批同被建议函数)
|
|
8
|
+
- **CLI 扫描模式**(`scripts/c-annotate.js --scan <dir> [--write] [--all] [--include-resource]`):dry-run 默认;--write 自动插入函数定义上方(写入后自动刷新 ir.json 防陈旧);保守门控(全部实测依据):establish/掩蔽风险跳过(不提供强制开关)、open/close 跳过(--include-resource 强制)
|
|
9
|
+
- **引擎加性字段**:`evaluateTrust.annotationSuggestions`(仅 C 生成;TS/Python 无该字段——零漂移)
|
|
10
|
+
- **验收(REALWORLD_C_V7.md)**:无注解 uftpd 副本金标恢复率 **4/4 角色正确**(check_user_pass=verify / handle_PASS=establish / do_RETR / do_STOR=guard);自动应用 7 条后与手写金标**等价**(真实代码 0 SSG FP、植入违规 2/2 精确定位、NEEDS_REVIEW 72 同分)
|
|
11
|
+
- **三个实测安全发现(自动写入的门控依据)**:①掩蔽风险——establish 注解把手握违规的流函数变「原语」(函数内顺序不检查)后植入违规被掩蔽(实测 2 处);②资源生命周期注解自动应用触发跨函数窗口 FP 类(实测 28 条,open/close 分处不同函数窗口);③new_session 词汇误判守卫(实测 4 FP,模式收紧为 channel 类)
|
|
12
|
+
- 回归:15 个新单元测试;引擎相关套件 98/98;Python 盲测 v1.2 零漂移(64);C 应用级金标 F1=95.7% 不变;演示重扫 SSG 结果不变
|
|
13
|
+
|
|
3
14
|
## [3.7.6] — 2026-08-28
|
|
4
15
|
|
|
5
16
|
### C 生产级路径收官:金标 5/5 + 采纳案例 + 正则层噪声治理
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* annotation-suggest.ts — C 注解建议引擎(确定性启发式,无 LLM)
|
|
4
|
+
*
|
|
5
|
+
* 注解驱动定位的「采纳生死线」:未注解 C 项目的 SSG 层静默(0 flags——
|
|
6
|
+
* 看不见问题,也看不见该在哪下注)。本模块按函数名词汇 + 已注解状态,
|
|
7
|
+
* 为项目生成「原语注解建议清单」——每条建议含角色(verify/establish/
|
|
8
|
+
* guard/open/close)、命名空间、状态转移与可直接粘贴的注释块模板。
|
|
9
|
+
*
|
|
10
|
+
* 设计原则:
|
|
11
|
+
* - 纯名称启发式,诚实标注置信度(high=多证据/强动词,medium=单证据);
|
|
12
|
+
* 不假装语义理解——建议是「填空起点」,人工确认后生效(与
|
|
13
|
+
* c-alias-propose.js 的人工确认门同一哲学)。
|
|
14
|
+
* - 词汇来自 3.7.6 金标 5/5 的真实注解反推(check_user_pass=verify、
|
|
15
|
+
* handle_PASS=establish、do_RETR/do_STOR=守卫、auth_password=verify、
|
|
16
|
+
* new_session_channel=会话守卫、open/close_data_connection=资源生命周期)。
|
|
17
|
+
* - 已注解函数、规则名函数(按名即命中,无需注解)、外部函数不重复建议。
|
|
18
|
+
*/
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.suggestAnnotations = suggestAnnotations;
|
|
21
|
+
const ROLE_DEFS = [
|
|
22
|
+
{
|
|
23
|
+
// 凭证比对(密码/口令/凭证 × 比对动词)——verify_password 同款语义
|
|
24
|
+
role: "verify",
|
|
25
|
+
namespace: "auth",
|
|
26
|
+
pre: ["UNAUTHENTICATED"],
|
|
27
|
+
post: ["PASSWORD_VERIFIED"],
|
|
28
|
+
patterns: [
|
|
29
|
+
["password", "check"],
|
|
30
|
+
["password", "compare"],
|
|
31
|
+
["password", "verify"],
|
|
32
|
+
["password", "auth"],
|
|
33
|
+
["passwd", "check"],
|
|
34
|
+
["pass", "check"],
|
|
35
|
+
["pass", "compare"],
|
|
36
|
+
["credential", "check"],
|
|
37
|
+
["credential", "compare"],
|
|
38
|
+
["secret", "check"],
|
|
39
|
+
["secret", "compare"],
|
|
40
|
+
["kbdint", "get"],
|
|
41
|
+
["otp", "check"],
|
|
42
|
+
],
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
// 登录完成(认证循环/命令处理器的完成点)——establish 原语
|
|
46
|
+
role: "establish",
|
|
47
|
+
namespace: "auth",
|
|
48
|
+
pre: [],
|
|
49
|
+
post: ["AUTHENTICATED"],
|
|
50
|
+
patterns: [
|
|
51
|
+
["authenticate"],
|
|
52
|
+
["login"],
|
|
53
|
+
["logon"],
|
|
54
|
+
["sign_in"],
|
|
55
|
+
["auth_success"],
|
|
56
|
+
["auth_ok"],
|
|
57
|
+
["handle", "pass"],
|
|
58
|
+
["do", "login"],
|
|
59
|
+
["do", "user"],
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
// 权限/会话守卫(权限词 × 检查动词,或 FTP/传输类命令处理器、
|
|
64
|
+
// 通道开启回调)——check_resource_ownership 同款语义(auth 命名空间,
|
|
65
|
+
// 见 REALWORLD_C_V6.md 发现 G5:跨命名空间 pre 不可满足)
|
|
66
|
+
role: "guard",
|
|
67
|
+
namespace: "auth",
|
|
68
|
+
pre: ["AUTHENTICATED"],
|
|
69
|
+
post: ["AUTHORIZED"],
|
|
70
|
+
patterns: [
|
|
71
|
+
["perm", "check"],
|
|
72
|
+
["authoriz", "check"],
|
|
73
|
+
["acl", "check"],
|
|
74
|
+
["grant", "check"],
|
|
75
|
+
["privilege", "check"],
|
|
76
|
+
["do", "retr"],
|
|
77
|
+
["do", "stor"],
|
|
78
|
+
["handle", "retr"],
|
|
79
|
+
["handle", "stor"],
|
|
80
|
+
["do", "download"],
|
|
81
|
+
["do", "upload"],
|
|
82
|
+
["do", "transfer"],
|
|
83
|
+
["start", "transfer"],
|
|
84
|
+
["send", "transfer"],
|
|
85
|
+
["open", "channel"],
|
|
86
|
+
["accept", "channel"],
|
|
87
|
+
["new", "channel"],
|
|
88
|
+
["new", "session", "channel"],
|
|
89
|
+
// 注意:不带 ["new","session"]——new_session 是会话工厂(创建而非检查),
|
|
90
|
+
// 实测(V7):守卫注解会误报其调用方(ftp_cb/tftp_cb/main 在登录前建会话)。
|
|
91
|
+
],
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
// 资源获取(打开文件/连接/日志)——open_file 同款语义
|
|
95
|
+
role: "open",
|
|
96
|
+
namespace: "file",
|
|
97
|
+
pre: [],
|
|
98
|
+
post: ["FILE_OPEN"],
|
|
99
|
+
patterns: [
|
|
100
|
+
["open", "file"],
|
|
101
|
+
["open", "data"],
|
|
102
|
+
["open", "connection"],
|
|
103
|
+
["open", "conn"],
|
|
104
|
+
["open", "log"],
|
|
105
|
+
["open", "db"],
|
|
106
|
+
["create", "connection"],
|
|
107
|
+
],
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
// 资源释放(关闭/销毁文件/连接)——close_file 同款语义
|
|
111
|
+
role: "close",
|
|
112
|
+
namespace: "file",
|
|
113
|
+
pre: ["FILE_OPEN"],
|
|
114
|
+
post: [],
|
|
115
|
+
invalidate: ["FILE_OPEN"],
|
|
116
|
+
patterns: [
|
|
117
|
+
["close", "file"],
|
|
118
|
+
["close", "data"],
|
|
119
|
+
["close", "connection"],
|
|
120
|
+
["close", "conn"],
|
|
121
|
+
["close", "log"],
|
|
122
|
+
["close", "db"],
|
|
123
|
+
["release", "connection"],
|
|
124
|
+
["destroy", "connection"],
|
|
125
|
+
],
|
|
126
|
+
},
|
|
127
|
+
];
|
|
128
|
+
/** 匹配命中数 ≥2 视为高置信(多个独立证据) */
|
|
129
|
+
const HIGH_CONFIDENCE_HITS = 2;
|
|
130
|
+
/**
|
|
131
|
+
* 为一组函数生成注解建议(确定性,同输入同输出)。
|
|
132
|
+
*
|
|
133
|
+
* @param functions — 项目函数列表(C IR)
|
|
134
|
+
* @param ruleNames — 已加载规则名集合(规则名函数按名即命中,无需注解建议)
|
|
135
|
+
* @param limit — 输出上限(默认 20,防大仓库刷屏;按置信度排序)
|
|
136
|
+
*/
|
|
137
|
+
function suggestAnnotations(functions, ruleNames, limit = 20) {
|
|
138
|
+
const suggestions = [];
|
|
139
|
+
const seen = new Set();
|
|
140
|
+
for (const fn of functions) {
|
|
141
|
+
if (!fn.name)
|
|
142
|
+
continue;
|
|
143
|
+
if (fn.protocol && (fn.protocol.pre_states?.length || fn.protocol.post_states?.length)) {
|
|
144
|
+
continue; // 已注解
|
|
145
|
+
}
|
|
146
|
+
if (ruleNames?.has(fn.name))
|
|
147
|
+
continue; // 规则名函数按名命中,无需注解
|
|
148
|
+
if (fn.external)
|
|
149
|
+
continue;
|
|
150
|
+
if (seen.has(fn.name))
|
|
151
|
+
continue;
|
|
152
|
+
seen.add(fn.name);
|
|
153
|
+
const lower = fn.name.toLowerCase();
|
|
154
|
+
for (const def of ROLE_DEFS) {
|
|
155
|
+
const hits = [];
|
|
156
|
+
for (const pattern of def.patterns) {
|
|
157
|
+
if (pattern.every((word) => lower.includes(word))) {
|
|
158
|
+
hits.push(pattern.join("+"));
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (hits.length === 0)
|
|
162
|
+
continue;
|
|
163
|
+
const confidence = hits.length >= HIGH_CONFIDENCE_HITS ? "high" : "medium";
|
|
164
|
+
const invalidatePart = def.invalidate
|
|
165
|
+
? `, invalidate=${fmtStates(def.invalidate)}`
|
|
166
|
+
: "";
|
|
167
|
+
suggestions.push({
|
|
168
|
+
function: fn.name,
|
|
169
|
+
file: fn.file || "",
|
|
170
|
+
role: def.role,
|
|
171
|
+
namespace: def.namespace,
|
|
172
|
+
pre: def.pre,
|
|
173
|
+
post: def.post,
|
|
174
|
+
invalidate: def.invalidate,
|
|
175
|
+
confidence,
|
|
176
|
+
reasons: hits,
|
|
177
|
+
template: `/* @progmune(namespace="${def.namespace}", pre=${fmtStates(def.pre)}, post=${fmtStates(def.post)}${invalidatePart}) */`,
|
|
178
|
+
maskRisk: false, // 两遍计算(见下)
|
|
179
|
+
});
|
|
180
|
+
break; // 一个函数只取最先命中的角色
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// 第二遍:掩蔽风险——函数体调用了「已存在规则原语」或「本批同被建议的
|
|
184
|
+
// 函数」→ 注解后体内序列不再被验证,可能掩蔽其握有的违规(V7 实测:
|
|
185
|
+
// 植入流被 establish 注解变不透明后违规消失)。
|
|
186
|
+
const coSuggested = new Set(suggestions.map((s) => s.function));
|
|
187
|
+
for (const s of suggestions) {
|
|
188
|
+
const fnInfo = functions.find((f) => f.name === s.function);
|
|
189
|
+
s.maskRisk = (fnInfo?.calls || []).some((c) => (ruleNames?.has(c) ?? false) || coSuggested.has(c));
|
|
190
|
+
}
|
|
191
|
+
// 稳定性排序:置信度高优先,其次按 文件+名字(结果可复现)
|
|
192
|
+
const rank = { high: 0, medium: 1 };
|
|
193
|
+
suggestions.sort((a, b) => rank[a.confidence] - rank[b.confidence] ||
|
|
194
|
+
a.file.localeCompare(b.file) ||
|
|
195
|
+
a.function.localeCompare(b.function));
|
|
196
|
+
return suggestions.slice(0, limit);
|
|
197
|
+
}
|
|
198
|
+
function fmtStates(states) {
|
|
199
|
+
return `[${states.map((s) => `"${s}"`).join(", ")}]`;
|
|
200
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/**
|
|
4
|
+
* annotation-suggest.test.ts — 注解建议引擎回归(纯函数,无文件系统 I/O)
|
|
5
|
+
*
|
|
6
|
+
* 词汇模式来自 3.7.6 金标 5/5 真实注解反推(REALWORLD_C_V6.md):
|
|
7
|
+
* check_user_pass/auth_password=verify、handle_PASS=establish、
|
|
8
|
+
* do_RETR/do_STOR/new_session_channel=guard、open/close_data_connection=资源生命周期。
|
|
9
|
+
*/
|
|
10
|
+
const vitest_1 = require("vitest");
|
|
11
|
+
const annotation_suggest_1 = require("./annotation-suggest");
|
|
12
|
+
const fn = (name, extra = {}) => ({
|
|
13
|
+
name,
|
|
14
|
+
file: "src/demo.c",
|
|
15
|
+
...extra,
|
|
16
|
+
});
|
|
17
|
+
(0, vitest_1.describe)("annotation-suggest", () => {
|
|
18
|
+
(0, vitest_1.it)("verify:凭证名词 × 比对动词(check_user_pass / auth_password)", () => {
|
|
19
|
+
const s = (0, annotation_suggest_1.suggestAnnotations)([fn("check_user_pass"), fn("auth_password")]);
|
|
20
|
+
(0, vitest_1.expect)(s).toHaveLength(2);
|
|
21
|
+
for (const x of s) {
|
|
22
|
+
(0, vitest_1.expect)(x.role).toBe("verify");
|
|
23
|
+
(0, vitest_1.expect)(x.namespace).toBe("auth");
|
|
24
|
+
(0, vitest_1.expect)(x.pre).toEqual(["UNAUTHENTICATED"]);
|
|
25
|
+
(0, vitest_1.expect)(x.post).toEqual(["PASSWORD_VERIFIED"]);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
(0, vitest_1.it)("establish:登录完成原语(handle_PASS / authenticate)", () => {
|
|
29
|
+
const s = (0, annotation_suggest_1.suggestAnnotations)([fn("handle_PASS"), fn("authenticate")]);
|
|
30
|
+
(0, vitest_1.expect)(s.map((x) => [x.function, x.role])).toEqual(vitest_1.expect.arrayContaining([
|
|
31
|
+
["handle_PASS", "establish"],
|
|
32
|
+
["authenticate", "establish"],
|
|
33
|
+
]));
|
|
34
|
+
(0, vitest_1.expect)(s[0].pre).toEqual([]);
|
|
35
|
+
(0, vitest_1.expect)(s[0].post).toEqual(["AUTHENTICATED"]);
|
|
36
|
+
});
|
|
37
|
+
(0, vitest_1.it)("guard:FTP 命令处理器与通道开启回调(do_RETR/do_STOR/new_session_channel)", () => {
|
|
38
|
+
const s = (0, annotation_suggest_1.suggestAnnotations)([
|
|
39
|
+
fn("do_RETR"),
|
|
40
|
+
fn("do_STOR"),
|
|
41
|
+
fn("new_session_channel"),
|
|
42
|
+
]);
|
|
43
|
+
for (const x of s) {
|
|
44
|
+
(0, vitest_1.expect)(x.role).toBe("guard");
|
|
45
|
+
(0, vitest_1.expect)(x.pre).toEqual(["AUTHENTICATED"]);
|
|
46
|
+
(0, vitest_1.expect)(x.post).toEqual(["AUTHORIZED"]);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
(0, vitest_1.it)("资源生命周期:open/close_data_connection", () => {
|
|
50
|
+
const s = (0, annotation_suggest_1.suggestAnnotations)([
|
|
51
|
+
fn("open_data_connection"),
|
|
52
|
+
fn("close_data_connection"),
|
|
53
|
+
]);
|
|
54
|
+
const open = s.find((x) => x.function === "open_data_connection");
|
|
55
|
+
const close = s.find((x) => x.function === "close_data_connection");
|
|
56
|
+
(0, vitest_1.expect)(open?.role).toBe("open");
|
|
57
|
+
(0, vitest_1.expect)(open?.post).toEqual(["FILE_OPEN"]);
|
|
58
|
+
(0, vitest_1.expect)(close?.role).toBe("close");
|
|
59
|
+
(0, vitest_1.expect)(close?.pre).toEqual(["FILE_OPEN"]);
|
|
60
|
+
(0, vitest_1.expect)(close?.invalidate).toEqual(["FILE_OPEN"]);
|
|
61
|
+
});
|
|
62
|
+
(0, vitest_1.it)("已注解函数不再建议", () => {
|
|
63
|
+
const annotated = fn("check_user_pass", {
|
|
64
|
+
protocol: { pre_states: ["UNAUTHENTICATED"], post_states: ["PASSWORD_VERIFIED"], namespace: "auth" },
|
|
65
|
+
});
|
|
66
|
+
(0, vitest_1.expect)((0, annotation_suggest_1.suggestAnnotations)([annotated])).toHaveLength(0);
|
|
67
|
+
});
|
|
68
|
+
(0, vitest_1.it)("规则名函数(按名即命中)不再建议", () => {
|
|
69
|
+
const s = (0, annotation_suggest_1.suggestAnnotations)([fn("verify_password")], new Set(["verify_password"]));
|
|
70
|
+
(0, vitest_1.expect)(s).toHaveLength(0);
|
|
71
|
+
});
|
|
72
|
+
(0, vitest_1.it)("外部函数不再建议", () => {
|
|
73
|
+
(0, vitest_1.expect)((0, annotation_suggest_1.suggestAnnotations)([fn("check_password", { external: true })])).toHaveLength(0);
|
|
74
|
+
});
|
|
75
|
+
(0, vitest_1.it)("模板可直接粘贴:完整注释块文本", () => {
|
|
76
|
+
const [s] = (0, annotation_suggest_1.suggestAnnotations)([fn("check_user_pass")]);
|
|
77
|
+
(0, vitest_1.expect)(s.template).toBe('/* @progmune(namespace="auth", pre=["UNAUTHENTICATED"], post=["PASSWORD_VERIFIED"]) */');
|
|
78
|
+
});
|
|
79
|
+
(0, vitest_1.it)("确定性 + 上限:同输入同输出,超过 limit 截断(置信度优先)", () => {
|
|
80
|
+
const fns = Array.from({ length: 30 }, (_, i) => fn(`do_RETR_${i}`) // 全部 guard,单证据 medium
|
|
81
|
+
);
|
|
82
|
+
const a = (0, annotation_suggest_1.suggestAnnotations)(fns, undefined, 10);
|
|
83
|
+
const b = (0, annotation_suggest_1.suggestAnnotations)(fns, undefined, 10);
|
|
84
|
+
(0, vitest_1.expect)(a).toEqual(b);
|
|
85
|
+
(0, vitest_1.expect)(a).toHaveLength(10);
|
|
86
|
+
(0, vitest_1.expect)(a[0].function).toBe("do_RETR_0");
|
|
87
|
+
});
|
|
88
|
+
(0, vitest_1.it)("无命中词汇的函数不产生建议", () => {
|
|
89
|
+
const s = (0, annotation_suggest_1.suggestAnnotations)([fn("parse_int"), fn("strlcat"), fn("main")]);
|
|
90
|
+
(0, vitest_1.expect)(s).toHaveLength(0);
|
|
91
|
+
});
|
|
92
|
+
(0, vitest_1.it)("掩蔽风险:函数体调用已有规则原语 → maskRisk=true", () => {
|
|
93
|
+
const [s] = (0, annotation_suggest_1.suggestAnnotations)([fn("login_flow", { calls: ["verify_password"] })], new Set(["verify_password"]));
|
|
94
|
+
(0, vitest_1.expect)(s.maskRisk).toBe(true);
|
|
95
|
+
});
|
|
96
|
+
(0, vitest_1.it)("掩蔽风险:函数体调用本批同被建议的函数 → maskRisk=true(co-suggestion)", () => {
|
|
97
|
+
const s = (0, annotation_suggest_1.suggestAnnotations)([
|
|
98
|
+
fn("login_flow", { calls: ["start_file_transfer"] }),
|
|
99
|
+
fn("start_file_transfer"),
|
|
100
|
+
]);
|
|
101
|
+
const flow = s.find((x) => x.function === "login_flow");
|
|
102
|
+
(0, vitest_1.expect)(flow?.maskRisk).toBe(true);
|
|
103
|
+
});
|
|
104
|
+
(0, vitest_1.it)("叶子函数(体内无规则原语调用)→ maskRisk=false", () => {
|
|
105
|
+
const [s] = (0, annotation_suggest_1.suggestAnnotations)([fn("check_user_pass", { calls: ["strcmp", "strlcpy"] })]);
|
|
106
|
+
(0, vitest_1.expect)(s.maskRisk).toBe(false);
|
|
107
|
+
});
|
|
108
|
+
(0, vitest_1.it)("会话工厂 new_session 不再误判为守卫", () => {
|
|
109
|
+
const s = (0, annotation_suggest_1.suggestAnnotations)([fn("new_session")]);
|
|
110
|
+
(0, vitest_1.expect)(s).toHaveLength(0);
|
|
111
|
+
});
|
|
112
|
+
(0, vitest_1.it)("通道守卫 new_session_channel 仍命中 guard", () => {
|
|
113
|
+
const s = (0, annotation_suggest_1.suggestAnnotations)([fn("new_session_channel")]);
|
|
114
|
+
(0, vitest_1.expect)(s).toHaveLength(1);
|
|
115
|
+
(0, vitest_1.expect)(s[0].role).toBe("guard");
|
|
116
|
+
});
|
|
117
|
+
});
|
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.
|
|
23
|
+
exports.RUNTIME_VERSION = "3.7.7";
|
|
24
24
|
function verify(filePath) {
|
|
25
25
|
const cert = (0, certify_1.certify)(filePath);
|
|
26
26
|
const kb = (0, protocol_knowledge_1.buildKnowledgeBase)();
|
package/dist/trust/engine.js
CHANGED
|
@@ -60,6 +60,7 @@ const confidence_calculator_1 = require("./confidence-calculator");
|
|
|
60
60
|
const violation_trace_1 = require("./violation-trace");
|
|
61
61
|
const api_semantic_mapper_1 = require("./api-semantic-mapper");
|
|
62
62
|
const protocol_domain_validator_1 = require("./protocol-domain-validator");
|
|
63
|
+
const annotation_suggest_1 = require("../annotation-suggest");
|
|
63
64
|
const call_graph_propagator_1 = require("./call-graph-propagator");
|
|
64
65
|
const ssg_bridge_1 = require("./ssg-bridge");
|
|
65
66
|
const call_sequence_1 = require("../call-sequence");
|
|
@@ -87,7 +88,7 @@ async function evaluateTrust(ctx) {
|
|
|
87
88
|
// ── Phase 5: Build call graph for cross-function propagation ──
|
|
88
89
|
const callGraph = (0, call_graph_propagator_1.buildCallGraphFromIR)(path.join(ctx.projectPath, "ir.json"));
|
|
89
90
|
const enterpriseViolations = collectEnterpriseViolations(ctx);
|
|
90
|
-
const { violations: protocolViolations, coverage: mappingCoverageData, ssgCoverage: ssgCov } = await collectProtocolViolations(ctx, callGraph);
|
|
91
|
+
const { violations: protocolViolations, coverage: mappingCoverageData, ssgCoverage: ssgCov, annotationSuggestions: cAnnotationSuggestions } = await collectProtocolViolations(ctx, callGraph);
|
|
91
92
|
const expressResult = collectExpressViolations(ctx);
|
|
92
93
|
const nestjsResult = collectNestJSViolations(ctx);
|
|
93
94
|
const trpcResult = collectTRPCViolations(ctx);
|
|
@@ -174,6 +175,7 @@ async function evaluateTrust(ctx) {
|
|
|
174
175
|
commit: ctx.commit,
|
|
175
176
|
timestamp,
|
|
176
177
|
engineVersion,
|
|
178
|
+
annotationSuggestions: cAnnotationSuggestions,
|
|
177
179
|
overall: {
|
|
178
180
|
score: effectiveScore,
|
|
179
181
|
decision,
|
|
@@ -717,6 +719,8 @@ async function collectProtocolViolations(ctx, callGraph) {
|
|
|
717
719
|
let ssgTotalCalls = 0;
|
|
718
720
|
let ssgMatchedCalls = 0;
|
|
719
721
|
let ssgViolationCount = 0;
|
|
722
|
+
// C 注解建议(函数级作用域——返回值在 try 外组装)
|
|
723
|
+
let annotationSuggestions;
|
|
720
724
|
try {
|
|
721
725
|
// ── P4.5 校准:TS/JS 项目在 ir.json 缺失时先提取 IR ──
|
|
722
726
|
// 序列必须来自「函数体内真实调用」而非「文件内函数声明名单」——
|
|
@@ -801,6 +805,10 @@ async function collectProtocolViolations(ctx, callGraph) {
|
|
|
801
805
|
// ── P4.6.1: 词段匹配门控的项目函数集合(best-effort,与注解合并共用 ir.json) ──
|
|
802
806
|
// 词段匹配只对项目函数适用(改名协议原语);外部库调用走 alias/关键词桥接。
|
|
803
807
|
let projectFunctions;
|
|
808
|
+
// ── 注解建议(采纳生死线):未注解 C 项目的原语注解候选(加性,仅 C) ──
|
|
809
|
+
// 未注解项目 SSG 层静默(0 flags)——建议清单是「看不见的问题」的入口:
|
|
810
|
+
// 按函数名词汇启发式给出现成注释块模板(角色/命名空间/状态转移预填),
|
|
811
|
+
// 人工确认后生效(与 c-alias-propose 的确认门同一哲学)。
|
|
804
812
|
try {
|
|
805
813
|
const fs = require("fs");
|
|
806
814
|
const irPath = path.join(ctx.projectPath, "ir.json");
|
|
@@ -808,6 +816,9 @@ async function collectProtocolViolations(ctx, callGraph) {
|
|
|
808
816
|
const ir = JSON.parse(fs.readFileSync(irPath, "utf-8"));
|
|
809
817
|
const functions = Array.isArray(ir) ? ir : (ir.functions || []);
|
|
810
818
|
projectFunctions = (0, call_sequence_1.collectProjectFunctionNames)(functions);
|
|
819
|
+
if ((ctx.language || "typescript") === "c") {
|
|
820
|
+
annotationSuggestions = (0, annotation_suggest_1.suggestAnnotations)(functions, protocolRulesData ? new Set(protocolRulesData.rules.keys()) : undefined);
|
|
821
|
+
}
|
|
811
822
|
}
|
|
812
823
|
}
|
|
813
824
|
catch { /* best-effort */ }
|
|
@@ -962,6 +973,7 @@ async function collectProtocolViolations(ctx, callGraph) {
|
|
|
962
973
|
aliasWarnings: protocolRulesData.aliasWarnings?.length
|
|
963
974
|
? protocolRulesData.aliasWarnings : undefined,
|
|
964
975
|
} : undefined,
|
|
976
|
+
annotationSuggestions,
|
|
965
977
|
};
|
|
966
978
|
}
|
|
967
979
|
function extractCallSequencesFromProject(projectPath, language, keepNames) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "progmune-runtime",
|
|
3
|
-
"version": "3.7.
|
|
3
|
+
"version": "3.7.7",
|
|
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/",
|