Skip to content

fix: stop production overlays defaulting to third-party LLM and online GeoIP (#607) - #608

Merged
NotYuSheng merged 2 commits into
mainfrom
feature/pin-prod-offline-defaults
Jul 28, 2026
Merged

fix: stop production overlays defaulting to third-party LLM and online GeoIP (#607)#608
NotYuSheng merged 2 commits into
mainfrom
feature/pin-prod-offline-defaults

Conversation

@NotYuSheng

@NotYuSheng NotYuSheng commented Jul 28, 2026

Copy link
Copy Markdown
Owner

Problem

On a deploy box with no .env, the production overlay resolved to:

LLM_API_BASE_URL: https://api.openai.com/v1
GEO_FORCE_OFFLINE: "false"

Neither prod overlay pinned these, so both inherited the base file's local-dev convenience defaults.

AI features (Story mode, Network Insights) build their prompts from analysed capture content, so the LLM endpoint is a data egress path — in the deployment most likely to hold real operational data, and in direct conflict with the offline requirement in CLAUDE.md.

docker-compose.offline.yml already handled this correctly (MMDB-only geo, a localhost LLM). The online production path never received the same treatment.

Why it stayed invisible

A developer .env typically overrides LLM_API_BASE_URL to a local or Tailscale host. It works on the developer's machine and only breaks the guarantee on a fresh deploy box — which is exactly where it matters.

Changes

docker-compose.prod.yml

docker-compose.offline-prod.yml

  • Both restated explicitly, so an air-gapped deployment's guarantee doesn't rest on a default in the file below it.

Docsproduction-hardening.rst previously said "ensure LLM_API_BASE_URL points to a locally-hosted model", advisory prose against a default that actively pointed outward. Now documents enforced behaviour.

The base docker-compose.yml is unchanged — local dev and CI depend on those defaults, and the base stack is the open testing path.

Verification

Case Result
Prod, LLM_API_BASE_URL unset ✅ Aborts with actionable message
Prod, set ✅ Geo offline; zero api.openai.com references
Offline-prod, no .env ✅ Still starts air-gapped (localhost LLM, geo true)
Base, no .env (CI) ✅ Unchanged
docker compose up -d --build ✅ API returns 200
Docs build ✅ Clean

Closes #607

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Production deployments now require an explicitly configured LLM endpoint.
    • Offline production configurations default to local LLM access and offline GeoIP resolution.
    • Offline GeoIP lookups use the bundled database by default.
  • Documentation

    • Added guidance for configuring local LLM servers.
    • Documented privacy considerations for sensitive capture data.
    • Explained how to enable online GeoIP lookups when internet access is available.

…e GeoIP (#607)

On a deploy box with no .env, the production overlay resolved to:

  LLM_API_BASE_URL: https://api.openai.com/v1
  GEO_FORCE_OFFLINE: "false"

Neither prod overlay pinned these, so both inherited the base file's local-dev
convenience defaults. AI features build their prompts from analysed capture
content, so that is a data egress path — in the deployment most likely to hold
real operational data, and in direct conflict with the offline requirement.

docker-compose.offline.yml already handled this correctly (MMDB-only geo, a
localhost LLM). The online production path never received the same treatment.

The failure mode is quiet: a developer .env typically overrides LLM_API_BASE_URL
to a local or Tailscale host, so it works on the developer's machine and only
breaks the guarantee on a fresh deploy box.

  docker-compose.prod.yml
    LLM_API_BASE_URL is now REQUIRED (${VAR:?}) — the endpoint must be a
    deliberate choice, following the same fail-fast pattern as the credentials
    in #595 rather than trusting an operator to read a doc.
    GEO_FORCE_OFFLINE defaults to true, matching docker-compose.offline.yml.

  docker-compose.offline-prod.yml
    Both restated explicitly, so an air-gapped deployment's guarantee doesn't
    rest on a default in the file below it.

Base docker-compose.yml is unchanged — local dev and CI depend on those defaults,
and the base stack is the open testing path.

Verified: prod aborts with an actionable message when LLM_API_BASE_URL is unset;
prod with it set resolves geo offline and contains zero api.openai.com
references; offline-prod still starts air-gapped with no .env; base config
unchanged; stack builds and API returns 200; docs build clean.

Closes #607

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

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@NotYuSheng, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 53 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 34b7c345-76ad-4baf-a12c-61e04ca25a0f

📥 Commits

Reviewing files that changed from the base of the PR and between b11d264 and 648bbe0.

📒 Files selected for processing (3)
  • .env.example
  • docker-compose.offline-prod.yml
  • docs/operations/production-hardening.rst
📝 Walkthrough

Walkthrough

Production Compose overlays now require explicit LLM endpoints and default GeoIP resolution to offline mode. Environment examples and production-hardening documentation describe local LLM configuration, capture-data egress, and conditions for enabling online GeoIP lookups.

Changes

Production egress controls

Layer / File(s) Summary
Overlay runtime defaults
docker-compose.prod.yml, docker-compose.offline-prod.yml
Production overlays require LLM_API_BASE_URL or provide a localhost default for offline production, and default GEO_FORCE_OFFLINE to true.
Operator configuration guidance
.env.example, docs/operations/production-hardening.rst
Configuration comments and production documentation describe local LLM endpoints, capture-data egress, bundled offline GeoIP data, and the explicit override for online lookups.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • NotYuSheng/TracePcap#474: Introduces the GEO_FORCE_OFFLINE behavior wired into these production overlays and documented here.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main production-overlay egress fix.
Linked Issues check ✅ Passed The changes satisfy #607 by requiring LLM_API_BASE_URL in prod, defaulting GEO_FORCE_OFFLINE=true in both overlays, and updating docs without changing base defaults.
Out of Scope Changes check ✅ Passed The .env.example and docs updates are directly tied to the production egress hardening scope, with no unrelated code changes shown.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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.

@coderabbitai coderabbitai 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.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.env.example:
- Around line 144-147: Update the .env.example LLM endpoint documentation to
recommend only reachable local inference servers, removing the OpenAI/API
option. Correct the production overlay explanation to distinguish the overlays:
document that the relevant overlay aborts when unset, while
docker-compose.offline-prod.yml uses a localhost fallback; do not imply every
production overlay aborts.

In `@docker-compose.offline-prod.yml`:
- Line 94: Align the LLM_API_BASE_URL documentation with each overlay’s
behavior: in docker-compose.offline-prod.yml, retain and document the localhost
fallback; in .env.example, remove the claim that every production overlay fails
when the variable is unset; and in docs/operations/production-hardening.rst,
state that the online overlay requires the variable while the offline overlay
uses its default.

In `@docker-compose.prod.yml`:
- Around line 94-96: Set GEO_FORCE_OFFLINE to the literal "true" in
docker-compose.prod.yml lines 94-96 and docker-compose.offline-prod.yml lines
91-95, removing the environment-variable override. In
docs/operations/production-hardening.rst lines 258-261, remove the instruction
to set GEO_FORCE_OFFLINE to false.
- Around line 91-93: Constrain LLM_API_BASE_URL in both
docker-compose.prod.yml:91-93 and docker-compose.offline-prod.yml:91-94 to
validated local-only hostnames and ports rather than accepting arbitrary .env or
CLI values. In the offline overlay, replace the container-localhost default with
an explicitly configured local inference gateway; preserve the required
configuration behavior while preventing external endpoints.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 300284fc-f264-4efb-bbd4-f07595616b9d

📥 Commits

Reviewing files that changed from the base of the PR and between dc53aa7 and b11d264.

📒 Files selected for processing (4)
  • .env.example
  • docker-compose.offline-prod.yml
  • docker-compose.prod.yml
  • docs/operations/production-hardening.rst

Comment thread .env.example Outdated
Comment thread docker-compose.offline-prod.yml Outdated
Comment thread docker-compose.prod.yml
Comment thread docker-compose.prod.yml
The docs and .env.example claimed both production overlays abort when
LLM_API_BASE_URL is unset, but offline-prod silently fell back to
http://localhost:1234/v1 — which resolves to the backend container itself, not
to any inference host on the network. An air-gapped operator who trusted that
wording would get a stack that starts fine and then fails at request time.

Makes offline-prod require the variable, matching prod, so the documented
behaviour is true. Also stops .env.example presenting OpenAI as a valid option
(it contradicts the offline requirement) and warns that localhost resolves
inside the container.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@NotYuSheng
NotYuSheng merged commit 0c02cc6 into main Jul 28, 2026
3 checks passed
@NotYuSheng
NotYuSheng deleted the feature/pin-prod-offline-defaults branch July 28, 2026 02:59
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.

fix: production overlays default to third-party LLM and online GeoIP

1 participant