Repository navigation
feat(workflow): allow using references for secret fields - #7995
Nixieboluo wants to merge 14 commits into
Conversation
Add reference mode to new password tool inputs and migrate existing password fields.
|
✅ Admin Preview Image Ready! 🕒 Time: 2026-10-23 17:51:12 (UTC+8) |
|
✅ Build and publish successful - Preview fastgpt Image: 🕒 Time: 2026-10-23 17:53:01 (UTC+8) |
Coverage Report
File CoverageNo changed files found. |
Signed-off-by: Nixieboluo <me@sagirii.me>
Signed-off-by: Nixieboluo <me@sagirii.me>
Signed-off-by: Nixieboluo <me@sagirii.me>
c121914yu
left a comment
There was a problem hiding this comment.
基于 HEAD 85f694c0b5,按 upstream/main...HEAD 梳理了 55 个文件(+2089 / -403)。
本次变更将密钥统一为互斥的 { value }、{ secret }、{ ref },并打通编辑器、工作流迁移及 HTTP/MCP/系统工具运行时。上下游同步总体属于合理扩散,但共享解密和类型转换的语义变化影响了历史聊天、管理员配置及普通节点。已确认并复现 2 个 P1、2 个 P2 问题,详见行内评论,建议修复后再合并。
验证情况:
- 局部 14 个文件、197 项测试通过。标准入口的 Service 阶段因 Mongo 内存实例启动超时中断;相关 Service/App 用例随后在跳过 Mongo 全局初始化的隔离配置下通过。
- 只读脚本对比了变更前后行为,复现了旧密码读取为空、旧系统密钥失效及脱敏失效、普通 JSON 的 ref 字段触发迁移错误、普通对象跳过字符串转换。
- 未运行全量测试、浏览器交互验证或最新主干合并后的验证。
测试缺口:部分历史兼容测试把 { value: '', secret } 样本直接替换成新格式,例如 packages/service/test/core/workflow/dispatch/variables.test.ts 的初始化用例。应保留旧格式回归,再补充新协议覆盖。
其他风格与范围建议:
HeaderAuthForm.tsx:110使用了t(condition ? keyA : keyB),请拆成两个静态t('literal')调用,保持与 i18n 清理脚本的约定一致。对应四套语言包目前均有 key。- 工作流工具 app/create、app/update 同时移除了
secretsVal持久化,与引用能力无直接依赖,请说明原因或拆分。 - 协议允许
ref: tuple[],但当前请求头和系统配置运行时会拒绝数组结果,请明确预期的兼容语义。
| return val.value; | ||
| if (typeof val !== 'object' || val === null) return val; | ||
| if (hasSecretValueField(val, 'ref')) return val; | ||
| if (hasSecretValueField(val, 'value')) return getSecretValueField(val, 'value'); |
There was a problem hiding this comment.
[P1] 保留旧密码对象的解密兼容
旧版本的正常持久化结果是 { value: '', secret: ciphertext }。这里改为只要存在 value 字段就返回,会把该结构及其 JSON 字符串形式都解密成空字符串,而不是原密码。新增的 workflow 迁移没有覆盖聊天变量;WorkflowVariableState.initConfiguredVariable 仍直接调用本函数,并把返回的空字符串重新加密为 storeValue。普通 password 输入的 input.value 也未在 migrateInputSecrets 中归一化。
已用同一旧对象对比:变更前返回原密码,当前返回 ''。请在历史数据读取边界先归一化旧结构,并覆盖旧聊天变量和密码输入默认值,避免升级后凭据失效或在后续保存时被空值覆盖。现有旧格式测试样本应保留。
|
|
||
| if (typeof value.value === 'string' && value.value !== '') return value.value; | ||
| if (!isEncryptedValue(value)) return value.value ?? ''; | ||
| if (hasSecretValueField(value, 'value') && hasSecretValueField(value, 'secret')) return ''; |
There was a problem hiding this comment.
[P1] 系统密钥尚未迁移,不能直接丢弃双字段结构
变更前的 encryptSystemToolSecrets 正常生成 { secret: ciphertext, value: '' },这些值仍由 MongoSystemTool 的 secretsVal/inputListVal 经 SystemToolCodec 直接读取,没有经过 workflow 迁移。此处将双字段值直接解密为空,导致已有系统密钥失效;同文件的 isConfiguredValue 也将其判为未配置,使 maskSystemToolSecrets 原样返回密文对象,并在提交 masked 标记时删除旧字段。
已复现:旧对象运行时得到空密钥,mask 返回对象而非标记,保留 masked 字段的更新结果变成空配置。请在系统密钥读取、脱敏及保留旧值的边界统一兼容/归一化,或先完成该存储范围的迁移,再拒绝旧格式。
| if ('ref' in value) { | ||
| // 引用必须在迁移边界校验,避免空引用进入 canonical workflow。 | ||
| return SecretRefValueSchema.parse(value); |
There was a problem hiding this comment.
[P2] 不要把任意业务 JSON 的 ref 字段当成密钥引用
migrateSelectedToolsSecrets 会对全部 tool.config 参数调用本函数,而这些参数允许普通业务 JSON。这里只判断存在 ref 就按严格密钥引用 schema parse,会把合法参数(例如 payload: { ref: 'main', repository: 'example' })判为非法,导致整个工作流迁移失败,影响版本读取、导入和发布。
已对比复现:基线正常保留上述 config,当前在这里抛出 Zod 错误。请根据输入定义或已知密钥容器限定迁移范围,避免将普通 JSON 字段解释为密钥协议;补充含 ref 字段的普通对象回归用例。
|
|
||
| // Password check | ||
| if (valueType === WorkflowIOValueTypeEnum.string && isSecretValue(value)) return value; | ||
| if (valueType === WorkflowIOValueTypeEnum.string && isSecretValueLike(value)) return value; |
There was a problem hiding this comment.
[P2] 收窄密钥判断,保留通用字符串转换的原有语义
isSecretValueLike 仅判断对象是否包含 value、secret 或 ref,并不保证它是合法密钥 wrapper。用于通用 valueTypeFormat 后,普通对象也会跳过字符串转换。例如 valueTypeFormat({ value: 1, other: 'data' }, 'string') 在变更前返回 JSON 字符串,当前直接返回对象。
该函数用于所有节点运行参数和变量更新,不限于密码字段,因而对象/any 输出流向 string 输入时会破坏原有类型约定。请将特殊处理限制为明确的密钥形态或密码输入上下文,保持普通对象继续 JSON 序列化,并补充此边界测试。
Normalize JSON-encoded legacy records before migration and resolution. Persist system-tool secrets on create and update.
|
✅ Docs preview deployed 🔗 👀 Click here to visit preview 🕒 Time: 2026-10-23 17:49:18 (UTC+8) |
Context
Workflow users need to connect existing variables to password inputs, tool parameters, and HTTP/MCP authentication headers without converting references into encrypted or static values. The change preserves existing configurations while making reference selection explicit in workflow-aware editors.
Description
This branch introduces a structured secret-value protocol with strict static and reference branches:
{ value },{ secret }, and{ ref: tuple | tuple[] }. Legacy{ value?, secret? }pairs are normalized before canonical validation. Workflow editors expose manual/reference modes, reference values bypass encryption, and Runtime resolution reuses existing type conversion and scalar validation.Changes in the codebase
SecretInputModalto support manual/reference modes forsecret,input,numberInput,switch, andselectfields with type-aware reference filtering and conversion.HeaderAuthFormfor Bearer, Basic, and custom header references while keeping header keys static.Changes outside the codebase
{ secret: '<ciphertext>' },{ value: '<plain value>' }, or{ ref: ['nodeId', 'outputId'] }.Aditional information
The first UI iteration exposes single-tuple selection while retaining tuple-array compatibility in the schema and Runtime. Reference pickers are injected only when workflow context is available, so management and configuration pages keep their static-input boundary; invalid-reference handling remains aligned with the existing editor/runtime behavior.