Skip to content

feat(core): --insecure flag and QWEN_TLS_INSECURE env var (#3535) - #3635

Closed
JahanzaibTayyab wants to merge 2 commits into
QwenLM:mainfrom
JahanzaibTayyab:feat/3535-tls-insecure-flag
Closed

feat(core): --insecure flag and QWEN_TLS_INSECURE env var (#3535)#3635
JahanzaibTayyab wants to merge 2 commits into
QwenLM:mainfrom
JahanzaibTayyab:feat/3535-tls-insecure-flag

Conversation

@JahanzaibTayyab

Copy link
Copy Markdown

Closes #3535.

What

Allow skipping TLS certificate verification for outbound HTTPS requests to model APIs and MCP servers. Required for self-signed dev / lab / homelab endpoints because Node's bundled HTTP client (undici, used by fetch) ignores NODE_TLS_REJECT_UNAUTHORIZED by design — Claude Code works in those setups only because Anthropic's SDK reads the env var back through a custom agent. Qwen Code does not, so today a user with a self-signed Qwen3.6 server has no escape hatch and just sees:

[API Error: Connection error. (cause: fetch failed)]

This PR adds three coordinated entry points and threads the resolved value through every place an undici dispatcher is constructed.

How (resolution order, highest to lowest)

  1. --insecure CLI flag
  2. QWEN_TLS_INSECURE=1|true|yes (case-insensitive)
  3. NODE_TLS_REJECT_UNAUTHORIZED=0 — for parity with Claude Code and Node's legacy http stack. We respect this even though fetch itself doesn't, because users reasonably expect the global Node convention to apply.

When set, the resolver passes connect: { rejectUnauthorized: false } to:

  • the OpenAI SDK's undici dispatcher (default + DashScope providers),
  • the Anthropic SDK's undici dispatcher,
  • and the global undici dispatcher used by MCP / streaming / telemetry traffic — so the flag is uniform across the whole process, not only the SDK clients we control.

Behavior matrix

Layer set Before After
--insecure unsupported TLS skipped ✅
QWEN_TLS_INSECURE=1 unsupported TLS skipped ✅
NODE_TLS_REJECT_UNAUTHORIZED=0 silent no-op TLS skipped ✅
NODE_TLS_REJECT_UNAUTHORIZED=1 n/a unchanged (verification on)
Combined with --proxy <url> n/a both honored on ProxyAgent

Areas needing careful review

  1. Backwards-compatible signature change to buildRuntimeFetchOptions. Second arg now accepts either a bare proxy-URL string (legacy) or a RuntimeFetchConfig object ({ proxyUrl?, insecure? }). normalizeConfig() reduces both to the same internal shape, and a regression test pins the equivalence ('treats a bare proxy-URL string identically to legacy callers'). Open to renaming the option to tlsRejectUnauthorized: false if maintainers prefer matching Node's exact spelling.
  2. Global dispatcher mutation. The constructor now also calls setGlobalDispatcher(new Agent({ connect: { rejectUnauthorized: false } })) when insecure is set without a proxy. This is process-wide, but only triggered by an explicit opt-in flag/env, and the existing proxy path already mutates global state in the same place — I followed that pattern rather than introducing a new injection point.
  3. insecure: undefined in two CliArgs literals. auth/handler.ts and gemini.test.tsx build a fully-spread CliArgs literal so I added insecure: undefined rather than make the field optional in the interface; matches the surrounding proxy: undefined style.

Tests

  • runtimeFetchOptions.test.ts: 5 new cases pinning the connect option behavior (omitted when unset, present on both Agent and ProxyAgent when insecure=true, also threaded for Anthropic), plus a string-vs-object equivalence test.
  • cli/config.test.ts: 7 new cases covering the three precedence layers, the negation cases (=0, =1, arbitrary values), and the --insecure overrides QWEN_TLS_INSECURE=0 interaction.
  • Existing provider mocks (default.test.ts, dashscope.test.ts, anthropicContentGenerator.test.ts) updated to expose getInsecure() so the new call sites resolve.

Testing

  • Tested locally
  • All targeted suites pass: 2,134 core + 439 CLI tests
  • npm run build clean (full TypeScript build)
  • Added tests for new functionality
  • Docs updated (docs/users/support/troubleshooting.md)

Prepared with assistance from Claude (Anthropic) under human review.

…#3535)

Allow skipping TLS certificate verification for outbound HTTPS requests
to model APIs and MCP servers. Required for self-signed dev/lab/homelab
endpoints because Node's bundled HTTP client (undici, used by fetch)
ignores NODE_TLS_REJECT_UNAUTHORIZED by design -- Claude Code works in
those setups only because Anthropic's SDK reads it back through a custom
agent. Qwen Code does not, so users had no escape hatch.

Resolution order (highest to lowest):
  1. --insecure CLI flag
  2. QWEN_TLS_INSECURE=1|true|yes (case-insensitive)
  3. NODE_TLS_REJECT_UNAUTHORIZED=0  (parity with Claude Code / legacy
     Node http stack -- now also respected here)

When set, the resolver passes connect: { rejectUnauthorized: false } to
the undici Agent / ProxyAgent used as the dispatcher for the OpenAI,
Anthropic, and DashScope SDK clients, and to the global dispatcher
that backs MCP / streaming / telemetry traffic.

- packages/core/src/utils/runtimeFetchOptions.ts: builder now accepts
  either a bare proxy-URL string (legacy positional form) or a
  RuntimeFetchConfig object carrying proxyUrl + insecure. Pre-existing
  callers continue to work unchanged.
- packages/core/src/config/config.ts: new ConfigParameters.insecure
  field, getInsecure() accessor, and setGlobalDispatcher block updated
  to apply rejectUnauthorized: false when no proxy is configured.
- packages/cli/src/config/config.ts: new --insecure yargs option and
  resolveInsecureFlag() helper that stitches the three sources
  together with a clear precedence.
- All three SDK provider builders (default OpenAI, DashScope, Anthropic)
  now thread cliConfig.getInsecure() through the runtime options.
- docs/users/support/troubleshooting.md: documents why
  NODE_TLS_REJECT_UNAUTHORIZED alone fails for fetch-based code paths
  and which flag/env vars to use instead.

Tests
- packages/core/src/utils/runtimeFetchOptions.test.ts: 5 new cases
  pinning the connect option behavior (omitted when unset, present on
  both Agent and ProxyAgent when insecure=true) and confirming the
  string and object forms produce identical output.
- packages/cli/src/config/config.test.ts: 7 new cases covering the
  three precedence layers, the negation cases (=0, =1, arbitrary
  values), and the override interaction.
- Existing provider mocks updated to expose getInsecure() so the new
  call sites resolve.

Affected suite: 2,134 core + 439 CLI tests pass; full TypeScript build
clean.

Prepared with assistance from Claude (Anthropic) under human review.
Copilot AI review requested due to automatic review settings April 26, 2026 07:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds an opt-in mechanism to disable TLS certificate verification for outbound HTTPS traffic (model providers, MCP, telemetry), addressing self-signed / lab endpoints where undici-backed fetch ignores NODE_TLS_REJECT_UNAUTHORIZED.

Changes:

  • Introduces --insecure and QWEN_TLS_INSECURE / NODE_TLS_REJECT_UNAUTHORIZED resolution in the CLI and threads the resolved value into core config.
  • Extends buildRuntimeFetchOptions() to accept { proxyUrl?, insecure? } (while preserving legacy string proxy argument) and applies connect: { rejectUnauthorized: false } to undici dispatchers.
  • Updates tests/mocks and troubleshooting docs to cover the new behavior.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
packages/core/src/utils/runtimeFetchOptions.ts Adds RuntimeFetchConfig + insecure TLS wiring into undici Agent/ProxyAgent dispatchers.
packages/core/src/utils/runtimeFetchOptions.test.ts Adds unit tests ensuring connect.rejectUnauthorized=false is applied/omitted correctly and preserves legacy proxy arg behavior.
packages/core/src/core/openaiContentGenerator/provider/default.ts Passes { proxyUrl, insecure } into runtime fetch options for OpenAI-compatible provider.
packages/core/src/core/openaiContentGenerator/provider/default.test.ts Updates provider mock config to include getInsecure().
packages/core/src/core/openaiContentGenerator/provider/dashscope.ts Threads { proxyUrl, insecure } into DashScope provider runtime fetch options.
packages/core/src/core/openaiContentGenerator/provider/dashscope.test.ts Updates provider mock config to include getInsecure().
packages/core/src/core/anthropicContentGenerator/anthropicContentGenerator.ts Threads { proxyUrl, insecure } into Anthropic SDK runtime fetch options.
packages/core/src/core/anthropicContentGenerator/anthropicContentGenerator.test.ts Updates generator mock config to include getInsecure().
packages/core/src/config/config.ts Adds insecure param + getter and applies it to the global undici dispatcher (with/without proxy).
packages/cli/src/config/config.ts Adds --insecure flag, env var resolution, and passes resolved value into core Config.
packages/cli/src/config/config.test.ts Adds precedence tests for --insecure, QWEN_TLS_INSECURE, and NODE_TLS_REJECT_UNAUTHORIZED.
packages/cli/src/commands/auth/handler.ts Extends minimal CliArgs literal to include insecure.
packages/cli/src/gemini.test.tsx Updates test CliArgs literal to include insecure.
docs/users/support/troubleshooting.md Documents self-signed endpoint failure mode and the new insecure escape hatches.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/cli/src/config/config.ts
…eview)

Yargs ``default: false`` collapsed two distinct user intents -- "didn't
pass the flag" and "passed --no-insecure" -- into a single boolean
``false`` at parse time, so ``QWEN_TLS_INSECURE=1 --no-insecure`` ended
up enabling insecure mode despite the documented "CLI wins" precedence.

Drop the default so the parsed value is tri-state
(``true | false | undefined``), and treat any explicit value
(including ``false``) as the highest-precedence override in
``resolveInsecureFlag``. ``undefined`` continues to fall through to
``QWEN_TLS_INSECURE`` and ``NODE_TLS_REJECT_UNAUTHORIZED`` as before.

Two new tests pin the override behavior:
- ``QWEN_TLS_INSECURE=1`` + ``--no-insecure`` -> verification on
- ``NODE_TLS_REJECT_UNAUTHORIZED=0`` + ``--no-insecure`` -> verification on
uri: proxyUrl,
headersTimeout: 0,
bodyTimeout: 0,
...(connect ? { connect } : {}),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Critical] This passes rejectUnauthorized: false under connect, but undici ProxyAgent does not use connect for TLS to the tunneled upstream request. In undici, the target HTTPS TLS options are read from requestTls, so --insecure will still reject self-signed model endpoints whenever --proxy is configured.

