DEBUG.WIKI
雨云;给项目一台云服务器
晚安云;香港 CN2 ¥15/月
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →

Deno execFileSync 删除 env 中的 CI,子进程仍收到父值

Deno 2.9.6 同步子进程兼容接口会叠加父环境,2.9.8 正式路径仍未清空。区分缺省和空值,使用明确的 clearEnv 或重新设计异步调用。

从复制的 process.env 中删除 CI,再通过 Deno 的 execFileSync() 启动脚本,子进程却仍读到 CI=true。如果同样的环境对象交给异步 spawn() 就正常,检查同步 Node 兼容接口是否仍继承了父环境。

Deno 2.9.6 的这条同步路径会在父环境上叠加传入的 env,而不是用它替换父环境;2.9.8 正式源码中的同步调用仍是 clearEnv: false。因此“对象里没有这个键”与“子进程里没有这个变量”可能不一致。

删除副本中的键,不会覆盖父进程的值

例如,以下片段只构造环境,不会改动父进程:

const childEnv = { ...process.env };
delete childEnv.CI;

Node 的相应子进程接口按显式 env 生成子环境;受影响的 Deno 同步实现仍保留父变量。异步路径已经使用 clearEnv: true,不能把异步接口的行为或修复范围自动延伸到 spawnSync()、execFileSync() 和 execSync()。

不要用打印整份环境的方式验证。环境里可能有访问令牌和服务密码,选择无敏感内容的探针变量,观察指定键是否存在即可。

需要真正隔离环境时,明确清空继承

应用可以使用 Deno 原生进程接口、且确实需要同步等待时,可评估 Deno.Command 的 clearEnv。下面是 POSIX 结构示例,程序路径和参数须替换为项目获准执行的目标:

const command = new Deno.Command('/absolute/path/to/program', {
  args: ['--check'],
  env: childEnv,
  clearEnv: true,
  stdout: 'piped',
  stderr: 'piped',
});
const output = command.outputSync();

目标程序、所需环境项、权限和退出状态仍由应用负责核对。outputSync() 返回的是 Deno 的输出结构,不是 execFileSync() 的字符串结果,不能只换函数名就沿用原来的调用方。Windows 的程序定位和必要系统变量也要按实际环境配置。

另一种选择是改用行为已核对的异步 spawn(),并按原有业务要求等待关闭、处理输出和错误;它会改变调用时序,不能把它塞进要求同步返回值的接口中。

如果子程序把空字符串当成未设置,显式写入 { ...process.env, CI: '' } 可以覆盖父值。但环境变量仍然存在;若子程序判断的是键是否存在,这个办法无效。需要严格去除凭据时,更不能把“置空 CI”的规避扩展成通用环境隔离方案。

验收变量是否存在,而不只是它的真假值

在受控环境中给父进程设置一个无敏感探针,分别检查子环境省略该键、显式空值与显式普通值的结果。应区分不存在、空字符串和原父值三种状态,避免子脚本的布尔判断隐藏了差异。

截至 2026 年 10 月 23 日,2.9.8 的同步接口仍需按上述环境继承规则处理。若采用更新的正式版,应核对实际安装版本对应的同步实现及上述隔离结果,再恢复项目原有进程调用方式。