@actiondock/core 2.5.1 → 2.7.0
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/dist/app/app.d.ts +14 -1
- package/dist/app/app.js +88 -222
- package/dist/app/static-index.d.ts +39 -0
- package/dist/app/static-index.js +164 -0
- package/dist/app/types.d.ts +5 -0
- package/dist/catalog/action-index.js +6 -4
- package/dist/catalog/package-catalog.js +2 -1
- package/dist/doctor/checks/index.d.ts +5 -0
- package/dist/doctor/checks/index.js +5 -0
- package/dist/doctor/checks/project-locate.d.ts +6 -0
- package/dist/doctor/checks/project-locate.js +36 -0
- package/dist/doctor/checks/project.d.ts +6 -0
- package/dist/doctor/checks/project.js +383 -0
- package/dist/doctor/checks/registry.d.ts +13 -0
- package/dist/doctor/checks/registry.js +207 -0
- package/dist/doctor/checks/runtime.d.ts +13 -0
- package/dist/doctor/checks/runtime.js +90 -0
- package/dist/doctor/checks/storage.d.ts +5 -0
- package/dist/doctor/checks/storage.js +34 -0
- package/dist/doctor/context.d.ts +35 -0
- package/dist/doctor/context.js +11 -0
- package/dist/doctor/doctor.d.ts +5 -0
- package/dist/doctor/doctor.js +33 -602
- package/dist/errors.d.ts +22 -0
- package/dist/errors.js +22 -0
- package/dist/execution/service.js +14 -9
- package/dist/export/templates.js +42 -30
- package/dist/host/host.d.ts +33 -0
- package/dist/host/host.js +222 -362
- package/dist/host/routing.d.ts +92 -0
- package/dist/host/routing.js +238 -0
- package/dist/host/types.d.ts +8 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/dist/input/advice.d.ts +100 -0
- package/dist/input/advice.js +767 -0
- package/dist/input/describe.d.ts +106 -0
- package/dist/input/describe.js +176 -0
- package/dist/input/file-input.d.ts +54 -0
- package/dist/input/file-input.js +124 -0
- package/dist/input/flat-decode.d.ts +11 -0
- package/dist/input/flat-decode.js +13 -0
- package/dist/input/flat-errors.d.ts +72 -0
- package/dist/input/flat-errors.js +87 -0
- package/dist/input/flat-materializer.d.ts +29 -0
- package/dist/input/flat-materializer.js +179 -0
- package/dist/input/flat-parser.d.ts +50 -0
- package/dist/input/flat-parser.js +169 -0
- package/dist/input/flat-predicates.d.ts +34 -0
- package/dist/input/flat-predicates.js +50 -0
- package/dist/input/index.d.ts +14 -0
- package/dist/input/index.js +14 -0
- package/dist/input/input-resolver.d.ts +63 -0
- package/dist/input/input-resolver.js +254 -0
- package/dist/input/json-depth-scanner.d.ts +17 -0
- package/dist/input/json-depth-scanner.js +49 -0
- package/dist/input/metadata.d.ts +99 -0
- package/dist/input/metadata.js +99 -0
- package/dist/input/stdin-input.d.ts +26 -0
- package/dist/input/stdin-input.js +125 -0
- package/dist/input/utf8.d.ts +19 -0
- package/dist/input/utf8.js +36 -0
- package/dist/input/validation-mapper.d.ts +27 -0
- package/dist/input/validation-mapper.js +144 -0
- package/dist/ipc/host.js +38 -0
- package/dist/json/index.d.ts +1 -0
- package/dist/json/index.js +1 -0
- package/dist/json/value-validator.d.ts +88 -0
- package/dist/json/value-validator.js +330 -0
- package/dist/platform/types.d.ts +7 -0
- package/dist/process/control-arbiter.d.ts +107 -0
- package/dist/process/control-arbiter.js +251 -0
- package/dist/process/diagnostics-sink.d.ts +26 -0
- package/dist/process/diagnostics-sink.js +35 -0
- package/dist/process/index.d.ts +7 -0
- package/dist/process/index.js +7 -0
- package/dist/process/input-dispatcher.d.ts +88 -0
- package/dist/process/input-dispatcher.js +240 -0
- package/dist/process/managed-record.d.ts +78 -0
- package/dist/process/managed-record.js +1 -0
- package/dist/process/process-manager.d.ts +15 -56
- package/dist/process/process-manager.js +119 -707
- package/dist/process/reservation-table.d.ts +39 -0
- package/dist/process/reservation-table.js +80 -0
- package/dist/process/run-executor.d.ts +16 -0
- package/dist/process/run-executor.js +155 -0
- package/dist/process/terminal-output-cache.d.ts +66 -0
- package/dist/process/terminal-output-cache.js +132 -0
- package/dist/profile/client-actions.d.ts +56 -0
- package/dist/profile/client-actions.js +215 -0
- package/dist/profile/client-config.d.ts +20 -0
- package/dist/profile/client-config.js +51 -0
- package/dist/profile/client-health.d.ts +14 -0
- package/dist/profile/client-health.js +69 -0
- package/dist/profile/client-playbooks.d.ts +19 -0
- package/dist/profile/client-playbooks.js +36 -0
- package/dist/profile/client-query.d.ts +30 -0
- package/dist/profile/client-query.js +70 -0
- package/dist/profile/client-runs.d.ts +42 -0
- package/dist/profile/client-runs.js +58 -0
- package/dist/profile/client-state.d.ts +56 -0
- package/dist/profile/client-state.js +83 -0
- package/dist/profile/client-transport.d.ts +61 -0
- package/dist/profile/client-transport.js +156 -0
- package/dist/profile/client.d.ts +23 -142
- package/dist/profile/client.js +28 -588
- package/dist/profile/manager.js +1 -1
- package/dist/project/closure.d.ts +4 -4
- package/dist/project/closure.js +11 -5
- package/dist/project/init.js +2 -2
- package/dist/project/loader.d.ts +0 -25
- package/dist/project/loader.js +1 -154
- package/dist/project/transactions.d.ts +12 -14
- package/dist/project/transactions.js +60 -836
- package/dist/registry/registry.js +6 -4
- package/dist/registry/resolve.js +1 -1
- package/dist/runtime/action-registry.d.ts +45 -0
- package/dist/runtime/action-registry.js +108 -0
- package/dist/runtime/clock.d.ts +5 -17
- package/dist/runtime/clock.js +5 -15
- package/dist/runtime/context.d.ts +3 -0
- package/dist/runtime/context.js +17 -56
- package/dist/runtime/index.d.ts +3 -0
- package/dist/runtime/index.js +3 -0
- package/dist/runtime/package-runner-factory.d.ts +82 -0
- package/dist/runtime/package-runner-factory.js +186 -0
- package/dist/runtime/run-persistence.d.ts +85 -0
- package/dist/runtime/run-persistence.js +111 -0
- package/dist/runtime/runner.d.ts +25 -45
- package/dist/runtime/runner.js +130 -354
- package/dist/runtime/standalone.d.ts +25 -2
- package/dist/runtime/standalone.js +305 -87
- package/dist/schema/index.d.ts +1 -0
- package/dist/schema/index.js +1 -0
- package/dist/schema/validator.d.ts +10 -0
- package/dist/schema/validator.js +48 -54
- package/dist/server/dispatcher.d.ts +8 -3
- package/dist/server/dispatcher.js +16 -40
- package/dist/server/routes/runs.js +6 -4
- package/dist/server/security.d.ts +1 -7
- package/dist/server/security.js +2 -13
- package/dist/storage/clock.d.ts +25 -0
- package/dist/storage/clock.js +23 -0
- package/dist/storage/data-dir-lock.d.ts +3 -36
- package/dist/storage/data-dir-lock.js +48 -881
- package/dist/storage/index.d.ts +8 -1
- package/dist/storage/index.js +8 -2
- package/dist/storage/lazy.js +1 -0
- package/dist/storage/lock-core.d.ts +162 -0
- package/dist/storage/lock-core.js +885 -0
- package/dist/storage/sqlite.d.ts +19 -6
- package/dist/storage/sqlite.js +81 -89
- package/dist/storage/types.d.ts +27 -5
- package/dist/storage/types.js +21 -0
- package/dist/storage/utils.d.ts +22 -0
- package/dist/storage/utils.js +34 -0
- package/dist/target/local.d.ts +1 -0
- package/dist/target/local.js +23 -17
- package/dist/target/remote-errors.d.ts +21 -0
- package/dist/target/remote-errors.js +51 -0
- package/dist/target/remote-polling.d.ts +35 -0
- package/dist/target/remote-polling.js +104 -0
- package/dist/target/remote.d.ts +4 -0
- package/dist/target/remote.js +108 -301
- package/dist/target/sse-parser.d.ts +35 -0
- package/dist/target/sse-parser.js +163 -0
- package/dist/target/target.js +2 -0
- package/dist/target/types.d.ts +6 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/net.d.ts +10 -0
- package/dist/utils/net.js +16 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
package/dist/schema/validator.js
CHANGED
|
@@ -18,75 +18,36 @@ const validatorCache = new WeakMap();
|
|
|
18
18
|
/**
|
|
19
19
|
* 递归检查数据中是否包含危险的原型污染属性键名(__proto__、constructor、prototype)。
|
|
20
20
|
*/
|
|
21
|
+
import { validateActionInputValue } from "../json/value-validator.js";
|
|
22
|
+
/**
|
|
23
|
+
* 递归检查数据中是否包含危险的原型污染属性键名(__proto__、constructor、prototype)。
|
|
24
|
+
* 内部委托 validateActionInputValue 执行迭代遍历,确保环路安全、有向无环图安全且无调用栈溢出风险。
|
|
25
|
+
*/
|
|
21
26
|
export function hasDangerousKeys(data) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
if (Array.isArray(data)) {
|
|
26
|
-
for (const item of data) {
|
|
27
|
-
if (hasDangerousKeys(item))
|
|
28
|
-
return true;
|
|
29
|
-
}
|
|
30
|
-
return false;
|
|
31
|
-
}
|
|
32
|
-
const obj = data;
|
|
33
|
-
const keys = Object.getOwnPropertyNames(obj);
|
|
34
|
-
for (const key of keys) {
|
|
35
|
-
if (key === "__proto__" || key === "constructor" || key === "prototype") {
|
|
36
|
-
return true;
|
|
37
|
-
}
|
|
38
|
-
if (hasDangerousKeys(obj[key])) {
|
|
39
|
-
return true;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
return false;
|
|
27
|
+
const result = validateActionInputValue(data);
|
|
28
|
+
return !result.valid && result.kind === "input-policy";
|
|
43
29
|
}
|
|
44
30
|
/**
|
|
45
|
-
*
|
|
31
|
+
* 内部纯 Schema 校验器。
|
|
32
|
+
* 仅处理布尔 Schema 与 Ajv 规则校验,严禁执行 dangerous-key 遍历。
|
|
46
33
|
*
|
|
47
|
-
*
|
|
48
|
-
* 1. 严格契约校验:当 Schema 中定义 additionalProperties: false 时,包含未声明属性的输入将被直接拒绝(返回 valid: false),系统不会静默过滤或篡改用户输入。
|
|
49
|
-
* 2. 危险原型键硬拦截:输入数据或其任意嵌套对象中若出现 __proto__、constructor 或 prototype 键名,即使 Schema 允许亦立即拒绝,彻底杜绝原型污染。
|
|
50
|
-
* 3. 布尔 Schema:false 显式拒绝所有输入;true 或未定义时允许所有合法非污染数据。
|
|
51
|
-
* 4. 无原型对象支持:完全支持 Object.create(null) 创建的无原型对象校验。
|
|
52
|
-
*
|
|
53
|
-
* @param schema 期望匹配的 JSON Schema 对象(未提供或为空对象/true 时默认通过;为 false 时拒绝所有数据)
|
|
34
|
+
* @param schema 期望匹配的 JSON Schema 对象
|
|
54
35
|
* @param data 待校验的原始数据
|
|
55
36
|
* @returns 包含 valid 状态与错误信息列表的 ValidationResult
|
|
56
37
|
*/
|
|
57
|
-
export function
|
|
58
|
-
// 1. 布尔 Schema 支持:false 拒绝一切输入;true/undefined 允许一切输入
|
|
38
|
+
export function validateSchemaOnly(schema, data) {
|
|
59
39
|
if (schema === false) {
|
|
60
40
|
return {
|
|
61
41
|
valid: false,
|
|
62
42
|
errors: ["Schema is false, rejecting all data"],
|
|
63
43
|
};
|
|
64
44
|
}
|
|
65
|
-
if (schema === true ||
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
errors: ["Data contains prohibited prototype pollution keys (__proto__, constructor, or prototype)"],
|
|
70
|
-
};
|
|
71
|
-
}
|
|
45
|
+
if (schema === true ||
|
|
46
|
+
!schema ||
|
|
47
|
+
typeof schema !== "object" ||
|
|
48
|
+
Object.keys(schema).length === 0) {
|
|
72
49
|
return { valid: true };
|
|
73
50
|
}
|
|
74
|
-
if (typeof schema !== "object" || Object.keys(schema).length === 0) {
|
|
75
|
-
if (hasDangerousKeys(data)) {
|
|
76
|
-
return {
|
|
77
|
-
valid: false,
|
|
78
|
-
errors: ["Data contains prohibited prototype pollution keys (__proto__, constructor, or prototype)"],
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
return { valid: true };
|
|
82
|
-
}
|
|
83
|
-
// 2. 危险原型键拦截
|
|
84
|
-
if (hasDangerousKeys(data)) {
|
|
85
|
-
return {
|
|
86
|
-
valid: false,
|
|
87
|
-
errors: ["Data contains prohibited prototype pollution keys (__proto__, constructor, or prototype)"],
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
51
|
try {
|
|
91
52
|
let validate = validatorCache.get(schema);
|
|
92
53
|
if (!validate) {
|
|
@@ -120,3 +81,36 @@ export function validateSchema(schema, data) {
|
|
|
120
81
|
};
|
|
121
82
|
}
|
|
122
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* 校验指定数据是否符合给定的 JSON Schema 契约。
|
|
86
|
+
*
|
|
87
|
+
* 行为与策略约定:
|
|
88
|
+
* 1. 严格契约校验:当 Schema 中定义 additionalProperties: false 时,包含未声明属性的输入将被直接拒绝(返回 valid: false),系统不会静默过滤或篡改用户输入。
|
|
89
|
+
* 2. 危险原型键硬拦截:输入数据或其任意嵌套对象中若出现 __proto__、constructor 或 prototype 键名,即使 Schema 允许亦立即拒绝,彻底杜绝原型污染。
|
|
90
|
+
* 3. 布尔 Schema:false 显式拒绝所有输入;true 或未定义时允许所有合法非污染数据。
|
|
91
|
+
* 4. 无原型对象支持:完全支持 Object.create(null) 创建的无原型对象校验。
|
|
92
|
+
*
|
|
93
|
+
* @param schema 期望匹配的 JSON Schema 对象(未提供或为空对象/true 时默认通过;为 false 时拒绝所有数据)
|
|
94
|
+
* @param data 待校验的原始数据
|
|
95
|
+
* @returns 包含 valid 状态与错误信息列表的 ValidationResult
|
|
96
|
+
*/
|
|
97
|
+
export function validateSchema(schema, data) {
|
|
98
|
+
// 1. 布尔 Schema 支持:false 拒绝一切输入
|
|
99
|
+
if (schema === false) {
|
|
100
|
+
return {
|
|
101
|
+
valid: false,
|
|
102
|
+
errors: ["Schema is false, rejecting all data"],
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
// 2. 危险原型键拦截(保持历史兼容,包含 schema 为 true / undefined / {} 的场景)
|
|
106
|
+
if (hasDangerousKeys(data)) {
|
|
107
|
+
return {
|
|
108
|
+
valid: false,
|
|
109
|
+
errors: [
|
|
110
|
+
"Data contains prohibited prototype pollution keys (__proto__, constructor, or prototype)",
|
|
111
|
+
],
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
// 3. 委托纯 Schema 校验器处理其余规则校验
|
|
115
|
+
return validateSchemaOnly(schema, data);
|
|
116
|
+
}
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
export type FetchDispatcherProvider = () => unknown;
|
|
5
5
|
/**
|
|
6
6
|
* 注册全局用于忽略服务端证书校验的调度器提供者。
|
|
7
|
+
* 唯一注册通道:平台适配层(如 @actiondock/runtime-node 的
|
|
8
|
+
* installInsecureDispatcher)显式调用完成注册,不再读取全局符号注入。
|
|
7
9
|
*/
|
|
8
10
|
export declare function setInsecureDispatcherProvider(provider?: FetchDispatcherProvider): void;
|
|
9
11
|
/**
|
|
@@ -13,12 +15,15 @@ export declare function getInsecureDispatcherProvider(): FetchDispatcherProvider
|
|
|
13
15
|
/**
|
|
14
16
|
* 获取用于忽略服务端证书校验的调度器实例。
|
|
15
17
|
* 纯粹解耦设计:
|
|
16
|
-
* 1. 优先调用显式注册的提供者(如由 @actiondock/runtime-node
|
|
17
|
-
* 2.
|
|
18
|
-
*
|
|
18
|
+
* 1. 优先调用显式注册的提供者(如由 @actiondock/runtime-node 显式安装);
|
|
19
|
+
* 2. 若在 Node 环境下且无注册提供者,动态加载 @actiondock/runtime-node
|
|
20
|
+
* (其入口聚合点会显式完成安装),绝不让 core 包产生静态硬编译依赖;
|
|
21
|
+
* 3. 仍不可得时返回 undefined,由调用方回退默认 fetch,绝不在 core 内
|
|
22
|
+
* 直接探测加载 undici,避免与平台适配层形成层次倒置与隐藏依赖环。
|
|
19
23
|
*/
|
|
20
24
|
export declare function getInsecureDispatcher(): unknown;
|
|
21
25
|
/**
|
|
22
26
|
* 显式强制重置并销毁调度器连接池(仅用于单元测试重置或进程退出)。
|
|
27
|
+
* core 自身不再持有任何兜底连接池,关闭语义完全委托已注册的平台提供者宿主。
|
|
23
28
|
*/
|
|
24
29
|
export declare function closeInsecureDispatcher(): Promise<void>;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
let insecureDispatcherProvider;
|
|
3
|
-
let fallbackInsecureAgent;
|
|
4
3
|
/**
|
|
5
4
|
* 注册全局用于忽略服务端证书校验的调度器提供者。
|
|
5
|
+
* 唯一注册通道:平台适配层(如 @actiondock/runtime-node 的
|
|
6
|
+
* installInsecureDispatcher)显式调用完成注册,不再读取全局符号注入。
|
|
6
7
|
*/
|
|
7
8
|
export function setInsecureDispatcherProvider(provider) {
|
|
8
9
|
insecureDispatcherProvider = provider;
|
|
@@ -16,18 +17,16 @@ export function getInsecureDispatcherProvider() {
|
|
|
16
17
|
/**
|
|
17
18
|
* 获取用于忽略服务端证书校验的调度器实例。
|
|
18
19
|
* 纯粹解耦设计:
|
|
19
|
-
* 1. 优先调用显式注册的提供者(如由 @actiondock/runtime-node
|
|
20
|
-
* 2.
|
|
21
|
-
*
|
|
20
|
+
* 1. 优先调用显式注册的提供者(如由 @actiondock/runtime-node 显式安装);
|
|
21
|
+
* 2. 若在 Node 环境下且无注册提供者,动态加载 @actiondock/runtime-node
|
|
22
|
+
* (其入口聚合点会显式完成安装),绝不让 core 包产生静态硬编译依赖;
|
|
23
|
+
* 3. 仍不可得时返回 undefined,由调用方回退默认 fetch,绝不在 core 内
|
|
24
|
+
* 直接探测加载 undici,避免与平台适配层形成层次倒置与隐藏依赖环。
|
|
22
25
|
*/
|
|
23
26
|
export function getInsecureDispatcher() {
|
|
24
27
|
if (insecureDispatcherProvider) {
|
|
25
28
|
return insecureDispatcherProvider();
|
|
26
29
|
}
|
|
27
|
-
const globalProvider = globalThis[Symbol.for("actiondock.insecureDispatcherProvider")];
|
|
28
|
-
if (typeof globalProvider === "function") {
|
|
29
|
-
return globalProvider();
|
|
30
|
-
}
|
|
31
30
|
if (typeof process !== "undefined" && process.versions?.node) {
|
|
32
31
|
try {
|
|
33
32
|
const req = createRequire(import.meta.url);
|
|
@@ -39,48 +38,25 @@ export function getInsecureDispatcher() {
|
|
|
39
38
|
catch {
|
|
40
39
|
// 忽略未安装 @actiondock/runtime-node 的情况
|
|
41
40
|
}
|
|
42
|
-
if (!fallbackInsecureAgent || fallbackInsecureAgent.closed || fallbackInsecureAgent.destroyed) {
|
|
43
|
-
try {
|
|
44
|
-
const req = createRequire(import.meta.url);
|
|
45
|
-
const undici = req("undici");
|
|
46
|
-
if (undici?.Agent) {
|
|
47
|
-
fallbackInsecureAgent = new undici.Agent({
|
|
48
|
-
connect: {
|
|
49
|
-
rejectUnauthorized: false,
|
|
50
|
-
},
|
|
51
|
-
bodyTimeout: 0,
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
catch {
|
|
56
|
-
// 忽略非 Node 环境或未安装 undici 的异常
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return fallbackInsecureAgent;
|
|
60
41
|
}
|
|
61
42
|
return undefined;
|
|
62
43
|
}
|
|
63
44
|
/**
|
|
64
45
|
* 显式强制重置并销毁调度器连接池(仅用于单元测试重置或进程退出)。
|
|
46
|
+
* core 自身不再持有任何兜底连接池,关闭语义完全委托已注册的平台提供者宿主。
|
|
65
47
|
*/
|
|
66
48
|
export async function closeInsecureDispatcher() {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
try {
|
|
70
|
-
await globalClose();
|
|
71
|
-
}
|
|
72
|
-
catch {
|
|
73
|
-
// 忽略关闭异常
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
if (fallbackInsecureAgent) {
|
|
77
|
-
const agent = fallbackInsecureAgent;
|
|
78
|
-
fallbackInsecureAgent = undefined;
|
|
49
|
+
if (insecureDispatcherProvider) {
|
|
50
|
+
// 提供者由平台层注册:优先委托提供者宿主的关闭语义(如可用)
|
|
79
51
|
try {
|
|
80
|
-
|
|
52
|
+
const req = createRequire(import.meta.url);
|
|
53
|
+
const runtimeNode = req("@actiondock/runtime-node");
|
|
54
|
+
if (typeof runtimeNode?.closeInsecureDispatcher === "function") {
|
|
55
|
+
await runtimeNode.closeInsecureDispatcher();
|
|
56
|
+
}
|
|
81
57
|
}
|
|
82
58
|
catch {
|
|
83
|
-
//
|
|
59
|
+
// 忽略未安装 @actiondock/runtime-node 的情况
|
|
84
60
|
}
|
|
85
61
|
}
|
|
86
62
|
}
|
|
@@ -49,12 +49,11 @@ export async function handleRunsRoutes(ctx) {
|
|
|
49
49
|
}
|
|
50
50
|
if (app.storage && typeof app.storage.listRuns === "function") {
|
|
51
51
|
try {
|
|
52
|
-
|
|
52
|
+
// 状态过滤下推到存储层 SQL,避免先分页后过滤导致某包前 N 条非目标状态时贡献 0 条
|
|
53
|
+
const records = app.storage.listRuns({ actionId, status, limit });
|
|
53
54
|
for (const r of records) {
|
|
54
55
|
if (!seenRunIds.has(r.id)) {
|
|
55
56
|
seenRunIds.add(r.id);
|
|
56
|
-
if (status && r.status !== status)
|
|
57
|
-
continue;
|
|
58
57
|
if (options.packageAllowlist &&
|
|
59
58
|
options.packageAllowlist.length > 0 &&
|
|
60
59
|
r.packageId &&
|
|
@@ -65,7 +64,10 @@ export async function handleRunsRoutes(ctx) {
|
|
|
65
64
|
}
|
|
66
65
|
}
|
|
67
66
|
}
|
|
68
|
-
catch {
|
|
67
|
+
catch (err) {
|
|
68
|
+
// 单包查询失败不阻断整体列表响应,但必须可观测
|
|
69
|
+
console.warn(`[actiondock] listRuns failed for package '${app.packageId}': ${err instanceof Error ? err.message : String(err)}`);
|
|
70
|
+
}
|
|
69
71
|
}
|
|
70
72
|
}
|
|
71
73
|
allRuns.sort((a, b) => (b.startedAt || "").localeCompare(a.startedAt || ""));
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { isLoopbackHost } from "../utils/net.js";
|
|
1
2
|
/**
|
|
2
3
|
* 恒定时间字符串比较(Constant-time comparison)。
|
|
3
4
|
* 使用底层的 `crypto.timingSafeEqual` 防范时序攻击(Timing Attack)。
|
|
@@ -7,13 +8,6 @@
|
|
|
7
8
|
* @returns 两个字符串内容是否完全一致
|
|
8
9
|
*/
|
|
9
10
|
export declare function safeEqual(a: string, b: string): boolean;
|
|
10
|
-
/**
|
|
11
|
-
* 检查指定的主机地址是否为本地回环接口(Loopback Host)。
|
|
12
|
-
* 支持 127.0.0.1, localhost, ::1 等形式。
|
|
13
|
-
*
|
|
14
|
-
* @param host 主机名或 IP 字符串
|
|
15
|
-
*/
|
|
16
|
-
export declare function isLoopbackHost(host: string): boolean;
|
|
17
11
|
/**
|
|
18
12
|
* 校验 HTTP 请求中的鉴权令牌选项。
|
|
19
13
|
*/
|
package/dist/server/security.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { timingSafeEqual } from "node:crypto";
|
|
2
|
+
// isLoopbackHost 已上移至 utils/net.ts(通用谓词单一事实源),此处仅保留 re-export 兼容旧引用路径
|
|
3
|
+
export { isLoopbackHost } from "../utils/net.js";
|
|
2
4
|
/**
|
|
3
5
|
* 恒定时间字符串比较(Constant-time comparison)。
|
|
4
6
|
* 使用底层的 `crypto.timingSafeEqual` 防范时序攻击(Timing Attack)。
|
|
@@ -15,19 +17,6 @@ export function safeEqual(a, b) {
|
|
|
15
17
|
}
|
|
16
18
|
return timingSafeEqual(aa, bb);
|
|
17
19
|
}
|
|
18
|
-
/**
|
|
19
|
-
* 检查指定的主机地址是否为本地回环接口(Loopback Host)。
|
|
20
|
-
* 支持 127.0.0.1, localhost, ::1 等形式。
|
|
21
|
-
*
|
|
22
|
-
* @param host 主机名或 IP 字符串
|
|
23
|
-
*/
|
|
24
|
-
export function isLoopbackHost(host) {
|
|
25
|
-
const trimmed = host.trim().toLowerCase().replace(/^\[|\]$/g, "");
|
|
26
|
-
return (trimmed === "127.0.0.1" ||
|
|
27
|
-
trimmed === "::1" ||
|
|
28
|
-
trimmed === "localhost" ||
|
|
29
|
-
trimmed === "0:0:0:0:0:0:0:1");
|
|
30
|
-
}
|
|
31
20
|
/**
|
|
32
21
|
* 校验 HTTP 请求中的鉴权令牌是否有效。
|
|
33
22
|
*
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 统一时间与时钟基础契约。
|
|
3
|
+
*
|
|
4
|
+
* 单一事实源:Clock 接口与 SystemClock 实现定义于此,runtime/clock.ts 与
|
|
5
|
+
* storage/types.ts 一律从本文件引用或转发,禁止重复实现。
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* 统一时间与时钟接口。
|
|
9
|
+
*/
|
|
10
|
+
export interface Clock {
|
|
11
|
+
/** 获取当前系统墙上时间 */
|
|
12
|
+
now(): Date;
|
|
13
|
+
/** 获取单调递增时间戳(单位:毫秒) */
|
|
14
|
+
monotonic(): number;
|
|
15
|
+
/** 异步休眠指定毫秒 */
|
|
16
|
+
sleep(ms: number): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* 生产环境系统时钟实现。
|
|
20
|
+
*/
|
|
21
|
+
export declare class SystemClock implements Clock {
|
|
22
|
+
now(): Date;
|
|
23
|
+
monotonic(): number;
|
|
24
|
+
sleep(ms: number): Promise<void>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 统一时间与时钟基础契约。
|
|
3
|
+
*
|
|
4
|
+
* 单一事实源:Clock 接口与 SystemClock 实现定义于此,runtime/clock.ts 与
|
|
5
|
+
* storage/types.ts 一律从本文件引用或转发,禁止重复实现。
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* 生产环境系统时钟实现。
|
|
9
|
+
*/
|
|
10
|
+
export class SystemClock {
|
|
11
|
+
now() {
|
|
12
|
+
return new Date();
|
|
13
|
+
}
|
|
14
|
+
monotonic() {
|
|
15
|
+
if (typeof performance !== "undefined" && typeof performance.now === "function") {
|
|
16
|
+
return performance.now();
|
|
17
|
+
}
|
|
18
|
+
return Date.now();
|
|
19
|
+
}
|
|
20
|
+
sleep(ms) {
|
|
21
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { cleanStaleQuarantines, isProcessAlive, parseQuarantineTimestamp, safeRemoveStaleReclaimGuard, safeRollbackLock } from "./lock-core.js";
|
|
1
2
|
/**
|
|
2
3
|
* 数据目录排他锁元数据契约。
|
|
3
4
|
*/
|
|
@@ -17,41 +18,7 @@ export interface DataDirLockInfo {
|
|
|
17
18
|
/** 宿主会话标识 */
|
|
18
19
|
hostSessionId?: string;
|
|
19
20
|
}
|
|
20
|
-
|
|
21
|
-
* 检查目标进程是否处于存活状态。
|
|
22
|
-
*
|
|
23
|
-
* @param pid 待检测的进程标识符
|
|
24
|
-
*/
|
|
25
|
-
export declare function isProcessAlive(pid: number): boolean;
|
|
26
|
-
/**
|
|
27
|
-
* 安全清理陈旧接管守卫(reclaim guard)。
|
|
28
|
-
* 采用原子重命名检疫并严格核对 guardToken 与持有者存活状态,确保仅删除目标陈旧 guard,严禁误删活跃守卫或并发新守卫。
|
|
29
|
-
*
|
|
30
|
-
* @param reclaimPath 目标守卫路径
|
|
31
|
-
* @param expectedGuardToken 预期持有的守卫令牌(必填,拒绝未指定令牌的盲目清理)
|
|
32
|
-
*/
|
|
33
|
-
export declare function safeRemoveStaleReclaimGuard(reclaimPath: string, expectedGuardToken: string): void;
|
|
34
|
-
/**
|
|
35
|
-
* 从隔离或回滚临时目录名称中解析操作者 PID 与隔离生成时间戳。
|
|
36
|
-
* 命名规范:*.(quarantine|rollback|release).<pid>.<timestamp>.<uuid>
|
|
37
|
-
*/
|
|
38
|
-
export declare function parseQuarantineTimestamp(entryName: string): {
|
|
39
|
-
operatorPid?: number;
|
|
40
|
-
timestamp?: number;
|
|
41
|
-
};
|
|
42
|
-
/**
|
|
43
|
-
* 清理过期的隔离目录(GC 回收机制)。
|
|
44
|
-
* 实施分流存活校验,防止误删活跃持锁者与回滚中目录,同时防止孤儿目录无限泄漏:
|
|
45
|
-
* - 共同前置条件:存活年龄必须超过 maxAgeMs(默认 10000ms),未超期前严禁清理(保持宽限期)。
|
|
46
|
-
* - 活跃隔离目录(quarantine / rollback / release):若 operatorPid 存活或内部 metadata.json 记录的 pid 与 childPids 存活,跳过不予清理。
|
|
47
|
-
* - 孤儿脱离目录(orphan):内部旧 metadata.pid 不再作为续命依据;提取其内部 orphanToken,仅当当前规范主路径(主锁目录与 reclaim 目录)依然持有该凭证时保守跳过;规范路径不存在或已变更凭据时直接安全清理。
|
|
48
|
-
*/
|
|
49
|
-
export declare function cleanStaleQuarantines(parentDir: string, basePrefix: string, maxAgeMs?: number, deadline?: number): void;
|
|
50
|
-
/**
|
|
51
|
-
* 安全回滚当前进程创建的主锁。
|
|
52
|
-
* 优先核对 lockToken,回退核对 sessionToken,防止误删接管者或并发新锁。
|
|
53
|
-
*/
|
|
54
|
-
export declare function safeRollbackLock(lockPath: string, expectedSessionToken: string, expectedLockToken?: string): void;
|
|
21
|
+
export { isProcessAlive, parseQuarantineTimestamp, cleanStaleQuarantines, safeRemoveStaleReclaimGuard, safeRollbackLock, };
|
|
55
22
|
/**
|
|
56
23
|
* 安全释放主锁。
|
|
57
24
|
* 仅当锁目录中持有当前 lockToken / sessionToken 时才删除,杜绝删除他人新锁。
|
|
@@ -95,7 +62,7 @@ export declare class DataDirLock {
|
|
|
95
62
|
/**
|
|
96
63
|
* 尝试获取指定数据目录的排他锁。
|
|
97
64
|
*
|
|
98
|
-
*
|
|
65
|
+
* 仲裁规则由目录锁内核(lock-core)统一承载:
|
|
99
66
|
* - 引入所有竞争者均遵守的原子 reclaim guard 机制(lockDirPath.reclaim),每个 guard 具备全局唯一 guardToken。
|
|
100
67
|
* - 基于原子目录创建 mkdirSync(lockDirPath, { mode: 0o700 }) 确立所有权,并在其下存放 metadata.json。
|
|
101
68
|
* - 兼容已有常规文件锁(如老版本或测试 mock 场景)。
|