Skip to content

fix(cli): 联网命令遵循 HTTP(S)_PROXY / NO_PROXY(0.9.1) - #30

Merged
HarlonWang merged 2 commits into
mainfrom
fix/cli-env-proxy
Oct 11, 2026
Merged

HarlonWang merged 2 commits into
mainfrom
fix/cli-env-proxy

Conversation

@HarlonWang

@HarlonWang HarlonWang commented Oct 11, 2026 •

Copy link
Copy Markdown
Member

问题

Node 内置 fetch 不读 HTTPS_PROXY 等代理环境变量(除非进程以 NODE_USE_ENV_PROXY 启动),挂代理的机器上 tinyui pull / publish / hosts upload 一律报 fetch failed。TrendingAI 的发版冒烟就因此拉不到内置包。

改动

  • packages/cli/src/proxy.ts:检测到代理变量时,用 undici 的 EnvHttpProxyAgent(同时遵循 NO_PROXY)设为全局 dispatcher;没有代理变量时不 import undici。bin.ts 在执行命令前调用。
  • undici 取 7.x:8.x 要求 Node >=22.19,而 F-Droid 构建机(Debian trixie)是 Node 20,那里会用 tinyui-cli 从源码编页面。
  • 测试:本地起一个处理 CONNECT 的代理,断言全局 fetch 经由它转发。
  • 版本号 0.9.1,RuntimeBytecode.kt 随之重新生成。quickjs-kmp 不变(仍 0.1.2)。

验证

  • 本地按 CI 顺序:build / schema:check / runtime:check / typecheck / test 全过(core 43、native 12、cli 93)。
  • 端到端:本机挂代理、未设 NODE_USE_ENV_PROXY,新 CLI tinyui pull 成功;同命令 0.9.0 报 fetch failed。

🤖 Generated with Claude Code

Summary by Sourcery

Enable reliable proxied network access for CLI commands while preserving direct connections when no proxy is configured.

New Features:

  • Make CLI network commands honor HTTP(S)_PROXY and NO_PROXY environment variables, including case variants.

Bug Fixes:

  • Fix CLI network operations failing behind configured proxies when Node does not automatically apply proxy environment settings.

Enhancements:

  • Load proxy support only when proxy variables are configured and use a Node 20-compatible undici release.
  • Add proxy routing coverage for global fetch through an HTTP CONNECT proxy.

Documentation:

  • Document proxy environment variable support for CLI network commands.

Tests:

  • Add tests covering disabled proxy configuration and proxied fetch requests.

Chores:

  • Bump tinyui-cli, tinyui-core, and tinyui-native to 0.9.1 and regenerate the associated runtime bytecode.

HarlonWang and others added 2 commits October 11, 2026 20:50
Node 内置 fetch 不读代理环境变量(除非以 NODE_USE_ENV_PROXY 启动),挂代理的机器上
pull / publish / hosts upload 等一律 "fetch failed"。检测到代理变量时用 undici 的
EnvHttpProxyAgent 设为全局 dispatcher;没有代理变量时不加载 undici。
undici 取 7.x:8.x 要求 Node >=22.19,而 F-Droid 构建机(Debian trixie)是 Node 20。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sourcery-ai

sourcery-ai Bot commented Oct 11, 2026 •

Copy link
Copy Markdown

Reviewer's Guide

该 PR 使用 undici 7.x 的 EnvHttpProxyAgent,在 CLI 执行联网命令前按需接管全局 fetch,使其遵循 HTTP(S)_PROXY 和 NO_PROXY,同时通过本地 CONNECT 代理测试验证转发,并将相关包版本发布为 0.9.1。

Sequence diagram for CLI proxy-aware fetch

sequenceDiagram
    participant User
    participant CLI as tinyui CLI
    participant ProxySetup as useEnvProxy
    participant Fetch as global fetch
    participant Proxy as HTTP(S) proxy
    participant Server as Updates server

    User->>CLI: run networking command
    CLI->>ProxySetup: useEnvProxy()
    alt HTTP_PROXY or HTTPS_PROXY is set
        ProxySetup->>ProxySetup: import("undici")
        ProxySetup->>ProxySetup: setGlobalDispatcher(new EnvHttpProxyAgent(...))
    end
    CLI->>Fetch: fetch(updates request)
    alt request matches NO_PROXY
        Fetch->>Server: direct HTTPS request
    else request uses proxy
        Fetch->>Proxy: CONNECT / proxied request
        Proxy->>Server: forward request
        Server-->>Proxy: response
        Proxy-->>Fetch: response
    end
    Fetch-->>CLI: response
Loading

File-Level Changes