Suggested change
...(connect ? { connect } : {}),
...(connect ? { requestTls: connect } : {}),

— gpt-5.5 via Qwen Code /review

new ProxyAgent({
uri: proxyUrl,
...(connect ? { connect } : {}),
}),

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Critical] The global proxy dispatcher has the same issue: ProxyAgent needs upstream TLS options in requestTls, not connect. As written, MCP/streaming/telemetry fetches that rely on the global dispatcher will still fail against self-signed HTTPS targets when a proxy is configured, despite insecure being enabled.

Suggested change
}),
...(connect ? { requestTls: connect } : {}),

— gpt-5.5 via Qwen Code /review

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

No additional inline comments from this review. The previously collected packages/cli/src/utils/modelConfigUtils.ts finding is not present in the current GitHub PR diff, so it was not posted. Existing Qwen Code comments on ProxyAgent TLS options still cover the remaining confirmed issue.

— gpt-5.5 via Qwen Code /review

@wenshao

wenshao commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

🔬 Local verification report — PR #3635 feat(core): --insecure flag and QWEN_TLS_INSECURE env var

Verdict: the mechanism works correctly and is safely gated, but this PR is not mergeable as-is and its motivating premise is outdated for the current runtime. Two things need maintainer attention before merge: (1) it conflicts with main and needs a rebase, and (2) NODE_TLS_REJECT_UNAUTHORIZED=0 already works for undici fetch in the current Node/undici, so the "no escape hatch" framing no longer holds — the genuinely-new value is the --insecure flag and QWEN_TLS_INSECURE var.

