@actiondock/core 2.7.0 → 2.9.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/README.md +77 -64
- package/dist/catalog/action-catalog.d.ts +56 -0
- package/dist/catalog/action-catalog.js +202 -0
- package/dist/catalog/discovery.d.ts +60 -0
- package/dist/catalog/discovery.js +119 -0
- package/dist/catalog/graph.d.ts +190 -0
- package/dist/catalog/graph.js +589 -0
- package/dist/catalog/index.d.ts +5 -5
- package/dist/catalog/index.js +5 -5
- package/dist/catalog/resolve-action.d.ts +43 -0
- package/dist/catalog/resolve-action.js +119 -0
- package/dist/catalog/resolve-playbook.d.ts +26 -0
- package/dist/catalog/resolve-playbook.js +114 -0
- package/dist/doctor/checks/project.js +27 -8
- package/dist/doctor/checks/registry.js +2 -2
- package/dist/doctor/checks/runtime.js +34 -1
- package/dist/errors.d.ts +106 -10
- package/dist/errors.js +105 -10
- package/dist/execution/service.d.ts +18 -16
- package/dist/execution/service.js +183 -252
- package/dist/execution/types.d.ts +25 -69
- package/dist/execution/types.js +2 -1
- package/dist/filter/intent.d.ts +8 -9
- package/dist/filter/intent.js +49 -10
- package/dist/graph/index.d.ts +4 -0
- package/dist/graph/index.js +4 -0
- package/dist/host/host.d.ts +74 -32
- package/dist/host/host.js +585 -336
- package/dist/host/routing.d.ts +15 -48
- package/dist/host/routing.js +90 -153
- package/dist/host/types.d.ts +50 -17
- package/dist/index.d.ts +21 -24
- package/dist/index.js +19 -23
- package/dist/input/advice.d.ts +5 -1
- package/dist/input/advice.js +163 -214
- package/dist/input/describe.d.ts +1 -1
- package/dist/input/flat-errors.d.ts +5 -6
- package/dist/input/flat-errors.js +6 -6
- package/dist/input/flat-materializer.js +42 -44
- package/dist/invocation/index.d.ts +2 -0
- package/dist/invocation/index.js +2 -0
- package/dist/invocation/policy.d.ts +157 -0
- package/dist/invocation/policy.js +231 -0
- package/dist/invocation/types.d.ts +172 -0
- package/dist/invocation/types.js +97 -0
- package/dist/ipc/diagnostic.d.ts +0 -12
- package/dist/ipc/diagnostic.js +0 -21
- package/dist/ipc/host.d.ts +4 -4
- package/dist/ipc/host.js +44 -47
- package/dist/ipc/index.d.ts +1 -1
- package/dist/ipc/index.js +1 -1
- package/dist/ipc/service.d.ts +40 -0
- package/dist/ipc/service.js +349 -0
- package/dist/ipc/types.d.ts +21 -15
- package/dist/node/index.d.ts +1 -0
- package/dist/node/index.js +1 -0
- package/dist/node/module-loader.d.ts +63 -0
- package/dist/node/module-loader.js +112 -0
- package/dist/package/index.d.ts +23 -0
- package/dist/package/index.js +18 -0
- package/dist/{app/app.d.ts → package/runtime.d.ts} +41 -20
- package/dist/{app/app.js → package/runtime.js} +140 -95
- package/dist/{app → package}/static-index.js +58 -41
- package/dist/package/storage-view.d.ts +13 -0
- package/dist/package/storage-view.js +22 -0
- package/dist/{app → package}/types.d.ts +76 -57
- package/dist/package/types.js +22 -0
- package/dist/platform/index.d.ts +1 -1
- package/dist/platform/index.js +1 -1
- package/dist/platform/node.d.ts +48 -0
- package/dist/platform/node.js +96 -0
- package/dist/platform/types.d.ts +0 -9
- package/dist/process/control-arbiter.d.ts +2 -1
- package/dist/process/control-arbiter.js +1 -2
- package/dist/process/driver.d.ts +9 -8
- package/dist/process/driver.js +11 -22
- package/dist/process/index.d.ts +2 -0
- package/dist/process/index.js +2 -0
- package/dist/process/managed-record.d.ts +2 -2
- package/dist/process/process-driver.d.ts +109 -0
- package/dist/process/process-driver.js +650 -0
- package/dist/process/process-executor.d.ts +47 -0
- package/dist/process/process-executor.js +296 -0
- package/dist/process/process-manager.js +48 -26
- package/dist/process/run-executor.js +12 -12
- package/dist/profile/client-actions.js +2 -2
- package/dist/profile/client-health.js +2 -2
- package/dist/profile/client-query.js +5 -6
- package/dist/profile/client-transport.d.ts +19 -17
- package/dist/profile/client-transport.js +47 -80
- package/dist/profile/client.d.ts +2 -2
- package/dist/profile/client.js +1 -1
- package/dist/profile/index.d.ts +1 -0
- package/dist/profile/index.js +1 -0
- package/dist/profile/manager.d.ts +5 -0
- package/dist/profile/manager.js +41 -6
- package/dist/project/closure.js +2 -2
- package/dist/project/index.d.ts +8 -1
- package/dist/project/index.js +10 -1
- package/dist/project/init.js +2 -2
- package/dist/project/loader.d.ts +1 -1
- package/dist/project/loader.js +26 -29
- package/dist/project/transactions.js +5 -10
- package/dist/project/types.d.ts +5 -0
- package/dist/registry/index.d.ts +3 -1
- package/dist/registry/index.js +2 -1
- package/dist/registry/lock.d.ts +28 -7
- package/dist/registry/lock.js +136 -16
- package/dist/registry/registry.d.ts +1 -5
- package/dist/registry/registry.js +1 -53
- package/dist/registry/scan.d.ts +0 -15
- package/dist/registry/scan.js +0 -59
- package/dist/registry/store.d.ts +42 -0
- package/dist/registry/store.js +43 -0
- package/dist/registry/types.d.ts +0 -24
- package/dist/runtime/action-collection.d.ts +1 -1
- package/dist/runtime/action-registry.d.ts +0 -4
- package/dist/runtime/action-registry.js +0 -7
- package/dist/runtime/context.js +5 -11
- package/dist/runtime/events.js +3 -6
- package/dist/runtime/identity.d.ts +22 -0
- package/dist/runtime/identity.js +10 -0
- package/dist/runtime/index.d.ts +1 -2
- package/dist/runtime/index.js +1 -2
- package/dist/runtime/module-loader.d.ts +2 -34
- package/dist/runtime/module-loader.js +1 -16
- package/dist/runtime/process.d.ts +6 -24
- package/dist/runtime/process.js +1 -118
- package/dist/runtime/run-persistence.js +2 -5
- package/dist/runtime/runner.d.ts +33 -93
- package/dist/runtime/runner.js +132 -364
- package/dist/runtime/standalone.d.ts +23 -8
- package/dist/runtime/standalone.js +100 -147
- package/dist/server/body.d.ts +16 -8
- package/dist/server/body.js +33 -16
- package/dist/server/dispatcher.d.ts +6 -10
- package/dist/server/dispatcher.js +24 -32
- package/dist/server/http-server.d.ts +87 -0
- package/dist/server/http-server.js +304 -0
- package/dist/server/index.d.ts +12 -0
- package/dist/server/index.js +11 -0
- package/dist/server/mcp-endpoint.d.ts +61 -0
- package/dist/server/mcp-endpoint.js +118 -0
- package/dist/server/policy.d.ts +138 -0
- package/dist/server/policy.js +368 -0
- package/dist/server/routes/actions.js +114 -64
- package/dist/server/routes/common.d.ts +18 -33
- package/dist/server/routes/common.js +45 -65
- package/dist/server/routes/config.d.ts +1 -1
- package/dist/server/routes/config.js +55 -65
- package/dist/server/routes/doctor.d.ts +1 -1
- package/dist/server/routes/doctor.js +13 -21
- package/dist/server/routes/health.d.ts +1 -1
- package/dist/server/routes/health.js +4 -5
- package/dist/server/routes/info.d.ts +2 -2
- package/dist/server/routes/info.js +17 -24
- package/dist/server/routes/playbooks.js +23 -36
- package/dist/server/routes/runs.js +151 -141
- package/dist/server/routes/state.d.ts +1 -1
- package/dist/server/routes/state.js +64 -63
- package/dist/server/security.d.ts +11 -0
- package/dist/server/security.js +36 -19
- package/dist/server/server.d.ts +2 -2
- package/dist/server/server.js +224 -238
- package/dist/server/types.d.ts +68 -21
- package/dist/service/factory.d.ts +12 -0
- package/dist/service/factory.js +85 -0
- package/dist/{target → service}/index.d.ts +1 -1
- package/dist/{target → service}/index.js +1 -1
- package/dist/service/local.d.ts +27 -0
- package/dist/service/local.js +138 -0
- package/dist/{target → service}/remote-errors.d.ts +3 -6
- package/dist/service/remote-errors.js +38 -0
- package/dist/{target → service}/remote-polling.d.ts +2 -2
- package/dist/{target → service}/remote-polling.js +8 -8
- package/dist/service/remote.d.ts +34 -0
- package/dist/service/remote.js +634 -0
- package/dist/service/sse-stream.d.ts +24 -0
- package/dist/service/sse-stream.js +139 -0
- package/dist/service/types.d.ts +272 -0
- package/dist/service/types.js +32 -0
- package/dist/storage/data-dir-lock.js +10 -5
- package/dist/storage/driver.d.ts +2 -1
- package/dist/storage/driver.js +3 -52
- package/dist/storage/index.d.ts +1 -0
- package/dist/storage/index.js +1 -0
- package/dist/storage/lock-core.d.ts +2 -6
- package/dist/storage/lock-core.js +4 -17
- package/dist/storage/params.d.ts +2 -8
- package/dist/storage/params.js +2 -8
- package/dist/storage/sqlite-driver.d.ts +40 -0
- package/dist/storage/sqlite-driver.js +116 -0
- package/dist/storage/sqlite.js +21 -6
- package/dist/storage/types.d.ts +4 -4
- package/dist/storage/types.js +2 -2
- package/dist/utils/index.d.ts +53 -0
- package/dist/utils/index.js +99 -4
- package/dist/utils/process.d.ts +10 -0
- package/dist/utils/process.js +21 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +41 -3
- package/dist/app/index.d.ts +0 -2
- package/dist/app/index.js +0 -2
- package/dist/app/types.js +0 -1
- package/dist/catalog/action-index.d.ts +0 -9
- package/dist/catalog/action-index.js +0 -95
- package/dist/catalog/action-resolver.d.ts +0 -20
- package/dist/catalog/action-resolver.js +0 -95
- package/dist/catalog/location-registry.d.ts +0 -15
- package/dist/catalog/location-registry.js +0 -138
- package/dist/catalog/package-catalog.d.ts +0 -7
- package/dist/catalog/package-catalog.js +0 -77
- package/dist/catalog/types.d.ts +0 -68
- package/dist/catalog/types.js +0 -1
- package/dist/export/index.d.ts +0 -1
- package/dist/export/index.js +0 -1
- package/dist/export/templates.d.ts +0 -71
- package/dist/export/templates.js +0 -635
- package/dist/ipc/target.d.ts +0 -74
- package/dist/ipc/target.js +0 -365
- package/dist/platform/default.d.ts +0 -38
- package/dist/platform/default.js +0 -78
- package/dist/project/resolver.d.ts +0 -116
- package/dist/project/resolver.js +0 -376
- package/dist/registry/resolve.d.ts +0 -62
- package/dist/registry/resolve.js +0 -195
- package/dist/runtime/execution-manager.d.ts +0 -48
- package/dist/runtime/execution-manager.js +0 -66
- package/dist/runtime/package-runner-factory.d.ts +0 -82
- package/dist/runtime/package-runner-factory.js +0 -186
- package/dist/target/local.d.ts +0 -53
- package/dist/target/local.js +0 -349
- package/dist/target/remote-errors.js +0 -51
- package/dist/target/remote.d.ts +0 -86
- package/dist/target/remote.js +0 -818
- package/dist/target/target.d.ts +0 -6
- package/dist/target/target.js +0 -37
- package/dist/target/types.d.ts +0 -261
- package/dist/target/types.js +0 -35
- /package/dist/{app → package}/static-index.d.ts +0 -0
- /package/dist/{target → service}/sse-parser.d.ts +0 -0
- /package/dist/{target → service}/sse-parser.js +0 -0
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { ActionResolver } from "../../catalog/action-resolver.js";
|
|
1
|
+
import { parseActionRef } from "../../catalog/resolve-action.js";
|
|
3
2
|
import { filterByIntent } from "../../filter/index.js";
|
|
4
|
-
import { ACTION_NOT_FOUND, ACTION_TIMEOUT, IDEMPOTENCY_CONFLICT, INPUT_VALIDATION_FAILED, PACKAGE_NOT_FOUND } from "../../errors.js";
|
|
3
|
+
import { ACTION_EXECUTION_ERROR, ACTION_FORBIDDEN, ACTION_NOT_FOUND, ACTION_START_FAILED, ACTION_TIMEOUT, ACTIONS_LIST_ERROR, IDEMPOTENCY_CONFLICT, INPUT_VALIDATION_FAILED, INVALID_JSON, PACKAGE_FORBIDDEN, PACKAGE_NOT_FOUND, REQUEST_TOO_LARGE, } from "../../errors.js";
|
|
5
4
|
import { InvalidJsonError, readJsonBody, RequestTooLargeError } from "../body.js";
|
|
6
|
-
import { getSubPath, jsonResponse } from "./common.js";
|
|
5
|
+
import { filterActionsByPolicy, getSubPath, isActionAllowedByPolicy, isPackageAllowedByPolicy, jsonResponse, } from "./common.js";
|
|
7
6
|
/**
|
|
8
7
|
* 处理 Action 相关的 HTTP 路由(列表、规范查询、同步执行与异步启动)。
|
|
9
8
|
*/
|
|
10
9
|
export async function handleActionsRoutes(ctx) {
|
|
11
|
-
const { req, url, pathname, corsHeaders, options,
|
|
10
|
+
const { req, url, pathname, corsHeaders, options, service, activePolicy: policy } = ctx;
|
|
12
11
|
const subpath = getSubPath(pathname);
|
|
13
12
|
// 1. Actions List: GET /api/v2/actions, GET /actions
|
|
14
13
|
if (subpath === "/actions" && req.method === "GET") {
|
|
@@ -18,7 +17,7 @@ export async function handleActionsRoutes(ctx) {
|
|
|
18
17
|
const targetPkg = url.searchParams.get("package") || url.searchParams.get("packageId") || undefined;
|
|
19
18
|
const prefix = url.searchParams.get("prefix") || undefined;
|
|
20
19
|
const tags = url.searchParams.getAll("tag");
|
|
21
|
-
let actions = await
|
|
20
|
+
let actions = await service.discovery.listActions({
|
|
22
21
|
query,
|
|
23
22
|
prefix,
|
|
24
23
|
tags: tags.length > 0 ? tags : undefined,
|
|
@@ -26,9 +25,7 @@ export async function handleActionsRoutes(ctx) {
|
|
|
26
25
|
if (targetPkg) {
|
|
27
26
|
actions = actions.filter((a) => a.packageId === targetPkg || a.id.startsWith(`${targetPkg}/`));
|
|
28
27
|
}
|
|
29
|
-
|
|
30
|
-
actions = actions.filter((a) => a.packageId && options.packageAllowlist.includes(a.packageId));
|
|
31
|
-
}
|
|
28
|
+
actions = filterActionsByPolicy(actions, policy);
|
|
32
29
|
if (intent) {
|
|
33
30
|
actions = filterByIntent(actions, intent, [(a) => a.id, (a) => a.description || "", (a) => a.packageId || ""], false);
|
|
34
31
|
}
|
|
@@ -37,7 +34,7 @@ export async function handleActionsRoutes(ctx) {
|
|
|
37
34
|
catch (err) {
|
|
38
35
|
return jsonResponse({
|
|
39
36
|
ok: false,
|
|
40
|
-
error: { code:
|
|
37
|
+
error: { code: ACTIONS_LIST_ERROR, message: err.message },
|
|
41
38
|
}, 500, corsHeaders);
|
|
42
39
|
}
|
|
43
40
|
}
|
|
@@ -46,20 +43,27 @@ export async function handleActionsRoutes(ctx) {
|
|
|
46
43
|
if (pkgActionShowMatch && req.method === "GET") {
|
|
47
44
|
const packageId = decodeURIComponent(pkgActionShowMatch[1]);
|
|
48
45
|
const actionId = decodeURIComponent(pkgActionShowMatch[2]);
|
|
49
|
-
if (
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
46
|
+
if (!isPackageAllowedByPolicy(packageId, policy)) {
|
|
47
|
+
return jsonResponse({
|
|
48
|
+
ok: false,
|
|
49
|
+
error: {
|
|
50
|
+
code: PACKAGE_FORBIDDEN,
|
|
51
|
+
message: `Package '${packageId}' is not in the allowed package list`,
|
|
52
|
+
},
|
|
53
|
+
}, 403, corsHeaders);
|
|
54
|
+
}
|
|
55
|
+
if (!isActionAllowedByPolicy({ packageId, actionId }, policy)) {
|
|
56
|
+
return jsonResponse({
|
|
57
|
+
ok: false,
|
|
58
|
+
error: {
|
|
59
|
+
code: ACTION_FORBIDDEN,
|
|
60
|
+
message: `Action '${packageId}/${actionId}' is not in the allowed action list`,
|
|
61
|
+
},
|
|
62
|
+
}, 403, corsHeaders);
|
|
59
63
|
}
|
|
60
64
|
const ref = `${packageId}/${actionId}`;
|
|
61
65
|
try {
|
|
62
|
-
const spec = await
|
|
66
|
+
const spec = await service.discovery.describeAction(ref);
|
|
63
67
|
return jsonResponse(spec, 200, corsHeaders);
|
|
64
68
|
}
|
|
65
69
|
catch (err) {
|
|
@@ -77,30 +81,46 @@ export async function handleActionsRoutes(ctx) {
|
|
|
77
81
|
if (actionShowMatch && req.method === "GET") {
|
|
78
82
|
const actionId = decodeURIComponent(actionShowMatch[1]);
|
|
79
83
|
try {
|
|
80
|
-
const parsed =
|
|
81
|
-
if (parsed.packageId
|
|
82
|
-
if (!
|
|
84
|
+
const parsed = parseActionRef(actionId);
|
|
85
|
+
if (parsed.packageId) {
|
|
86
|
+
if (!isPackageAllowedByPolicy(parsed.packageId, policy)) {
|
|
83
87
|
return jsonResponse({
|
|
84
88
|
ok: false,
|
|
85
89
|
error: {
|
|
86
|
-
code:
|
|
90
|
+
code: PACKAGE_FORBIDDEN,
|
|
87
91
|
message: `Package '${parsed.packageId}' is not in the allowed package list`,
|
|
88
92
|
},
|
|
89
93
|
}, 403, corsHeaders);
|
|
90
94
|
}
|
|
95
|
+
if (!isActionAllowedByPolicy({ packageId: parsed.packageId, actionId: parsed.actionId }, policy)) {
|
|
96
|
+
return jsonResponse({
|
|
97
|
+
ok: false,
|
|
98
|
+
error: {
|
|
99
|
+
code: ACTION_FORBIDDEN,
|
|
100
|
+
message: `Action '${actionId}' is not in the allowed action list`,
|
|
101
|
+
},
|
|
102
|
+
}, 403, corsHeaders);
|
|
103
|
+
}
|
|
91
104
|
}
|
|
92
105
|
}
|
|
93
106
|
catch { }
|
|
94
107
|
try {
|
|
95
|
-
const spec = await
|
|
96
|
-
if (
|
|
97
|
-
|
|
98
|
-
|
|
108
|
+
const spec = await service.discovery.describeAction(actionId);
|
|
109
|
+
if (!isPackageAllowedByPolicy(spec.packageId, policy)) {
|
|
110
|
+
return jsonResponse({
|
|
111
|
+
ok: false,
|
|
112
|
+
error: {
|
|
113
|
+
code: PACKAGE_FORBIDDEN,
|
|
114
|
+
message: `Package '${spec.packageId || "unknown"}' is not in the allowed package list`,
|
|
115
|
+
},
|
|
116
|
+
}, 403, corsHeaders);
|
|
117
|
+
}
|
|
118
|
+
if (!isActionAllowedByPolicy({ packageId: spec.packageId, actionId: spec.id }, policy)) {
|
|
99
119
|
return jsonResponse({
|
|
100
120
|
ok: false,
|
|
101
121
|
error: {
|
|
102
|
-
code:
|
|
103
|
-
message: `
|
|
122
|
+
code: ACTION_FORBIDDEN,
|
|
123
|
+
message: `Action '${spec.packageId ? `${spec.packageId}/${spec.id}` : spec.id}' is not in the allowed action list`,
|
|
104
124
|
},
|
|
105
125
|
}, 403, corsHeaders);
|
|
106
126
|
}
|
|
@@ -128,9 +148,10 @@ export async function handleActionsRoutes(ctx) {
|
|
|
128
148
|
let actionRef;
|
|
129
149
|
let endpointMode;
|
|
130
150
|
let pkgId;
|
|
151
|
+
let actId;
|
|
131
152
|
if (pkgRunMatch) {
|
|
132
153
|
pkgId = decodeURIComponent(pkgRunMatch[1]);
|
|
133
|
-
|
|
154
|
+
actId = decodeURIComponent(pkgRunMatch[2]);
|
|
134
155
|
endpointMode = pkgRunMatch[3];
|
|
135
156
|
actionRef = `${pkgId}/${actId}`;
|
|
136
157
|
}
|
|
@@ -138,33 +159,55 @@ export async function handleActionsRoutes(ctx) {
|
|
|
138
159
|
actionRef = decodeURIComponent(shortRunMatch[1]);
|
|
139
160
|
endpointMode = shortRunMatch[2];
|
|
140
161
|
try {
|
|
141
|
-
const parsed =
|
|
162
|
+
const parsed = parseActionRef(actionRef);
|
|
142
163
|
pkgId = parsed.packageId;
|
|
164
|
+
actId = parsed.actionId;
|
|
143
165
|
}
|
|
144
166
|
catch { }
|
|
145
167
|
}
|
|
146
|
-
//
|
|
147
|
-
if (
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
}
|
|
153
|
-
catch { }
|
|
168
|
+
// 解析并补全包与动作标识(仅在必要时单次查询 spec)
|
|
169
|
+
if ((!pkgId || !actId) && (policy.packageAllowlist?.length || policy.actionAllowlist?.length)) {
|
|
170
|
+
try {
|
|
171
|
+
const spec = await service.discovery.describeAction(actionRef);
|
|
172
|
+
pkgId = pkgId || spec?.packageId;
|
|
173
|
+
actId = actId || spec?.id;
|
|
154
174
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
}, 403, corsHeaders);
|
|
175
|
+
catch { }
|
|
176
|
+
}
|
|
177
|
+
if (!actId) {
|
|
178
|
+
try {
|
|
179
|
+
const parsed = parseActionRef(actionRef);
|
|
180
|
+
actId = parsed.actionId;
|
|
181
|
+
pkgId = pkgId || parsed.packageId;
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
actId = actionRef;
|
|
166
185
|
}
|
|
167
186
|
}
|
|
187
|
+
// 校验 Package 允许白名单
|
|
188
|
+
if (!isPackageAllowedByPolicy(pkgId, policy)) {
|
|
189
|
+
return jsonResponse({
|
|
190
|
+
ok: false,
|
|
191
|
+
runId: "",
|
|
192
|
+
error: {
|
|
193
|
+
code: PACKAGE_FORBIDDEN,
|
|
194
|
+
message: pkgId
|
|
195
|
+
? `Package '${pkgId}' is not in the allowed package list`
|
|
196
|
+
: `Action '${actionRef}' does not belong to any allowed package`,
|
|
197
|
+
},
|
|
198
|
+
}, 403, corsHeaders);
|
|
199
|
+
}
|
|
200
|
+
// 校验 Action 允许白名单
|
|
201
|
+
if (!isActionAllowedByPolicy({ packageId: pkgId, actionId: actId }, policy)) {
|
|
202
|
+
return jsonResponse({
|
|
203
|
+
ok: false,
|
|
204
|
+
runId: "",
|
|
205
|
+
error: {
|
|
206
|
+
code: ACTION_FORBIDDEN,
|
|
207
|
+
message: `Action '${actionRef}' is not in the allowed action list`,
|
|
208
|
+
},
|
|
209
|
+
}, 403, corsHeaders);
|
|
210
|
+
}
|
|
168
211
|
let body = {};
|
|
169
212
|
try {
|
|
170
213
|
body = await readJsonBody(req, { maxBytes: options.maxBodyBytes });
|
|
@@ -173,21 +216,21 @@ export async function handleActionsRoutes(ctx) {
|
|
|
173
216
|
if (err instanceof RequestTooLargeError) {
|
|
174
217
|
return jsonResponse({
|
|
175
218
|
ok: false,
|
|
176
|
-
runId:
|
|
177
|
-
error: { code:
|
|
219
|
+
runId: "",
|
|
220
|
+
error: { code: REQUEST_TOO_LARGE, message: err.message },
|
|
178
221
|
}, 413, corsHeaders);
|
|
179
222
|
}
|
|
180
223
|
if (err instanceof InvalidJsonError) {
|
|
181
224
|
return jsonResponse({
|
|
182
225
|
ok: false,
|
|
183
|
-
runId:
|
|
184
|
-
error: { code:
|
|
226
|
+
runId: "",
|
|
227
|
+
error: { code: INVALID_JSON, message: err.message },
|
|
185
228
|
}, 400, corsHeaders);
|
|
186
229
|
}
|
|
187
230
|
return jsonResponse({
|
|
188
231
|
ok: false,
|
|
189
|
-
runId:
|
|
190
|
-
error: { code:
|
|
232
|
+
runId: "",
|
|
233
|
+
error: { code: INVALID_JSON, message: `Failed to parse request body: ${err.message}` },
|
|
191
234
|
}, 400, corsHeaders);
|
|
192
235
|
}
|
|
193
236
|
const isAsync = endpointMode === "start" ||
|
|
@@ -205,9 +248,16 @@ export async function handleActionsRoutes(ctx) {
|
|
|
205
248
|
body?.requestId ||
|
|
206
249
|
body?.execution?.requestId ||
|
|
207
250
|
undefined;
|
|
251
|
+
let actionRefObj;
|
|
252
|
+
try {
|
|
253
|
+
actionRefObj = parseActionRef(actionRef);
|
|
254
|
+
}
|
|
255
|
+
catch {
|
|
256
|
+
actionRefObj = { actionId: actionRef };
|
|
257
|
+
}
|
|
208
258
|
if (isAsync) {
|
|
209
259
|
try {
|
|
210
|
-
const ticket = await
|
|
260
|
+
const ticket = await service.execution.start(actionRefObj, input, {
|
|
211
261
|
timeoutMs,
|
|
212
262
|
config: configOverrides,
|
|
213
263
|
requestId,
|
|
@@ -236,9 +286,9 @@ export async function handleActionsRoutes(ctx) {
|
|
|
236
286
|
}
|
|
237
287
|
return jsonResponse({
|
|
238
288
|
ok: false,
|
|
239
|
-
runId:
|
|
289
|
+
runId: "",
|
|
240
290
|
error: {
|
|
241
|
-
code:
|
|
291
|
+
code: ACTION_START_FAILED,
|
|
242
292
|
message: err.message || String(err),
|
|
243
293
|
},
|
|
244
294
|
}, 500, corsHeaders);
|
|
@@ -246,7 +296,7 @@ export async function handleActionsRoutes(ctx) {
|
|
|
246
296
|
}
|
|
247
297
|
// 同步执行模式
|
|
248
298
|
try {
|
|
249
|
-
const result = await
|
|
299
|
+
const result = await service.execution.run(actionRefObj, input, {
|
|
250
300
|
signal: req.signal,
|
|
251
301
|
timeoutMs,
|
|
252
302
|
config: configOverrides,
|
|
@@ -286,9 +336,9 @@ export async function handleActionsRoutes(ctx) {
|
|
|
286
336
|
}
|
|
287
337
|
return jsonResponse({
|
|
288
338
|
ok: false,
|
|
289
|
-
runId:
|
|
339
|
+
runId: "",
|
|
290
340
|
error: {
|
|
291
|
-
code:
|
|
341
|
+
code: ACTION_EXECUTION_ERROR,
|
|
292
342
|
message: err.message || String(err),
|
|
293
343
|
},
|
|
294
344
|
}, 500, corsHeaders);
|
|
@@ -1,47 +1,32 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
* 路由处理统一上下文对象。
|
|
7
|
-
*/
|
|
8
|
-
export interface RouteContext {
|
|
9
|
-
req: Request;
|
|
10
|
-
url: URL;
|
|
11
|
-
pathname: string;
|
|
12
|
-
corsHeaders: Record<string, string>;
|
|
13
|
-
projectRoot: string | null;
|
|
14
|
-
customHome?: string;
|
|
15
|
-
host?: ActionDockHost;
|
|
16
|
-
target: ActionDockTarget;
|
|
17
|
-
options: ServerOptions;
|
|
18
|
-
}
|
|
1
|
+
import type { PackageInfo } from "../../package/types.js";
|
|
2
|
+
import type { EffectiveServerPolicy, RouteContext, ServerOptions } from "../types.js";
|
|
3
|
+
import { ActionForbiddenError, assertActionAllowedByPolicy, assertPackageAllowedByPolicy, filterActionsByPolicy, filterPackagesByPolicy, isActionAllowed, isActionAllowedByPolicy, isManagementAllowedByPolicy, isPackageAllowedByPolicy, PackageNotAllowedError } from "../policy.js";
|
|
4
|
+
export type { RouteContext };
|
|
5
|
+
export { ActionForbiddenError, PackageNotAllowedError, isActionAllowed, isActionAllowedByPolicy, isPackageAllowedByPolicy, isManagementAllowedByPolicy, filterActionsByPolicy, filterPackagesByPolicy, assertActionAllowedByPolicy, assertPackageAllowedByPolicy, };
|
|
19
6
|
/**
|
|
20
7
|
* 构造带 CORS 头的标准 JSON HTTP 响应。
|
|
21
8
|
*/
|
|
22
9
|
export declare function jsonResponse(data: unknown, status?: number, corsHeaders?: Record<string, string>): Response;
|
|
23
10
|
/**
|
|
24
|
-
* 剥离标准版本前缀 (/api/v2/
|
|
11
|
+
* 剥离标准版本前缀 (/api/v2/),获取相对路由子路径。
|
|
25
12
|
*/
|
|
26
13
|
export declare function getSubPath(pathname: string): string;
|
|
27
14
|
/**
|
|
28
|
-
*
|
|
15
|
+
* 校验目标 action 是否属于允许动作白名单。
|
|
16
|
+
* 当 options 或 policy 中的 actionAllowlist 存在且目标 action 不在白名单中时抛出 403 ACTION_FORBIDDEN 异常。
|
|
29
17
|
*/
|
|
30
|
-
export declare
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
18
|
+
export declare function assertActionAllowed(action: {
|
|
19
|
+
actionId?: string;
|
|
20
|
+
id?: string;
|
|
21
|
+
packageId?: string;
|
|
22
|
+
} | string, options?: ServerOptions | EffectiveServerPolicy): void;
|
|
36
23
|
/**
|
|
37
24
|
* 校验目标 packageId 是否属于允许包白名单。
|
|
38
|
-
* 当 options
|
|
25
|
+
* 当 options 或 policy 中的 packageAllowlist 存在且目标 packageId 不在白名单中时抛出 403 PACKAGE_NOT_ALLOWED 异常。
|
|
39
26
|
*/
|
|
40
|
-
export declare function assertPackageAllowed(packageId: string
|
|
41
|
-
packageAllowlist?: string[];
|
|
42
|
-
}): void;
|
|
27
|
+
export declare function assertPackageAllowed(packageId: string, options?: ServerOptions | EffectiveServerPolicy): void;
|
|
43
28
|
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
29
|
+
* 解析并确定生效的目标 packageId。
|
|
30
|
+
* 遵循严格的解析规则与白名单检查。
|
|
46
31
|
*/
|
|
47
|
-
export declare function
|
|
32
|
+
export declare function resolveTargetPackageId(packages: PackageInfo[], requestedPackageId?: string, options?: ServerOptions | EffectiveServerPolicy): string;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { assertValidPackageId } from "../../utils/index.js";
|
|
2
|
+
import { ActionDockError, PACKAGE_NOT_FOUND } from "../../errors.js";
|
|
3
|
+
import { ActionForbiddenError, assertActionAllowedByPolicy, assertPackageAllowedByPolicy, filterActionsByPolicy, filterPackagesByPolicy, isActionAllowed, isActionAllowedByPolicy, isManagementAllowedByPolicy, isPackageAllowedByPolicy, PackageNotAllowedError, } from "../policy.js";
|
|
4
|
+
export { ActionForbiddenError, PackageNotAllowedError, isActionAllowed, isActionAllowedByPolicy, isPackageAllowedByPolicy, isManagementAllowedByPolicy, filterActionsByPolicy, filterPackagesByPolicy, assertActionAllowedByPolicy, assertPackageAllowedByPolicy, };
|
|
2
5
|
/**
|
|
3
6
|
* 构造带 CORS 头的标准 JSON HTTP 响应。
|
|
4
7
|
*/
|
|
@@ -12,93 +15,70 @@ export function jsonResponse(data, status = 200, corsHeaders = {}) {
|
|
|
12
15
|
});
|
|
13
16
|
}
|
|
14
17
|
/**
|
|
15
|
-
* 剥离标准版本前缀 (/api/v2/
|
|
18
|
+
* 剥离标准版本前缀 (/api/v2/),获取相对路由子路径。
|
|
16
19
|
*/
|
|
17
20
|
export function getSubPath(pathname) {
|
|
18
21
|
if (pathname.startsWith("/api/v2/")) {
|
|
19
22
|
return pathname.slice(7);
|
|
20
23
|
}
|
|
21
|
-
if (pathname.startsWith("/api/v1/")) {
|
|
22
|
-
return pathname.slice(7);
|
|
23
|
-
}
|
|
24
24
|
return pathname;
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
|
-
*
|
|
27
|
+
* 校验目标 action 是否属于允许动作白名单。
|
|
28
|
+
* 当 options 或 policy 中的 actionAllowlist 存在且目标 action 不在白名单中时抛出 403 ACTION_FORBIDDEN 异常。
|
|
28
29
|
*/
|
|
29
|
-
export
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
export function assertActionAllowed(action, options) {
|
|
31
|
+
const policy = options
|
|
32
|
+
? {
|
|
33
|
+
packageAllowlist: options.packageAllowlist,
|
|
34
|
+
actionAllowlist: options.actionAllowlist,
|
|
35
|
+
}
|
|
36
|
+
: undefined;
|
|
37
|
+
assertActionAllowedByPolicy(action, policy);
|
|
37
38
|
}
|
|
38
39
|
/**
|
|
39
40
|
* 校验目标 packageId 是否属于允许包白名单。
|
|
40
|
-
* 当 options
|
|
41
|
+
* 当 options 或 policy 中的 packageAllowlist 存在且目标 packageId 不在白名单中时抛出 403 PACKAGE_NOT_ALLOWED 异常。
|
|
41
42
|
*/
|
|
42
43
|
export function assertPackageAllowed(packageId, options) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (!packageId || !options.packageAllowlist.includes(packageId)) {
|
|
47
|
-
throw new PackageNotAllowedError(packageId || "");
|
|
44
|
+
const policy = options
|
|
45
|
+
? {
|
|
46
|
+
packageAllowlist: options.packageAllowlist,
|
|
48
47
|
}
|
|
49
|
-
|
|
48
|
+
: undefined;
|
|
49
|
+
assertPackageAllowedByPolicy(packageId, policy);
|
|
50
50
|
}
|
|
51
51
|
/**
|
|
52
|
-
*
|
|
53
|
-
*
|
|
52
|
+
* 解析并确定生效的目标 packageId。
|
|
53
|
+
* 遵循严格的解析规则与白名单检查。
|
|
54
54
|
*/
|
|
55
|
-
export function
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const app = host.getApp(packageIdOrPath);
|
|
61
|
-
if (app)
|
|
62
|
-
return app;
|
|
63
|
-
}
|
|
64
|
-
const innerTarget = target?.unwrap?.();
|
|
65
|
-
if (innerTarget && "packageId" in innerTarget && innerTarget.packageId === packageIdOrPath) {
|
|
66
|
-
return innerTarget;
|
|
55
|
+
export function resolveTargetPackageId(packages, requestedPackageId, options) {
|
|
56
|
+
const allowlist = options?.packageAllowlist;
|
|
57
|
+
if (requestedPackageId) {
|
|
58
|
+
if (requestedPackageId === "global") {
|
|
59
|
+
return "global";
|
|
67
60
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
61
|
+
assertValidPackageId(requestedPackageId);
|
|
62
|
+
assertPackageAllowed(requestedPackageId, options);
|
|
63
|
+
const matched = packages.find((p) => p.id === requestedPackageId || p.packageRoot === requestedPackageId);
|
|
64
|
+
if (!matched) {
|
|
65
|
+
throw new ActionDockError(PACKAGE_NOT_FOUND, `Unknown or unregistered package: '${requestedPackageId}'`);
|
|
72
66
|
}
|
|
73
|
-
|
|
67
|
+
return matched.id;
|
|
74
68
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
if (allowedApp)
|
|
82
|
-
return allowedApp;
|
|
83
|
-
}
|
|
84
|
-
if (apps.length > 0)
|
|
85
|
-
return apps[0];
|
|
69
|
+
let targetId;
|
|
70
|
+
if (allowlist &&
|
|
71
|
+
Array.isArray(allowlist) &&
|
|
72
|
+
allowlist.length > 0) {
|
|
73
|
+
const allowed = packages.find((p) => allowlist.includes(p.id));
|
|
74
|
+
targetId = allowed ? allowed.id : (packages[0]?.id || "");
|
|
86
75
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
const apps = innerTarget.listApps();
|
|
90
|
-
if (options?.packageAllowlist &&
|
|
91
|
-
Array.isArray(options.packageAllowlist) &&
|
|
92
|
-
options.packageAllowlist.length > 0) {
|
|
93
|
-
const allowedApp = apps.find((a) => options.packageAllowlist.includes(a.packageId));
|
|
94
|
-
if (allowedApp)
|
|
95
|
-
return allowedApp;
|
|
96
|
-
}
|
|
97
|
-
if (apps.length > 0)
|
|
98
|
-
return apps[0];
|
|
76
|
+
else if (packages.length > 0) {
|
|
77
|
+
targetId = packages[0].id;
|
|
99
78
|
}
|
|
100
|
-
|
|
101
|
-
|
|
79
|
+
else {
|
|
80
|
+
throw new ActionDockError(PACKAGE_NOT_FOUND, "No registered package found in service");
|
|
102
81
|
}
|
|
103
|
-
|
|
82
|
+
assertPackageAllowed(targetId, options);
|
|
83
|
+
return targetId;
|
|
104
84
|
}
|