@forestadmin/workflow-executor 1.13.0 → 1.15.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 +18 -0
- package/dist/adapters/ai-client-adapter.d.ts +5 -1
- package/dist/adapters/ai-client-adapter.js +4 -1
- package/dist/adapters/always-error-ai-model-port.d.ts +5 -1
- package/dist/adapters/always-error-ai-model-port.js +6 -1
- package/dist/adapters/server-ai-adapter.d.ts +5 -1
- package/dist/adapters/server-ai-adapter.js +4 -1
- package/dist/adapters/step-outcome-to-update-step-mapper.js +4 -1
- package/dist/build-workflow-executor.js +87 -2
- package/dist/crypto/credential-encryption.d.ts +10 -0
- package/dist/crypto/credential-encryption.js +75 -0
- package/dist/defaults.d.ts +1 -0
- package/dist/defaults.js +5 -2
- package/dist/errors.d.ts +22 -0
- package/dist/errors.js +59 -2
- package/dist/executors/load-related-record-step-executor.d.ts +4 -9
- package/dist/executors/load-related-record-step-executor.js +164 -97
- package/dist/executors/mcp-step-executor.d.ts +7 -2
- package/dist/executors/mcp-step-executor.js +78 -14
- package/dist/executors/step-executor-factory.d.ts +1 -1
- package/dist/executors/step-executor-factory.js +24 -3
- package/dist/http/executor-http-server.d.ts +12 -0
- package/dist/http/executor-http-server.js +90 -1
- package/dist/http/mcp-oauth-credentials.d.ts +24 -0
- package/dist/http/mcp-oauth-credentials.js +77 -0
- package/dist/http/step-serializer.js +5 -2
- package/dist/index.d.ts +7 -1
- package/dist/index.js +10 -3
- package/dist/oauth/keyed-mutex.d.ts +5 -0
- package/dist/oauth/keyed-mutex.js +27 -0
- package/dist/oauth/refresh-grant.d.ts +15 -0
- package/dist/oauth/refresh-grant.js +112 -0
- package/dist/oauth/token-endpoint-url.d.ts +2 -0
- package/dist/oauth/token-endpoint-url.js +103 -0
- package/dist/oauth/token-service.d.ts +34 -0
- package/dist/oauth/token-service.js +172 -0
- package/dist/ports/ai-model-port.d.ts +5 -1
- package/dist/ports/mcp-oauth-credentials-store.d.ts +24 -0
- package/dist/ports/mcp-oauth-credentials-store.js +3 -0
- package/dist/ports/run-store.d.ts +1 -0
- package/dist/remote-tool-fetcher.d.ts +7 -2
- package/dist/remote-tool-fetcher.js +53 -6
- package/dist/runner.d.ts +2 -0
- package/dist/runner.js +3 -3
- package/dist/stores/database-mcp-oauth-credentials-store.d.ts +22 -0
- package/dist/stores/database-mcp-oauth-credentials-store.js +188 -0
- package/dist/stores/database-store.d.ts +1 -1
- package/dist/stores/database-store.js +17 -50
- package/dist/stores/in-memory-mcp-oauth-credentials-store.d.ts +13 -0
- package/dist/stores/in-memory-mcp-oauth-credentials-store.js +44 -0
- package/dist/stores/in-memory-store.d.ts +1 -0
- package/dist/stores/in-memory-store.js +6 -1
- package/dist/stores/schema-migrations.d.ts +19 -0
- package/dist/stores/schema-migrations.js +69 -0
- package/dist/types/step-execution-data.d.ts +2 -1
- package/dist/types/validated/execution.d.ts +15 -6
- package/dist/types/validated/step-definition.d.ts +9 -6
- package/dist/types/validated/step-definition.js +4 -4
- package/dist/types/validated/step-outcome.d.ts +10 -0
- package/dist/types/validated/step-outcome.js +7 -2
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -128,6 +128,20 @@ npx @forestadmin/workflow-executor
|
|
|
128
128
|
|
|
129
129
|
---
|
|
130
130
|
|
|
131
|
+
## OAuth-protected MCP connectors
|
|
132
|
+
|
|
133
|
+
When your workflows use OAuth-protected MCP connectors, the executor stores each user's OAuth credentials in its database, encrypted at rest. Provide the encryption key the same way as the other secrets (in `.env`, or with `-e` on `docker run`):
|
|
134
|
+
|
|
135
|
+
| Variable | Description |
|
|
136
|
+
| --- | --- |
|
|
137
|
+
| `FOREST_EXECUTOR_ENCRYPTION_KEY` | At-rest encryption key (AES-256-GCM) for the OAuth credentials the executor stores. Generate with `openssl rand -hex 32`. Use a **separate** secret from `FOREST_AUTH_SECRET`. The value isn't validated, so use a genuinely random secret. |
|
|
138
|
+
|
|
139
|
+
- **Required only for OAuth-protected MCP connectors**, and read lazily — an executor that stores no such credentials boots and runs fine without it.
|
|
140
|
+
- **Use the same value on every instance that shares a database.** Otherwise an instance cannot decrypt credentials stored by another.
|
|
141
|
+
- **Treat it as permanent: there is no managed rotation.** Changing it forces every affected user to reconnect their OAuth-protected MCP connectors.
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
131
145
|
## Testing only
|
|
132
146
|
|
|
133
147
|
The following modes skip the database requirement but are **not suitable for production** — state is lost on restart.
|
|
@@ -152,3 +166,7 @@ FOREST_AUTH_SECRET="your-auth-secret" \
|
|
|
152
166
|
AGENT_URL="https://your-agent-url" \
|
|
153
167
|
npx @forestadmin/workflow-executor --in-memory
|
|
154
168
|
```
|
|
169
|
+
|
|
170
|
+
### OAuth2-protected MCP
|
|
171
|
+
|
|
172
|
+
To exercise the executor's OAuth2-protected MCP path end-to-end, point it at [mcp-oauth-test-server](https://github.com/hercemer42/mcp-oauth-test-server) — a standalone OAuth2 + MCP server that can simulate refresh-token revocation/rotation, consent denial, and upstream 403s.
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import type { AiModelPort, GetModelOptions } from '../ports/ai-model-port';
|
|
2
|
-
import type { AiConfiguration, BaseChatModel, RemoteTool, ToolConfig } from '@forestadmin/ai-proxy';
|
|
2
|
+
import type { AiConfiguration, BaseChatModel, McpServerLoadFailure, RemoteTool, ToolConfig } from '@forestadmin/ai-proxy';
|
|
3
3
|
export default class AiClientAdapter implements AiModelPort {
|
|
4
4
|
private readonly aiClient;
|
|
5
5
|
constructor(aiConfigurations: AiConfiguration[]);
|
|
6
6
|
getModel({ aiConfigName }?: GetModelOptions): BaseChatModel;
|
|
7
7
|
loadRemoteTools(configs: Record<string, ToolConfig>): Promise<RemoteTool[]>;
|
|
8
|
+
loadRemoteToolsWithFailures(configs: Record<string, ToolConfig>): Promise<{
|
|
9
|
+
tools: RemoteTool[];
|
|
10
|
+
failures: McpServerLoadFailure[];
|
|
11
|
+
}>;
|
|
8
12
|
closeConnections(): Promise<void>;
|
|
9
13
|
private callPort;
|
|
10
14
|
}
|
|
@@ -20,6 +20,9 @@ class AiClientAdapter {
|
|
|
20
20
|
loadRemoteTools(configs) {
|
|
21
21
|
return this.callPort('loadRemoteTools', () => this.aiClient.loadRemoteTools(configs));
|
|
22
22
|
}
|
|
23
|
+
loadRemoteToolsWithFailures(configs) {
|
|
24
|
+
return this.callPort('loadRemoteToolsWithFailures', () => this.aiClient.loadRemoteToolsWithFailures(configs));
|
|
25
|
+
}
|
|
23
26
|
closeConnections() {
|
|
24
27
|
return this.callPort('closeConnections', () => this.aiClient.closeConnections());
|
|
25
28
|
}
|
|
@@ -35,4 +38,4 @@ class AiClientAdapter {
|
|
|
35
38
|
}
|
|
36
39
|
}
|
|
37
40
|
exports.default = AiClientAdapter;
|
|
38
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
41
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWktY2xpZW50LWFkYXB0ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYWRhcHRlcnMvYWktY2xpZW50LWFkYXB0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFTQSxvREFBaUQ7QUFFakQsc0NBQW9FO0FBRXBFLE1BQXFCLGVBQWU7SUFHbEMsWUFBWSxnQkFBbUM7UUFDN0MsTUFBTSxXQUFXLEdBQUcsZ0JBQWdCLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLFVBQVUsRUFBRSxDQUFDLEVBQUUsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFDekUsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLG1CQUFRLENBQUMsRUFBRSxnQkFBZ0IsRUFBRSxXQUFnQyxFQUFFLENBQUMsQ0FBQztJQUN2RixDQUFDO0lBRUQsUUFBUSxDQUFDLEVBQUUsWUFBWSxLQUFzQixFQUFFO1FBQzdDLElBQUksQ0FBQztZQUNILE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsWUFBWSxDQUFDLENBQUM7UUFDOUMsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixJQUFJLEtBQUssWUFBWSw4QkFBcUI7Z0JBQUUsTUFBTSxLQUFLLENBQUM7WUFDeEQsTUFBTSxJQUFJLHlCQUFnQixDQUFDLFVBQVUsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUNoRCxDQUFDO0lBQ0gsQ0FBQztJQUVELGVBQWUsQ0FBQyxPQUFtQztRQUNqRCxPQUFPLElBQUksQ0FBQyxRQUFRLENBQUMsaUJBQWlCLEVBQUUsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxlQUFlLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQztJQUN4RixDQUFDO0lBRUQsMkJBQTJCLENBQ3pCLE9BQW1DO1FBRW5DLE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQyw2QkFBNkIsRUFBRSxHQUFHLEVBQUUsQ0FDdkQsSUFBSSxDQUFDLFFBQVEsQ0FBQywyQkFBMkIsQ0FBQyxPQUFPLENBQUMsQ0FDbkQsQ0FBQztJQUNKLENBQUM7SUFFRCxnQkFBZ0I7UUFDZCxPQUFPLElBQUksQ0FBQyxRQUFRLENBQUMsa0JBQWtCLEVBQUUsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDLENBQUM7SUFDbkYsQ0FBQztJQUVPLEtBQUssQ0FBQyxRQUFRLENBQUksU0FBaUIsRUFBRSxFQUFvQjtRQUMvRCxJQUFJLENBQUM7WUFDSCxPQUFPLE1BQU0sRUFBRSxFQUFFLENBQUM7UUFDcEIsQ0FBQztRQUFDLE9BQU8sS0FBSyxFQUFFLENBQUM7WUFDZixJQUFJLEtBQUssWUFBWSw4QkFBcUI7Z0JBQUUsTUFBTSxLQUFLLENBQUM7WUFDeEQsTUFBTSxJQUFJLHlCQUFnQixDQUFDLFNBQVMsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUMvQyxDQUFDO0lBQ0gsQ0FBQztDQUNGO0FBekNELGtDQXlDQyJ9
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import type { AiModelPort } from '../ports/ai-model-port';
|
|
2
|
-
import type { BaseChatModel, RemoteTool, ToolConfig } from '@forestadmin/ai-proxy';
|
|
2
|
+
import type { BaseChatModel, McpServerLoadFailure, RemoteTool, ToolConfig } from '@forestadmin/ai-proxy';
|
|
3
3
|
export default class AlwaysErrorAiModelPort implements AiModelPort {
|
|
4
4
|
getModel(): BaseChatModel;
|
|
5
5
|
loadRemoteTools(_configs: Record<string, ToolConfig>): Promise<RemoteTool[]>;
|
|
6
|
+
loadRemoteToolsWithFailures(_configs: Record<string, ToolConfig>): Promise<{
|
|
7
|
+
tools: RemoteTool[];
|
|
8
|
+
failures: McpServerLoadFailure[];
|
|
9
|
+
}>;
|
|
6
10
|
closeConnections(): Promise<void>;
|
|
7
11
|
}
|
|
8
12
|
//# sourceMappingURL=always-error-ai-model-port.d.ts.map
|
|
@@ -15,9 +15,14 @@ class AlwaysErrorAiModelPort {
|
|
|
15
15
|
loadRemoteTools(_configs) {
|
|
16
16
|
return Promise.resolve([]);
|
|
17
17
|
}
|
|
18
|
+
loadRemoteToolsWithFailures(
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
20
|
+
_configs) {
|
|
21
|
+
return Promise.resolve({ tools: [], failures: [] });
|
|
22
|
+
}
|
|
18
23
|
closeConnections() {
|
|
19
24
|
return Promise.resolve();
|
|
20
25
|
}
|
|
21
26
|
}
|
|
22
27
|
exports.default = AlwaysErrorAiModelPort;
|
|
23
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
28
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWx3YXlzLWVycm9yLWFpLW1vZGVsLXBvcnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYWRhcHRlcnMvYWx3YXlzLWVycm9yLWFpLW1vZGVsLXBvcnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFRQSxzQ0FBNkM7QUFFN0MsMEZBQTBGO0FBQzFGLGdFQUFnRTtBQUNoRSxNQUFxQixzQkFBc0I7SUFDekMsUUFBUTtRQUNOLE9BQU87WUFDTCxTQUFTLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQztnQkFDaEIsTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUNYLE9BQU8sQ0FBQyxNQUFNLENBQ1osSUFBSSx5QkFBZ0IsQ0FBQyxRQUFRLEVBQUUsSUFBSSxLQUFLLENBQUMsaUNBQWlDLENBQUMsQ0FBQyxDQUM3RTthQUNKLENBQUM7U0FDeUIsQ0FBQztJQUNoQyxDQUFDO0lBRUQsNkRBQTZEO0lBQzdELGVBQWUsQ0FBQyxRQUFvQztRQUNsRCxPQUFPLE9BQU8sQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDN0IsQ0FBQztJQUVELDJCQUEyQjtJQUN6Qiw2REFBNkQ7SUFDN0QsUUFBb0M7UUFFcEMsT0FBTyxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUUsS0FBSyxFQUFFLEVBQUUsRUFBRSxRQUFRLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUN0RCxDQUFDO0lBRUQsZ0JBQWdCO1FBQ2QsT0FBTyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUM7SUFDM0IsQ0FBQztDQUNGO0FBM0JELHlDQTJCQyJ9
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AiModelPort, GetModelOptions } from '../ports/ai-model-port';
|
|
2
|
-
import type { BaseChatModel, RemoteTool, ToolConfig } from '@forestadmin/ai-proxy';
|
|
2
|
+
import type { BaseChatModel, McpServerLoadFailure, RemoteTool, ToolConfig } from '@forestadmin/ai-proxy';
|
|
3
3
|
export interface ServerAiAdapterOptions {
|
|
4
4
|
forestServerUrl: string;
|
|
5
5
|
envSecret: string;
|
|
@@ -10,6 +10,10 @@ export default class ServerAiAdapter implements AiModelPort {
|
|
|
10
10
|
constructor(options: ServerAiAdapterOptions);
|
|
11
11
|
getModel({ userId }?: GetModelOptions): BaseChatModel;
|
|
12
12
|
loadRemoteTools(configs: Record<string, ToolConfig>): Promise<RemoteTool[]>;
|
|
13
|
+
loadRemoteToolsWithFailures(configs: Record<string, ToolConfig>): Promise<{
|
|
14
|
+
tools: RemoteTool[];
|
|
15
|
+
failures: McpServerLoadFailure[];
|
|
16
|
+
}>;
|
|
13
17
|
closeConnections(): Promise<void>;
|
|
14
18
|
private static buildProxyConfiguration;
|
|
15
19
|
private callPort;
|
|
@@ -25,6 +25,9 @@ class ServerAiAdapter {
|
|
|
25
25
|
loadRemoteTools(configs) {
|
|
26
26
|
return this.callPort('loadRemoteTools', () => this.aiClient.loadRemoteTools(configs));
|
|
27
27
|
}
|
|
28
|
+
loadRemoteToolsWithFailures(configs) {
|
|
29
|
+
return this.callPort('loadRemoteToolsWithFailures', () => this.aiClient.loadRemoteToolsWithFailures(configs));
|
|
30
|
+
}
|
|
28
31
|
closeConnections() {
|
|
29
32
|
return this.callPort('closeConnections', () => this.aiClient.closeConnections());
|
|
30
33
|
}
|
|
@@ -64,4 +67,4 @@ class ServerAiAdapter {
|
|
|
64
67
|
}
|
|
65
68
|
}
|
|
66
69
|
exports.default = ServerAiAdapter;
|
|
67
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
70
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmVyLWFpLWFkYXB0ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYWRhcHRlcnMvc2VydmVyLWFpLWFkYXB0ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFTQSxvREFBaUQ7QUFFakQsc0NBQW9FO0FBT3BFLE1BQXFCLGVBQWU7SUFJbEMsWUFBWSxPQUErQjtRQUN6QyxJQUFJLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQztRQUN2QixJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksbUJBQVEsQ0FBQztZQUMzQixnQkFBZ0IsRUFBRSxDQUFDLGVBQWUsQ0FBQyx1QkFBdUIsQ0FBQyxPQUFPLENBQUMsQ0FBQztTQUNyRSxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQsUUFBUSxDQUFDLEVBQUUsTUFBTSxLQUFzQixFQUFFO1FBQ3ZDLElBQUksQ0FBQztZQUNILE1BQU0sTUFBTSxHQUFHLElBQUksbUJBQVEsQ0FBQztnQkFDMUIsZ0JBQWdCLEVBQUUsQ0FBQyxlQUFlLENBQUMsdUJBQXVCLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxNQUFNLENBQUMsQ0FBQzthQUNsRixDQUFDLENBQUM7WUFFSCxPQUFPLE1BQU0sQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUMzQixDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLElBQUksS0FBSyxZQUFZLDhCQUFxQjtnQkFBRSxNQUFNLEtBQUssQ0FBQztZQUN4RCxNQUFNLElBQUkseUJBQWdCLENBQUMsVUFBVSxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQ2hELENBQUM7SUFDSCxDQUFDO0lBRUQsZUFBZSxDQUFDLE9BQW1DO1FBQ2pELE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQyxpQkFBaUIsRUFBRSxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLGVBQWUsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO0lBQ3hGLENBQUM7SUFFRCwyQkFBMkIsQ0FDekIsT0FBbUM7UUFFbkMsT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDLDZCQUE2QixFQUFFLEdBQUcsRUFBRSxDQUN2RCxJQUFJLENBQUMsUUFBUSxDQUFDLDJCQUEyQixDQUFDLE9BQU8sQ0FBQyxDQUNuRCxDQUFDO0lBQ0osQ0FBQztJQUVELGdCQUFnQjtRQUNkLE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQyxrQkFBa0IsRUFBRSxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLGdCQUFnQixFQUFFLENBQUMsQ0FBQztJQUNuRixDQUFDO0lBRUQsNkZBQTZGO0lBQzdGLDhGQUE4RjtJQUM5Rix3REFBd0Q7SUFDaEQsTUFBTSxDQUFDLHVCQUF1QixDQUNwQyxFQUFFLGVBQWUsRUFBRSxTQUFTLEVBQTBCLEVBQ3RELE1BQWU7UUFFZixNQUFNLFVBQVUsR0FBRyxHQUFHLGVBQWUsb0JBQW9CLENBQUM7UUFFMUQsT0FBTztZQUNMLElBQUksRUFBRSxlQUFlO1lBQ3JCLFFBQVEsRUFBRSxRQUFRO1lBQ2xCLEtBQUssRUFBRSxTQUFTO1lBQ2hCLFVBQVUsRUFBRSxDQUFDO1lBQ2IsYUFBYSxFQUFFO2dCQUNiLE1BQU0sRUFBRSxRQUFRO2dCQUNoQixLQUFLLEVBQUUsQ0FBQyxJQUF1QixFQUFFLElBQWtCLEVBQUUsRUFBRTtvQkFDckQsTUFBTSxPQUFPLEdBQUcsSUFBSSxPQUFPLENBQUMsSUFBSSxFQUFFLE9BQU8sQ0FBQyxDQUFDO29CQUMzQyxPQUFPLENBQUMsTUFBTSxDQUFDLGVBQWUsQ0FBQyxDQUFDO29CQUNoQyxPQUFPLENBQUMsR0FBRyxDQUFDLG1CQUFtQixFQUFFLFNBQVMsQ0FBQyxDQUFDO29CQUM1QyxnRkFBZ0Y7b0JBQ2hGLElBQUksTUFBTSxLQUFLLFNBQVM7d0JBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxTQUFTLEVBQUUsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7b0JBRWpFLE9BQU8sS0FBSyxDQUFDLFVBQVUsRUFBRSxFQUFFLEdBQUcsSUFBSSxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUM7Z0JBQ2pELENBQUM7YUFDRjtTQUNGLENBQUM7SUFDSixDQUFDO0lBRU8sS0FBSyxDQUFDLFFBQVEsQ0FBSSxTQUFpQixFQUFFLEVBQW9CO1FBQy9ELElBQUksQ0FBQztZQUNILE9BQU8sTUFBTSxFQUFFLEVBQUUsQ0FBQztRQUNwQixDQUFDO1FBQUMsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNmLElBQUksS0FBSyxZQUFZLDhCQUFxQjtnQkFBRSxNQUFNLEtBQUssQ0FBQztZQUN4RCxNQUFNLElBQUkseUJBQWdCLENBQUMsU0FBUyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQy9DLENBQUM7SUFDSCxDQUFDO0NBQ0Y7QUE3RUQsa0NBNkVDIn0=
|
|
@@ -24,6 +24,9 @@ function toUpdateStepRequest(runId, outcome) {
|
|
|
24
24
|
if (outcome.type === 'record' && outcome.approvalRequest !== undefined) {
|
|
25
25
|
context.approvalRequest = outcome.approvalRequest;
|
|
26
26
|
}
|
|
27
|
+
if (outcome.type === 'mcp' && outcome.awaitingInputReason !== undefined) {
|
|
28
|
+
context.awaitingInputReason = outcome.awaitingInputReason;
|
|
29
|
+
}
|
|
27
30
|
const attributes = {
|
|
28
31
|
done: outcome.status !== 'awaiting-input',
|
|
29
32
|
context,
|
|
@@ -34,4 +37,4 @@ function toUpdateStepRequest(runId, outcome) {
|
|
|
34
37
|
executionStatus: toExecutionStatus(outcome),
|
|
35
38
|
};
|
|
36
39
|
}
|
|
37
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
40
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RlcC1vdXRjb21lLXRvLXVwZGF0ZS1zdGVwLW1hcHBlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hZGFwdGVycy9zdGVwLW91dGNvbWUtdG8tdXBkYXRlLXN0ZXAtbWFwcGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBdUJBLHNDQTZCQztBQTdDRCxTQUFTLGlCQUFpQixDQUFDLE9BQW9CO0lBQzdDLElBQUksT0FBTyxDQUFDLE1BQU0sS0FBSyxPQUFPLEVBQUUsQ0FBQztRQUMvQiwwRUFBMEU7UUFDMUUsaUZBQWlGO1FBQ2pGLE9BQU8sRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxPQUFPLENBQUMsS0FBSyxJQUFJLGVBQWUsRUFBRSxDQUFDO0lBQ3RFLENBQUM7SUFFRCxJQUFJLE9BQU8sQ0FBQyxNQUFNLEtBQUssZ0JBQWdCLEVBQUUsQ0FBQztRQUN4QyxPQUFPLEVBQUUsSUFBSSxFQUFFLGdCQUFnQixFQUFFLENBQUM7SUFDcEMsQ0FBQztJQUVELE9BQU8sRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLENBQUM7QUFDN0IsQ0FBQztBQUVELG1HQUFtRztBQUNuRyxxRUFBcUU7QUFDckUsU0FBd0IsbUJBQW1CLENBQ3pDLEtBQWEsRUFDYixPQUFvQjtJQUVwQixNQUFNLE9BQU8sR0FBNEIsRUFBRSxNQUFNLEVBQUUsT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDO0lBQ3BFLElBQUksT0FBTyxDQUFDLEtBQUssS0FBSyxTQUFTO1FBQUUsT0FBTyxDQUFDLEtBQUssR0FBRyxPQUFPLENBQUMsS0FBSyxDQUFDO0lBRS9ELElBQUksT0FBTyxDQUFDLElBQUksS0FBSyxXQUFXLElBQUksT0FBTyxDQUFDLGNBQWMsS0FBSyxTQUFTLEVBQUUsQ0FBQztRQUN6RSxPQUFPLENBQUMsY0FBYyxHQUFHLE9BQU8sQ0FBQyxjQUFjLENBQUM7SUFDbEQsQ0FBQztJQUVELElBQUksT0FBTyxDQUFDLElBQUksS0FBSyxRQUFRLElBQUksT0FBTyxDQUFDLGVBQWUsS0FBSyxTQUFTLEVBQUUsQ0FBQztRQUN2RSxPQUFPLENBQUMsZUFBZSxHQUFHLE9BQU8sQ0FBQyxlQUFlLENBQUM7SUFDcEQsQ0FBQztJQUVELElBQUksT0FBTyxDQUFDLElBQUksS0FBSyxLQUFLLElBQUksT0FBTyxDQUFDLG1CQUFtQixLQUFLLFNBQVMsRUFBRSxDQUFDO1FBQ3hFLE9BQU8sQ0FBQyxtQkFBbUIsR0FBRyxPQUFPLENBQUMsbUJBQW1CLENBQUM7SUFDNUQsQ0FBQztJQUVELE1BQU0sVUFBVSxHQUE0QjtRQUMxQyxJQUFJLEVBQUUsT0FBTyxDQUFDLE1BQU0sS0FBSyxnQkFBZ0I7UUFDekMsT0FBTztLQUNSLENBQUM7SUFFRixPQUFPO1FBQ0wsS0FBSyxFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUM7UUFDcEIsVUFBVSxFQUFFLEVBQUUsU0FBUyxFQUFFLE9BQU8sQ0FBQyxTQUFTLEVBQUUsVUFBVSxFQUFFO1FBQ3hELGVBQWUsRUFBRSxpQkFBaUIsQ0FBQyxPQUFPLENBQUM7S0FDNUMsQ0FBQztBQUNKLENBQUMifQ==
|
|
@@ -1,4 +1,37 @@
|
|
|
1
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
|
+
})();
|
|
2
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
37
|
};
|
|
@@ -14,11 +47,16 @@ const console_logger_1 = __importDefault(require("./adapters/console-logger"));
|
|
|
14
47
|
const forest_server_workflow_port_1 = __importDefault(require("./adapters/forest-server-workflow-port"));
|
|
15
48
|
const forestadmin_client_activity_log_port_factory_1 = __importDefault(require("./adapters/forestadmin-client-activity-log-port-factory"));
|
|
16
49
|
const server_ai_adapter_1 = __importDefault(require("./adapters/server-ai-adapter"));
|
|
50
|
+
const credential_encryption_1 = __importStar(require("./crypto/credential-encryption"));
|
|
17
51
|
const defaults_1 = require("./defaults");
|
|
18
52
|
const executor_http_server_1 = __importDefault(require("./http/executor-http-server"));
|
|
53
|
+
const token_service_1 = __importDefault(require("./oauth/token-service"));
|
|
54
|
+
const remote_tool_fetcher_1 = __importDefault(require("./remote-tool-fetcher"));
|
|
19
55
|
const runner_1 = __importDefault(require("./runner"));
|
|
20
56
|
const schema_cache_1 = __importDefault(require("./schema-cache"));
|
|
57
|
+
const database_mcp_oauth_credentials_store_1 = __importDefault(require("./stores/database-mcp-oauth-credentials-store"));
|
|
21
58
|
const database_store_1 = __importDefault(require("./stores/database-store"));
|
|
59
|
+
const in_memory_mcp_oauth_credentials_store_1 = __importDefault(require("./stores/in-memory-mcp-oauth-credentials-store"));
|
|
22
60
|
const in_memory_store_1 = __importDefault(require("./stores/in-memory-store"));
|
|
23
61
|
const FORCE_EXIT_DELAY_S = 5;
|
|
24
62
|
// A bad timeout config (0, negative, non-finite) must fall back to the default rather than
|
|
@@ -29,6 +67,11 @@ function positiveOrDefault(value, fallback) {
|
|
|
29
67
|
function buildCommonDependencies(options) {
|
|
30
68
|
const forestServerUrl = options.forestServerUrl ?? defaults_1.DEFAULT_FOREST_SERVER_URL;
|
|
31
69
|
const logger = options.logger ?? (0, console_logger_1.default)(options.loggerLevel ?? defaults_1.DEFAULT_LOGGER_LEVEL);
|
|
70
|
+
// Lazy key by design (OAuth-less executors boot without it), but surface a security-relevant
|
|
71
|
+
// heads-up so a missing key isn't discovered only when a deposit 503s.
|
|
72
|
+
if (!(0, credential_encryption_1.isExecutorEncryptionKeyConfigured)()) {
|
|
73
|
+
logger('Warn', 'FOREST_EXECUTOR_ENCRYPTION_KEY is not set — OAuth-protected MCP servers are unavailable (credential deposits return 503) until it is configured.');
|
|
74
|
+
}
|
|
32
75
|
const workflowPort = new forest_server_workflow_port_1.default({
|
|
33
76
|
envSecret: options.envSecret,
|
|
34
77
|
forestServerUrl,
|
|
@@ -120,7 +163,15 @@ function createWorkflowExecutor(runner, server, logger, manageProcessSignals) {
|
|
|
120
163
|
},
|
|
121
164
|
async start() {
|
|
122
165
|
await runner.start();
|
|
123
|
-
|
|
166
|
+
// server.start() runs the OAuth-store migration; if it fails, don't leave the runner polling
|
|
167
|
+
// in the background — stop it so start() is all-or-nothing.
|
|
168
|
+
try {
|
|
169
|
+
await server.start();
|
|
170
|
+
}
|
|
171
|
+
catch (err) {
|
|
172
|
+
await runner.stop().catch(() => { });
|
|
173
|
+
throw err;
|
|
174
|
+
}
|
|
124
175
|
// Only own the host's signals when explicitly allowed (the standalone CLI). When embedded,
|
|
125
176
|
// the host process must keep control of SIGTERM/SIGINT and its own exit.
|
|
126
177
|
if (manageProcessSignals) {
|
|
@@ -141,9 +192,21 @@ function createWorkflowExecutor(runner, server, logger, manageProcessSignals) {
|
|
|
141
192
|
}
|
|
142
193
|
function buildInMemoryExecutor(options) {
|
|
143
194
|
const deps = buildCommonDependencies(options);
|
|
195
|
+
const mcpOAuthCredentialsStore = new in_memory_mcp_oauth_credentials_store_1.default();
|
|
196
|
+
const credentialEncryption = new credential_encryption_1.default();
|
|
197
|
+
// Shares the store + encryption with the deposit endpoint so runtime reads and writes (rotation)
|
|
198
|
+
// go through the same instance the HTTP server exposes. In-memory is dev-only: credentials live
|
|
199
|
+
// only for the process lifetime, but oauth2 steps work end-to-end just like the database executor.
|
|
200
|
+
const mcpOAuthTokenService = new token_service_1.default({
|
|
201
|
+
store: mcpOAuthCredentialsStore,
|
|
202
|
+
encryption: credentialEncryption,
|
|
203
|
+
logger: deps.logger,
|
|
204
|
+
});
|
|
205
|
+
const remoteToolFetcher = new remote_tool_fetcher_1.default(deps.workflowPort, deps.aiModelPort, deps.logger, mcpOAuthTokenService);
|
|
144
206
|
const runner = new runner_1.default({
|
|
145
207
|
...deps,
|
|
146
208
|
runStore: new in_memory_store_1.default(),
|
|
209
|
+
mcpOAuthTokenService,
|
|
147
210
|
});
|
|
148
211
|
const server = new executor_http_server_1.default({
|
|
149
212
|
port: options.httpPort,
|
|
@@ -151,6 +214,10 @@ function buildInMemoryExecutor(options) {
|
|
|
151
214
|
authSecret: options.authSecret,
|
|
152
215
|
workflowPort: deps.workflowPort,
|
|
153
216
|
logger: deps.logger,
|
|
217
|
+
mcpOAuthCredentialsStore,
|
|
218
|
+
credentialEncryption,
|
|
219
|
+
remoteToolFetcher,
|
|
220
|
+
oauthTokenService: mcpOAuthTokenService,
|
|
154
221
|
});
|
|
155
222
|
return createWorkflowExecutor(runner, server, deps.logger, options.manageProcessSignals ?? true);
|
|
156
223
|
}
|
|
@@ -166,9 +233,23 @@ function buildDatabaseExecutor(options) {
|
|
|
166
233
|
if (mergedOptions.logging === undefined)
|
|
167
234
|
mergedOptions.logging = false;
|
|
168
235
|
const sequelize = uri ? new sequelize_1.Sequelize(uri, mergedOptions) : new sequelize_1.Sequelize(mergedOptions);
|
|
236
|
+
const mcpOAuthCredentialsStore = new database_mcp_oauth_credentials_store_1.default({
|
|
237
|
+
sequelize,
|
|
238
|
+
schema: mergedOptions.schema,
|
|
239
|
+
});
|
|
240
|
+
const credentialEncryption = new credential_encryption_1.default();
|
|
241
|
+
// Shares the store + encryption with the deposit endpoint so runtime reads and writes (rotation)
|
|
242
|
+
// go through the same instance the HTTP server migrates on start.
|
|
243
|
+
const mcpOAuthTokenService = new token_service_1.default({
|
|
244
|
+
store: mcpOAuthCredentialsStore,
|
|
245
|
+
encryption: credentialEncryption,
|
|
246
|
+
logger: deps.logger,
|
|
247
|
+
});
|
|
248
|
+
const remoteToolFetcher = new remote_tool_fetcher_1.default(deps.workflowPort, deps.aiModelPort, deps.logger, mcpOAuthTokenService);
|
|
169
249
|
const runner = new runner_1.default({
|
|
170
250
|
...deps,
|
|
171
251
|
runStore: new database_store_1.default({ sequelize, schema: mergedOptions.schema }),
|
|
252
|
+
mcpOAuthTokenService,
|
|
172
253
|
});
|
|
173
254
|
const server = new executor_http_server_1.default({
|
|
174
255
|
port: options.httpPort,
|
|
@@ -176,7 +257,11 @@ function buildDatabaseExecutor(options) {
|
|
|
176
257
|
authSecret: options.authSecret,
|
|
177
258
|
workflowPort: deps.workflowPort,
|
|
178
259
|
logger: deps.logger,
|
|
260
|
+
mcpOAuthCredentialsStore,
|
|
261
|
+
credentialEncryption,
|
|
262
|
+
remoteToolFetcher,
|
|
263
|
+
oauthTokenService: mcpOAuthTokenService,
|
|
179
264
|
});
|
|
180
265
|
return createWorkflowExecutor(runner, server, deps.logger, options.manageProcessSignals ?? true);
|
|
181
266
|
}
|
|
182
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
267
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnVpbGQtd29ya2Zsb3ctZXhlY3V0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvYnVpbGQtd29ya2Zsb3ctZXhlY3V0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUE0T0Esc0RBd0NDO0FBRUQsc0RBbURDO0FBcFVELHdFQUFxRjtBQUNyRix5Q0FBc0M7QUFFdEMsaUdBQXNFO0FBQ3RFLHFGQUEyRDtBQUMzRCx1R0FBMkU7QUFDM0UsK0VBQTREO0FBQzVELHlHQUE4RTtBQUM5RSwySUFBOEc7QUFDOUcscUZBQTJEO0FBQzNELHdGQUV3QztBQUN4Qyx5Q0FPb0I7QUFDcEIsdUZBQTZEO0FBQzdELDBFQUFzRDtBQUN0RCxnRkFBc0Q7QUFDdEQsc0RBQThCO0FBQzlCLGtFQUF5QztBQUN6Qyx5SEFBNkY7QUFDN0YsNkVBQW9EO0FBQ3BELDJIQUE4RjtBQUM5RiwrRUFBcUQ7QUFFckQsTUFBTSxrQkFBa0IsR0FBRyxDQUFDLENBQUM7QUFxQzdCLDJGQUEyRjtBQUMzRiw2RkFBNkY7QUFDN0YsU0FBUyxpQkFBaUIsQ0FBQyxLQUF5QixFQUFFLFFBQWdCO0lBQ3BFLE9BQU8sT0FBTyxLQUFLLEtBQUssUUFBUSxJQUFJLE1BQU0sQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLElBQUksS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUM7QUFDN0YsQ0FBQztBQUVELFNBQVMsdUJBQXVCLENBQUMsT0FBd0I7SUFDdkQsTUFBTSxlQUFlLEdBQUcsT0FBTyxDQUFDLGVBQWUsSUFBSSxvQ0FBeUIsQ0FBQztJQUM3RSxNQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsTUFBTSxJQUFJLElBQUEsd0JBQW1CLEVBQUMsT0FBTyxDQUFDLFdBQVcsSUFBSSwrQkFBb0IsQ0FBQyxDQUFDO0lBRWxHLDZGQUE2RjtJQUM3Rix1RUFB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
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare function isExecutorEncryptionKeyConfigured(): boolean;
|
|
2
|
+
export interface EncryptedValue {
|
|
3
|
+
ciphertext: Buffer;
|
|
4
|
+
}
|
|
5
|
+
export default class CredentialEncryption {
|
|
6
|
+
encrypt(plaintext: string): EncryptedValue;
|
|
7
|
+
decrypt(value: Buffer): string;
|
|
8
|
+
private deriveKey;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=credential-encryption.d.ts.map
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isExecutorEncryptionKeyConfigured = isExecutorEncryptionKeyConfigured;
|
|
4
|
+
const crypto_1 = require("crypto");
|
|
5
|
+
const errors_1 = require("../errors");
|
|
6
|
+
const ENV_KEY = 'FOREST_EXECUTOR_ENCRYPTION_KEY';
|
|
7
|
+
// Fixed context label bound into the HKDF derivation — domain-separates this key from any other
|
|
8
|
+
// use of the same secret. Changing it would make every existing row undecryptable.
|
|
9
|
+
const HKDF_INFO = 'forest-executor:mcp-oauth-credentials';
|
|
10
|
+
const HKDF_DIGEST = 'sha256';
|
|
11
|
+
const KEY_BYTES = 32; // AES-256
|
|
12
|
+
const IV_BYTES = 12; // GCM standard nonce length
|
|
13
|
+
const AUTH_TAG_BYTES = 16;
|
|
14
|
+
const ALGORITHM = 'aes-256-gcm';
|
|
15
|
+
// Boot-time check (no derivation, no throw): is the at-rest key configured? Lets startup emit a
|
|
16
|
+
// warning that OAuth-protected MCP servers are unavailable until it is set. There is deliberately no
|
|
17
|
+
// default key — a hardcoded one would be public in this open-source package and defeat the at-rest
|
|
18
|
+
// encryption (a DB dump would be decryptable with the shipped key).
|
|
19
|
+
function isExecutorEncryptionKeyConfigured() {
|
|
20
|
+
return Boolean(process.env[ENV_KEY]);
|
|
21
|
+
}
|
|
22
|
+
// Concatenate byte arrays without going through Buffer.concat — keeps everything in the concrete
|
|
23
|
+
// Uint8Array<ArrayBuffer> domain the Node crypto types expect.
|
|
24
|
+
function concatBytes(parts) {
|
|
25
|
+
const total = parts.reduce((length, part) => length + part.length, 0);
|
|
26
|
+
const out = new Uint8Array(total);
|
|
27
|
+
let offset = 0;
|
|
28
|
+
for (const part of parts) {
|
|
29
|
+
out.set(part, offset);
|
|
30
|
+
offset += part.length;
|
|
31
|
+
}
|
|
32
|
+
return out;
|
|
33
|
+
}
|
|
34
|
+
// At-rest encryption for secrets the executor stores. The HKDF key (from
|
|
35
|
+
// FOREST_EXECUTOR_ENCRYPTION_KEY) is read lazily — an executor that stores no such secrets boots
|
|
36
|
+
// without it — and fails closed: a missing key throws rather than persisting or returning an
|
|
37
|
+
// unprotected value.
|
|
38
|
+
class CredentialEncryption {
|
|
39
|
+
encrypt(plaintext) {
|
|
40
|
+
const iv = (0, crypto_1.randomFillSync)(new Uint8Array(IV_BYTES));
|
|
41
|
+
const cipher = (0, crypto_1.createCipheriv)(ALGORITHM, this.deriveKey(), iv);
|
|
42
|
+
const encrypted = concatBytes([
|
|
43
|
+
new Uint8Array(cipher.update(plaintext, 'utf8')),
|
|
44
|
+
new Uint8Array(cipher.final()),
|
|
45
|
+
]);
|
|
46
|
+
const authTag = new Uint8Array(cipher.getAuthTag());
|
|
47
|
+
return {
|
|
48
|
+
ciphertext: Buffer.from(concatBytes([iv, authTag, encrypted])),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
decrypt(value) {
|
|
52
|
+
const bytes = new Uint8Array(value);
|
|
53
|
+
const iv = bytes.subarray(0, IV_BYTES);
|
|
54
|
+
const authTag = bytes.subarray(IV_BYTES, IV_BYTES + AUTH_TAG_BYTES);
|
|
55
|
+
const encrypted = bytes.subarray(IV_BYTES + AUTH_TAG_BYTES);
|
|
56
|
+
const decipher = (0, crypto_1.createDecipheriv)(ALGORITHM, this.deriveKey(), iv);
|
|
57
|
+
decipher.setAuthTag(authTag);
|
|
58
|
+
const decrypted = concatBytes([
|
|
59
|
+
new Uint8Array(decipher.update(encrypted)),
|
|
60
|
+
new Uint8Array(decipher.final()),
|
|
61
|
+
]);
|
|
62
|
+
return Buffer.from(decrypted).toString('utf8');
|
|
63
|
+
}
|
|
64
|
+
deriveKey() {
|
|
65
|
+
const secret = process.env[ENV_KEY];
|
|
66
|
+
if (!secret)
|
|
67
|
+
throw new errors_1.ExecutorEncryptionKeyMissingError();
|
|
68
|
+
// Empty salt is intentional: the fixed HKDF_INFO label gives domain separation and the
|
|
69
|
+
// single high-entropy secret needs no salt. Wrap hkdfSync's ArrayBuffer as a concrete
|
|
70
|
+
// Uint8Array<ArrayBuffer> to satisfy CipherKey (Buffer's ArrayBufferLike backing does not).
|
|
71
|
+
return new Uint8Array((0, crypto_1.hkdfSync)(HKDF_DIGEST, secret, new Uint8Array(0), HKDF_INFO, KEY_BYTES));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
exports.default = CredentialEncryption;
|
|
75
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlZGVudGlhbC1lbmNyeXB0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NyeXB0by9jcmVkZW50aWFsLWVuY3J5cHRpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFrQkEsOEVBRUM7QUFwQkQsbUNBQW9GO0FBRXBGLHNDQUE4RDtBQUU5RCxNQUFNLE9BQU8sR0FBRyxnQ0FBZ0MsQ0FBQztBQUNqRCxnR0FBZ0c7QUFDaEcsbUZBQW1GO0FBQ25GLE1BQU0sU0FBUyxHQUFHLHVDQUF1QyxDQUFDO0FBQzFELE1BQU0sV0FBVyxHQUFHLFFBQVEsQ0FBQztBQUM3QixNQUFNLFNBQVMsR0FBRyxFQUFFLENBQUMsQ0FBQyxVQUFVO0FBQ2hDLE1BQU0sUUFBUSxHQUFHLEVBQUUsQ0FBQyxDQUFDLDRCQUE0QjtBQUNqRCxNQUFNLGNBQWMsR0FBRyxFQUFFLENBQUM7QUFDMUIsTUFBTSxTQUFTLEdBQUcsYUFBYSxDQUFDO0FBRWhDLGdHQUFnRztBQUNoRyxxR0FBcUc7QUFDckcsbUdBQW1HO0FBQ25HLG9FQUFvRTtBQUNwRSxTQUFnQixpQ0FBaUM7SUFDL0MsT0FBTyxPQUFPLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO0FBQ3ZDLENBQUM7QUFPRCxpR0FBaUc7QUFDakcsK0RBQStEO0FBQy9ELFNBQVMsV0FBVyxDQUFDLEtBQW1CO0lBQ3RDLE1BQU0sS0FBSyxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxNQUFNLEVBQUUsSUFBSSxFQUFFLEVBQUUsQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQztJQUN0RSxNQUFNLEdBQUcsR0FBRyxJQUFJLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUNsQyxJQUFJLE1BQU0sR0FBRyxDQUFDLENBQUM7SUFFZixLQUFLLE1BQU0sSUFBSSxJQUFJLEtBQUssRUFBRSxDQUFDO1FBQ3pCLEdBQUcs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
|
package/dist/defaults.d.ts
CHANGED
|
@@ -8,4 +8,5 @@ export declare const DEFAULT_STOP_TIMEOUT_S = 30;
|
|
|
8
8
|
export declare const DEFAULT_MAX_CHAIN_DEPTH = 50;
|
|
9
9
|
export declare const DEFAULT_SCHEMA_CACHE_TTL_S: number;
|
|
10
10
|
export declare const DEFAULT_LOGGER_LEVEL: LoggerLevel;
|
|
11
|
+
export declare const DEFAULT_OAUTH_EXPIRY_SKEW_S = 60;
|
|
11
12
|
//# sourceMappingURL=defaults.d.ts.map
|
package/dist/defaults.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DEFAULT_LOGGER_LEVEL = exports.DEFAULT_SCHEMA_CACHE_TTL_S = exports.DEFAULT_MAX_CHAIN_DEPTH = exports.DEFAULT_STOP_TIMEOUT_S = exports.DEFAULT_AI_INVOKE_TIMEOUT_S = exports.DEFAULT_STEP_TIMEOUT_S = exports.DEFAULT_POLLING_INTERVAL_S = exports.DEFAULT_FOREST_SERVER_URL = exports.DEFAULT_HTTP_PORT = void 0;
|
|
3
|
+
exports.DEFAULT_OAUTH_EXPIRY_SKEW_S = exports.DEFAULT_LOGGER_LEVEL = exports.DEFAULT_SCHEMA_CACHE_TTL_S = exports.DEFAULT_MAX_CHAIN_DEPTH = exports.DEFAULT_STOP_TIMEOUT_S = exports.DEFAULT_AI_INVOKE_TIMEOUT_S = exports.DEFAULT_STEP_TIMEOUT_S = exports.DEFAULT_POLLING_INTERVAL_S = exports.DEFAULT_FOREST_SERVER_URL = exports.DEFAULT_HTTP_PORT = void 0;
|
|
4
4
|
exports.DEFAULT_HTTP_PORT = 3400;
|
|
5
5
|
exports.DEFAULT_FOREST_SERVER_URL = 'https://api.forestadmin.com';
|
|
6
6
|
exports.DEFAULT_POLLING_INTERVAL_S = 30;
|
|
@@ -10,4 +10,7 @@ exports.DEFAULT_STOP_TIMEOUT_S = 30;
|
|
|
10
10
|
exports.DEFAULT_MAX_CHAIN_DEPTH = 50;
|
|
11
11
|
exports.DEFAULT_SCHEMA_CACHE_TTL_S = 10 * 60;
|
|
12
12
|
exports.DEFAULT_LOGGER_LEVEL = 'Info';
|
|
13
|
-
|
|
13
|
+
// Refresh an OAuth access token this many seconds before it actually expires, so a token never
|
|
14
|
+
// goes stale mid-request between the skew check and the downstream MCP call.
|
|
15
|
+
exports.DEFAULT_OAUTH_EXPIRY_SKEW_S = 60;
|
|
16
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVmYXVsdHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvZGVmYXVsdHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBRWEsUUFBQSxpQkFBaUIsR0FBRyxJQUFJLENBQUM7QUFDekIsUUFBQSx5QkFBeUIsR0FBRyw2QkFBNkIsQ0FBQztBQUMxRCxRQUFBLDBCQUEwQixHQUFHLEVBQUUsQ0FBQztBQUNoQyxRQUFBLHNCQUFzQixHQUFHLENBQUMsR0FBRyxFQUFFLENBQUM7QUFDaEMsUUFBQSwyQkFBMkIsR0FBRyxFQUFFLENBQUM7QUFDakMsUUFBQSxzQkFBc0IsR0FBRyxFQUFFLENBQUM7QUFDNUIsUUFBQSx1QkFBdUIsR0FBRyxFQUFFLENBQUM7QUFDN0IsUUFBQSwwQkFBMEIsR0FBRyxFQUFFLEdBQUcsRUFBRSxDQUFDO0FBQ3JDLFFBQUEsb0JBQW9CLEdBQWdCLE1BQU0sQ0FBQztBQUN4RCwrRkFBK0Y7QUFDL0YsNkVBQTZFO0FBQ2hFLFFBQUEsMkJBQTJCLEdBQUcsRUFBRSxDQUFDIn0=
|
package/dist/errors.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { MalformedRunInfo } from './ports/workflow-port';
|
|
2
2
|
import type { RecordId } from './types/validated/collection';
|
|
3
|
+
import type { AwaitingInputReason } from './types/validated/step-outcome';
|
|
3
4
|
import type { z } from 'zod';
|
|
4
5
|
export declare function causeMessage(error: unknown): string | undefined;
|
|
5
6
|
export declare function extractErrorMessage(err?: unknown): string | undefined;
|
|
@@ -91,6 +92,10 @@ export declare class StepTimeoutError extends WorkflowExecutorError {
|
|
|
91
92
|
export declare class AiInvokeTimeoutError extends WorkflowExecutorError {
|
|
92
93
|
constructor(timeoutS: number);
|
|
93
94
|
}
|
|
95
|
+
export declare class AiAssistUnavailableError extends WorkflowExecutorError {
|
|
96
|
+
readonly reason: unknown;
|
|
97
|
+
constructor(reason: unknown);
|
|
98
|
+
}
|
|
94
99
|
export declare class NoMcpToolsError extends WorkflowExecutorError {
|
|
95
100
|
constructor(requestedMcpServerId: string);
|
|
96
101
|
}
|
|
@@ -115,6 +120,23 @@ export declare class McpToolInvocationError extends WorkflowExecutorError {
|
|
|
115
120
|
export declare class ConfigurationError extends Error {
|
|
116
121
|
constructor(message: string);
|
|
117
122
|
}
|
|
123
|
+
export declare class OAuthReauthRequiredError extends WorkflowExecutorError {
|
|
124
|
+
readonly awaitingInputReason: AwaitingInputReason;
|
|
125
|
+
constructor(mcpServerId: string, awaitingInputReason?: AwaitingInputReason);
|
|
126
|
+
}
|
|
127
|
+
export declare class OAuthRefreshError extends WorkflowExecutorError {
|
|
128
|
+
constructor(message: string, cause?: unknown);
|
|
129
|
+
}
|
|
130
|
+
export declare class OAuthInvalidGrantError extends WorkflowExecutorError {
|
|
131
|
+
constructor(detail?: string);
|
|
132
|
+
}
|
|
133
|
+
export declare class InvalidTokenEndpointError extends WorkflowExecutorError {
|
|
134
|
+
constructor(reason: string);
|
|
135
|
+
}
|
|
136
|
+
export declare class ExecutorEncryptionKeyMissingError extends Error {
|
|
137
|
+
readonly code = "executor_encryption_key_missing";
|
|
138
|
+
constructor();
|
|
139
|
+
}
|
|
118
140
|
export declare class RunNotFoundError extends NotFoundError {
|
|
119
141
|
constructor(runId: string, cause?: unknown);
|
|
120
142
|
}
|