Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import {
} from '@/features/workflow-builder/hooks/useWorkflowGraphControllers';
import type { FrontendNodeData } from '@/schemas/node';
import type { Node as ReactFlowNode, Edge as ReactFlowEdge } from 'reactflow';
import { useSecretStore } from '@/store/secretStore';
import { useComponentStore } from '@/store/componentStore';
interface WorkflowMetadataShape {
id: string | null;
name: string;
Expand Down Expand Up @@ -98,6 +100,54 @@ export function useWorkflowImportExport({
const normalizedNodes = deserializeNodes(workflowGraph);
const normalizedEdges = deserializeEdges(workflowGraph);

// Validate secret references
const removedSecrets: { param: string; node: string; secretId: string }[] = [];
try {
await useSecretStore.getState().fetchSecrets();
const secrets = useSecretStore.getState().secrets;
const secretIds = new Set(secrets.map((s) => s.id));

const componentStore = useComponentStore.getState();
if (Object.keys(componentStore.components).length === 0) {
await componentStore.fetchComponents();
}
const components = useComponentStore.getState().components;

normalizedNodes.forEach((node) => {
const data = node.data as FrontendNodeData;
const componentRef = data.componentId || data.componentSlug;
if (!componentRef) return;

const component =
componentStore.getComponent(componentRef) ||
Object.values(components).find((c) => c.slug === componentRef);

if (!component || !component.parameters) return;

// Find parameters that are secrets
const secretParams = component.parameters.filter((p) => p.type === 'secret');
const configParams = node.data.config.params || {};

secretParams.forEach((param) => {
const val = configParams[param.id];
// If value is a string (ID) and not in available secrets, remove it
if (typeof val === 'string' && val.trim().length > 0) {
if (!secretIds.has(val)) {
console.warn(
`[Import] Removing invalid secret reference for param "${param.id}" in node "${node.id}" (secret ID: ${val})`,
);
removedSecrets.push({ param: param.id, node: node.id, secretId: val });
// Set to undefined to clear it
configParams[param.id] = undefined;
}
}
});
});
} catch (error) {
console.error('Failed to validate secrets during import:', error);
// Continue with import even if validation fails
}

resetWorkflow();
setDesignNodes(normalizedNodes);
setDesignEdges(normalizedEdges);
Expand All @@ -118,6 +168,15 @@ export function useWorkflowImportExport({
title: 'Workflow imported',
description: `Loaded ${parsed.name}`,
});

// Show warning if any invalid secret references were removed
if (removedSecrets.length > 0) {
toast({
variant: 'warning',
title: 'Invalid secret references removed',
description: `${removedSecrets.length} secret reference(s) could not be resolved and were cleared. Please select valid secrets from the Secrets Manager.`,
});
}
},
[
canManageWorkflows,
Expand Down
9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,17 @@
"undici": "^7.19.0"
},
"lint-staged": {
"frontend/**/*.{ts,tsx,js,jsx}": "bunx eslint --fix --config frontend/eslint.config.mjs",
"backend/**/*.{ts,js}": "bunx eslint --fix --config backend/eslint.config.mjs",
"worker/**/*.{ts,js}": "bunx eslint --fix --config worker/eslint.config.mjs",
"frontend/**/*.{ts,tsx,js,jsx}": "bunx eslint@9 --fix --config frontend/eslint.config.mjs",
"backend/**/*.{ts,js}": "bunx eslint@9 --fix --config backend/eslint.config.mjs",
"worker/**/*.{ts,js}": "bunx eslint@9 --fix --config worker/eslint.config.mjs",
"*.{json,md,yml,yaml}": "bunx prettier --write"
},
"dependencies": {
"@googleapis/admin": "^30.2.0",
"@grpc/grpc-js": "^1.14.3",
"chalk": "^5.6.2",
"chalk-animation": "^2.0.3",
"long": "^5.3.2"
"long": "^5.3.2",
"zod": "^4.3.6"
}
}