Skip to content

feat!: resolve IB Gateway and Java on demand instead of bundling binaries (v2) - #74

Open
NitayRabi wants to merge 3 commits into
masterfrom
v2
Open

feat!: resolve IB Gateway and Java on demand instead of bundling binaries (v2)#74
NitayRabi wants to merge 3 commits into
masterfrom
v2

Conversation

@NitayRabi

Copy link
Copy Markdown
Contributor

Closes #67 (umbrella for #62, #63).

Summary

v2 stops checking in and publishing the IB Client Portal Gateway jars and the per-platform Java runtimes (~350 MB). They are now downloaded on demand from official vendor sources, verified, and cached in a per-user directory outside the package. The npm tarball drops from hundreds of MB to ~265 kB packed / 46 files / 0 binaries.

This is a breaking change (first run needs network access), released as 2.0.0.

What changed

  • DependencyResolver (src/dependency-resolver.ts) resolves dependencies in order:
    1. User-managed — IB_GATEWAY_DIR, IB_JAVA_HOME/JAVA_HOME, or a compatible system java (auto-adopted only for major 11–17).
    2. Otherwise download + verify pinned artifacts from dependencies.manifest.json.
    3. Extract atomically into ~/.cache/interactive-brokers-mcp (or IB_CACHE_DIR) and reuse.
  • Java: BellSoft Liberica JRE 11 for all platforms (glibc + musl), pinned sha256 (verified against the vendor's published sha1 at pin time).
  • Gateway: downloaded only over HTTPS from the official IB host and verified against both the live CDN ETag MD5 and a pinned sha256. IB publishes no checksum file, so this hybrid gives an always-from-IB dynamic check plus a reviewed anchor. IB_GATEWAY_ALLOW_UNVERIFIED=true allows proceeding past a sha256 rotation while the live ETag check still runs.
  • No config overlay: the downloaded gateway runs with IB's own default configuration; a user-managed IB_GATEWAY_DIR gateway is used as-is. (See the security note below.)
  • Controls: IB_DOWNLOADS_DISABLED, IB_CACHE_DIR, IB_GATEWAY_DIR, IB_JAVA_HOME, IB_GATEWAY_ALLOW_UNVERIFIED. Session metadata/locks/logs moved to <cache>/run/.
  • SECURITY.md documenting the supply-chain and network posture + vulnerability reporting; linked from the README.
  • Removed the bundled-runtime build scripts; added scripts/update-dependency-manifest.mjs (maintainer tool, npm run manifest:update).
  • Swapped extract-zipadm-zip (extract-zip's promise never resolves under Node 24).

⚠️ Security tradeoff to review

Dropping the config overlay means the gateway now uses IB's default ips.allow, which permits IB's default ranges (192.*, 131.216.*) in addition to loopback — vs. the previous loopback-only hardening. This was a deliberate choice (prefer not modifying IB's defaults). The loopback-only hardening recipe and network exposure are documented in SECURITY.md.

User impact / migration

  • First npx run may require network access, take longer, and create a local cache.
  • Fully-offline users can pin to interactive-brokers-mcp@1, or pre-install Java + the gateway and set IB_DOWNLOADS_DISABLED=true with IB_GATEWAY_DIR / IB_JAVA_HOME.

Verification

  • npm run build ✅ · vitest ✅ 193 passed / 2 skipped (added 11 resolver tests) · oxlint ✅ (warnings only) · npm audit --omit=dev ✅ 0 vulns · knip ✅ clean.
  • End-to-end: resolver downloads + verifies JRE 11 and the gateway (both ETag-MD5 and pinned sha256), and IBGatewayManager starts the gateway on IB's unmodified default config (came up READY).

🤖 Generated with Claude Code

Copilot AI 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.

Copilot wasn't able to review this pull request because it exceeds the maximum number of files (300). Try reducing the number of changed files and requesting a review from Copilot again.

NitayRabi added a commit that referenced this pull request Jul 13, 2026
…harden unverified escape hatch

Three follow-ups from review of #74:

- Dockerfile: the production stage never copied dependencies.manifest.json,
  which DependencyResolver requires from the package root at construction
  time. Every run in the container died with MODULE_NOT_FOUND before it could
  resolve anything. Verified by building the image before and after.

- ib-client: runtimeDir still pointed at <package>/ib-gateway/.runtime, so the
  tickler recreated state inside the installed package (the directory v2
  removes) and split session state across two locations. It also fails with
  EACCES on a root-owned global install. It now uses DependencyResolver.runDir()
  like the gateway manager.

- dependency-resolver: IB_GATEWAY_ALLOW_UNVERIFIED waived the pinned sha256 even
  when the live CDN ETag was unavailable, installing wholly unverified bytes
  while the error text claimed the ETag was still checked. The escape hatch now
  requires the live ETag check to have actually run.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
NitayRabi and others added 3 commits July 13, 2026 15:07
…ries

Stop checking in and publishing the IB Client Portal Gateway jars and the
per-platform Java runtimes (~350MB). They are now downloaded on demand from
official vendor sources, verified, and cached in a per-user directory outside
the package.

- New DependencyResolver resolves user-managed deps first (IB_GATEWAY_DIR,
  IB_JAVA_HOME/JAVA_HOME, or a compatible system java), else downloads and
  verifies pinned artifacts recorded in dependencies.manifest.json.
- Java: BellSoft Liberica JRE 11 for all platforms (glibc + musl), pinned sha256.
- Gateway: downloaded only over HTTPS from the official IB host and verified
  against both the live CDN ETag MD5 and a pinned sha256; IB_GATEWAY_ALLOW_UNVERIFIED
  allows proceeding past a sha256 rotation while the live ETag check still runs.
- The downloaded gateway runs with IB's own default configuration (no overlay);
  hardening guidance is in SECURITY.md.
- Controls: IB_DOWNLOADS_DISABLED, IB_CACHE_DIR, IB_GATEWAY_DIR, IB_JAVA_HOME,
  IB_GATEWAY_ALLOW_UNVERIFIED. Session metadata/locks/logs moved to <cache>/run/.
- Add SECURITY.md documenting the supply-chain and network posture.
- Replace bundled-runtime build scripts with scripts/update-dependency-manifest.mjs.

Closes #67. Addresses #62 and #63.

BREAKING CHANGE: the package no longer bundles the IB Gateway or a Java runtime.
First run requires network access to download and verify them. Users who need the
previous fully-offline behavior can pin to interactive-brokers-mcp@1, or pre-install
the dependencies and set IB_DOWNLOADS_DISABLED=true.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…harden unverified escape hatch

Three follow-ups from review of #74:

- Dockerfile: the production stage never copied dependencies.manifest.json,
  which DependencyResolver requires from the package root at construction
  time. Every run in the container died with MODULE_NOT_FOUND before it could
  resolve anything. Verified by building the image before and after.

- ib-client: runtimeDir still pointed at <package>/ib-gateway/.runtime, so the
  tickler recreated state inside the installed package (the directory v2
  removes) and split session state across two locations. It also fails with
  EACCES on a root-owned global install. It now uses DependencyResolver.runDir()
  like the gateway manager.

- dependency-resolver: IB_GATEWAY_ALLOW_UNVERIFIED waived the pinned sha256 even
  when the live CDN ETag was unavailable, installing wholly unverified bytes
  while the error text claimed the ETag was still checked. The escape hatch now
  requires the live ETag check to have actually run.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ResolvedGateway is only used inside dependency-resolver.ts as the return type
of resolveGateway(); nothing imports it (unlike ResolvedJava, which
gateway-manager does import). Exporting it tripped knip's unused-exports check.

Co-Authored-By: Claude Opus 4.8 <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.

v2: remove bundled third-party binaries and switch to verified on-demand installs

2 participants