progmune-runtime 3.7.64 → 3.7.65
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
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [3.7.65] — 2026-10-11
|
|
4
|
+
|
|
5
|
+
### 队列/定时/事件处理器无请求面豁免(修冤枉第六刀:授权族告警的「作业处理器不是请求面」根因)
|
|
6
|
+
|
|
7
|
+
**根因**:docmost 补标注里队列作业/定时任务类 FP 占授权族 FP 的
|
|
8
|
+
10/111——鉴权发生在入队侧(controller 把任务塞进队列时已鉴权),
|
|
9
|
+
BullMQ 处理器 / NestJS Schedule / EventEmitter 监听器的函数体
|
|
10
|
+
不面向 HTTP 请求,「缺鉴权/缺属主校验」的提问在处理器层不适用。
|
|
11
|
+
|
|
12
|
+
- **机制**:提取器注入 `__progmune_no_request_surface__` 标记——
|
|
13
|
+
类级 `@Processor(队列名)`(BullMQ,该类全部方法)、方法级
|
|
14
|
+
`@Interval/@Cron/@Timeout/@OnEvent`(须带实参);规则侧仅授权族
|
|
15
|
+
四条(Unauthenticated Access/Mutation + Ownership Check + Resource
|
|
16
|
+
Ownership)在 safeguard 位接受该标记(与 E2 同款「只做减法」)
|
|
17
|
+
- **反例挡住(是请求面,不注入)**:@Sse(HTTP SSE)、
|
|
18
|
+
@SubscribeMessage(WebSocket)、@MessagePattern/@EventPattern
|
|
19
|
+
(微服务 RPC);`@Processor()` 空实参不是 BullMQ 形态不注入
|
|
20
|
+
- **同条件 A/B(docmost 双扫描,fresh IR 各自重提)**:主告警流
|
|
21
|
+
748→720(−28 = Ownership Check 10 + Unauthenticated Access 9 +
|
|
22
|
+
Unauthenticated Mutation 9),**主路径 violations 11=11 内容级零差 /
|
|
23
|
+
score 84=84 / suppressed 117=117**;注入关对照 = 748 与 3.7.64 时代
|
|
24
|
+
基线一致 ⇒ 压降完全归因本刀,非扫描间抖动
|
|
25
|
+
- **可压名单交叉核对**:28 条被压告警逐条列函数/文件,全部命中
|
|
26
|
+
@Processor(FileTask/Notification/History/GeneralQueue ×4 类)或
|
|
27
|
+
@Interval(cleanupSessions/cleanupOldTrash/sendTelemetry)或
|
|
28
|
+
@OnEvent(Page/Space/Workspace Listener)形态,TP 0
|
|
29
|
+
- **回归锁定**:提取器测试 4 例(类级全方法/方法级四种/反例四种/
|
|
30
|
+
空实参边界)+ 规则侧测试 5 例(四族抑制 + 非授权族不受影响);
|
|
31
|
+
TS 盲测 119 项目零漂移(LOST 0/ADDED 0——generated 语料无装饰器
|
|
32
|
+
形状,此门对本改动是空过,真实门=docmost A/B + 定向测试,如实记录)
|
|
33
|
+
- **⚠ 过程教训(TSError 型 toggle)**:上一会话用 `return [];` 做
|
|
34
|
+
A/B 开关——unreachable 代码中 TS 控制流分析不执行收窄,`name`
|
|
35
|
+
保持 `string | undefined` 编译失败,对照扫描 0 字节静默中断两轮。
|
|
36
|
+
toggle 必须用环境变量分支,且对照扫描前必须删 ir.json(IR-STALE
|
|
37
|
+
复用含标记缓存会让「对照」跑在注入开的数据上)
|
|
38
|
+
|
|
3
39
|
## [3.7.64] — 2026-10-10
|
|
4
40
|
|
|
5
41
|
### 守卫沿调用链传播(修冤枉第五刀:授权族告警的「守卫在 controller 层」根因)
|
|
@@ -0,0 +1,142 @@
|
|
|
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
|
+
const vitest_1 = require("vitest");
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const os = __importStar(require("os"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const extract_ir_1 = require("./extract-ir");
|
|
41
|
+
/**
|
|
42
|
+
* 修冤枉第六刀(2026-10-10):队列/定时/事件处理器 → 无请求面标记锁定。
|
|
43
|
+
*
|
|
44
|
+
* 数据:docmost 补标注 111 条授权族 FP 里 10 条是队列作业/定时任务——
|
|
45
|
+
* 鉴权发生在入队侧,处理器函数不面向 HTTP 请求,授权族规则按「请求面
|
|
46
|
+
* 缺鉴权」提问时结论不适用。
|
|
47
|
+
*
|
|
48
|
+
* 注入形态:@Processor(队列名) 类级(BullMQ,全方法);
|
|
49
|
+
* @Interval/@Cron/@Timeout/@OnEvent 方法级(须带实参)。
|
|
50
|
+
* 反例(是请求面,不注入):@Sse / @SubscribeMessage / @MessagePattern。
|
|
51
|
+
*/
|
|
52
|
+
const MARK = "__progmune_no_request_surface__";
|
|
53
|
+
const TSCONFIG = JSON.stringify({
|
|
54
|
+
compilerOptions: { target: "ES2020", module: "commonjs", strict: false, skipLibCheck: true, noEmit: true },
|
|
55
|
+
include: ["**/*.ts"],
|
|
56
|
+
});
|
|
57
|
+
function makeProject(files) {
|
|
58
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "pm-nosurface-"));
|
|
59
|
+
fs.writeFileSync(path.join(dir, "tsconfig.json"), TSCONFIG);
|
|
60
|
+
fs.writeFileSync(path.join(dir, "package.json"), JSON.stringify({ name: "fixture", version: "0.0.0", private: true }));
|
|
61
|
+
for (const [rel, body] of Object.entries(files)) {
|
|
62
|
+
const abs = path.join(dir, rel);
|
|
63
|
+
fs.mkdirSync(path.dirname(abs), { recursive: true });
|
|
64
|
+
fs.writeFileSync(abs, body);
|
|
65
|
+
}
|
|
66
|
+
return dir;
|
|
67
|
+
}
|
|
68
|
+
function callsOf(dir, fnName) {
|
|
69
|
+
const fns = (0, extract_ir_1.extractIR)(dir);
|
|
70
|
+
const f = fns.find((x) => x.name === fnName);
|
|
71
|
+
return f ? (f.calls ?? []) : [];
|
|
72
|
+
}
|
|
73
|
+
(0, vitest_1.describe)("extractIR:无请求面标记(修冤枉第六刀)", () => {
|
|
74
|
+
(0, vitest_1.it)("@Processor(队列名) 类级 ⇒ 全部方法注入", () => {
|
|
75
|
+
const dir = makeProject({
|
|
76
|
+
"a.ts": `
|
|
77
|
+
declare const Processor: any;
|
|
78
|
+
@Processor("notification-queue")
|
|
79
|
+
export class NotificationProcessor {
|
|
80
|
+
process() { this.markAsEmailed(); }
|
|
81
|
+
onCompleted() {}
|
|
82
|
+
}
|
|
83
|
+
`,
|
|
84
|
+
});
|
|
85
|
+
(0, vitest_1.expect)(callsOf(dir, "NotificationProcessor.process")).toContain(MARK);
|
|
86
|
+
(0, vitest_1.expect)(callsOf(dir, "NotificationProcessor.onCompleted")).toContain(MARK);
|
|
87
|
+
});
|
|
88
|
+
(0, vitest_1.it)("@Interval/@Cron/@Timeout/@OnEvent 方法级 ⇒ 仅该方法注入", () => {
|
|
89
|
+
const dir = makeProject({
|
|
90
|
+
"a.ts": `
|
|
91
|
+
declare const Interval: any; declare const Cron: any; declare const Timeout: any; declare const OnEvent: any;
|
|
92
|
+
export class SessionService {
|
|
93
|
+
@Interval("session-cleanup", 86400000)
|
|
94
|
+
cleanupSessions() {}
|
|
95
|
+
@Cron("0 0 * * *")
|
|
96
|
+
dailyJob() {}
|
|
97
|
+
@Timeout(5000)
|
|
98
|
+
delayedJob() {}
|
|
99
|
+
@OnEvent("user.created")
|
|
100
|
+
onUserCreated() {}
|
|
101
|
+
normalMethod() {}
|
|
102
|
+
}
|
|
103
|
+
`,
|
|
104
|
+
});
|
|
105
|
+
for (const fn of ["SessionService.cleanupSessions", "SessionService.dailyJob", "SessionService.delayedJob", "SessionService.onUserCreated"]) {
|
|
106
|
+
(0, vitest_1.expect)(callsOf(dir, fn)).toContain(MARK);
|
|
107
|
+
}
|
|
108
|
+
(0, vitest_1.expect)(callsOf(dir, "SessionService.normalMethod")).not.toContain(MARK);
|
|
109
|
+
});
|
|
110
|
+
(0, vitest_1.it)("反例:@Sse/@SubscribeMessage/@MessagePattern/@EventPattern 是请求面,不注入", () => {
|
|
111
|
+
const dir = makeProject({
|
|
112
|
+
"a.ts": `
|
|
113
|
+
declare const Sse: any; declare const SubscribeMessage: any; declare const MessagePattern: any; declare const EventPattern: any;
|
|
114
|
+
export class Gateway {
|
|
115
|
+
@Sse("events")
|
|
116
|
+
events() {}
|
|
117
|
+
@SubscribeMessage("chat")
|
|
118
|
+
onMessage() {}
|
|
119
|
+
@MessagePattern("orders.get")
|
|
120
|
+
getOrder() {}
|
|
121
|
+
@EventPattern("orders.created")
|
|
122
|
+
onOrderCreated() {}
|
|
123
|
+
}
|
|
124
|
+
`,
|
|
125
|
+
});
|
|
126
|
+
for (const fn of ["Gateway.events", "Gateway.onMessage", "Gateway.getOrder", "Gateway.onOrderCreated"]) {
|
|
127
|
+
(0, vitest_1.expect)(callsOf(dir, fn)).not.toContain(MARK);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
(0, vitest_1.it)("边界:@Processor() 空实参不注入(非 BullMQ 形态)", () => {
|
|
131
|
+
const dir = makeProject({
|
|
132
|
+
"a.ts": `
|
|
133
|
+
declare const Processor: any;
|
|
134
|
+
@Processor()
|
|
135
|
+
export class Odd {
|
|
136
|
+
run() {}
|
|
137
|
+
}
|
|
138
|
+
`,
|
|
139
|
+
});
|
|
140
|
+
(0, vitest_1.expect)(callsOf(dir, "Odd.run")).not.toContain(MARK);
|
|
141
|
+
});
|
|
142
|
+
});
|
package/dist/extract-ir.js
CHANGED
|
@@ -462,6 +462,44 @@ function authMachineryFromDecorators(decorators) {
|
|
|
462
462
|
return auth && !skip ? [AUTH_MACHINERY_MARKER] : [];
|
|
463
463
|
}
|
|
464
464
|
// ═══════════════════════════════════════════════════════════════
|
|
465
|
+
// 修冤枉第六刀(2026-10-10):队列/定时/事件处理器 → 无请求面标记
|
|
466
|
+
//
|
|
467
|
+
// 数据:docmost 补标注 111 条授权族 FP 里 10 条是队列作业/定时任务——
|
|
468
|
+
// 鉴权发生在入队侧(controller 层),处理器函数本身不面向 HTTP 请求,
|
|
469
|
+
// 授权族规则按「请求面缺鉴权」提问时结论不适用。
|
|
470
|
+
// 当前流量化:44 个队列/定时函数命中 19 条授权族告警(全 FP 类)。
|
|
471
|
+
//
|
|
472
|
+
// 形态:@Processor(队列名) 类级(BullMQ,该类全部方法都是作业);
|
|
473
|
+
// @Interval/@Cron/@Timeout 方法级(NestJS Schedule);
|
|
474
|
+
// @OnEvent 方法级(NestJS EventEmitter2)。
|
|
475
|
+
// ⚠ 反例(是请求面,不注入):@Sse(HTTP SSE)、@SubscribeMessage
|
|
476
|
+
// (WebSocket 消息)、@MessagePattern/@EventPattern(微服务 RPC)。
|
|
477
|
+
// ═══════════════════════════════════════════════════════════════
|
|
478
|
+
const NO_REQUEST_SURFACE_MARKER = "__progmune_no_request_surface__";
|
|
479
|
+
/** 队列/定时/事件装饰器 —— 出现即注入无请求面标记(须带实参:@Interval('name', ms) 等) */
|
|
480
|
+
const NO_SURFACE_CLASS_DECORATOR = /^Processor$/i;
|
|
481
|
+
const NO_SURFACE_METHOD_DECORATOR = /^(?:Interval|Cron|Timeout|OnEvent)$/i;
|
|
482
|
+
/**
|
|
483
|
+
* 由类/方法装饰器判定是否注入无请求面标记(与 authMachineryFromDecorators 同款文本匹配)。
|
|
484
|
+
* @returns [] 或 [NO_REQUEST_SURFACE_MARKER]
|
|
485
|
+
*/
|
|
486
|
+
function noRequestSurfaceFromDecorators(decorators) {
|
|
487
|
+
let noSurface = false;
|
|
488
|
+
for (const d of decorators) {
|
|
489
|
+
const text = (d?.getText?.() ?? "").trim();
|
|
490
|
+
const name = /^@([A-Za-z_$][\w$]*)/.exec(text)?.[1];
|
|
491
|
+
if (!name)
|
|
492
|
+
continue;
|
|
493
|
+
if (!NO_SURFACE_CLASS_DECORATOR.test(name) && !NO_SURFACE_METHOD_DECORATOR.test(name))
|
|
494
|
+
continue;
|
|
495
|
+
// 须带实参(@Processor() 空参不是 BullMQ 形态;@Interval 必带名字+毫秒)
|
|
496
|
+
if (!/^@[\w$]*\([^)]+\)/.test(text))
|
|
497
|
+
continue;
|
|
498
|
+
noSurface = true;
|
|
499
|
+
}
|
|
500
|
+
return noSurface ? [NO_REQUEST_SURFACE_MARKER] : [];
|
|
501
|
+
}
|
|
502
|
+
// ═══════════════════════════════════════════════════════════════
|
|
465
503
|
// E3(2026-09-22):TS 侧「入参已按 schema 校验」语义标记
|
|
466
504
|
//
|
|
467
505
|
// 判据(先抄准再写 expect,R22):
|
|
@@ -3256,6 +3294,15 @@ function _extractSingleProject(absRoot, tsconfigPath) {
|
|
|
3256
3294
|
if (!mCalls.includes(mk))
|
|
3257
3295
|
mCalls.push(mk);
|
|
3258
3296
|
}
|
|
3297
|
+
// 修冤枉第六刀:队列/定时/事件处理器 → 无请求面标记(与 E2 并列,
|
|
3298
|
+
// 语义相反——E2 是「有鉴权」,本标记是「鉴权问题不适用」)
|
|
3299
|
+
for (const mk of noRequestSurfaceFromDecorators([
|
|
3300
|
+
...(cls.getDecorators?.() ?? []),
|
|
3301
|
+
...(m.getDecorators?.() ?? []),
|
|
3302
|
+
])) {
|
|
3303
|
+
if (!mCalls.includes(mk))
|
|
3304
|
+
mCalls.push(mk);
|
|
3305
|
+
}
|
|
3259
3306
|
funcs.push({
|
|
3260
3307
|
name: `${cn}.${mn}`,
|
|
3261
3308
|
params: mParams.map((p) => ({ name: p.getName(), type: getParamType(p), typeDetail: getParamTypeDetail(p) })),
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const vitest_1 = require("vitest");
|
|
4
|
+
const protocol_detector_1 = require("./protocol-detector");
|
|
5
|
+
/**
|
|
6
|
+
* 修冤枉第六刀(2026-10-10):无请求面标记的规则侧接受位锁定。
|
|
7
|
+
*
|
|
8
|
+
* 语义:队列/定时/事件处理器不面向 HTTP 请求,鉴权发生在入队侧——
|
|
9
|
+
* 授权族四条的「缺鉴权/缺属主校验」提问在处理器层不适用(N/A 抑制)。
|
|
10
|
+
* 只抑制 authorization 类;其他族规则不受标记影响。
|
|
11
|
+
*/
|
|
12
|
+
const M = "__progmune_no_request_surface__";
|
|
13
|
+
const has = (vs, rule) => vs.some((v) => v.rule === rule);
|
|
14
|
+
(0, vitest_1.describe)("no_request_surface 标记:授权族四条接受、其他族不受影响", () => {
|
|
15
|
+
const calls = ["getWorkspaceUrl", M];
|
|
16
|
+
(0, vitest_1.it)("Unauthenticated Access 被抑制", () => {
|
|
17
|
+
const bare = (0, protocol_detector_1.detectSafeguardViolations)(["getWorkspaceUrl"], "NotificationProcessor.getWorkspaceUrl", "typescript", ["job"], true);
|
|
18
|
+
(0, vitest_1.expect)(has(bare, "Authorization (Unauthenticated Access)")).toBe(true);
|
|
19
|
+
const withMark = (0, protocol_detector_1.detectSafeguardViolations)(calls, "NotificationProcessor.getWorkspaceUrl", "typescript", ["job"], true);
|
|
20
|
+
(0, vitest_1.expect)(has(withMark, "Authorization (Unauthenticated Access)")).toBe(false);
|
|
21
|
+
});
|
|
22
|
+
(0, vitest_1.it)("Unauthenticated Mutation 被抑制", () => {
|
|
23
|
+
const bare = (0, protocol_detector_1.detectSafeguardViolations)(["updateTable"], "HistoryProcessor.process", "typescript", ["job"], true);
|
|
24
|
+
(0, vitest_1.expect)(has(bare, "Authorization (Unauthenticated Mutation)")).toBe(true);
|
|
25
|
+
const withMark = (0, protocol_detector_1.detectSafeguardViolations)(["updateTable", M], "HistoryProcessor.process", "typescript", ["job"], true);
|
|
26
|
+
(0, vitest_1.expect)(has(withMark, "Authorization (Unauthenticated Mutation)")).toBe(false);
|
|
27
|
+
});
|
|
28
|
+
(0, vitest_1.it)("Ownership Check 被抑制(queue job 的属主校验提问不适用)", () => {
|
|
29
|
+
const bare = (0, protocol_detector_1.detectSafeguardViolations)(["deleteSessions"], "SessionService.cleanupSessions", "typescript", ["job"], true);
|
|
30
|
+
(0, vitest_1.expect)(has(bare, "Authorization (Ownership Check)")).toBe(true);
|
|
31
|
+
const withMark = (0, protocol_detector_1.detectSafeguardViolations)(["deleteSessions", M], "SessionService.cleanupSessions", "typescript", ["job"], true);
|
|
32
|
+
(0, vitest_1.expect)(has(withMark, "Authorization (Ownership Check)")).toBe(false);
|
|
33
|
+
});
|
|
34
|
+
(0, vitest_1.it)("Resource Ownership 被抑制", () => {
|
|
35
|
+
const bare = (0, protocol_detector_1.detectSafeguardViolations)(["removeIcon"], "AttachmentProcessor.process", "typescript", ["job"], true);
|
|
36
|
+
(0, vitest_1.expect)(has(bare, "Authorization (Resource Ownership)")).toBe(true);
|
|
37
|
+
const withMark = (0, protocol_detector_1.detectSafeguardViolations)(["removeIcon", M], "AttachmentProcessor.process", "typescript", ["job"], true);
|
|
38
|
+
(0, vitest_1.expect)(has(withMark, "Authorization (Resource Ownership)")).toBe(false);
|
|
39
|
+
});
|
|
40
|
+
(0, vitest_1.it)("非授权族规则不受标记影响(渲染 sink 照报)", () => {
|
|
41
|
+
const vs = (0, protocol_detector_1.detectSafeguardViolations)(["render", M], "EmailProcessor.renderTemplate", "typescript");
|
|
42
|
+
(0, vitest_1.expect)(has(vs, "No Input Sanitization")).toBe(true);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -385,6 +385,9 @@ const SAFEGUARD_RULES = [
|
|
|
385
385
|
safeguards: [
|
|
386
386
|
{ pattern: /\b(checkOwner|isOwner|ownerId\s*[!=]==?|authorId\s*[!=]==?|userId\s*[!=]==?|createdBy\s*[!=]==?|\.owner\s*[!=]==?|\.user\s*[!=]==?)\b/i, label: "ownership_check" },
|
|
387
387
|
{ pattern: /\b(hasPermission|checkPermission|checkAccess|isAuthorized|checkRole|requireRole|adminCheck|isAdmin|canModify|canDelete|canEdit)\b/i, label: "authz_check" },
|
|
388
|
+
// 修冤枉第六刀:队列/定时/事件处理器不面向请求面——鉴权发生在入队侧,
|
|
389
|
+
// 「改资源没查属主」的提问在处理器层不适用(docmost 补标注 FP 类)
|
|
390
|
+
{ pattern: /\b(__progmune_no_request_surface__)\b/, label: "no_request_surface" },
|
|
388
391
|
{ pattern: /\b(__progmune_ownership_checked__)\b/, label: "inline_ownership_check" },
|
|
389
392
|
// §46 ②:资源属主被**赋值为当前主体**(`{ userId: user.id }` / `where:{userId: user.id}`)。
|
|
390
393
|
// 这类函数的被操作对象就是(或已被限定在)主体自己,谈不上「改别人的东西」。
|
|
@@ -428,7 +431,7 @@ const SAFEGUARD_RULES = [
|
|
|
428
431
|
paramTypeSafeguards: [SESSION_BEARING_TYPE_RE],
|
|
429
432
|
trigger: /\b(list|download|view|fetch)(?:[A-Z]\w*|_\w+)|get(?:[A-Z]\w+|_\w+)/i,
|
|
430
433
|
safeguards: [
|
|
431
|
-
{ pattern: /\b(getUser|validateToken|verifyToken|verifySession|validateSession|getSessionUser|getSession\b|getCurrentUser|token\w*(Check|Verify|Valid)|session\w*(Check|Verify|Valid)|auth\w*(Check|Verify|Valid|Guard|Middleware|Required)|requireAuth|withAuth|authenticate\w*(User|Request|Token)?|checkAuth|isAuth|hasAuth|checkAccess|hasAccess|get_user|get_session_user|get_current_user|validate_session|verify_token|require_auth|with_auth|check_auth|auth_required|authenticate_user|authenticate_request|authenticate_token|token_check|token_verify|token_valid|session_check|session_verify|session_valid|auth_check|auth_guard|auth_middleware|get_current_user_authorizer|current_user_authorizer|login_required|permission_required|user_passes_test|check_authorization|check_permission|jwt\.decode|decode_token|__progmune_auth_checked__|__progmune_credential_check__|__progmune_drf_permissions__|__progmune_auth_machinery__)\b/i, label: "auth_check" },
|
|
434
|
+
{ pattern: /\b(getUser|validateToken|verifyToken|verifySession|validateSession|getSessionUser|getSession\b|getCurrentUser|token\w*(Check|Verify|Valid)|session\w*(Check|Verify|Valid)|auth\w*(Check|Verify|Valid|Guard|Middleware|Required)|requireAuth|withAuth|authenticate\w*(User|Request|Token)?|checkAuth|isAuth|hasAuth|checkAccess|hasAccess|get_user|get_session_user|get_current_user|validate_session|verify_token|require_auth|with_auth|check_auth|auth_required|authenticate_user|authenticate_request|authenticate_token|token_check|token_verify|token_valid|session_check|session_verify|session_valid|auth_check|auth_guard|auth_middleware|get_current_user_authorizer|current_user_authorizer|login_required|permission_required|user_passes_test|check_authorization|check_permission|jwt\.decode|decode_token|__progmune_auth_checked__|__progmune_credential_check__|__progmune_drf_permissions__|__progmune_auth_machinery__|__progmune_no_request_surface__)\b/i, label: "auth_check" },
|
|
432
435
|
// §40 C1:裸 can —— verdaccio 的 can('publish') 中间件就是这里的授权判定
|
|
433
436
|
{ pattern: exports.AUTHZ_BARE_CAN_RE, label: "bare_can", callsOnly: true },
|
|
434
437
|
],
|
|
@@ -464,7 +467,7 @@ const SAFEGUARD_RULES = [
|
|
|
464
467
|
// (listPosts/getPost/deletePost fire via identifier-parsed words).
|
|
465
468
|
trigger: /\b(add|create|update|set|publish|insert|submit)(?:[A-Z]\w*|_\w+)|(?:[A-Z]\w*|_\w+)(Add|Create|Update|Set|Publish|Insert|Submit)\b/i,
|
|
466
469
|
safeguards: [
|
|
467
|
-
{ pattern: /\b(getUser|validateToken|verifyToken|verifySession|validateSession|getSessionUser|getSession\b|getCurrentUser|token\w*(Check|Verify|Valid)|session\w*(Check|Verify|Valid)|auth\w*(Check|Verify|Valid|Guard|Middleware|Required)|requireAuth|withAuth|authenticate\w*(User|Request|Token)?|checkAuth|isAuth|hasAuth|checkAccess|hasAccess|get_user|get_session_user|get_current_user|validate_session|verify_token|require_auth|with_auth|check_auth|auth_required|authenticate_user|authenticate_request|authenticate_token|token_check|token_verify|token_valid|session_check|session_verify|session_valid|auth_check|auth_guard|auth_middleware|get_current_user_authorizer|current_user_authorizer|login_required|permission_required|user_passes_test|check_authorization|check_permission|__progmune_auth_checked__|__progmune_credential_check__|__progmune_drf_permissions__|__progmune_auth_machinery__)\b/i, label: "auth_check" },
|
|
470
|
+
{ pattern: /\b(getUser|validateToken|verifyToken|verifySession|validateSession|getSessionUser|getSession\b|getCurrentUser|token\w*(Check|Verify|Valid)|session\w*(Check|Verify|Valid)|auth\w*(Check|Verify|Valid|Guard|Middleware|Required)|requireAuth|withAuth|authenticate\w*(User|Request|Token)?|checkAuth|isAuth|hasAuth|checkAccess|hasAccess|get_user|get_session_user|get_current_user|validate_session|verify_token|require_auth|with_auth|check_auth|auth_required|authenticate_user|authenticate_request|authenticate_token|token_check|token_verify|token_valid|session_check|session_verify|session_valid|auth_check|auth_guard|auth_middleware|get_current_user_authorizer|current_user_authorizer|login_required|permission_required|user_passes_test|check_authorization|check_permission|__progmune_auth_checked__|__progmune_credential_check__|__progmune_drf_permissions__|__progmune_auth_machinery__|__progmune_no_request_surface__)\b/i, label: "auth_check" },
|
|
468
471
|
// §40 C1:裸 can —— 同上
|
|
469
472
|
{ pattern: exports.AUTHZ_BARE_CAN_RE, label: "bare_can", callsOnly: true },
|
|
470
473
|
// §46 ①:凭签发入口豁免 —— 独立 safeguard,**不并入 auth_check**。
|
|
@@ -624,6 +627,8 @@ const SAFEGUARD_RULES = [
|
|
|
624
627
|
safeguards: [
|
|
625
628
|
{ pattern: /\b(ownerId\s*[!=]==?|authorId\s*[!=]==?|userId\s*[!=]==?|createdBy|\.owner\s*[!=]==?)/i, label: "ownership_comparison" },
|
|
626
629
|
{ pattern: /\b(__progmune_ownership_checked__)\b/, label: "inline_ownership_check" },
|
|
630
|
+
// 修冤枉第六刀:同上(无请求面 ⇒ 属主校验提问不适用)
|
|
631
|
+
{ pattern: /\b(__progmune_no_request_surface__)\b/, label: "no_request_surface" },
|
|
627
632
|
// §38:同 Ownership Check,组合式谓语一并接上(这条规则更严,更需要)
|
|
628
633
|
{ pattern: exports.AUTHZ_PREDICATE_RE, label: "casl_predicate" },
|
|
629
634
|
{ pattern: exports.AUTHZ_CAN_HELPER_RE, label: "can_helper" },
|
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.65";
|
|
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.65",
|
|
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/",
|