How it was verified

Real vitest + a real self-signed HTTPS server driven via tsx under tmux, on a worktree at the PR head (b1eb211a). Env: Node v22.22.2, undici 7.27.2. (The PR could not be merged into main to verify the merged state — see conflicts below — so functionality was verified on the PR head directly.)

1) Merge status — ⚠️ conflicting, needs rebase

git merge-tree origin/main pr3635-head8 conflicting files, including a modify/delete conflict:

  • packages/cli/src/commands/auth/handler.tsdeleted on main, modified by the PR
  • content conflicts in cli/config.ts, core/config.ts, runtimeFetchOptions.ts(+test), provider/default.ts, provider/dashscope.ts, anthropicContentGenerator.ts(+test)

The branch is ~2 months old (merge-base a6b0b7e5, Apr 26) and main has refactored most of the touched files. It cannot be merged without a non-trivial rebase, and the threading into providers/config will need to be re-applied against the current code.

2) Mechanism — ✅ correct & safe (real self-signed HTTPS E2E)

A self-signed cert + a real https server, fetched through the dispatcher that buildRuntimeFetchOptions produces:

scenario result
plain fetch, verification on (control) FAILS DEPTH_ZERO_SELF_SIGNED_CERT
buildRuntimeFetchOptions(insecure:false) FAILS ✅ (no accidental bypass)
legacy string form (proxy only, no insecure) FAILS ✅ (back-compat safe)
buildRuntimeFetchOptions(insecure:true) (OpenAI) 200 OK
Anthropic shape, insecure:true 200 OK
global dispatcher insecure, plain fetch (MCP/streaming/telemetry path) 200 OK

