Skip to content

feat(#535): zero-file injection phases 2+3 — absolute-form forward proxy, hermes/dsh env routing - #537

Closed
ranxianglei wants to merge 3 commits into
masterfrom
2026-09-04_zero-file-injection
Closed

ranxianglei wants to merge 3 commits into
masterfrom
2026-09-04_zero-file-injection

Conversation

@ranxianglei

Copy link
Copy Markdown
Owner

What

Continues #535 (注入零文件化) after PR #536 (phase 1, pi). Three commits:

  1. feat: absolute-form http forward-proxy requests ride the full pipeline (src/server.ts)
    resolveUpstream now recognizes standard forward-proxy request lines (POST http://host/path) and routes them exactly like the /bili/ absolute-URL form: full compression pipeline + tunnel: true, so [SECURITY] /bili/<绝对URL> 零配置隧道无目标准入:可回环访问自家管理面、触达 link-local 元数据;0.0.0.0 部署下 LAN 可经 PUT 劫持全部流量凭据(架空自述的 loopback-only 防线) #409 destination admission applies (self/link-local denied, private per client locality). Malformed URLs fall through to passthrough. This is what lets hermes's httpx stack route plaintext-http upstreams through bili via HTTP_PROXY.

  2. feat: hermes/dsh zero-file injection (src/launcher.ts + tests)

    • hermes: prepareHermesHome / HERMES_HOME overlay deleted. https upstream hosts are MITM-whitelisted (HTTPS_PROXY + HERMES_CA_BUNDLE → combined-ca.pem, since httpx builds its own bundle from that env — combined keeps system roots for blind-tunnelled hosts); plaintext-http upstreams ride HTTP_PROXY (absolute-form). Inherited NO_PROXY is loopback-sanitized in the child env so local sglang still reaches bili. The session-identity plugin (会话身份不稳定:credential/upstream 维度导致长会话状态孤儿化(sessions 缺失) #286) is installed idempotently into the real ~/.hermes/plugins/model-providers/bili-session-identity/ (bili-owned subdir, coexists with user plugins; old skip-on-user-plugins guard removed).
    • dsh: split by destination. Non-loopback https → MITM whitelist; non-loopback plaintext-http → HTTP_PROXY; built-in deepseek route captured by whitelisting api.deepseek.com instead of clobbering $DEEPSEEK_BASE_URL. Loopback destinations keep the legacy settings.yaml overlay rewrite — documented exception: dsh bypasses proxies for localhost/127.0.0.1/::1 unconditionally (LOOPBACK_NO_PROXY, "the bypass is not optional"), so no env route exists there.
    • New exported helpers: isLoopbackHost, stripLoopbackNoProxy. DiscoveredRoutes += httpEnvRoutes / providerKeys.
    • Tests: hermes/dsh discoverRoutes split coverage, helper unit tests, real-home identity-plugin test, runLaunch env assertions for both clients (incl. NO_PROXY sanitize + MITM domain lists), forward-absolute-url test extended with x-bili-tunnel marker assertion + self-destination 403 case.
  3. docs: EN+ZH launcher one-liners, redirect table, discovery table, temp-config bullets; injection-priority note (env > CLI/extension API > generated files) next to "Two compression modes".

Deliberately NOT in this PR

Ordering note

Best merged after #536 (doc hunks are adjacent but disjoint; code hunks don't overlap). Based on master fadfcdd.

Pre-flight

  • npm run typecheck clean
  • npm test: 1036/1037 — sole failure is the pre-existing sandbox-only resolveClientCommand: codex/claude resolve to themselves (sandbox has /usr/bin/codex), present on pristine master
  • npm run build OK

ework-agent added 3 commits September 4, 2026 21:24
…ipeline

Standard HTTP forward-proxy request lines (POST http://host/path) are now
routed by resolveUpstream with the same semantics as the /bili/ path form:
full compression pipeline plus #409 destination admission (tunnel: true),
which also rejects self/link-local targets. Previously an absolute-form
request forwarded raw with no pipeline. This unlocks env-based proxying
for clients whose HTTP stack honors HTTP_PROXY (hermes's httpx).
…ocumented exceptions

- server: absolute-form http request lines ride the full pipeline with #409 destination admission (previous commit)
- hermes: no more HERMES_HOME overlay — https upstreams MITM-whitelisted via HTTPS_PROXY + HERMES_CA_BUNDLE (combined-ca.pem), plaintext-http upstreams via HTTP_PROXY absolute-form; NO_PROXY loopback-sanitized in the child env; session-identity plugin installed idempotently into the REAL ~/.hermes/plugins (coexists with user plugins)
- dsh: split by destination — non-loopback https MITM-whitelisted, non-loopback plaintext-http via HTTP_PROXY, built-in deepseek route captured by whitelisting api.deepseek.com (no DEEPSEEK_BASE_URL clobbering); loopback destinations keep the settings.yaml overlay rewrite (dsh bypasses proxies for localhost unconditionally)
- DiscoveredRoutes += httpEnvRoutes/providerKeys; new exported helpers isLoopbackHost/stripLoopbackNoProxy
- prepareHermesHome deleted; writeHermesIdentityPlugin now targets the real home
… > generated files

hermes/dsh one-liners, per-client redirect table, discovery table and temp-config bullets updated in EN+ZH; injection-priority note added next to 'Two compression modes'. pi/omp doc lines intentionally left to PR #536.
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

📦 Built Package Artifact

Branch: 2026-09-04_zero-file-injection (a8f3970)

Option A — Install from npm PR tag (recommended)

npm install -g billion-context@pr-537

Each push to this PR publishes a new version under the pr-537 npm tag.

Option B — Download artifact

  1. Download the artifact from the Actions run
  2. Extract the tarball and install:
tar xzf billion-context-pr537.tgz
npm install -g package

This comment is automatically updated on each push.

@ranxianglei

Copy link
Copy Markdown
Owner Author

🤖 ework agent · qwen3.8-27b

[bot] 🏷 Review of PR #537 complete — LGTM (non-blocking findings only).

Pre-flight re-verified on a8f3970 (matches your claims):

  • npm run typecheck — clean
  • npm test — 1036/1037; sole failure is resolveClientCommand: codex/claude resolve to themselves, which I reproduced identically on pristine master fadfcdd in a separate worktree → pre-existing sandbox-only failure (/usr/bin/codex exists here), not caused by this PR
  • npm run build — OK (dist 2.63 MB)
  • Docs commit a8f3970: redirect table, discovery table, temp-config bullets, and the new "Injection priority" README section all consistent with the code (incl. the dsh loopback exception wording and "~/.hermes-bili left unmigrated")

Merge-ordering check: current master is exactly fadfcdd (the PR base); #536 is not merged yet. I simulated the recommended landing order (worktree checkout of #536 head 03f7753, then merge a8f3970) — zero conflicts. Your "merge after #536" note holds.

Security review highlights (commit cd7a8ce, src/server.ts:265-277):

  • Absolute-form requests get tunnel: true → [SECURITY] /bili/<绝对URL> 零配置隧道无目标准入:可回环访问自家管理面、触达 link-local 元数据;0.0.0.0 部署下 LAN 可经 PUT 劫持全部流量凭据(架空自述的 loopback-only 防线) #409 destination admission applies; self/link-local denied even in absolute form (new 403 test confirms)
  • Admin plane unaffected: isAdminPath only matches origin-form URLs; an absolute-form request targeting /__bili/* misses the admin gate but is caught by tunnel admission (self-port deny) instead
  • Chained bili forwards carry x-bili-tunnel: 1 (asserted in the extended test), so a second hop still admits by locality
  • buildForwardTarget sets Host from the real upstream for undici's origin-form rewrite — correct forward-proxy semantics; malformed URLs fall through to legacy passthrough
  • CA plumbing: HERMES_CA_BUNDLE→combined-ca.pem (replace semantics, httpx builds its own bundle) vs NODE_EXTRA_CA_CERTS→root-ca.pem (append) are each correct per client; ensureRootCA() runs at proxy startup before ready, so no race with hermes reading the bundle

Findings (minor, non-blocking):

  1. dsh custom $DEEPSEEK_BASE_URL silently bypasses bili. readDshConfig only reads ~/.dsh/settings.yaml, so discovery can't see an env-set base URL. Old code clobbered DEEPSEEK_BASE_URL unconditionally (built-in route always proxied); new code respects a user-set value but that host's traffic then skips compression with no signal. Suggest one line in the dsh branch of runLaunch: warn on stderr when process.env.DEEPSEEK_BASE_URL is set and ≠ https://api.deepseek.com. Happy to add it as a follow-up commit if you want.
  2. Nit: isLoopbackHost/stripLoopbackNoProxy don't match port-suffixed entries (127.0.0.1:8199) — such NO_PROXY entries survive sanitization. Rare in practice; matches dsh's documented bypass list as-is otherwise.

E2E caveat: I could not run tests/e2e/e2e-codex.test.ts from this sandbox — no reachable Responses-compatible upstream (default 127.0.0.1:8199 down, no E2E_UPSTREAM_URL). The server.ts change is purely additive (+13 lines in resolveUpstream) with dedicated unit coverage, but please run the 4-phase core (ACP_TEST_E2E=1) where a local sglang exists before merging, per AGENTS.md §3.

Not merging — human-only. Ready for merge after #536 lands.

@ranxianglei

Copy link
Copy Markdown
Owner Author

Superseded by PR #538 (hermes/omp file-free routing), which the owner has designated as the vehicle for phases 2+3. This PR’s absolute-form + hermes hunks overlap #538 in src/server.ts / src/launcher.ts / tests/launcher.test.ts and would conflict on merge. Its remaining unique content — the dsh destination-split (loopback exception, api.deepseek.com MITM whitelist instead of DEEPSEEK_BASE_URL clobbering, full test coverage) — stays available on branch 2026-09-04_zero-file-injection as reference for the deferred phase 4. Closing to keep the merge path clean.

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