Skip to content

Commit 19044ed

Browse files
committed
Revert "merge: main into mcp-tool-mode"
This reverts commit f80f253, reversing changes made to 7d7836b.
1 parent f80f253 commit 19044ed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+2774
-3922
lines changed

backend/src/workflows/workflows.service.ts

Lines changed: 73 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import {
88
BadRequestException,
99
} from '@nestjs/common';
1010
import { status as grpcStatus, type ServiceError } from '@grpc/grpc-js';
11-
import { z } from 'zod';
1211

1312
import { compileWorkflowGraph } from '../dsl/compiler';
1413
// Ensure all worker components are registered before accessing the registry
@@ -22,8 +21,6 @@ import {
2221
import {
2322
WorkflowGraphDto,
2423
WorkflowGraphSchema,
25-
WorkflowNodeSchema,
26-
WorkflowNodeDataSchema,
2724
ServiceWorkflowResponse,
2825
UpdateWorkflowMetadataDto,
2926
} from './dto/workflow-graph.dto';
@@ -43,7 +40,7 @@ import {
4340
ExecutionInputPreview,
4441
ExecutionTriggerMetadata,
4542
} from '@shipsec/shared';
46-
import type { WorkflowRunRecord, WorkflowVersionRecord, WorkflowGraph } from '../database/schema';
43+
import type { WorkflowRunRecord, WorkflowVersionRecord } from '../database/schema';
4744
import type { AuthContext } from '../auth/types';
4845

4946
export interface WorkflowRunRequest {
@@ -369,155 +366,13 @@ export class WorkflowsService {
369366
record: WorkflowRecord,
370367
version?: WorkflowVersionRecord | null,
371368
): ServiceWorkflowResponse {
372-
// Resolve dynamic ports for the graph so Entry Point nodes show correct outputs
373-
const resolvedGraph = this.resolveGraphPorts(record.graph);
374-
375369
return {
376370
...record,
377-
graph: resolvedGraph,
378371
currentVersionId: version?.id ?? null,
379372
currentVersion: version?.version ?? null,
380373
};
381374
}
382375

383-
/**
384-
* Extract component parameters from node data, handling legacy schema formats.
385-
* This handles the migration from old formats where params might be at:
386-
* - nodeData.config.params (current schema)
387-
* - nodeData.parameters (legacy)
388-
* - nodeData.config (legacy - when config was the params object directly)
389-
*/
390-
private extractNodeParams(
391-
nodeData: z.infer<typeof WorkflowNodeDataSchema>,
392-
): Record<string, unknown> {
393-
// Current schema: params are in config.params
394-
if (nodeData.config?.params && Object.keys(nodeData.config.params).length > 0) {
395-
return nodeData.config.params;
396-
}
397-
398-
// Legacy: params stored directly on nodeData (via extended properties)
399-
const extendedNodeData = nodeData as Record<string, unknown>;
400-
if (extendedNodeData.parameters && typeof extendedNodeData.parameters === 'object') {
401-
return extendedNodeData.parameters as Record<string, unknown>;
402-
}
403-
404-
// Legacy: config was the params object itself (before nested config.params structure)
405-
// Only use this if config doesn't have the modern structure
406-
if (
407-
nodeData.config &&
408-
!('params' in nodeData.config) &&
409-
!('inputOverrides' in nodeData.config) &&
410-
typeof nodeData.config === 'object'
411-
) {
412-
return nodeData.config as Record<string, unknown>;
413-
}
414-
415-
return {};
416-
}
417-
418-
/**
419-
* Extract component ID from node, handling frontend extensions.
420-
* The componentId might be in node.type or in extended nodeData properties.
421-
*/
422-
private extractComponentId(
423-
node: z.infer<typeof WorkflowNodeSchema>,
424-
nodeData: z.infer<typeof WorkflowNodeDataSchema>,
425-
): string | null {
426-
// In backend schema, node.type contains the component ID
427-
if (node.type && node.type !== 'workflow') {
428-
return node.type;
429-
}
430-
431-
// Frontend extensions might store componentId/componentSlug in nodeData
432-
const extendedNodeData = nodeData as Record<string, unknown>;
433-
if (typeof extendedNodeData.componentId === 'string') {
434-
return extendedNodeData.componentId;
435-
}
436-
if (typeof extendedNodeData.componentSlug === 'string') {
437-
return extendedNodeData.componentSlug;
438-
}
439-
440-
return null;
441-
}
442-
443-
/**
444-
* Resolve dynamic ports for a single node based on its component and parameters.
445-
*/
446-
private resolveNodePorts(
447-
node: z.infer<typeof WorkflowNodeSchema>,
448-
): z.infer<typeof WorkflowNodeSchema> {
449-
const nodeData = node.data;
450-
const componentId = this.extractComponentId(node, nodeData);
451-
452-
if (!componentId) {
453-
return node;
454-
}
455-
456-
try {
457-
const entry = componentRegistry.getMetadata(componentId);
458-
if (!entry) {
459-
return node;
460-
}
461-
const component = entry.definition;
462-
const baseInputs = entry.inputs ?? extractPorts(component.inputs);
463-
const baseOutputs = entry.outputs ?? extractPorts(component.outputs);
464-
465-
const params = this.extractNodeParams(nodeData);
466-
467-
if (typeof component.resolvePorts === 'function') {
468-
try {
469-
const resolved = component.resolvePorts(params);
470-
return {
471-
...node,
472-
data: {
473-
...nodeData,
474-
dynamicInputs: resolved.inputs ? extractPorts(resolved.inputs) : baseInputs,
475-
dynamicOutputs: resolved.outputs ? extractPorts(resolved.outputs) : baseOutputs,
476-
},
477-
};
478-
} catch (resolveError) {
479-
this.logger.warn(`Failed to resolve ports for component ${componentId}: ${resolveError}`);
480-
return {
481-
...node,
482-
data: {
483-
...nodeData,
484-
dynamicInputs: baseInputs,
485-
dynamicOutputs: baseOutputs,
486-
},
487-
};
488-
}
489-
} else {
490-
return {
491-
...node,
492-
data: {
493-
...nodeData,
494-
dynamicInputs: baseInputs,
495-
dynamicOutputs: baseOutputs,
496-
},
497-
};
498-
}
499-
} catch (error) {
500-
this.logger.warn(`Failed to get component ${componentId} for port resolution: ${error}`);
501-
return node;
502-
}
503-
}
504-
505-
/**
506-
* Resolve dynamic ports for all nodes in a workflow graph.
507-
* This ensures Entry Point nodes and other components with resolvePorts
508-
* have their dynamicInputs/dynamicOutputs populated correctly.
509-
*/
510-
private resolveGraphPorts(graph: WorkflowGraph): WorkflowGraph {
511-
if (!graph || !Array.isArray(graph.nodes)) {
512-
return graph;
513-
}
514-
515-
return {
516-
...graph,
517-
nodes: graph.nodes.map((node) => this.resolveNodePorts(node)),
518-
};
519-
}
520-
521376
async delete(id: string, auth?: AuthContext | null): Promise<void> {
522377
const organizationId = await this.requireWorkflowAdmin(id, auth);
523378
await this.repository.delete(id, { organizationId });
@@ -1358,11 +1213,80 @@ export class WorkflowsService {
13581213
return 0;
13591214
}
13601215

1361-
private parse(dto: WorkflowGraphDto): WorkflowGraph {
1216+
private parse(dto: WorkflowGraphDto) {
13621217
const parsed = WorkflowGraphSchema.parse(dto);
13631218

1364-
// Resolve dynamic ports for all nodes using the shared helper
1365-
return this.resolveGraphPorts(parsed);
1219+
// Resolve dynamic ports for each node based on its component and parameters
1220+
const nodesWithResolvedPorts = parsed.nodes.map((node) => {
1221+
const nodeData = node.data as any;
1222+
// Component ID can be in node.type, data.componentId, or data.componentSlug
1223+
// In the workflow graph schema, node.type contains the component ID (e.g., "security.virustotal.lookup")
1224+
const componentId =
1225+
node.type !== 'workflow' ? node.type : nodeData.componentId || nodeData.componentSlug;
1226+
1227+
if (!componentId) {
1228+
return node;
1229+
}
1230+
1231+
try {
1232+
const entry = componentRegistry.getMetadata(componentId);
1233+
if (!entry) {
1234+
return node;
1235+
}
1236+
const component = entry.definition;
1237+
const baseInputs = entry.inputs ?? extractPorts(component.inputs);
1238+
const baseOutputs = entry.outputs ?? extractPorts(component.outputs);
1239+
1240+
// Get parameters from node data (they may be stored in config.params, parameters, or at data level)
1241+
const params = nodeData.parameters || nodeData.config?.params || nodeData.config || {};
1242+
1243+
// Resolve ports using the component's resolvePorts function if available
1244+
if (typeof component.resolvePorts === 'function') {
1245+
try {
1246+
const resolved = component.resolvePorts(params);
1247+
return {
1248+
...node,
1249+
data: {
1250+
...nodeData,
1251+
dynamicInputs: resolved.inputs ? extractPorts(resolved.inputs) : baseInputs,
1252+
dynamicOutputs: resolved.outputs ? extractPorts(resolved.outputs) : baseOutputs,
1253+
},
1254+
};
1255+
} catch (resolveError) {
1256+
this.logger.warn(
1257+
`Failed to resolve ports for component ${componentId}: ${resolveError}`,
1258+
);
1259+
// Fall back to static metadata
1260+
return {
1261+
...node,
1262+
data: {
1263+
...nodeData,
1264+
dynamicInputs: baseInputs,
1265+
dynamicOutputs: baseOutputs,
1266+
},
1267+
};
1268+
}
1269+
} else {
1270+
// No dynamic resolver, use static metadata
1271+
return {
1272+
...node,
1273+
data: {
1274+
...nodeData,
1275+
dynamicInputs: baseInputs,
1276+
dynamicOutputs: baseOutputs,
1277+
},
1278+
};
1279+
}
1280+
} catch (error) {
1281+
this.logger.warn(`Failed to get component ${componentId} for port resolution: ${error}`);
1282+
return node;
1283+
}
1284+
});
1285+
1286+
return {
1287+
...parsed,
1288+
nodes: nodesWithResolvedPorts,
1289+
};
13661290
}
13671291

13681292
private formatInputSummary(inputs?: Record<string, unknown>): string {

0 commit comments

Comments
 (0)