So connect:{rejectUnauthorized:false} genuinely disables verification when opted in, and verification stays on otherwise — no accidental weakening. The precedence resolver and string/object equivalence are also unit-tested.

3) Unit tests on PR head — ✅

  • runtimeFetchOptions.test.ts: 9/9 pass
  • cli/config.test.tsInsecure / TLS-skip configuration (#3535): 8/8 pass (all three precedence layers + --no-insecure overrides + negation cases)
  • eslint on the changed source files: clean

4) ⚠️ Premise check — NODE_TLS_REJECT_UNAUTHORIZED=0 already works today

The PR's motivation is "undici (used by fetch) ignores NODE_TLS_REJECT_UNAUTHORIZED by design … so today a user has no escape hatch" and lists that layer as "Before: silent no-op". In the current runtime this is no longer true:

NODE_TLS_REJECT_UNAUTHORIZED=0  →  plain undici fetch         → SUCCEEDED (200)
NODE_TLS_REJECT_UNAUTHORIZED=0  →  provider Agent (insecure:false, the Agent main builds today) → SUCCEEDED (200)
NODE_TLS_REJECT_UNAUTHORIZED=1  →  same paths                 → FAILED  (DEPTH_ZERO_SELF_SIGNED_CERT)

Because the provider Agent does not explicitly set rejectUnauthorized, it inherits Node's global TLS default, which NODE_TLS_REJECT_UNAUTHORIZED controls. So on current main, NODE_TLS_REJECT_UNAUTHORIZED=0 already lets fetch-based provider calls skip verification — the escape hatch the PR says is missing already exists (likely a Node/undici behavior change since April). This makes the PR's NODE_TLS_REJECT_UNAUTHORIZED layer largely redundant. The net-new, still-valuable parts are the explicit, discoverable --insecure flag and QWEN_TLS_INSECURE env var, and making the intent explicit rather than relying on Node's implicit global inheritance.

5) Security considerations (for review)

  • Disabling TLS verification exposes traffic to MITM. The PR correctly gates it behind explicit opt-in (flag/env) and keeps verification on by default — verified above. 👍
  • All-or-nothing scope. The global-dispatcher mutation makes the setting process-wide: enabling --insecure for one self-signed model endpoint also disables verification for every other outbound call (telemetry, all MCP servers, streaming). There is no per-host scoping. Worth calling out in the docs/UX (a one-time warning when insecure mode is active would be prudent).

Recommendation

