Repository navigation
fix(docker): bind app/sidecar compose ports to loopback by default (#12568, #12578) - #13240
Merged
Merged
Conversation
…12568, #12578) docker-compose.yml and docker-compose.prod.yml defaulted API_HOST/LIVE_WS_HOST/ HOSTNAME to 0.0.0.0 and published the dashboard/API/live-WS ports with bare, unscoped specs, which Docker expands to every interface. Combined with REQUIRE_API_KEY=false shipping as the .env.example default, this exposed the anonymous /v1 LLM proxy to the whole LAN/WAN (#12568). The optional cliproxyapi sidecar had the same unscoped publish spec plus no forwarded auth env var, exposing a credential-bearing service the same way (#12578); qdrant and bifrost had the identical gap. Applies the existing Redis loopback-bind precedent (tests/unit/compose-redis- loopback-bind.test.ts) to the app's own ports and to cliproxyapi/qdrant/bifrost: - New APP_BIND_HOST / CLIPROXY_BIND_HOST / QDRANT_BIND_HOST / BIFROST_BIND_HOST opt-in vars, defaulting to 127.0.0.1, documented in .env.example and docs/reference/ENVIRONMENT.md. - API_HOST/LIVE_WS_HOST default to 127.0.0.1 in both compose files; the prod file no longer hardcodes HOSTNAME=0.0.0.0. - cliproxyapi now forwards CLIPROXYAPI_MANAGEMENT_KEY as MANAGEMENT_PASSWORD, the one env var the pinned image actually reads for its management API. - A new boot-time guard (src/lib/startup/nonLoopbackApiKeyGuard.ts) logs a warning — never a hard failure — when the API bridge or live-WS server ends up bound to a non-loopback host while REQUIRE_API_KEY is disabled.⚠️ base-red inherited: #12732 — unit #12058, integration codex-cache, package-artifact, tarball-smoke, agent-skills-sync Closes #12568 Closes #12578
Githab-capibara
added a commit
to Githab-capibara/OmniRoute
that referenced
this pull request
Sep 17, 2026
…heaper-inference#12568, cheaper-inference#12578) (cheaper-inference#13240) Merged as part of the 39-PR owner batch of 2026-09-11, validated as a unit. Boarded into one consolidated worktree cut from `release/v3.8.51` with the other 38 — zero conflicts between them. - ESLint over every changed file: no errors (the only finding was one suppression entry the batch emptied, pruned on cheaper-inference#13243) - `typecheck:core` clean; `check:dashboard-typecheck` OK (206 pre-existing, within baseline); `check:changelog-integrity` OK - complexity 2821 / baseline 3218 and cognitive-complexity 1272 / baseline 1437 — both under baseline - 256 assertions green: 246 under node:test and 10 under vitest, which is where `tests/unit/**/*.test.tsx` actually runs - `check-file-size`: `chatCore.ts` rebaselined 6144 → 6146 for cheaper-inference#13278 and cheaper-inference#13276, annotated and landed on cheaper-inference#13243⚠️ base-red inherited: cheaper-inference#12732 — the provider count (356 in the docs vs the 358 the modules define) and `open-sse/utils/stream.ts` at 3115 > frozen 3098 both reproduce on the pure tip with zero contribution from this batch.
muhamadgalihsaputra
pushed a commit
to niyatna/NiyatnaRoute
that referenced
this pull request
Sep 27, 2026
…heaper-inference#12568, cheaper-inference#12578) (cheaper-inference#13240) Merged as part of the 39-PR owner batch of 2026-09-11, validated as a unit. Boarded into one consolidated worktree cut from `release/v3.8.51` with the other 38 — zero conflicts between them. - ESLint over every changed file: no errors (the only finding was one suppression entry the batch emptied, pruned on cheaper-inference#13243) - `typecheck:core` clean; `check:dashboard-typecheck` OK (206 pre-existing, within baseline); `check:changelog-integrity` OK - complexity 2821 / baseline 3218 and cognitive-complexity 1272 / baseline 1437 — both under baseline - 256 assertions green: 246 under node:test and 10 under vitest, which is where `tests/unit/**/*.test.tsx` actually runs - `check-file-size`: `chatCore.ts` rebaselined 6144 → 6146 for cheaper-inference#13278 and cheaper-inference#13276, annotated and landed on cheaper-inference#13243⚠️ base-red inherited: cheaper-inference#12732 — the provider count (356 in the docs vs the 358 the modules define) and `open-sse/utils/stream.ts` at 3115 > frozen 3098 both reproduce on the pure tip with zero contribution from this batch.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
docker-compose.ymlanddocker-compose.prod.ymldefaultedAPI_HOST/LIVE_WS_HOST/HOSTNAMEto0.0.0.0and published the dashboard/API/live-WS ports with bare, unscoped specs — Docker expands those to every interface. Combined withREQUIRE_API_KEY=falseshipping as the.env.exampledefault, this exposed the anonymous/v1LLM proxy to the whole LAN/WAN (#12568). The optionalcliproxyapisidecar had the same unscoped publish spec and no forwarded auth env var, exposing a credential-bearing service (its data volume holds provider OAuth/API credentials) the same way (#12578);qdrantandbifrosthad the identical gap, per the owner's own follow-up comment on #12578.This applies the existing Redis loopback-bind precedent (
tests/unit/compose-redis-loopback-bind.test.ts, from #9286) to the app's own ports and to the three sidecars.Root cause
docker-compose.yml(x-commonenv block + theomniroute-web/omniroute-hostservice blocks that don't inherit it) anddocker-compose.prod.ymlboth defaultedAPI_HOST/LIVE_WS_HOSTto0.0.0.0and publishedDASHBOARD_PORT/API_PORT/LIVE_WS_PORTwith bare port specs.127.0.0.1code-level defaults insrc/server/ws/liveServer.ts:53andsrc/lib/apiBridgeServer.ts:186.cliproxyapi'senvironment:block carriedHOST=0.0.0.0/PORT=..., which are dead no-ops for the pinnedeceasy/cli-proxy-api:v6.9.7image (verified against the upstream source at that tag — it has no env-var support for host/port/api-keys, onlyconfig.yaml); the one env var it does read for auth isMANAGEMENT_PASSWORD, which was never wired from our already-documentedCLIPROXYAPI_MANAGEMENT_KEY.Fix
127.0.0.1, documented in.env.exampleanddocs/reference/ENVIRONMENT.md:APP_BIND_HOST(dashboard/API/live-WS ports, both compose files),CLIPROXY_BIND_HOST,QDRANT_BIND_HOST,BIFROST_BIND_HOST.API_HOST/LIVE_WS_HOSTdefault to127.0.0.1in both compose files;docker-compose.prod.ymlno longer hardcodesHOSTNAME=0.0.0.0.cliproxyapinow forwardsCLIPROXYAPI_MANAGEMENT_KEYasMANAGEMENT_PASSWORD(the env var the pinned binary actually reads).src/lib/startup/nonLoopbackApiKeyGuard.ts, wired into the API bridge server and the live-dashboard WebSocket server: logs a loud warning (never a hard failure, so a deployment intentionally fronted by a reverse-proxy auth layer keeps working) when the resolved bind host is non-loopback whileREQUIRE_API_KEYis disabled.docs/guides/DOCKER_GUIDE.mdupdated with the new vars.Regression tests (TDD)
tests/unit/compose-app-ports-loopback-bind.test.ts(new) — asserts both compose files no longer publish the app ports unscoped and no longer defaultAPI_HOST/LIVE_WS_HOST/HOSTNAMEto0.0.0.0; asserts the boot-time guard exists; asserts.env.exampledocumentsAPP_BIND_HOST.tests/unit/compose-cliproxyapi-loopback-bind.test.ts(new) — asserts thecliproxyapipublish spec is loopback-scoped, forwardsCLIPROXYAPI_MANAGEMENT_KEY, and thatqdrant/bifrostare scoped too.tests/unit/non-loopback-api-key-guard.test.ts(new) — unit-tests the guard's warn/silent matrix (loopback vs non-loopback host ×REQUIRE_API_KEYtrue/false/unset).RED confirmed against
origin/release/v3.8.51tip viagit show <ref>:<path>(no worktree checkout, per the repo's cross-session-safety rule) — both bare publish specs ("${DASHBOARD_PORT:-20128}:${DASHBOARD_PORT:-20128}","${CLIPROXYAPI_PORT:-8317}:${CLIPROXYAPI_PORT:-8317}") are present on the base tip. GREEN after the fix:Existing compose-touching tests re-run and still pass unmodified:
tests/unit/podman-machine-guidance-8497.test.ts,tests/unit/dockerfile-base-path-arg.test.ts, and the live-WS/API-bridge suites (instrumentation-live-ws,live-ws-cookie-parse,live-ws-standalone-wiring,live-ws-eaddrinuse-6324,runtime/live-ws-default,security/live-server-allowlist,httpClientAbortGuard*) — 40+13 tests, all green.Gates run
node scripts/check/check-file-size.mjs— OKnode scripts/check/check-complexity.mjs— OK (2798 violations vs baseline 3218)node scripts/check/check-cognitive-complexity.mjs— OK (1265 violations vs baseline 1437)npm run typecheck:core— exit 0npx eslint --suppressions-location config/quality/eslint-suppressions.json <changed files>— exit 0node scripts/check/check-env-doc-sync.mjs— in syncnode scripts/check/check-changelog-integrity.mjs— OKnpm run check:docs-all— doc-links PASS, fabricated-docs PASS (only pre-existing stale-date/stale-version drift noise, unrelated to this diff)Breaking change note
Existing LAN/cloud-VM deployments that relied on the previous
0.0.0.0default with no.envoverride will need to setAPP_BIND_HOST=0.0.0.0(andCLIPROXY_BIND_HOST/QDRANT_BIND_HOST/BIFROST_BIND_HOSTas needed) after upgrading — the same migration UX already accepted forREDIS_BIND_HOST. Both new .env.example blocks document this tradeoff and recommend pairing it withREQUIRE_API_KEY=trueor a reverse-proxy auth layer.Closes #12568
Closes #12578