已合并
fix(secrets): call auto_save_from_env on startup paths before env injection (closes #149) #461
xujing99创建于 9 天前
fix(secrets): call auto_save_from_env on startup paths before env injection (closes #149) #461
已合并
xujing99创建于 9 天前
xujing99
xujing99成员
9 天前

当前PR是否有AI参与:

[ ] 否

[x] 是
__1. AI Agent 平台: opencode
__2. AI 模型: GLM-5.3
__3. Prompt上下文 : NA

参考:openEuler社区《生成式AI工具使用与开源贡献政策》

PR功能描述 / 为什么需要这个合入**:

1.1 修改目的

本项目把大模型的 API 密钥加密存放在 config.toml 同目录的 llm_secrets.json 里,进程启动时再把这些密钥“注入”回环境变量供下游 SDK 使用。设计文档承诺“首次启动时自动把环境变量里的密钥收进加密存储”,但实现这一承诺的函数(auto_save_from_env())在整个代码库里没有任何调用方——自动保存从未真正发生过。本次提交让三个启动入口真正执行它,并顺带把存储写入改造为原子写 + 跨进程加锁,使新引入的启动期写入不会引发撕裂文件和并发覆盖问题。

1.2 关键变更点

  1. 新增统一密钥引导入口 init_llm_secrets(),daemon / TUI / CLI run 三个启动路径全部改走它,修复自动保存零调用、功能失效的问题。
  2. 引导内部强制“先保存后注入”:注入会用存储里的值覆盖同名环境变量,顺序颠倒会永久吞掉用户在环境里提供的密钥。
  3. 自动保存改为“仅首次”:存储里已有该条目时跳过环境变量值,防止残留的旧环境变量回滚用户显式轮换过的密钥。
  4. 存储落盘改为“写同目录临时文件 + rename 覆盖”,进程崩溃不会留下半写的密钥文件(否则后续每次启动解密都会失败)。
  5. 自动保存 / set-secret / delete-secret 三条“读-改-写”路径全程持有 flock 排他锁,并发进程不会互相覆盖更新。
  6. 同步设计文档:改写保存路径一节的首启语义与并发说明,删掉“零调用已知缺口”备注,刷新过期的代码行号引用。

1.3 实现思路与机制原理

背景:密钥存储由共享库 apps/shared/src/llm_secrets.rs 提供,支持两种写入来源——显式的 config set-secret 命令 / TUI 弹窗,以及文档承诺但从未生效的“首启从环境变量自动保存”。本次的整体方案是“补接线 + 顺手加固”:不造旁路,而是新增引导函数 init_llm_secrets(),把既有的“自动保存”和“注入”两个函数按正确顺序串起来,三个启动入口统一换用它;同时把存储写入从裸写升级为原子写 + 文件锁,因为“每次启动都可能写盘”从假设变成了现实。

启动链路(以 daemon 为例):

  1. run_daemon() 解析配置路径后调用 init_llm_secrets()(apps/serverside/src/main.rs:545;TUI 在 apps/endside/src/main.rs:81,CLI run 在 apps/endside/src/cli/entry.rs:224)。
  2. 先执行自动保存:读配置里 llm.api_key_env 指定的变量名(如 OPENAI_API_KEY),环境变量有非空值才继续,否则静默跳过。
  3. 持锁加载存储:已有该条目就跳过并记 debug 日志,没有则把环境变量里的值加密写入。
  4. 最后才注入:把整个存储加载回进程环境变量。

顺序是核心机制:注入会覆盖同名环境变量。若先注入,用户在环境里提供的新 key 会被存储里的旧值盖掉,随后的“首次保存”存不进任何东西。“先保存后注入”从结构上杜绝了这一点。

“仅首次”语义防回滚,一个最小示例:

[llm]
api_key_env = "OPENAI_API_KEY"

首次启动时环境中 OPENAI_API_KEY=sk-a → 自动写入加密存储;之后用户通过 set-secret 显式换成 sk-b → 再启动时 shell 里残留的 sk-a 被忽略。旧实现复用 save_llm_secret()(无条件插入覆盖),有回滚风险;新实现自带存在性检查,且检查与写入在同一锁临界区内完成——否则两步之间插入一个并发的 set-secret,仍可能被覆盖。

崩溃与并发安全:写入端先写同目录临时文件(.llm_secrets.json.tmp.<pid>)再 rename 覆盖,rename 在同一文件系统上是原子的,读者只会看到旧或新的完整文件;三条“读-改-写”路径全程持有基于 flock 的排他锁(StoreLock,锁文件内容恒为空、仅当句柄用,进程崩溃时内核自动释放,不会死锁);注入 / 查询等只读路径不加锁,靠 rename 原子性读到完整文件,无额外开销。

错误分层:配置缺失、环境变量未设或为空都视为正常情况静默跳过(首次无密钥很常见);真实的 I/O 或加解密失败则带阶段上下文向上传播,让启动报错而非带着坏存储继续跑。

与前版差异:旧逻辑三处缺陷分别对应本次三个机制——零调用失效 → 统一入口 + 顺序约束;无条件覆盖有回滚风险 → 仅首次语义;裸写可撕裂、并发丢更新 → 原子写 + 文件锁。

1.4 影响范围/兼容性影响

  • 存储文件格式不变,仍是加密的 llm_secrets.json;配置目录新增 .llm_secrets.json.lock(内容恒为空)与瞬时的 .tmp.<pid> 临时文件。
  • 行为变化:首次启动且环境变量有值时会多出一次写盘;存储已有条目时环境变量不再能覆盖它(有意为之)。
  • 只读路径零开销;写路径增加一次 flock,可忽略。
  • 启动失败面略变:自动保存遇到真实 I/O / 加密错误现在会让启动报错(此前该路径根本不执行)。

该PR关联的issue

fixes #149

likedislike
Pull Request已成功合入, 合并人@openeuler-ci-bot
(感谢 xujing99 的贡献)
xujing99xujing99成员
9 天前 创建了 pull request,commit 681c1c85
xujing99xujing99成员
9 天前 关联了issue:auto_save_from_env 零调用方:文档宣称的「首次启动自动保存」不会发生
openeuler-ci-botopeneuler-ci-bot成员
9 天前 将lyhu,huzhengce,liumiao27,zxstty,fromhsc,gogoxiaoxiao,wqianli,leon-wang2021,kaitiandu设为审查人
openeuler-ci-botopeneuler-ci-bot成员
9 天前 添加了label:sig/sig-intelligence
openeuler-ci-bot
openeuler-ci-bot成员
9 天前 评论:

Welcome To openEuler Community

Hey @xujing99 , thanks for your contribution to the community.

Bot Usage Manual

I'm the Bot here serving you. You can find the instructions on how to interact with me at Here . That means you can comment below every pull request or issue to trigger Bot Commands. You can self-configure the PR merge rules for this repository. For more details, please refer to Here.

Contact Guide

If you have any questions, please contact the SIG: sig-intelligence ,
and any of the maintainers: @fromhsc, @gogoxiaoxiao, @huzhengce, @kaitiandu, @leon-wang2021, @liumiao27, @lyhu, @wqianli, @zxstty ,
and any of the committers: @extinctfire, @hypothesiser, @xiangyou_xie, @xujing99 .

likedislike
openeuler-ci-botopeneuler-ci-bot成员
9 天前 添加了label:ai-co-authored
openeuler-ci-botopeneuler-ci-bot成员
9 天前 添加了label:openeuler-cla/yes
openeuler-ci-botopeneuler-ci-bot成员
9 天前 添加了label:ai-includes-code
openeuler-botopeneuler-bot成员
9 天前 添加了label:ci_processing
openeuler-bot
openeuler-bot成员
9 天前 评论:

门禁正在运行, 您可以通过以下链接查看实时门禁检查结果.
若您对门禁结果含义不清晰或者遇到问题不知如何解决,可参考门禁指导手册
门禁入口及编码规范检查: multiarch/openeuler/trigger/xiaoO/1027

likedislike
openeuler-ci-botopeneuler-ci-bot成员
9 天前 添加了label:ai-compliance-successful
openeuler-botopeneuler-bot成员
9 天前 删除了label:ci_processing
openeuler-bot
openeuler-bot成员
9 天前 评论:
Check Name Build Result 详情 Build Details
check_package_license ⚠WARNING • 仓库copyright检查未通过: 缺少项目级Copyright声明文件 #1027
check_sca ✅SUCCESS
check_ci ✅SUCCESS
x86_64 check_build ✅SUCCESS #1050
aarch64 check_build ✅SUCCESS #1032
likedislike
openeuler-botopeneuler-bot成员
9 天前 添加了label:ci_successful
openeuler-bot
openeuler-bot成员
9 天前 评论:
likedislike
xujing99xujing99成员
9 天前 预合并成功(commit_id: 1aa6025a7a82fdfeffb03c8e9c7befac009914ab)
xujing99xujing99成员
9 天前 强制推送  1 个提交:cdd8c881-fix(secrets): wire first-run env auto-save into startup paths (closes #149)
xujing99xujing99成员
9 天前 预合并成功(commit_id: c4de69d13161a19a0165a1aa4d332af9579dd2f8)
openeuler-ci-botopeneuler-ci-bot成员
9 天前 删除了label:openeuler-cla/yes
openeuler-ci-botopeneuler-ci-bot成员
9 天前 删除了label:ci_successful
openeuler-ci-bot
openeuler-ci-bot成员
9 天前 评论:

Notification

This pull request has been changed(code update) or closed, so removes the following label(s): ci_successful.

likedislike
openeuler-ci-botopeneuler-ci-bot成员
9 天前 添加了label:openeuler-cla/yes
openeuler-botopeneuler-bot成员
9 天前 添加了label:ci_processing
openeuler-bot
openeuler-bot成员
9 天前 评论:

门禁正在运行, 您可以通过以下链接查看实时门禁检查结果.
若您对门禁结果含义不清晰或者遇到问题不知如何解决,可参考门禁指导手册
门禁入口及编码规范检查: multiarch/openeuler/trigger/xiaoO/1028

likedislike
xujing99xujing99成员
9 天前 修改了pull request 的描述
openeuler-botopeneuler-bot成员
9 天前 删除了label:ci_processing
openeuler-bot
openeuler-bot成员
9 天前 评论:
Check Name Build Result 详情 Build Details
check_package_license ⚠WARNING • 仓库copyright检查未通过: 缺少项目级Copyright声明文件 #1028
check_sca ✅SUCCESS
check_ci ✅SUCCESS
x86_64 check_build ✅SUCCESS #1051
aarch64 check_build ✅SUCCESS #1033
likedislike
openeuler-botopeneuler-bot成员
9 天前 添加了label:ci_successful
openeuler-bot
openeuler-bot成员
9 天前 评论:
likedislike
xujing99xujing99成员
9 天前 预合并成功(commit_id: d1e76bf9174f39f6aa8bc9585446ad63bedffc81)
xujing99xujing99成员
9 天前 强制推送  1 个提交:a26ee26d-fix(secrets): wire first-run env auto-save into startup paths (closes #149)
xujing99xujing99成员
9 天前 预合并成功(commit_id: 2145804afb4d72bdac435a10311ca04f9f9b0b60)
openeuler-ci-botopeneuler-ci-bot成员
9 天前 删除了label:openeuler-cla/yes
openeuler-ci-botopeneuler-ci-bot成员
9 天前 删除了label:ci_successful
openeuler-ci-bot
openeuler-ci-bot成员
9 天前 评论:

Notification

This pull request has been changed(code update) or closed, so removes the following label(s): ci_successful.

likedislike
openeuler-ci-botopeneuler-ci-bot成员
9 天前 添加了label:openeuler-cla/yes
openeuler-ci-bot
openeuler-ci-bot成员
9 天前 评论:

CLA Signature Pass

xujing99, thanks for your pull request. All authors of the commits have signed the CLA. 👍

likedislike
openeuler-botopeneuler-bot成员
9 天前 添加了label:ci_processing
openeuler-bot
openeuler-bot成员
9 天前 评论:

门禁正在运行, 您可以通过以下链接查看实时门禁检查结果.
若您对门禁结果含义不清晰或者遇到问题不知如何解决,可参考门禁指导手册
门禁入口及编码规范检查: multiarch/openeuler/trigger/xiaoO/1029

likedislike
openeuler-botopeneuler-bot成员
9 天前 删除了label:ci_processing
openeuler-bot
openeuler-bot成员
9 天前 评论:
Check Name Build Result 详情 Build Details
check_package_license ⚠WARNING • 仓库copyright检查未通过: 缺少项目级Copyright声明文件 #1029
check_sca ✅SUCCESS
check_ci ✅SUCCESS
x86_64 check_build ✅SUCCESS #1052
aarch64 check_build ✅SUCCESS #1034
likedislike
openeuler-botopeneuler-bot成员
9 天前 添加了label:ci_successful
openeuler-bot
openeuler-bot成员
9 天前 评论:
likedislike
hypothesiser
hypothesiser成员
8 天前 评论:

/lgtm

likedislike
openeuler-ci-botopeneuler-ci-bot成员
8 天前 添加了label:lgtm
hypothesiser
hypothesiser成员
8 天前 评论:

/approve

likedislike
openeuler-ci-bot
openeuler-ci-bot成员
8 天前 评论:

Review Code Feedback

  • The label lgtm was added to this pull request. It means that hypothesiser reviewed the code changes. 👋
Tips
  • If this pull request is not merged while all conditions are met, comment /check-pr to try again. 😄
likedislike
openeuler-ci-botopeneuler-ci-bot成员
8 天前 添加了label:approved
openeuler-ci-bot
openeuler-ci-bot成员
8 天前 评论:

Review Code Feedback

  • The label approved was added to this pull request. It means that hypothesiser reviewed the code changes. 👋
Tips
  • If this pull request is not merged while all conditions are met, comment /check-pr to try again. 😄
likedislike
openeuler-ci-botopeneuler-ci-bot成员
8 天前 合入了pull request,合并节点 SHA:539052f26d74e8f5cb3011cc1ac84dc983de1d35