The feature is implemented soundly and is safe-by-default, but: (a) rebase onto current main (re-applying the provider/config threading; resolve the auth/handler.ts modify/delete), (b) re-validate the premise — NODE_TLS_REJECT_UNAUTHORIZED=0 already works, so the description/behavior-matrix should be updated and the team should decide whether the remaining value (--insecure / QWEN_TLS_INSECURE convenience + explicitness) justifies the surface area, (c) re-run npm run build / typecheck after the rebase (not meaningfully runnable on this stale branch against current deps), and consider a runtime warning given the all-or-nothing scope.

🇨🇳 中文版(点击展开)

🔬 本地验证报告 — PR #3635 feat(core): --insecure 标志与 QWEN_TLS_INSECURE 环境变量

结论:机制本身正确、且默认安全(仅显式开启时才跳过校验),但本 PR 目前无法直接合并,且其立论前提在当前运行时已过时。 合并前需要维护者关注两点:(1) 它与 main 存在冲突,需要 rebase;(2) 在当前 Node/undici 下,NODE_TLS_REJECT_UNAUTHORIZED=0 已经能让 undici fetch 跳过校验,因此“没有逃生通道”的说法不再成立——真正新增的价值是 --insecure 标志和 QWEN_TLS_INSECURE 变量。

验证方式

tmux 中运行真实 vitest + 一个真实的自签名 HTTPS 服务器(用 tsx 驱动),worktree 检出在 PR head(b1eb211a)。环境:Node v22.22.2、undici 7.27.2。(由于存在冲突,无法把 PR 合入 main 后验证合并态——见下——所以直接在 PR head 上验证功能。)

1) 合并状态 —— ⚠️ 冲突,需要 rebase

git merge-tree origin/main pr3635-head8 个冲突文件,含一个 modify/delete 冲突:

  • packages/cli/src/commands/auth/handler.ts —— 在 main已被删除,本 PR 又修改了它
  • 内容冲突:cli/config.tscore/config.tsruntimeFetchOptions.ts(+test)、provider/default.tsprovider/dashscope.tsanthropicContentGenerator.ts(+test)

该分支约 2 个月前(merge-base a6b0b7e5,4/26),main 已重构了大部分被改文件。没有非平凡的 rebase 无法合并,对 providers/config 的串联需要在当前代码上重新施加。

2) 机制 —— ✅ 正确且安全(真实自签名 HTTPS E2E)

自签名证书 + 真实 https 服务器,经 buildRuntimeFetchOptions 产出的 dispatcher 发起请求:

场景 结果
普通 fetch,开启校验(对照) 失败 DEPTH_ZERO_SELF_SIGNED_CERT
buildRuntimeFetchOptions(insecure:false) 失败 ✅(不会误绕过)
旧版字符串形式(仅 proxy,无 insecure) 失败 ✅(向后兼容安全)
buildRuntimeFetchOptions(insecure:true)(OpenAI) 200 OK
Anthropic 形态,insecure:true 200 OK
全局 dispatcher insecure,普通 fetch(MCP/streaming/telemetry 路径) 200 OK

connect:{rejectUnauthorized:false} 在显式开启时确实跳过校验,否则保持开启——不会意外削弱安全。优先级解析与字符串/对象等价也有单测覆盖。

3) PR head 上的单测 —— ✅

  • runtimeFetchOptions.test.ts9/9 通过
  • cli/config.test.tsInsecure / TLS-skip configuration (#3535)8/8 通过(三层优先级 + --no-insecure 覆盖 + 反向用例)
  • 改动源文件 eslint:干净

4) ⚠️ 前提核查 —— NODE_TLS_REJECT_UNAUTHORIZED=0 现在已经生效

PR 的立论是“undici(fetch 使用)按设计忽略 NODE_TLS_REJECT_UNAUTHORIZED …… 所以用户没有逃生通道”,并把该层标为 “Before: silent no-op”。在当前运行时这已不成立

NODE_TLS_REJECT_UNAUTHORIZED=0  →  普通 undici fetch                → 成功 (200)
NODE_TLS_REJECT_UNAUTHORIZED=0  →  provider Agent(insecure:false,即 main 今天构造的 Agent) → 成功 (200)
NODE_TLS_REJECT_UNAUTHORIZED=1  →  同上路径                         → 失败 (DEPTH_ZERO_SELF_SIGNED_CERT)