Change Details Files
为 CLI 全局 fetch 增加基于环境变量的 HTTP(S) 代理支持。
  • 在命令执行前检测大小写形式的 HTTP(S)_PROXY,并按需动态加载 undici 7.x。
  • 通过 EnvHttpProxyAgent 配置代理与 NO_PROXY,并设置为全局 dispatcher。
  • 新增本地 CONNECT 代理测试,覆盖无代理与 HTTP_PROXY 转发场景。
packages/cli/src/proxy.ts
packages/cli/src/bin.ts
packages/cli/test/proxy.test.ts
packages/cli/package.json
pnpm-lock.yaml
同步发布 0.9.1 版本及生成产物。
  • 将 CLI、core 和 native 的版本从 0.9.0 更新到 0.9.1。
  • 重新生成运行时字节码并更新 CLI 文档中的代理行为说明。
packages/cli/package.json
packages/core/package.json
packages/core/src/version.ts
packages/native/package.json
packages/native/src/index.ts
compose/src/commonMain/kotlin/app/tinyui/generated/RuntimeBytecode.kt
packages/cli/README.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Oct 11, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: c733c34c-b416-4537-9622-20532bd0b27c

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codeseerbot codeseerbot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CodeSeer 审查

结论:批准

摘要

本次改动为 CLI 在检测到 HTTP(S)_PROXY 时安装 undici 的 EnvHttpProxyAgent,使全局 fetch 同时遵循 NO_PROXY,并补充了代理转发测试与文档说明。bin.ts 在命令执行前完成初始化,未设置代理变量时不会动态加载 undici。同步将 core、native 和 CLI 版本更新为 0.9.1,并重新生成运行时字节码。

按规则不审的文件

  • pnpm-lock.yaml:lock 文件

整个 PR 至 ead8589 · gpt-5.6-terra

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 3 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="packages/cli/src/proxy.ts" line_range="15-18" />
<code_context>
+    const httpProxy = env.HTTP_PROXY ?? env.http_proxy;
+    const httpsProxy = env.HTTPS_PROXY ?? env.https_proxy;
+    const noProxy = env.NO_PROXY ?? env.no_proxy;
+    setGlobalDispatcher(new EnvHttpProxyAgent({
+        ...(httpProxy !== undefined && { httpProxy }),
+        ...(httpsProxy !== undefined && { httpsProxy }),
+        ...(noProxy !== undefined && { noProxy }),
+    }));
+    return true;
</code_context>
<issue_to_address>
**Loopback requests leak tokens**

When a proxy is configured and an authenticated command targets an allowed loopback HTTP URL that `NO_PROXY` does not exclude, `EnvHttpProxyAgent` sends the request through the proxy, so local Wrangler commands fail to reach the server and the proxy can read bearer tokens. Add loopback hosts to the default `NO_PROXY` exclusions.

Ensure localhost and loopback addresses are excluded from proxying even when `NO_PROXY` is unset or does not list them.
</issue_to_address>

### Comment 2
<location path="packages/cli/src/bin.ts" line_range="394" />
<code_context>
         return argv.includes("--help") || argv.includes("-h") ? 0 : 2;
     }
     const { values, positionals } = parseArgs({ args: argv, allowPositionals: true, options: command.options });
+    await useEnvProxy();
     return command.run(values, positionals);
 }
</code_context>
<issue_to_address>
**Offline commands fail**

When a proxy variable contains a malformed URL and the user invokes an offline command, `useEnvProxy()` constructs `EnvHttpProxyAgent` before `command.run`, so the malformed URL throws and commands such as `build`, `bundle`, and `schema` do not run.

Bypass proxy initialization for commands that do not make network requests.
</issue_to_address>

