Skip to content

feat(lc): lc code 在 .env 落在 Codex 工作区里时警告,并把「在哪跑」写进文档 - #49

Merged
LouisDM merged 1 commit into
mainfrom
feat/issue-46
Aug 12, 2026
Merged

feat(lc): lc code 在 .env 落在 Codex 工作区里时警告,并把「在哪跑」写进文档#49
LouisDM merged 1 commit into
mainfrom
feat/issue-46

Conversation

@LouisDM

@LouisDM LouisDM commented Aug 12, 2026

Copy link
Copy Markdown
Owner

Closes #46

按 issue 里定下的范围做三件事,不搬 .env

问题

#42 / #45 把注入给 Codex 的环境变量收到了最小集,那只关掉了进程环境这条读法。
lc code 是在当前工作目录里启动 Codex 的,而生成的配置是
approval_policy = "never" + sandbox_mode = "workspace-write"。按 quick start
cd airgap-coder && ./bin/lc code,CWD 就是仓库根目录,.env 是工作区里的一个
普通文件——一句 cat .env 就把 #42 收回去的东西全拿回来了。0600 挡的是别的
用户,挡不住以同一用户身份运行的 Codex。

根子不在「.env 放错了地方」,而在文档把工具目录和工作目录教成了同一个。

1. lc code 警告(不阻断)

新增 env_in_workspace() + warn_env_in_workspace(),在解析出 profile 之后、
启动 Codex 之前调用。

判据是「.env 在 CWD 这棵树里」,不是 CWD == ROOT:用户在仓库上一层启动
cd ~ && ~/airgap-coder/bin/lc code)时 .env 同样在工作区里。反过来在自己的
项目目录里跑就不响。

实际输出:

⚠️  这次 Codex 的工作目录里有 .env:/home/you/airgap-coder/.env
   会话是 approval_policy = "never",模型发的 shell 命令不用批准就执行,一句 `cat .env` 就能读走 2 个上游的地址与凭证。
   0600 挡的是别的用户,挡不住以你的身份运行的 Codex。
   要避开:cd 到你自己的项目目录再跑 lc code——工具目录和工作目录是两回事。

不阻断是有意的,理由写进了代码注释和威胁模型:在这个仓库里用 Codex 改这个
仓库是正当用法(docs/codex-workflow.md 正是这么教的),拒绝会挡住它;而加一个
放行 flag 的人以后会永远带着那个 flag,等于回到只警告但多一步。

2. docs/threat-model.md

新增 “Credentials in the Codex workspace” 一节:.env 为什么读得到、
workspace-write 只约束写不约束读、为什么选警告而不是阻断、以及真正的缓解手段
是目录分离。威胁表里加一行指向这一节。

3. 快速开始的措辞

README.md / README.zh-CN.md / docs/offline-deployment.mdlc code
「在仓库目录里那一串命令」里拆出来,改成先 cd 到自己的项目目录再跑,并加一条
[!IMPORTANT] 说清暴露面。离线包那条同理——lc init 把站点凭证写进包目录的
.env,在包目录里跑 lc code 是同一个形态。

明确没做

没有把 .env 搬出仓库。 按 issue 里的要求,那会牵动离线包流程、
docker run -v $PWD:/workspace 的挂载、lc init 的路径推导和所有测试里造假
.env 的方式,是个独立的架构决策。实现过程中也没有出现「非搬不可」的理由。

也没动 lc doctor(原提案里有,维护者收窄到了这三件)。

CI 覆盖

ci.yml 已经在跑 bash scripts/test-lc-commands.sh(static job),新断言随脚本
进 CI,不需要改 .github/。新增 [6f2],四种 CWD 各一条:

CWD 期望
工具目录本身 警告出现、点名文件路径、说出「2 个上游」、给出 cd 到你自己的项目目录,且照常启动 Codex--profile beta
用户自己的项目目录 出现警告,照常启动 Codex
仓库的上一层 出现警告(钉住判据是包含关系而非 CWD == ROOT
没有 .env 不出现警告

外加两条:警告本身不许把 API Key / master key 的值打出来——否则它自己就成了
泄漏源。新增 run_at() 辅助函数(在指定 CWD 下跑 lc)。

验证

本地跑过(无 GPU / 无模型 / 无 API Key):

  • python3 -m py_compile bin/lc scripts/*.pybash -n scripts/*.sh docker/entrypoint.shpython3 bin/lc --help
  • bash scripts/test-lc-commands.sh → 全部通过
  • test-lc-secrets.sh / test-export.sh / test-version.sh / test-doctor-probe.sh / test-entrypoint.sh / test-codex-review-script.sh / test-project-metadata.py → 全部通过(元数据检查覆盖双语 README 的章节数与链接有效性)
  • registry.example.json 当假 registry 跑 lc sync,生成的 litellm/config.yamluse_chat_completions_api: true 在)和 codex/config.toml 正确,跑完已删除

双向变异测试(这条警告最容易写成假的):

  1. 去掉 warn_env_in_workspace(reg) 调用 → 5 条「该响」的断言变红;
  2. relative_to 那道包含关系判断改成恒真 → 「在自己的项目目录里跑时不警告」
    变红。

第 2 条是关键:只有正向断言的话,一个恒真的实现也能全绿,而那正是「一条永远都
响的警告」。

🤖 Generated with Claude Code

#42 把注入给 Codex 的环境变量收到最小集,只关掉了「进程环境」这条读法。
lc code 是在当前工作目录里启动 Codex 的,配置又是 approval_policy = "never":
工作区里放着 .env 的话,一句 `cat .env` 就把 #42 收回去的东西全拿回来了。
0600 挡的是别的用户,挡不住以你的身份运行的 Codex。

按 issue 里定的范围做三件事,不搬 .env:

1. lc code 检测到「它要用的 .env 在 Codex 的工作目录这棵树里」时警告。判据是
   包含关系而不是 CWD == ROOT,所以在仓库上一层启动也会响;在自己的项目目录
   里跑不响——一条永远都响的警告等于没有警告。警告不阻断:在这个仓库里用
   Codex 改这个仓库是正当用法。
2. docs/threat-model.md 补一节,写清谁能读到什么、以及为什么是警告不是阻断。
3. README / README.zh-CN / docs/offline-deployment.md 的快速开始分开「工具目录」
   和「你的项目目录」,别再教用户在仓库根目录里跑 lc code。

Closes #46

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

lc code 在仓库目录里启动 Codex 时,.env 就躺在工作区里,模型直接 cat 就能读——#42 只堵住了进程环境那一面

1 participant