因为 provider 的 Agent 没有显式设置 rejectUnauthorized,它会继承 Node 的全局 TLS 默认值,而该默认值由 NODE_TLS_REJECT_UNAUTHORIZED 控制。因此在当前 main 上,NODE_TLS_REJECT_UNAUTHORIZED=0 已经能让基于 fetch 的 provider 调用跳过校验——PR 所说“缺失”的逃生通道其实已存在(很可能是 4 月以来 Node/undici 行为变化所致)。这使 PR 的 NODE_TLS_REJECT_UNAUTHORIZED 这一层基本变得冗余。真正新增且仍有价值的是显式、可发现的 --insecure 标志与 QWEN_TLS_INSECURE 环境变量,以及让意图显式化(而非依赖 Node 的隐式全局继承)。

5) 安全考量(供评审)

  • 关闭 TLS 校验会暴露于中间人攻击。PR 正确地将其限定为显式开启(标志/环境变量),默认仍开启校验——上文已验证。👍
  • 全有或全无的范围。 全局 dispatcher 改动让该设置作用于整个进程:为某个自签名模型端点开启 --insecure,也会对所有其他出站请求(telemetry、所有 MCP server、streaming)关闭校验,没有按 host 的细分。建议在文档/UX 里明确提示(开启 insecure 模式时给一次性告警更稳妥)。

建议

功能实现稳健、默认安全,但:(a) rebase 到当前 main(重新施加 provider/config 串联,解决 auth/handler.ts 的 modify/delete),(b) 重新核对前提——NODE_TLS_REJECT_UNAUTHORIZED=0 现已生效,应更新描述/行为矩阵,并由团队决定剩余价值(--insecure/QWEN_TLS_INSECURE 的便利性与显式性)是否值得这部分代码面;(c) rebase 后重跑 npm run build/typecheck(在这个对着当前依赖的陈旧分支上跑没有意义),并考虑鉴于“全有或全无”的范围加一个运行时告警。


Verified locally under tmux on a worktree at the PR head (Node 22.22.2 / undici 7.27.2): merge-conflict detection vs current main, PR unit suites, a real self-signed-HTTPS end-to-end exercising the insecure/secure dispatcher + global dispatcher, and a direct premise check showing NODE_TLS_REJECT_UNAUTHORIZED=0 already disables undici-fetch verification in this runtime. Full build/typecheck deferred to post-rebase.

@DragonnZhang DragonnZhang left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

No new blocking issues at this commit. The opt-in design is safe-by-default (TLS verification stays on unless explicitly disabled), the --insecure / QWEN_TLS_INSECURE / NODE_TLS_REJECT_UNAUTHORIZED precedence is correctly implemented and tested, and all three SDK providers plus the global undici dispatcher (MCP / telemetry / streaming) thread the flag consistently. CI is green. The substantive items previously raised — that proxied insecure TLS on undici ProxyAgent needs requestTls rather than connect, and the suggestion to surface a runtime warning given the process-wide scope — already cover the remaining concerns and are not repeated here.

— Qwen Code /review


Generated by Claude Code

proxyUrlOrConfig?: string | RuntimeFetchConfig,
): OpenAIRuntimeFetchOptions | AnthropicRuntimeFetchOptions {
const runtime = detectRuntime();
const { proxyUrl, insecure } = normalizeConfig(proxyUrlOrConfig);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Security / Correctness] insecure is extracted from the config here, but the case 'bun': branch (line 108) never reads it. When running on Bun, --insecure, QWEN_TLS_INSECURE=1, and NODE_TLS_REJECT_UNAUTHORIZED=0 are all silently ignored -- TLS verification stays on with no warning to the user. This defeats the feature's purpose (self-signed dev/lab endpoints) on Bun without any diagnostic.

