progmune-runtime 3.7.13 → 3.7.14
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 +12 -0
- package/README.md +2 -2
- package/README.zh-CN.md +2 -2
- package/dist/extract-ir-go.js +42 -6
- package/dist/extract-ir-go.test.js +17 -0
- package/dist/sdk.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [3.7.14] — 2026-09-02
|
|
4
|
+
|
|
5
|
+
### Go 提取器修复 + 恢复率裁决 + 框架诚实分层 + 三语料实验
|
|
6
|
+
|
|
7
|
+
- **提取器两处修复**:①无函数体声明行(`//go:linkname` 类)吞并下一个函数(Getuid/RoundTrip 漏检根因——与 C 3.7.4「# 行吞函数」同族);②接收者方法 receiver 括号组误当参数组(returnType 取到整签名)——回归测试锁定
|
|
8
|
+
- **恢复率裁决**(评审第 3 条落地):tools/go-fn-list.go(go/parser 金标,同一文件集+只计有体函数)+ scan-go-recovery.ts——stdlib 四包 **2434/2434 = 100.0%** → **维持纯词法,go/parser 桥推迟**
|
|
9
|
+
- **命名鸿沟测量**(孵化器理论核心数据):词段可桥接 0-1.9%——Go stdlib 惯用命名无法桥接内置规则词汇(与 C 命名鸿沟同构)
|
|
10
|
+
- **框架诚实分层**(评审第 5 条落地):「12/13 结构级」→「**12 专用检测器 = 4 结构级(AST:NestJS/FastAPI/Django/Flask)+ 8 启发式(代码串:Express/tRPC/Fastify/Next.js/Koa/Hapi/Gin/Fiber)**」;转正门槛 = 真实项目 FP 数据点;CLAUDE.md 矛盾行修复;落地页/矩阵/README 双语同步
|
|
11
|
+
- **Go 三语料实验**(REALWORLD_GO_V1.md,评审第 4 条落地):stdlib 4 FP 全 FP(readColonFile 词段桥接跨窗口类);govwa(vendored benchmarks/go-apps/)B 路径 0 flags;**A 路径 demo-real-go-govwa**:真实代码 3 注解(loginAction=verify/SetSession=establish/AuthCheck=guard)→ 0 FP + 植入违规精确定位 + 3 注解/协议——**Go 定位维持注解驱动(Beta)**
|
|
12
|
+
- **TS 795 完整复跑**(评审第 6 条落地):recall 98.5%(有效 100%)/ precision 100% / FP 0——12 个框架探测器全上线后与历史基线一致
|
|
13
|
+
- 验证:35 定向测试;Python 盲测 v1.2 64 零漂移;check 免疫正常
|
|
14
|
+
|
|
3
15
|
## [3.7.13] — 2026-09-02
|
|
4
16
|
|
|
5
17
|
### Go 语言支持 + Gin/Fiber 框架适配——12/13
|
package/README.md
CHANGED
|
@@ -109,7 +109,7 @@ Progmune is honest about what it can and cannot verify.
|
|
|
109
109
|
|
|
110
110
|
**Multi-language IR (registry-based).** TypeScript (ts-morph) and Python (AST) extractors are registered entries in one registry (`src/extract-project-ir.ts`); `extractProjectIR` merges every detected language into a single function IR shared by the agent loop, `execute()`, and the MCP server — the agent composes function-protocol chains across both languages. Adding a language (Go, Java, …) = register one extractor entry; callers don't change.
|
|
111
111
|
|
|
112
|
-
**Framework adapters: 12
|
|
112
|
+
**Framework adapters: 12 dedicated detectors (4 structural + 8 heuristic).** Express ✅, tRPC ✅, FastAPI ✅, Django ✅ (structural route-level auth analysis — every mutation route checked for auth), Flask ✅ (route/before_request auth guard analysis), Fastify ✅ (route preHandler/hook auth analysis) and Next.js ✅ (App Router route-handler auth analysis), NestJS ✅ (decorator route parsing + global APP_GUARD recognition + @Public exemption), Koa ✅, Hapi ✅ (route-config auth strategy analysis), Gin ✅ and Fiber ✅ (Go route/auth-middleware analysis) have dedicated detectors. Next.js version-aware governance also exists. Spring Boot/Go frameworks and a few TS frameworks remain — framework adaptation is the #1 product gap.
|
|
113
113
|
|
|
114
114
|
### What Progmune does NOT cover (honest boundaries)
|
|
115
115
|
|
|
@@ -235,7 +235,7 @@ High-impact contribution areas:
|
|
|
235
235
|
- **Runtime Pipeline:** Detect → Explain → Repair → Validate (L1–L4)
|
|
236
236
|
- **Trust Engine:** 4-dimension scoring with binary explainability gate
|
|
237
237
|
- **MCP Tools:** 19 — `progmune_trust_check`, `progmune_score`, `progmune_policy_check`, `progmune_certify`, and more
|
|
238
|
-
- **Framework Adapters:**
|
|
238
|
+
- **Framework Adapters:** 12 dedicated detectors — 4 structural (NestJS/FastAPI/Django/Flask) + 8 heuristic (Express/tRPC/Fastify/Next.js/Koa/Hapi/Gin/Fiber)
|
|
239
239
|
- **Knowledge Base:** 31 domains, 148 protocol rules, 22 detectors, 26 safeguards, PLSB 13/13 categories — plus 15 source-level detection rules (Python)
|
|
240
240
|
- **Corpus:** 2,500+ trajectories across 6+ repositories; blind benchmarks 100 (TS) + 90 (Python) projects; real-world validation on 4 application repos
|
|
241
241
|
- **Current focus:** Enterprise PoC validation + remaining framework-internal boundary FPs
|
package/README.zh-CN.md
CHANGED
|
@@ -109,7 +109,7 @@ Progmune 对能验证什么、不能验证什么保持诚实。
|
|
|
109
109
|
|
|
110
110
|
**多语言 IR(注册表式)。** TypeScript(ts-morph)与 Python(AST)提取器是同一注册表(`src/extract-project-ir.ts`)中的注册项;`extractProjectIR` 把检测到的所有语言合并为一份函数 IR,由 agent loop、`execute()` 与 MCP server 共享——agent 可在两种语言上编排函数协议链。新增语言(Go、Java……)= 注册一条提取器,调用方零改动。
|
|
111
111
|
|
|
112
|
-
**框架适配器:12
|
|
112
|
+
**框架适配器:12 专用检测器(4 结构级 + 8 启发式)。** Express ✅、tRPC ✅、FastAPI ✅、Django ✅(结构级路由认证分析——逐条检查写操作入口的认证)、Flask ✅(路由/before_request 认证守卫分析)、Fastify ✅(路由 preHandler/钩子认证分析)与 Next.js ✅(App Router 路由处理器认证分析)、NestJS ✅(装饰器路由解析 + 全局 APP_GUARD 守卫识别 + @Public 豁免)、Koa ✅、Hapi ✅(路由配置认证策略分析)、Gin ✅ 与 Fiber ✅(Go 路由/认证中间件分析)有专用检测器;Next.js 另有版本感知治理。结构级 = AST 解析(NestJS/FastAPI/Django/Flask——合成金标 P=R=100%);启发式 = 代码串模式(Express/tRPC/Fastify/Next.js/Koa/Hapi/Gin/Fiber——单测覆盖,真实项目 FP 数据待补)。Spring Boot 待适配——框架适配是 #1 产品缺口。
|
|
113
113
|
|
|
114
114
|
### Progmune 不覆盖什么(诚实边界)
|
|
115
115
|
|
|
@@ -234,7 +234,7 @@ Progmune 建立在"**LLM 输出是统计表演而非推理**"这一前提上—
|
|
|
234
234
|
- **运行时管线:** 检测 → 解释 → 修复 → 验证(L1–L4)
|
|
235
235
|
- **信任引擎:** 四维评分 + 二元可解释性门
|
|
236
236
|
- **MCP 工具:** 19 个——`progmune_trust_check`、`progmune_score`、`progmune_policy_check`、`progmune_certify` 等
|
|
237
|
-
- **框架适配器:**
|
|
237
|
+
- **框架适配器:** 12 专用检测器——4 结构级(NestJS/FastAPI/Django/Flask)+ 8 启发式(Express/tRPC/Fastify/Next.js/Koa/Hapi/Gin/Fiber)
|
|
238
238
|
- **知识库:** 31 个域、148 条协议规则、22 个检测器、26 条防护规则、PLSB 13/13 类别——另加 15 条源码级检测规则(Python)
|
|
239
239
|
- **语料:** 6+ 仓库 2,500+ 轨迹;盲测基准 100(TS)+ 90(Python)个项目;4 个应用仓库真实验证
|
|
240
240
|
- **当前重点:** 企业 PoC 验证 + 剩余框架内部边界误报
|
package/dist/extract-ir-go.js
CHANGED
|
@@ -230,11 +230,15 @@ function extractGoFile(filePath) {
|
|
|
230
230
|
const name = plain ? plain[1] : receiver ? receiver[1] : null;
|
|
231
231
|
if (!name)
|
|
232
232
|
continue;
|
|
233
|
-
// 多行签名:从 func 起拼接直到找到 { 或
|
|
233
|
+
// 多行签名:从 func 起拼接直到找到 { 或 ;——遇到下一个 func 行即停
|
|
234
|
+
// (无函数体声明行如 `func runtime_args() []string // in package runtime`
|
|
235
|
+
// 不能吞掉紧随其后的函数定义——proc.go::Getuid 漏检根因)
|
|
234
236
|
let sigText = lines[i];
|
|
235
237
|
let j = i;
|
|
236
238
|
while (!sigText.includes("{") && !sigText.includes(";") && j < lines.length - 1) {
|
|
237
239
|
j++;
|
|
240
|
+
if (/^\s*func\b/.test(lines[j]) && j > i)
|
|
241
|
+
break;
|
|
238
242
|
sigText += "\n" + lines[j];
|
|
239
243
|
}
|
|
240
244
|
const braceIdx = sigText.indexOf("{");
|
|
@@ -274,15 +278,47 @@ function extractGoFile(filePath) {
|
|
|
274
278
|
const requires = docTag(commentText, "requires")?.split(/[,\s]+/).filter(Boolean);
|
|
275
279
|
const produces = docTag(commentText, "produces")?.split(/[,\s]+/).filter(Boolean);
|
|
276
280
|
const useWhen = docTag(commentText, "useWhen")?.split(/[,\s]+/).filter(Boolean);
|
|
277
|
-
// 参数列表:签名中第一个 ( ... )
|
|
278
|
-
|
|
279
|
-
|
|
281
|
+
// 参数列表:签名中第一个 ( ... )——接收者方法的 receiver 括号组要先跳过
|
|
282
|
+
// (bug 修复:func (s *Service) Login(...) 的 (s *Service) 曾被当作参数组,
|
|
283
|
+
// returnType 取到整个签名)
|
|
284
|
+
let sigAfterReceiver = signature;
|
|
285
|
+
if (receiver) {
|
|
286
|
+
let depth = 0;
|
|
287
|
+
for (let ci = signature.indexOf("("); ci < signature.length; ci++) {
|
|
288
|
+
if (signature[ci] === "(")
|
|
289
|
+
depth++;
|
|
290
|
+
else if (signature[ci] === ")") {
|
|
291
|
+
depth--;
|
|
292
|
+
if (depth === 0) {
|
|
293
|
+
sigAfterReceiver = signature.slice(ci + 1);
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
const openParen = sigAfterReceiver.indexOf("(");
|
|
300
|
+
let closeParen = -1;
|
|
301
|
+
if (openParen >= 0) {
|
|
302
|
+
// 平衡括号匹配(参数可含 func 类型嵌套括号)
|
|
303
|
+
let depth = 0;
|
|
304
|
+
for (let ci = openParen; ci < sigAfterReceiver.length; ci++) {
|
|
305
|
+
if (sigAfterReceiver[ci] === "(")
|
|
306
|
+
depth++;
|
|
307
|
+
else if (sigAfterReceiver[ci] === ")") {
|
|
308
|
+
depth--;
|
|
309
|
+
if (depth === 0) {
|
|
310
|
+
closeParen = ci;
|
|
311
|
+
break;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
280
316
|
let params = [];
|
|
281
317
|
if (openParen >= 0 && closeParen > openParen) {
|
|
282
|
-
params = splitTopLevelParams(
|
|
318
|
+
params = splitTopLevelParams(sigAfterReceiver.slice(openParen + 1, closeParen));
|
|
283
319
|
}
|
|
284
320
|
// 返回类型:签名尾部(剥除泛型括号)
|
|
285
|
-
const returnType =
|
|
321
|
+
const returnType = sigAfterReceiver.slice(closeParen + 1).replace(/\[[^\]]*\]/g, "").trim();
|
|
286
322
|
// 函数体:从签名行(j)的 { 起逐行扫描到匹配 }(掩码后括号平衡,
|
|
287
323
|
// 增量计数——每行只数一次,避免累积体重复计数)
|
|
288
324
|
let body = "";
|
|
@@ -85,6 +85,23 @@ func (r *Repo) SaveUser(u User) error {
|
|
|
85
85
|
(0, vitest_1.expect)(ir.some((f) => f.name === "SaveUser")).toBe(true);
|
|
86
86
|
(0, vitest_1.expect)(ir.find((f) => f.name === "SaveUser")?.exported).toBe(true);
|
|
87
87
|
});
|
|
88
|
+
(0, vitest_1.it)("接收者方法 returnType 与参数正确(receiver 括号组不被误取——回归)", () => {
|
|
89
|
+
write("svc.go", `
|
|
90
|
+
package main
|
|
91
|
+
|
|
92
|
+
func (s *Service) Login(ctx Context, user, password string) (Token, error) {
|
|
93
|
+
return Token{}, nil
|
|
94
|
+
}
|
|
95
|
+
`);
|
|
96
|
+
const ir = (0, extract_ir_go_1.extractIRGo)(dir);
|
|
97
|
+
const fn = ir.find((f) => f.name === "Login");
|
|
98
|
+
(0, vitest_1.expect)(fn?.returnType).toBe("(Token, error)");
|
|
99
|
+
// Go 语义:ctx / user / password 是 3 个参数(user 与 password 共享类型)
|
|
100
|
+
(0, vitest_1.expect)(fn?.params).toHaveLength(3);
|
|
101
|
+
(0, vitest_1.expect)(fn?.params[0].type).toContain("ctx");
|
|
102
|
+
(0, vitest_1.expect)(fn?.params[1].type).toContain("user");
|
|
103
|
+
(0, vitest_1.expect)(fn?.params[2].type).toContain("string");
|
|
104
|
+
});
|
|
88
105
|
(0, vitest_1.it)("多行签名 + 返回类型", () => {
|
|
89
106
|
write("multi.go", `
|
|
90
107
|
package main
|
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.14";
|
|
24
24
|
function verify(filePath) {
|
|
25
25
|
const cert = (0, certify_1.certify)(filePath);
|
|
26
26
|
const kb = (0, protocol_knowledge_1.buildKnowledgeBase)();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "progmune-runtime",
|
|
3
|
-
"version": "3.7.
|
|
3
|
+
"version": "3.7.14",
|
|
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/",
|