@forestadmin/agent 1.79.5 → 1.80.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.
|
@@ -6,9 +6,13 @@ import BaseRoute from '../base-route';
|
|
|
6
6
|
export default class WorkflowExecutorProxyRoute extends BaseRoute {
|
|
7
7
|
readonly type = RouteType.PrivateRoute;
|
|
8
8
|
private readonly executorUrl;
|
|
9
|
+
protected readonly requestTimeoutMs: number;
|
|
9
10
|
constructor(services: ForestAdminHttpDriverServices, options: AgentOptionsWithDefaults);
|
|
10
11
|
setupRoutes(router: KoaRouter): void;
|
|
11
12
|
private handleProxy;
|
|
13
|
+
private buildTargetUrl;
|
|
14
|
+
private executorPath;
|
|
15
|
+
private forwardedHeaders;
|
|
12
16
|
private forwardRequest;
|
|
13
17
|
}
|
|
14
18
|
//# sourceMappingURL=workflow-executor-proxy.d.ts.map
|
|
@@ -3,46 +3,94 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const datasource_toolkit_1 = require("@forestadmin/datasource-toolkit");
|
|
6
7
|
const http_1 = require("http");
|
|
7
8
|
const https_1 = require("https");
|
|
8
9
|
const types_1 = require("../../types");
|
|
9
10
|
const base_route_1 = __importDefault(require("../base-route"));
|
|
11
|
+
const AGENT_PREFIX = '/_internal/workflow-executions';
|
|
12
|
+
const EXECUTOR_PREFIX = '/runs';
|
|
13
|
+
// Never forwarded: hop-by-hop headers, Host (Node derives the executor's from the target URL),
|
|
14
|
+
// and length/encoding the HTTP client recomputes.
|
|
15
|
+
const SKIPPED_HEADERS = new Set([
|
|
16
|
+
'connection',
|
|
17
|
+
'keep-alive',
|
|
18
|
+
'transfer-encoding',
|
|
19
|
+
'upgrade',
|
|
20
|
+
'te',
|
|
21
|
+
'trailer',
|
|
22
|
+
'proxy-authenticate',
|
|
23
|
+
'proxy-authorization',
|
|
24
|
+
'host',
|
|
25
|
+
'content-length',
|
|
26
|
+
]);
|
|
27
|
+
// Substrings that could let the wildcard escape EXECUTOR_PREFIX (traversal, encoded dots,
|
|
28
|
+
// backslash, null byte).
|
|
29
|
+
const UNSAFE_PATH_FRAGMENTS = ['..', '%2e', '%2E', '\\', '\0'];
|
|
30
|
+
const REQUEST_TIMEOUT_MS = 120000;
|
|
10
31
|
class WorkflowExecutorProxyRoute extends base_route_1.default {
|
|
11
32
|
constructor(services, options) {
|
|
12
33
|
super(services, options);
|
|
13
34
|
this.type = types_1.RouteType.PrivateRoute;
|
|
35
|
+
// Overridable so tests can exercise the timeout branch without waiting the full default.
|
|
36
|
+
this.requestTimeoutMs = REQUEST_TIMEOUT_MS;
|
|
14
37
|
// Remove trailing slash for clean URL joining
|
|
15
38
|
this.executorUrl = new URL(options.workflowExecutorUrl.replace(/\/+$/, ''));
|
|
16
39
|
}
|
|
40
|
+
// Single catch-all: any sub-path/verb under AGENT_PREFIX is forwarded to EXECUTOR_PREFIX, so a
|
|
41
|
+
// new executor route needs no change here (PRD-567).
|
|
17
42
|
setupRoutes(router) {
|
|
18
|
-
router.
|
|
19
|
-
router.post('/_internal/workflow-executions/:runId/trigger', this.handleProxy.bind(this));
|
|
43
|
+
router.all(`${AGENT_PREFIX}/:path(.*)`, this.handleProxy.bind(this));
|
|
20
44
|
}
|
|
21
45
|
async handleProxy(context) {
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
};
|
|
31
|
-
const response = await this.forwardRequest(context.method, targetUrl, context.request.body, forwardedHeaders);
|
|
46
|
+
const targetUrl = this.buildTargetUrl(context);
|
|
47
|
+
const response = await this.forwardRequest({
|
|
48
|
+
method: context.method,
|
|
49
|
+
url: targetUrl,
|
|
50
|
+
// Raw body forwarded verbatim (set by @koa/bodyparser); undefined for GET.
|
|
51
|
+
body: context.method === 'GET' ? undefined : context.request.rawBody,
|
|
52
|
+
headers: this.forwardedHeaders(context),
|
|
53
|
+
});
|
|
32
54
|
context.response.status = response.status;
|
|
55
|
+
// Forward every executor response header (minus hop-by-hop) so new executor headers never
|
|
56
|
+
// require an agent change (PRD-567: zero breaking, the agent stays a transparent proxy).
|
|
57
|
+
for (const [name, value] of Object.entries(response.headers)) {
|
|
58
|
+
if (value !== undefined && !SKIPPED_HEADERS.has(name.toLowerCase())) {
|
|
59
|
+
context.response.set(name, value);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
33
62
|
context.response.body = response.body;
|
|
34
63
|
}
|
|
35
|
-
|
|
64
|
+
buildTargetUrl(context) {
|
|
65
|
+
const path = this.executorPath(String(context.params.path ?? ''));
|
|
66
|
+
const qs = context.querystring ? `?${context.querystring}` : '';
|
|
67
|
+
return new URL(`${path}${qs}`, this.executorUrl);
|
|
68
|
+
}
|
|
69
|
+
// Security boundary: the wildcard can only ever map into EXECUTOR_PREFIX. Reject anything that
|
|
70
|
+
// could escape it so executor routes outside EXECUTOR_PREFIX stay unreachable through the proxy.
|
|
71
|
+
executorPath(wildcard) {
|
|
72
|
+
const unsafe = wildcard === '' ||
|
|
73
|
+
wildcard.startsWith('/') ||
|
|
74
|
+
UNSAFE_PATH_FRAGMENTS.some(fragment => wildcard.includes(fragment));
|
|
75
|
+
if (unsafe)
|
|
76
|
+
throw new datasource_toolkit_1.NotFoundError('Invalid workflow executor path');
|
|
77
|
+
return `${EXECUTOR_PREFIX}/${wildcard}`;
|
|
78
|
+
}
|
|
79
|
+
// Forwards every client header except the ones in SKIPPED_HEADERS.
|
|
80
|
+
forwardedHeaders(context) {
|
|
81
|
+
const headers = {};
|
|
82
|
+
for (const [name, value] of Object.entries(context.request.headers)) {
|
|
83
|
+
if (value !== undefined && !SKIPPED_HEADERS.has(name.toLowerCase())) {
|
|
84
|
+
headers[name] = value;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return headers;
|
|
88
|
+
}
|
|
89
|
+
forwardRequest(request) {
|
|
90
|
+
const { method, url, body, headers } = request;
|
|
36
91
|
const requestFn = url.protocol === 'https:' ? https_1.request : http_1.request;
|
|
37
|
-
const headers = { 'Content-Type': 'application/json' };
|
|
38
|
-
// Forward the caller's auth so the executor's JWT middleware can validate it.
|
|
39
|
-
// Agent and executor share the same FOREST_AUTH_SECRET so the token is valid on both.
|
|
40
|
-
if (forwardedHeaders.authorization)
|
|
41
|
-
headers.Authorization = forwardedHeaders.authorization;
|
|
42
|
-
if (forwardedHeaders.cookie)
|
|
43
|
-
headers.Cookie = forwardedHeaders.cookie;
|
|
44
92
|
return new Promise((resolve, reject) => {
|
|
45
|
-
const req = requestFn(url, { method, headers }, res => {
|
|
93
|
+
const req = requestFn(url, { method, headers, timeout: this.requestTimeoutMs }, res => {
|
|
46
94
|
const chunks = [];
|
|
47
95
|
res.on('data', chunk => chunks.push(chunk));
|
|
48
96
|
res.on('end', () => {
|
|
@@ -54,17 +102,21 @@ class WorkflowExecutorProxyRoute extends base_route_1.default {
|
|
|
54
102
|
catch {
|
|
55
103
|
parsed = raw;
|
|
56
104
|
}
|
|
57
|
-
resolve({
|
|
105
|
+
resolve({
|
|
106
|
+
status: res.statusCode ?? types_1.HttpCode.InternalServerError,
|
|
107
|
+
body: parsed,
|
|
108
|
+
headers: res.headers,
|
|
109
|
+
});
|
|
58
110
|
});
|
|
59
111
|
res.on('error', reject);
|
|
60
112
|
});
|
|
61
113
|
req.on('error', reject);
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
114
|
+
req.on('timeout', () => req.destroy(new Error('Workflow executor request timed out')));
|
|
115
|
+
if (body !== undefined && method !== 'GET')
|
|
116
|
+
req.write(body);
|
|
65
117
|
req.end();
|
|
66
118
|
});
|
|
67
119
|
}
|
|
68
120
|
}
|
|
69
121
|
exports.default = WorkflowExecutorProxyRoute;
|
|
70
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
122
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid29ya2Zsb3ctZXhlY3V0b3ItcHJveHkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcm91dGVzL3dvcmtmbG93L3dvcmtmbG93LWV4ZWN1dG9yLXByb3h5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBTUEsd0VBQWdFO0FBQ2hFLCtCQUE4QztBQUM5QyxpQ0FBZ0Q7QUFFaEQsdUNBQWtEO0FBQ2xELCtEQUFzQztBQUV0QyxNQUFNLFlBQVksR0FBRyxnQ0FBZ0MsQ0FBQztBQUN0RCxNQUFNLGVBQWUsR0FBRyxPQUFPLENBQUM7QUFDaEMsK0ZBQStGO0FBQy9GLGtEQUFrRDtBQUNsRCxNQUFNLGVBQWUsR0FBRyxJQUFJLEdBQUcsQ0FBQztJQUM5QixZQUFZO0lBQ1osWUFBWTtJQUNaLG1CQUFtQjtJQUNuQixTQUFTO0lBQ1QsSUFBSTtJQUNKLFNBQVM7SUFDVCxvQkFBb0I7SUFDcEIscUJBQXFCO0lBQ3JCLE1BQU07SUFDTixnQkFBZ0I7Q0FDakIsQ0FBQyxDQUFDO0FBQ0gsMEZBQTBGO0FBQzFGLHlCQUF5QjtBQUN6QixNQUFNLHFCQUFxQixHQUFHLENBQUMsSUFBSSxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDO0FBQy9ELE1BQU0sa0JBQWtCLEdBQUcsTUFBTyxDQUFDO0FBRW5DLE1BQXFCLDBCQUEyQixTQUFRLG9CQUFTO0lBTS9ELFlBQVksUUFBdUMsRUFBRSxPQUFpQztRQUNwRixLQUFLLENBQUMsUUFBUSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBTmxCLFNBQUksR0FBRyxpQkFBUyxDQUFDLFlBQVksQ0FBQztRQUV2Qyx5RkFBeUY7UUFDdEUscUJBQWdCLEdBQVcsa0JBQWtCLENBQUM7UUFJL0QsOENBQThDO1FBQzlDLElBQUksQ0FBQyxXQUFXLEdBQUcsSUFBSSxHQUFHLENBQUMsT0FBTyxDQUFDLG1CQUFtQixDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsRUFB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
|
|
@@ -3,10 +3,12 @@ import type { Collection } from '@forestadmin/datasource-toolkit';
|
|
|
3
3
|
import type { ForestServerCollection } from '@forestadmin/forestadmin-client';
|
|
4
4
|
export default class SchemaGeneratorCollection {
|
|
5
5
|
private readonly schemaGeneratorActions;
|
|
6
|
+
private readonly useUnsafeActionEndpoint;
|
|
6
7
|
constructor(options: AgentOptionsWithDefaults);
|
|
7
8
|
/** Build forest-server schema for a collection */
|
|
8
9
|
buildSchema(collection: Collection): Promise<ForestServerCollection>;
|
|
9
10
|
private buildActions;
|
|
11
|
+
private static assertNoActionSlugCollision;
|
|
10
12
|
private static buildFields;
|
|
11
13
|
private static buildSegments;
|
|
12
14
|
}
|
|
@@ -10,6 +10,7 @@ const generator_segments_1 = __importDefault(require("./generator-segments"));
|
|
|
10
10
|
class SchemaGeneratorCollection {
|
|
11
11
|
constructor(options) {
|
|
12
12
|
this.schemaGeneratorActions = new generator_actions_1.default(options);
|
|
13
|
+
this.useUnsafeActionEndpoint = options.useUnsafeActionEndpoint;
|
|
13
14
|
}
|
|
14
15
|
/** Build forest-server schema for a collection */
|
|
15
16
|
async buildSchema(collection) {
|
|
@@ -28,9 +29,23 @@ class SchemaGeneratorCollection {
|
|
|
28
29
|
};
|
|
29
30
|
}
|
|
30
31
|
buildActions(collection) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
.
|
|
32
|
+
const names = Object.keys(collection.schema.actions).sort();
|
|
33
|
+
if (this.useUnsafeActionEndpoint) {
|
|
34
|
+
SchemaGeneratorCollection.assertNoActionSlugCollision(collection.name, names);
|
|
35
|
+
}
|
|
36
|
+
return Promise.all(names.map(name => this.schemaGeneratorActions.buildSchema(collection, name)));
|
|
37
|
+
}
|
|
38
|
+
static assertNoActionSlugCollision(collectionName, names) {
|
|
39
|
+
const nameBySlug = new Map();
|
|
40
|
+
names.forEach(name => {
|
|
41
|
+
const slug = generator_actions_1.default.getActionSlug(name);
|
|
42
|
+
const existing = nameBySlug.get(slug);
|
|
43
|
+
if (existing) {
|
|
44
|
+
throw new Error(`Actions "${existing}" and "${name}" on collection "${collectionName}" resolve to the ` +
|
|
45
|
+
`same endpoint slug "${slug}". Rename one of them or disable useUnsafeActionEndpoint.`);
|
|
46
|
+
}
|
|
47
|
+
nameBySlug.set(slug, name);
|
|
48
|
+
});
|
|
34
49
|
}
|
|
35
50
|
static buildFields(collection) {
|
|
36
51
|
// Do not export foreign keys as those will be edited using the many to one relationship.
|
|
@@ -48,4 +63,4 @@ class SchemaGeneratorCollection {
|
|
|
48
63
|
}
|
|
49
64
|
}
|
|
50
65
|
exports.default = SchemaGeneratorCollection;
|
|
51
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
66
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2VuZXJhdG9yLWNvbGxlY3Rpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdXRpbHMvZm9yZXN0LXNjaGVtYS9nZW5lcmF0b3ItY29sbGVjdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQVNBLHdFQUE4RDtBQUU5RCw0RUFBeUQ7QUFDekQsMEVBQXVEO0FBQ3ZELDhFQUEyRDtBQUUzRCxNQUFxQix5QkFBeUI7SUFJNUMsWUFBWSxPQUFpQztRQUMzQyxJQUFJLENBQUMsc0JBQXNCLEdBQUcsSUFBSSwyQkFBc0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNsRSxJQUFJLENBQUMsdUJBQXVCLEdBQUcsT0FBTyxDQUFDLHVCQUF1QixDQUFDO0lBQ2pFLENBQUM7SUFFRCxrREFBa0Q7SUFDbEQsS0FBSyxDQUFDLFdBQVcsQ0FBQyxVQUFzQjtRQUN0QyxPQUFPO1lBQ0wsT0FBTyxFQUFFLE1BQU0sSUFBSSxDQUFDLFlBQVksQ0FBQyxVQUFVLENBQUM7WUFDNUMsTUFBTSxFQUFFLHlCQUF5QixDQUFDLFdBQVcsQ0FBQyxVQUFVLENBQUM7WUFDekQsSUFBSSxFQUFFLElBQUk7WUFDVixXQUFXLEVBQUUsSUFBSTtZQUNqQixVQUFVLEVBQUUsTUFBTSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLEtBQUssQ0FDdkQsS0FBSyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsSUFBSSxLQUFLLFFBQVEsSUFBSSxLQUFLLENBQUMsVUFBVSxDQUNyRDtZQUNELFlBQVksRUFBRSxVQUFVLENBQUMsTUFBTSxDQUFDLFVBQVU7WUFDMUMsU0FBUyxFQUFFLEtBQUs7WUFDaEIsSUFBSSxFQUFFLFVBQVUsQ0FBQyxJQUFJO1lBQ3JCLG9CQUFvQixFQUFFLEtBQUs7WUFDM0IsY0FBYyxFQUFFLE1BQU07WUFDdEIsUUFBUSxFQUFFLHlCQUF5QixDQUFDLGFBQWEsQ0FBQyxVQUFVLENBQUM7U0FDOUQsQ0FBQztJQUNKLENBQUM7SUFFTyxZQUFZLENBQUMsVUFBc0I7UUFDekMsTUFBTSxLQUFLLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDO1FBRTVELElBQUksSUFBSSxDQUFDLHVCQUF1QixFQUFFLENBQUM7WUFDakMseUJBQXlCLENBQUMsMkJBQTJCLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxLQUFLLENBQUMsQ0FBQztRQUNoRixDQUFDO1FBRUQsT0FBTyxPQUFPLENBQUMsR0FBRyxDQUNoQixLQUFLLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLHNCQUFzQixDQUFDLFdBQVcsQ0FBQyxVQUFVLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FDN0UsQ0FBQztJQUNKLENBQUM7SUFFTyxNQUFNLENBQUMsMkJBQTJCLENBQUMsY0FBc0IsRUFBRSxLQUFlO1FBQ2hGLE1BQU0sVUFBVSxHQUFHLElBQUksR0FBRyxFQUFrQixDQUFDO1FBRTdDLEtBQUssQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEVBQUU7WUFDbkIsTUFBTSxJQUFJLEdBQUcsMkJBQXNCLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ3hELE1BQU0sUUFBUSxHQUFHLFVBQVUsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7WUFFdEMsSUFBSSxRQUFRLEVBQUUsQ0FBQztnQkFDYixNQUFNLElBQUksS0FBSyxDQUNiLFlBQVksUUFBUSxVQUFVLElBQUksb0JBQW9CLGNBQWMsbUJBQW1CO29CQUNyRix1QkFBdUIsSUFBSSwyREFBMkQsQ0FDekYsQ0FBQztZQUNKLENBQUM7WUFFRCxVQUFVLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQztRQUM3QixDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFTyxNQUFNLENBQUMsV0FBVyxDQUFDLFVBQXNCO1FBQy9DLHlGQUF5RjtRQUN6Riw4RkFBOEY7UUFDOUYsT0FBTyxNQUFNLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDO2FBQ3pDLE1BQU0sQ0FDTCxJQUFJLENBQUMsRUFBRSxDQUNMLGdDQUFXLENBQUMsWUFBWSxDQUFDLFVBQVUsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDO1lBQ2pELENBQUMsZ0NBQVcsQ0FBQyxZQUFZLENBQUMsVUFBVSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsQ0FDckQ7YUFDQSxJQUFJLEVBQUU7YUFDTixHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQywwQkFBcUIsQ0FBQyxXQUFXLENBQUMsVUFBVSxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDdEUsQ0FBQztJQUVPLE1BQU0sQ0FBQyxhQUFhLENBQUMsVUFBc0I7UUFDakQsT0FBTyxVQUFVLENBQUMsTUFBTSxDQUFDLFFBQVE7YUFDOUIsSUFBSSxFQUFFO2FBQ04sR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsNEJBQXVCLENBQUMsV0FBVyxDQUFDLFVBQVUsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQ3hFLENBQUM7Q0FDRjtBQTVFRCw0Q0E0RUMifQ==
|