Suggested fix: either propagate the flag in the Bun branch (e.g. set process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0' at startup when insecure is resolved true, since Bun honors that env var), or emit a runtime warning that --insecure has no effect on Bun so the user is not left guessing.

if (proxyUrl) {
setGlobalDispatcher(new ProxyAgent(proxyUrl));
setGlobalDispatcher(
new ProxyAgent({

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Correctness] The global ProxyAgent is constructed without headersTimeout: 0 and bodyTimeout: 0, while the per-SDK ProxyAgent instances created in buildFetchOptionsWithDispatcher (in runtimeFetchOptions.ts) explicitly set both to 0. This is inconsistent.

The global dispatcher backs MCP transports, streaming endpoints, and telemetry -- all of which can involve long-lived or idle connections. Undici's default timeouts (300 s for headers, 300 s for body) will apply here, which can silently kill MCP long-polls or streaming reads that exceed the default. Adding headersTimeout: 0, bodyTimeout: 0 to match the per-SDK ProxyAgent configuration would prevent this.

@wenshao

wenshao commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /triage

@wenshao

wenshao commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /resolve

1 similar comment
@wenshao

wenshao commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /resolve

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for the PR, @JahanzaibTayyab!

Template: needs update ⚠️ — the PR body uses custom headings ("What", "How", "Behavior matrix", "Areas needing careful review") instead of the required template sections. The PR template requires:

  • "What this PR does" and "Why it's needed" (prose, not code-level)
  • "Reviewer Test Plan" with "How to verify", "Evidence (Before & After)", and "Tested on" (OS table)
  • "Risk & Scope" (main risk, what's out of scope, breaking changes)
  • Chinese translation in the <details> block

Could you restructure the body to match the template? The technical content is solid — it just needs to be reorganized into the expected sections so reviewers can find what they need.

Additional context for the rebase (from the prior verification report): this branch is ~2 months old and conflicts with main in 8 files, including a modify/delete on auth/handler.ts. The NODE_TLS_REJECT_UNAUTHORIZED=0 premise has also been partially invalidated — it now works for undici fetch in the current runtime (Node 22.22.2 / undici 7.27.2). The genuinely new value is the explicit --insecure flag and QWEN_TLS_INSECURE env var.

中文说明

感谢 PR,@JahanzaibTayyab

模板需要更新 ⚠️ — PR 正文使用了自定义标题("What"、"How"、"Behavior matrix"等),而不是模板要求的标题。PR 模板 要求包含:

  • "What this PR does""Why it's needed"(用散文描述,非代码层面)
  • "Reviewer Test Plan" 包括 "How to verify"、"Evidence (Before & After)" 和 "Tested on"(操作系统表格)
  • "Risk & Scope"(主要风险、不在范围内的内容、破坏性变更)
  • <details> 块中的中文翻译

请按照模板重新组织正文。技术内容本身很好——只是需要重新组织到预期的章节中,以便审查者找到所需信息。

关于 rebase 的额外信息(来自先前的验证报告):该分支约 2 个月前创建,与 main 在 8 个文件中存在冲突,包括 auth/handler.ts 的 modify/delete 冲突。NODE_TLS_REJECT_UNAUTHORIZED=0 的前提也已部分失效——在当前运行时(Node 22.22.2 / undici 7.27.2)中它已能正常作用于 undici fetch。真正新增的价值是显式的 --insecure 标志和 QWEN_TLS_INSECURE 环境变量。

Qwen Code · qwen3.7-max

@wenshao

wenshao commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /resolve

1 similar comment
@wenshao

wenshao commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /resolve

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

Qwen Code attempted to resolve merge conflicts but the run did not complete successfully.

Check the workflow run for full logs.

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

Qwen Code attempted to resolve merge conflicts but the run did not complete successfully.

Check the workflow run for full logs.

@wenshao

wenshao commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /resolve

2 similar comments
@wenshao

wenshao commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /resolve

@wenshao

wenshao commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /resolve

@wenshao

wenshao commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /triage

@wenshao

wenshao commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /resolve

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

Qwen Code attempted to resolve merge conflicts but the run did not complete successfully.

Check the workflow run for full logs.

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

Qwen Code attempted to resolve merge conflicts but the run did not complete successfully.

Check the workflow run for full logs.

@wenshao

wenshao commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /resolve

2 similar comments
@wenshao

wenshao commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /resolve

@wenshao

wenshao commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /resolve

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Gate — PR #3635

This PR is fully superseded by PR #5962 (commit 35a8851a3), which landed the same --insecure / QWEN_TLS_INSECURE / NODE_TLS_REJECT_UNAUTHORIZED=0 feature on main with a more mature implementation:

  • Standalone isTlsVerificationDisabled() helper in runtimeFetchOptions.ts — no config threading needed
  • Dispatcher cache with secure/insecure key separation for connection pool reuse
  • Runtime warning displayed when TLS verification is disabled
  • getOrCreateSharedDispatcher() with proper requestTls/proxyTls handling for proxy scenarios

The branch also has 8 conflicting files against current main, including a modify/delete on auth/handler.ts (deleted upstream).

Recommendation: close as superseded. The author's intent was good and the implementation on the stale branch is sound, but the feature has already shipped via a different path.

中文说明

门禁 — PR #3635

本 PR 已被 PR #5962(commit 35a8851a3完全取代。后者在 main 上实现了相同的 --insecure / QWEN_TLS_INSECURE / NODE_TLS_REJECT_UNAUTHORIZED=0 功能,且实现更成熟:

  • 独立的 isTlsVerificationDisabled() 辅助函数——无需在 config 层串联
  • dispatcher 缓存按 secure/insecure 分 key,复用连接池
  • 关闭 TLS 校验时显示运行时告警
  • getOrCreateSharedDispatcher() 对代理场景正确处理 requestTls/proxyTls

分支与当前 main 存在 8 个文件冲突,其中 auth/handler.ts 为 modify/delete(上游已删除)。

建议: 以"已被取代"关闭。作者的意图正确,在过期分支上的实现也合理,但该功能已通过另一条路径上线。

Qwen Code · qwen3.7-max

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Closing as superseded — this feature has already shipped via PR #5962. Thanks for the effort, @JahanzaibTayyab! 🙏

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

Qwen Code resolved the merge conflicts, but could not push to JahanzaibTayyab/qwen-code. For a fork PR this needs Allow edits by maintainers enabled, and GitHub blocks maintainer edits on forks owned by an organization. The resolved diff is attached as the qwen-resolve-pr-3635 artifact on the workflow run.

Merge Conflict Resolution Summary — PR #3635

Branch: feat/3535-tls-insecure-flagmain
Merge commit: f7b6d89ad
Date: 2026-07-07

Context

PR #3635 added a --insecure CLI flag to bypass TLS certificate verification. While the PR was open, main independently implemented the same feature using a fundamentally different architecture: env-var propagation (QWEN_TLS_INSECURE, NODE_TLS_REJECT_UNAUTHORIZED) with a central isTlsVerificationDisabled() function, connection pool caching, and EnvHttpProxyAgent with NO_PROXY support.

The PR's unique value-add is the tri-state resolveInsecureFlag() — using yargs with no default, it distinguishes --insecure (true), --no-insecure (false), and "not passed" (undefined). This lets --no-insecure explicitly override env-var settings, which main's default: false approach cannot do.

Conflicted Files (9 total)

1. packages/cli/src/commands/auth/handler.tsaccepted deletion

Main deleted this file entirely (commit 7e1142854: "refactor(cli): remove legacy qwen auth CLI subcommand"). PR only added insecure: undefined to an object literal. No value in keeping it.

2. packages/core/src/config/config.tstook main

Three conflicts: imports (Agent/ProxyAgent vs EnvHttpProxyAgent), class fields (insecure field), and dispatcher setup. All PR changes were superseded by main's env-var approach which doesn't need an insecure field on Config. Non-conflicted PR additions (insecure?: boolean in ConfigParameters, getInsecure()) were also superseded.

3. packages/core/src/core/anthropicContentGenerator/anthropicContentGenerator.test.tstook main

Main already has complete insecure support via isTlsVerificationDisabled() in test setup.

4. packages/core/src/core/anthropicContentGenerator/anthropicContentGenerator.tstook main

Main passes rejectUnauthorized via buildRuntimeFetchOptions() using `isTlsVerificationDisab

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

Qwen Code did not run conflict resolution for this request.

PR #3635 is CLOSED.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type/feature-request New feature or enhancement request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature request: a CLI flag or environment variable to allow Qwen Code to ignore SSL errors

7 participants