### Comment 3
<location path="packages/cli/src/proxy.ts" line_range="12" />
<code_context>
+export async function useEnvProxy(env: NodeJS.ProcessEnv = process.env): Promise<boolean> {
+    if (!PROXY_ENV.some((name) => env[name])) return false;
+    const { EnvHttpProxyAgent, setGlobalDispatcher } = await import("undici");
+    const httpProxy = env.HTTP_PROXY ?? env.http_proxy;
+    const httpsProxy = env.HTTPS_PROXY ?? env.https_proxy;
+    const noProxy = env.NO_PROXY ?? env.no_proxy;
</code_context>
<issue_to_address>
**Configured proxy is ignored**

When an uppercase proxy or `NO_PROXY` variable is empty while its lowercase counterpart is configured, `??` selects the empty uppercase value instead of the configured lowercase value, so `EnvHttpProxyAgent` receives an empty proxy URL or `noProxy` list and requests use the wrong routing behavior.

Treat empty uppercase values as unset when falling back to lowercase environment variables.
</issue_to_address>

Sourcery assessment

Needs a human reviewer. 3 findings to address first, and the change reroutes authenticated CLI requests through environment-selected proxies and introduces a new networking dependency; if the proxy handling is wrong, update tokens or publish operations could be exposed or sent to an unintended intermediary. Reverting stops future rerouting, but any credential exposure or externally performed request that already occurred cannot be undone.

Blocking findings: packages/cli/src/proxy.ts:18, packages/cli/src/bin.ts:394, packages/cli/src/proxy.ts:12


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread packages/cli/src/proxy.ts
Comment on lines +15 to +18
setGlobalDispatcher(new EnvHttpProxyAgent({
...(httpProxy !== undefined && { httpProxy }),
...(httpsProxy !== undefined && { httpsProxy }),
...(noProxy !== undefined && { noProxy }),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium · Loopback requests leak tokens

When a proxy is configured and an authenticated command targets an allowed loopback HTTP URL that NO_PROXY does not exclude, EnvHttpProxyAgent sends the request through the proxy, so local Wrangler commands fail to reach the server and the proxy can read bearer tokens. Add loopback hosts to the default NO_PROXY exclusions.

Ensure localhost and loopback addresses are excluded from proxying even when NO_PROXY is unset or does not list them.

Prompt for AI agents
In `packages/cli/src/proxy.ts` at lines 15-18:

**Loopback requests leak tokens**

When a proxy is configured and an authenticated command targets an allowed loopback HTTP URL that `NO_PROXY` does not exclude, `EnvHttpProxyAgent` sends the request through the proxy, so local Wrangler commands fail to reach the server and the proxy can read bearer tokens. Add loopback hosts to the default `NO_PROXY` exclusions.

Ensure localhost and loopback addresses are excluded from proxying even when `NO_PROXY` is unset or does not list them.

Comment thread packages/cli/src/bin.ts
return argv.includes("--help") || argv.includes("-h") ? 0 : 2;
}
const { values, positionals } = parseArgs({ args: argv, allowPositionals: true, options: command.options });
await useEnvProxy();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium · Offline commands fail

When a proxy variable contains a malformed URL and the user invokes an offline command, useEnvProxy() constructs EnvHttpProxyAgent before command.run, so the malformed URL throws and commands such as build, bundle, and schema do not run.

Bypass proxy initialization for commands that do not make network requests.

Prompt for AI agents
In `packages/cli/src/bin.ts` at line 394:

**Offline commands fail**

When a proxy variable contains a malformed URL and the user invokes an offline command, `useEnvProxy()` constructs `EnvHttpProxyAgent` before `command.run`, so the malformed URL throws and commands such as `build`, `bundle`, and `schema` do not run.

Bypass proxy initialization for commands that do not make network requests.

Comment thread packages/cli/src/proxy.ts
export async function useEnvProxy(env: NodeJS.ProcessEnv = process.env): Promise<boolean> {
if (!PROXY_ENV.some((name) => env[name])) return false;
const { EnvHttpProxyAgent, setGlobalDispatcher } = await import("undici");
const httpProxy = env.HTTP_PROXY ?? env.http_proxy;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium · Configured proxy is ignored

When an uppercase proxy or NO_PROXY variable is empty while its lowercase counterpart is configured, ?? selects the empty uppercase value instead of the configured lowercase value, so EnvHttpProxyAgent receives an empty proxy URL or noProxy list and requests use the wrong routing behavior.

Treat empty uppercase values as unset when falling back to lowercase environment variables.

Prompt for AI agents
In `packages/cli/src/proxy.ts` at line 12:

**Configured proxy is ignored**

When an uppercase proxy or `NO_PROXY` variable is empty while its lowercase counterpart is configured, `??` selects the empty uppercase value instead of the configured lowercase value, so `EnvHttpProxyAgent` receives an empty proxy URL or `noProxy` list and requests use the wrong routing behavior.

Treat empty uppercase values as unset when falling back to lowercase environment variables.

@HarlonWang
HarlonWang merged commit fc5071d into main Oct 11, 2026
5 checks passed
@HarlonWang
HarlonWang deleted the fix/cli-env-proxy branch October 11, 2026 12:55
HarlonWang added a commit that referenced this pull request Oct 11, 2026
* fix(cli): 代理按审查意见收紧——回环直连、无法解析时不中断、空大写变量回退小写

#30 的 Sourcery 审查指出的三处(0.9.1 已发出):
- 本机回环地址始终加入 NO_PROXY:本地实例经代理不可达,明文 http 下 token 会经过代理
- 代理变量无法解析时提示并直连,不再让 build / bundle / schema 等离线命令失败
- `??` 改 `||`:HTTP_PROXY="" 不再遮住已配置的 http_proxy
每条各有测试;改回旧写法时对应测试失败。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* chore: 版本号 0.9.2

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(cli): 代理初始化失败时装回直连 dispatcher,与「直连」提示一致

CodeSeer 审查 #31:先装过有效代理、再遇到无法解析的设置时,旧代理仍在生效。

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.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.

1 participant