@desplega.ai/agent-swarm 1.80.0 → 1.80.2
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/openapi.json +399 -14
- package/package.json +3 -1
- package/src/artifact-sdk/server.ts +2 -1
- package/src/be/db.ts +1 -1
- package/src/be/migrations/064_scripts.sql +39 -0
- package/src/be/migrations/065_script_embeddings.sql +7 -0
- package/src/be/migrations/066_scripts_args_json_schema.sql +1 -0
- package/src/be/scripts/db.ts +417 -0
- package/src/be/scripts/embeddings.ts +233 -0
- package/src/be/scripts/extract-schema.ts +55 -0
- package/src/be/scripts/maintenance.ts +9 -0
- package/src/be/scripts/typecheck.ts +199 -0
- package/src/cli.tsx +22 -5
- package/src/commands/artifact.ts +3 -2
- package/src/commands/claude-managed-setup.ts +2 -1
- package/src/commands/codex-login.ts +5 -3
- package/src/commands/onboard.tsx +2 -1
- package/src/commands/runner.ts +153 -20
- package/src/commands/setup.tsx +5 -3
- package/src/hooks/hook.ts +4 -3
- package/src/http/index.ts +40 -29
- package/src/http/memory.ts +28 -0
- package/src/http/openapi.ts +1 -0
- package/src/http/page-proxy.ts +2 -1
- package/src/http/route-def.ts +1 -0
- package/src/http/schedules.ts +37 -0
- package/src/http/scripts.ts +388 -0
- package/src/linear/outbound.ts +9 -2
- package/src/otel.ts +5 -0
- package/src/providers/claude-adapter.ts +23 -1
- package/src/providers/types.ts +8 -0
- package/src/scripts-runtime/ctx.ts +23 -0
- package/src/scripts-runtime/eval-harness.ts +63 -0
- package/src/scripts-runtime/executors/native.ts +232 -0
- package/src/scripts-runtime/executors/registry.ts +16 -0
- package/src/scripts-runtime/executors/types.ts +63 -0
- package/src/scripts-runtime/extract-args-schema.ts +69 -0
- package/src/scripts-runtime/extract-signature.ts +81 -0
- package/src/scripts-runtime/import-allowlist.ts +109 -0
- package/src/scripts-runtime/loader.ts +96 -0
- package/src/scripts-runtime/redacted.ts +48 -0
- package/src/scripts-runtime/sdk-allowlist.ts +29 -0
- package/src/scripts-runtime/stdlib/fetch.ts +46 -0
- package/src/scripts-runtime/stdlib/glob.ts +8 -0
- package/src/scripts-runtime/stdlib/grep.ts +34 -0
- package/src/scripts-runtime/stdlib/index.ts +16 -0
- package/src/scripts-runtime/stdlib/table.ts +17 -0
- package/src/scripts-runtime/swarm-config.ts +35 -0
- package/src/scripts-runtime/swarm-sdk.ts +197 -0
- package/src/scripts-runtime/types/stdlib.d.ts +104 -0
- package/src/scripts-runtime/types/swarm-sdk.d.ts +86 -0
- package/src/server.ts +12 -0
- package/src/tests/api-key.test.ts +33 -0
- package/src/tests/codex-login.test.ts +1 -1
- package/src/tests/error-tracker.test.ts +44 -0
- package/src/tests/linear-outbound-sync.test.ts +109 -0
- package/src/tests/mcp-tools.test.ts +69 -0
- package/src/tests/rate-limit-event.test.ts +292 -0
- package/src/tests/redacted.test.ts +29 -0
- package/src/tests/runner-tool-spans.test.ts +268 -0
- package/src/tests/script-executor-conformance.test.ts +142 -0
- package/src/tests/script-executor-registry.test.ts +17 -0
- package/src/tests/scripts-db.test.ts +329 -0
- package/src/tests/scripts-embeddings.test.ts +291 -0
- package/src/tests/scripts-extract-signature.test.ts +47 -0
- package/src/tests/scripts-http.test.ts +403 -0
- package/src/tests/scripts-import-allowlist.test.ts +55 -0
- package/src/tests/scripts-mcp-e2e.test.ts +269 -0
- package/src/tests/scripts-runtime-secret-egress.test.ts +44 -0
- package/src/tests/scripts-runtime.test.ts +344 -0
- package/src/tests/sdk-allowlist.test.ts +59 -0
- package/src/tests/secret-scrubber.test.ts +35 -1
- package/src/tests/swarm-config.test.ts +38 -0
- package/src/tests/tool-annotations.test.ts +2 -2
- package/src/tests/tool-call-progress.test.ts +30 -0
- package/src/tests/workflow-e2e.test.ts +218 -0
- package/src/tests/workflow-executors.test.ts +32 -2
- package/src/tests/workflow-input-redaction.test.ts +232 -0
- package/src/tests/workflow-swarm-script.test.ts +273 -0
- package/src/tools/memory-rate.ts +2 -1
- package/src/tools/script-common.ts +88 -0
- package/src/tools/script-delete.ts +35 -0
- package/src/tools/script-query-types.ts +37 -0
- package/src/tools/script-run.ts +43 -0
- package/src/tools/script-search.ts +32 -0
- package/src/tools/script-upsert.ts +43 -0
- package/src/tools/tool-config.ts +7 -0
- package/src/types.ts +61 -1
- package/src/utils/api-key.ts +28 -0
- package/src/utils/error-tracker.ts +58 -0
- package/src/utils/page-session.ts +8 -6
- package/src/utils/secret-scrubber.ts +22 -1
- package/src/workflows/engine.ts +12 -4
- package/src/workflows/executors/index.ts +1 -0
- package/src/workflows/executors/registry.ts +2 -0
- package/src/workflows/executors/script.ts +12 -1
- package/src/workflows/executors/swarm-script.ts +170 -0
- package/src/workflows/input.ts +65 -0
- package/src/workflows/recovery.ts +31 -3
- package/src/workflows/resume.ts +43 -5
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { getScript, getScriptVersion } from "../../be/scripts/db";
|
|
3
|
+
import { runScript } from "../../scripts-runtime/loader";
|
|
4
|
+
import type { ExecutorMeta } from "../../types";
|
|
5
|
+
import { BaseExecutor, type ExecutorResult } from "./base";
|
|
6
|
+
|
|
7
|
+
export const SwarmScriptConfigSchema = z.object({
|
|
8
|
+
scriptName: z.string().min(1),
|
|
9
|
+
scope: z.enum(["global", "agent"]).optional(),
|
|
10
|
+
pinHash: z.string().min(1).optional(),
|
|
11
|
+
args: z.record(z.string(), z.unknown()).default({}),
|
|
12
|
+
fsMode: z.enum(["none", "workspace-rw"]).default("none"),
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export const SwarmScriptOutputSchema = z.object({
|
|
16
|
+
result: z.unknown().optional(),
|
|
17
|
+
stdout: z.string(),
|
|
18
|
+
stderr: z.string(),
|
|
19
|
+
truncated: z.object({ stdout: z.boolean(), stderr: z.boolean() }),
|
|
20
|
+
durationMs: z.number(),
|
|
21
|
+
exitCode: z.number(),
|
|
22
|
+
scriptName: z.string(),
|
|
23
|
+
contentHash: z.string(),
|
|
24
|
+
version: z.number(),
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
type SwarmScriptConfig = z.infer<typeof SwarmScriptConfigSchema>;
|
|
28
|
+
type SwarmScriptOutput = z.infer<typeof SwarmScriptOutputSchema>;
|
|
29
|
+
|
|
30
|
+
export class SwarmScriptExecutor extends BaseExecutor<
|
|
31
|
+
typeof SwarmScriptConfigSchema,
|
|
32
|
+
typeof SwarmScriptOutputSchema
|
|
33
|
+
> {
|
|
34
|
+
readonly type = "swarm-script";
|
|
35
|
+
readonly mode = "instant" as const;
|
|
36
|
+
readonly configSchema = SwarmScriptConfigSchema;
|
|
37
|
+
readonly outputSchema = SwarmScriptOutputSchema;
|
|
38
|
+
|
|
39
|
+
protected async execute(
|
|
40
|
+
config: SwarmScriptConfig,
|
|
41
|
+
context: Readonly<Record<string, unknown>>,
|
|
42
|
+
meta: ExecutorMeta,
|
|
43
|
+
): Promise<ExecutorResult<SwarmScriptOutput>> {
|
|
44
|
+
if (config.fsMode === "workspace-rw") {
|
|
45
|
+
return {
|
|
46
|
+
status: "failed",
|
|
47
|
+
error: "swarm-script: fsMode 'workspace-rw' is v2 only; use 'none' or omit",
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const workflow = this.deps.db.getWorkflow(meta.workflowId);
|
|
52
|
+
const agentId = workflow?.createdByAgentId ?? agentIdFromContext(context);
|
|
53
|
+
const resolved = resolveScriptSource(config, agentId);
|
|
54
|
+
|
|
55
|
+
if (!resolved.ok) {
|
|
56
|
+
return { status: "failed", error: resolved.error };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const output = await runScript({
|
|
60
|
+
source: resolved.source,
|
|
61
|
+
args: config.args,
|
|
62
|
+
fsMode: "none",
|
|
63
|
+
agentId: agentId ?? "workflow",
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const workflowOutput = {
|
|
67
|
+
result: output.result,
|
|
68
|
+
stdout: output.stdout,
|
|
69
|
+
stderr: output.stderr,
|
|
70
|
+
truncated: output.truncated,
|
|
71
|
+
durationMs: output.durationMs,
|
|
72
|
+
exitCode: output.exitCode,
|
|
73
|
+
scriptName: resolved.script.name,
|
|
74
|
+
contentHash: resolved.contentHash,
|
|
75
|
+
version: resolved.version,
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
if (output.exitCode !== 0 || output.error) {
|
|
79
|
+
return {
|
|
80
|
+
status: "failed",
|
|
81
|
+
error:
|
|
82
|
+
output.stderr ||
|
|
83
|
+
`swarm-script: script exited with code ${output.exitCode}${
|
|
84
|
+
output.error ? ` (${output.error})` : ""
|
|
85
|
+
}`,
|
|
86
|
+
output: workflowOutput,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
status: "success",
|
|
92
|
+
output: workflowOutput,
|
|
93
|
+
nextPort: "success",
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function agentIdFromContext(context: Readonly<Record<string, unknown>>): string | undefined {
|
|
99
|
+
const trigger = context.trigger;
|
|
100
|
+
if (trigger && typeof trigger === "object") {
|
|
101
|
+
const value = (trigger as Record<string, unknown>).agentId;
|
|
102
|
+
if (typeof value === "string" && value.length > 0) return value;
|
|
103
|
+
}
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function resolveScriptSource(
|
|
108
|
+
config: SwarmScriptConfig,
|
|
109
|
+
agentId: string | undefined,
|
|
110
|
+
):
|
|
111
|
+
| {
|
|
112
|
+
ok: true;
|
|
113
|
+
script: NonNullable<ReturnType<typeof getScript>>;
|
|
114
|
+
source: string;
|
|
115
|
+
contentHash: string;
|
|
116
|
+
version: number;
|
|
117
|
+
}
|
|
118
|
+
| { ok: false; error: string } {
|
|
119
|
+
if (config.scope === "agent" && !agentId) {
|
|
120
|
+
return {
|
|
121
|
+
ok: false,
|
|
122
|
+
error:
|
|
123
|
+
"swarm-script: agent-scoped scripts require the workflow to have createdByAgentId or trigger.agentId",
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const script =
|
|
128
|
+
config.scope === "global"
|
|
129
|
+
? getScript({ name: config.scriptName, scope: "global" })
|
|
130
|
+
: config.scope === "agent"
|
|
131
|
+
? getScript({ name: config.scriptName, scope: "agent", scopeId: agentId })
|
|
132
|
+
: agentId
|
|
133
|
+
? (getScript({ name: config.scriptName, scope: "agent", scopeId: agentId }) ??
|
|
134
|
+
getScript({ name: config.scriptName, scope: "global" }))
|
|
135
|
+
: getScript({ name: config.scriptName, scope: "global" });
|
|
136
|
+
|
|
137
|
+
if (!script) {
|
|
138
|
+
const scopeHint = config.scope ? ` in ${config.scope} scope` : "";
|
|
139
|
+
return {
|
|
140
|
+
ok: false,
|
|
141
|
+
error: `swarm-script: script '${config.scriptName}' not found${scopeHint}`,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (!config.pinHash) {
|
|
146
|
+
return {
|
|
147
|
+
ok: true,
|
|
148
|
+
script,
|
|
149
|
+
source: script.source,
|
|
150
|
+
contentHash: script.contentHash,
|
|
151
|
+
version: script.version,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const version = getScriptVersion({ scriptId: script.id, contentHash: config.pinHash });
|
|
156
|
+
if (!version) {
|
|
157
|
+
return {
|
|
158
|
+
ok: false,
|
|
159
|
+
error: `swarm-script: pinHash '${config.pinHash}' not found for script '${config.scriptName}'`,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
ok: true,
|
|
165
|
+
script,
|
|
166
|
+
source: version.source,
|
|
167
|
+
contentHash: version.contentHash,
|
|
168
|
+
version: version.version,
|
|
169
|
+
};
|
|
170
|
+
}
|
package/src/workflows/input.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getSwarmConfigs } from "../be/db";
|
|
2
|
+
import { isSensitiveKey } from "../utils/secret-scrubber";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Resolve workflow input values.
|
|
@@ -44,3 +45,67 @@ function resolveValue(value: string): string {
|
|
|
44
45
|
// Literal
|
|
45
46
|
return value;
|
|
46
47
|
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Marker placed in persisted step inputs in place of a secret value.
|
|
51
|
+
* Kept short and stable so future readers (logs, debug tools) can grep for it.
|
|
52
|
+
*/
|
|
53
|
+
export const REDACTED_SECRET_VALUE = "***REDACTED***";
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Determine which keys of a workflow's `input` map carry a secret value once
|
|
57
|
+
* resolved. A key is treated as a secret iff it references either:
|
|
58
|
+
* - `secret.NAME` — always sensitive (DB-stored swarm secrets).
|
|
59
|
+
* - `${ENV_VAR}` where ENV_VAR's name matches the secret-scrubber sensitive
|
|
60
|
+
* heuristic (`*_TOKEN`, `*_KEY`, `*_SECRET`, etc., or an explicit
|
|
61
|
+
* `SENSITIVE_KEY_EXACT` entry).
|
|
62
|
+
*
|
|
63
|
+
* Pure function — does NOT resolve values. Safe to call during recovery
|
|
64
|
+
* without DB lookups.
|
|
65
|
+
*/
|
|
66
|
+
export function getSecretInputKeys(input: Record<string, string> | undefined): Set<string> {
|
|
67
|
+
const keys = new Set<string>();
|
|
68
|
+
if (!input) return keys;
|
|
69
|
+
for (const [key, value] of Object.entries(input)) {
|
|
70
|
+
if (typeof value !== "string") continue;
|
|
71
|
+
if (value.startsWith("secret.")) {
|
|
72
|
+
keys.add(key);
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
const envMatch = /^\$\{(.+)\}$/.exec(value);
|
|
76
|
+
if (envMatch?.[1] && isSensitiveKey(envMatch[1])) {
|
|
77
|
+
keys.add(key);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return keys;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Return a shallow clone of `ctx` suitable for persistence to
|
|
85
|
+
* `workflow_run_steps.input`, with `ctx.input[k]` replaced by
|
|
86
|
+
* `REDACTED_SECRET_VALUE` for every k in `secretKeys`.
|
|
87
|
+
*
|
|
88
|
+
* The live `ctx` is not mutated — executors continue to see real values.
|
|
89
|
+
* Only the persisted record is redacted, eliminating the leak surface that
|
|
90
|
+
* `get-workflow-run` and any other reader of `workflow_run_steps` exposes.
|
|
91
|
+
*
|
|
92
|
+
* Empty secretKeys → returns `ctx` unchanged (no allocation).
|
|
93
|
+
*/
|
|
94
|
+
export function redactSecretsForStorage(
|
|
95
|
+
ctx: Record<string, unknown>,
|
|
96
|
+
secretKeys: Set<string>,
|
|
97
|
+
): Record<string, unknown> {
|
|
98
|
+
if (secretKeys.size === 0) return ctx;
|
|
99
|
+
const inputBlock = ctx.input;
|
|
100
|
+
if (!inputBlock || typeof inputBlock !== "object") return ctx;
|
|
101
|
+
const redactedInput: Record<string, unknown> = { ...(inputBlock as Record<string, unknown>) };
|
|
102
|
+
let touched = false;
|
|
103
|
+
for (const key of secretKeys) {
|
|
104
|
+
if (key in redactedInput) {
|
|
105
|
+
redactedInput[key] = REDACTED_SECRET_VALUE;
|
|
106
|
+
touched = true;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (!touched) return ctx;
|
|
110
|
+
return { ...ctx, input: redactedInput };
|
|
111
|
+
}
|
|
@@ -14,6 +14,7 @@ import { checkpointStep } from "./checkpoint";
|
|
|
14
14
|
import { getSuccessors } from "./definition";
|
|
15
15
|
import { findReadyNodes, walkGraph } from "./engine";
|
|
16
16
|
import type { ExecutorRegistry } from "./executors/registry";
|
|
17
|
+
import { getSecretInputKeys } from "./input";
|
|
17
18
|
import { finalizeOrWait, resumeWaitState } from "./resume";
|
|
18
19
|
|
|
19
20
|
/**
|
|
@@ -78,7 +79,16 @@ async function recoverRunningRuns(registry: ExecutorRegistry): Promise<number> {
|
|
|
78
79
|
finishedAt: new Date().toISOString(),
|
|
79
80
|
});
|
|
80
81
|
} else {
|
|
81
|
-
|
|
82
|
+
const secretKeys = getSecretInputKeys(workflow.input);
|
|
83
|
+
await walkGraph(
|
|
84
|
+
workflow.definition,
|
|
85
|
+
runId,
|
|
86
|
+
ctx,
|
|
87
|
+
readyNodes,
|
|
88
|
+
registry,
|
|
89
|
+
workflow.id,
|
|
90
|
+
secretKeys,
|
|
91
|
+
);
|
|
82
92
|
}
|
|
83
93
|
recovered++;
|
|
84
94
|
} catch (err) {
|
|
@@ -112,7 +122,16 @@ async function recoverWaitingRuns(registry: ExecutorRegistry): Promise<number> {
|
|
|
112
122
|
updateWorkflowRun(stuck.runId, { status: "running" });
|
|
113
123
|
|
|
114
124
|
const successors = getSuccessors(workflow.definition, stuck.nodeId, "default");
|
|
115
|
-
|
|
125
|
+
const secretKeys = getSecretInputKeys(workflow.input);
|
|
126
|
+
await walkGraph(
|
|
127
|
+
workflow.definition,
|
|
128
|
+
stuck.runId,
|
|
129
|
+
ctx,
|
|
130
|
+
successors,
|
|
131
|
+
registry,
|
|
132
|
+
workflow.id,
|
|
133
|
+
secretKeys,
|
|
134
|
+
);
|
|
116
135
|
} else {
|
|
117
136
|
// Task failed or cancelled — mark run failed
|
|
118
137
|
const reason =
|
|
@@ -191,7 +210,16 @@ async function recoverApprovalWaitingRuns(registry: ExecutorRegistry): Promise<n
|
|
|
191
210
|
const successors = getSuccessors(workflow.definition, stuck.nodeId, nextPort);
|
|
192
211
|
|
|
193
212
|
if (successors.length > 0) {
|
|
194
|
-
|
|
213
|
+
const secretKeys = getSecretInputKeys(workflow.input);
|
|
214
|
+
await walkGraph(
|
|
215
|
+
workflow.definition,
|
|
216
|
+
stuck.runId,
|
|
217
|
+
ctx,
|
|
218
|
+
successors,
|
|
219
|
+
registry,
|
|
220
|
+
workflow.id,
|
|
221
|
+
secretKeys,
|
|
222
|
+
);
|
|
195
223
|
} else {
|
|
196
224
|
finalizeOrWait(stuck.runId);
|
|
197
225
|
}
|
package/src/workflows/resume.ts
CHANGED
|
@@ -20,6 +20,7 @@ import type { WorkflowEventBus } from "./event-bus";
|
|
|
20
20
|
import { workflowEventBus } from "./event-bus";
|
|
21
21
|
import type { ExecutorRegistry } from "./executors/registry";
|
|
22
22
|
import { computeNextPort } from "./executors/wait";
|
|
23
|
+
import { getSecretInputKeys } from "./input";
|
|
23
24
|
import { matchesFilter } from "./wait-filter";
|
|
24
25
|
|
|
25
26
|
interface TaskEvent {
|
|
@@ -137,7 +138,16 @@ async function resumeFromTaskCompletion(
|
|
|
137
138
|
const successors = getSuccessors(workflow.definition, step.nodeId);
|
|
138
139
|
|
|
139
140
|
if (successors.length > 0) {
|
|
140
|
-
|
|
141
|
+
const secretKeys = getSecretInputKeys(workflow.input);
|
|
142
|
+
await walkGraph(
|
|
143
|
+
workflow.definition,
|
|
144
|
+
run.id,
|
|
145
|
+
ctx,
|
|
146
|
+
successors,
|
|
147
|
+
registry,
|
|
148
|
+
workflow.id,
|
|
149
|
+
secretKeys,
|
|
150
|
+
);
|
|
141
151
|
} else {
|
|
142
152
|
finalizeOrWait(run.id);
|
|
143
153
|
}
|
|
@@ -201,7 +211,16 @@ async function handleTaskFailure(
|
|
|
201
211
|
const successors = getSuccessors(workflow.definition, step.nodeId);
|
|
202
212
|
|
|
203
213
|
if (successors.length > 0) {
|
|
204
|
-
|
|
214
|
+
const secretKeys = getSecretInputKeys(workflow.input);
|
|
215
|
+
await walkGraph(
|
|
216
|
+
workflow.definition,
|
|
217
|
+
run.id,
|
|
218
|
+
ctx,
|
|
219
|
+
successors,
|
|
220
|
+
registry,
|
|
221
|
+
workflow.id,
|
|
222
|
+
secretKeys,
|
|
223
|
+
);
|
|
205
224
|
} else {
|
|
206
225
|
finalizeOrWait(run.id);
|
|
207
226
|
}
|
|
@@ -254,7 +273,8 @@ export async function retryFailedRun(runId: string, registry: ExecutorRegistry):
|
|
|
254
273
|
const nodesToRun = readyNodes.some((n) => n.id === failedNode.id)
|
|
255
274
|
? readyNodes
|
|
256
275
|
: [failedNode, ...readyNodes];
|
|
257
|
-
|
|
276
|
+
const secretKeys = getSecretInputKeys(workflow.input);
|
|
277
|
+
await walkGraph(workflow.definition, runId, ctx, nodesToRun, registry, workflow.id, secretKeys);
|
|
258
278
|
}
|
|
259
279
|
|
|
260
280
|
/**
|
|
@@ -343,7 +363,16 @@ async function resumeFromApprovalResolution(
|
|
|
343
363
|
const successors = getSuccessors(workflow.definition, step.nodeId, nextPort);
|
|
344
364
|
|
|
345
365
|
if (successors.length > 0) {
|
|
346
|
-
|
|
366
|
+
const secretKeys = getSecretInputKeys(workflow.input);
|
|
367
|
+
await walkGraph(
|
|
368
|
+
workflow.definition,
|
|
369
|
+
run.id,
|
|
370
|
+
ctx,
|
|
371
|
+
successors,
|
|
372
|
+
registry,
|
|
373
|
+
workflow.id,
|
|
374
|
+
secretKeys,
|
|
375
|
+
);
|
|
347
376
|
} else {
|
|
348
377
|
finalizeOrWait(run.id);
|
|
349
378
|
}
|
|
@@ -423,7 +452,16 @@ export async function resumeWaitState(
|
|
|
423
452
|
|
|
424
453
|
const successors = getSuccessors(workflow.definition, step.nodeId, nextPort);
|
|
425
454
|
if (successors.length > 0) {
|
|
426
|
-
|
|
455
|
+
const secretKeys = getSecretInputKeys(workflow.input);
|
|
456
|
+
await walkGraph(
|
|
457
|
+
workflow.definition,
|
|
458
|
+
run.id,
|
|
459
|
+
ctx,
|
|
460
|
+
successors,
|
|
461
|
+
registry,
|
|
462
|
+
workflow.id,
|
|
463
|
+
secretKeys,
|
|
464
|
+
);
|
|
427
465
|
} else {
|
|
428
466
|
finalizeOrWait(run.id);
|
|
429
467
|
}
|