Skip to content

fix CLI overriding environment variables#812

Merged
PythonFZ merged 6 commits intomainfrom
fix-cli-env-var-override
Dec 17, 2025
Merged

fix CLI overriding environment variables#812
PythonFZ merged 6 commits intomainfrom
fix-cli-env-var-override

Conversation

@PythonFZ
Copy link
Copy Markdown
Member

@PythonFZ PythonFZ commented Dec 17, 2025

CLI options with defaults (--port, --host, --simgen, --file-browser) were always overriding environment variables like ZNDRAW_SIMGEN_ENABLED because they were unconditionally added to config_kwargs.

Changed these options to use None defaults, only adding them to config_kwargs when explicitly provided. This allows pydantic-settings to properly read from environment variables when CLI flags are not specified.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores

    • Server CLI options (port, host) and feature flags (SiMGen, file browser) are now optional and fall back to environment/config defaults; help text updated.
    • Default server binding changed to 0.0.0.0 (server listens on all interfaces by default).
  • Bug Fixes / UX

    • Startup messages, status URLs and remote upload links now reflect the final runtime configuration (config-driven values) rather than raw CLI inputs.

✏️ Tip: You can customize this high-level summary in your review settings.

CLI options with defaults (--port, --host, --simgen, --file-browser) were
always overriding environment variables like ZNDRAW_SIMGEN_ENABLED because
they were unconditionally added to config_kwargs.

Changed these options to use None defaults, only adding them to config_kwargs
when explicitly provided. This allows pydantic-settings to properly read
from environment variables when CLI flags are not specified.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Dec 17, 2025

Walkthrough

CLI host/port and feature flags (simgen, file_browser) are now optional. Config builder and main only set server and feature values when provided; runtime URLs, messages, and SocketIO startup use values resolved from ZnDrawConfig. Default server bind changed to 0.0.0.0.

Changes

Cohort / File(s) Summary
CLI parameter optionality
src/zndraw/cli.py
_build_config() and main() signatures made port, host, simgen, and file_browser optional (`...
Default server binding
src/zndraw/config.py
ZnDrawConfig.server_host default changed from "localhost" to "0.0.0.0", so the server binds to all interfaces by default.
Tests updated
tests/test_config.py
Test expectations adjusted to reflect the new default server_host ("0.0.0.0").

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Verify _build_config() omits server_* and feature flags when CLI args are None and that environment-variable fallbacks remain intact.
  • Confirm main() consistently uses config.server_port, config.server_host, and config.server_url for messaging, URL construction, and SocketIO startup.
  • Check tests reflect the new default and update any other docs or integrations that assume localhost.
  • Pay attention to network/security implications of changing the default bind address.

Poem

🐰 I hopped through options, made them light,

Flags now sleep until called to fight.
Host opens wide to let connections flow,
Config speaks only when values show.
🥕✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: fixing CLI arguments from unconditionally overriding environment variables to only doing so when explicitly provided.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix-cli-env-var-override

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dd1ce62 and 79a98ea.

📒 Files selected for processing (1)
  • tests/test_config.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: If sensible, implement collections.abc interfaces for classes, such as MutableMapping or MutableSequence
Use numpy style docstrings
Docstrings must be concise and to the point
Use type hints wherever possible. Import typing as t if necessary, but use list[int|float] | None instead of t.Optional[t.List[int|float]]
Imports should always be at the top of the file

Files:

  • tests/test_config.py
**/test_*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/test_*.py: Use pytest.mark.parametrize to avoid code duplication in tests
Tests should be very specific and test only one thing
Avoid complex test setups
Each test must be a function, not a method of a class

Files:

  • tests/test_config.py
🪛 Ruff (0.14.8)
tests/test_config.py

54-54: Possible binding to all interfaces

(S104)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: pytest (3.13, ubuntu-latest)
  • GitHub Check: pytest (3.12, ubuntu-latest)
  • GitHub Check: pytest (3.11, ubuntu-latest)
🔇 Additional comments (1)
tests/test_config.py (1)

54-54: The default server_host of "0.0.0.0" is intentional for containerized deployments.

The Dockerfile explicitly sets ZNDRAW_SERVER_HOST=0.0.0.0 as the container default, and the config includes a safeguard that auto-converts 0.0.0.0 to localhost when generating the server_url for client callbacks (lines 187-190 in config.py). Users can override the bind address via the ZNDRAW_SERVER_HOST environment variable for non-containerized deployments. The test correctly validates this default behavior.


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 and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/zndraw/cli.py (1)

561-561: Use config.server_host in socketio.run() to respect the --host CLI flag and ZNDRAW_SERVER_HOST environment variable.

The server binds to hardcoded "0.0.0.0" instead of config.server_host. Users who specify --host 127.0.0.1 or set ZNDRAW_SERVER_HOST=127.0.0.1 for security (localhost-only access) will have their security intent silently bypassed—the server still binds to all interfaces. Replace socketio.run(flask_app, debug=debug, host="0.0.0.0", port=config.server_port) with socketio.run(flask_app, debug=debug, host=config.server_host, port=config.server_port).

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 84d9a57 and 94e8539.

📒 Files selected for processing (1)
  • src/zndraw/cli.py (9 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: If sensible, implement collections.abc interfaces for classes, such as MutableMapping or MutableSequence
Use numpy style docstrings
Docstrings must be concise and to the point
Use type hints wherever possible. Import typing as t if necessary, but use list[int|float] | None instead of t.Optional[t.List[int|float]]
Imports should always be at the top of the file

Files:

  • src/zndraw/cli.py
🧬 Code graph analysis (1)
src/zndraw/cli.py (1)
src/zndraw/server_manager.py (1)
  • write_server_info (82-93)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: pytest (3.12, ubuntu-latest)
  • GitHub Check: pytest (3.11, ubuntu-latest)
  • GitHub Check: pytest (3.13, ubuntu-latest)
🔇 Additional comments (5)
src/zndraw/cli.py (5)

77-78: LGTM! Signature changes enable environment variable fallback.

The parameter type changes correctly allow CLI arguments to be optional, enabling pydantic-settings to read from environment variables when values are not explicitly provided via CLI.

Also applies to: 85-86


98-102: LGTM! Conditional logic correctly prevents CLI defaults from overriding env vars.

The implementation only adds server settings to config when explicitly provided, allowing pydantic-settings to read from environment variables otherwise.


136-141: LGTM! Feature flags correctly support environment variable configuration.

The conditional logic ensures that feature flags are only set from CLI when explicitly provided, allowing environment variables like ZNDRAW_SIMGEN_ENABLED to control defaults otherwise.


174-174: LGTM! CLI option defaults correctly updated to support env vars.

All four CLI options now default to None with updated help text, enabling pydantic-settings to read from environment variables when flags are not specified. The implementation is consistent across all affected options.

Also applies to: 208-210, 238-241, 253-256


526-526: LGTM! Correct usage of config values ensures consistency.

Using config.server_port instead of the raw CLI port parameter ensures the correct value is used, whether it comes from CLI, environment variables, or config defaults.

Also applies to: 531-531, 553-553, 556-556

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Dec 17, 2025

Codecov Report

❌ Patch coverage is 14.28571% with 12 lines in your changes missing coverage. Please review.
✅ Project coverage is 78.34%. Comparing base (84d9a57) to head (79a98ea).
⚠️ Report is 3 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/zndraw/cli.py 0.00% 12 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #812      +/-   ##
==========================================
+ Coverage   78.05%   78.34%   +0.28%     
==========================================
  Files         153      153              
  Lines       18357    18396      +39     
==========================================
+ Hits        14329    14412      +83     
+ Misses       4028     3984      -44     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5efea06 and dd1ce62.

📒 Files selected for processing (1)
  • src/zndraw/config.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

**/*.py: If sensible, implement collections.abc interfaces for classes, such as MutableMapping or MutableSequence
Use numpy style docstrings
Docstrings must be concise and to the point
Use type hints wherever possible. Import typing as t if necessary, but use list[int|float] | None instead of t.Optional[t.List[int|float]]
Imports should always be at the top of the file

Files:

  • src/zndraw/config.py
🪛 Ruff (0.14.8)
src/zndraw/config.py

120-120: Possible binding to all interfaces

(S104)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: pytest (3.12, ubuntu-latest)
  • GitHub Check: pytest (3.13, ubuntu-latest)
  • GitHub Check: pytest (3.11, ubuntu-latest)

Comment thread src/zndraw/config.py
server_host: str = Field(
default="localhost", description="Server bind host address"
)
server_host: str = Field(default="0.0.0.0", description="Server bind host address")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# 1. Check the actual code at line 120
echo "=== Checking config.py around line 120 ==="
sed -n '115,130p' src/zndraw/config.py

echo -e "\n=== Checking for admin credentials defaults ==="
sed -n '135,145p' src/zndraw/config.py

echo -e "\n=== Full server_host related lines ==="
grep -n 'server_host' src/zndraw/config.py

echo -e "\n=== Checking admin_username and admin_password ==="
grep -n 'admin_username\|admin_password' src/zndraw/config.py

Repository: zincware/ZnDraw

Length of output: 1892


🏁 Script executed:

#!/bin/bash
# 2. Check CLI code for server_host usage and context
echo "=== CLI code: server_host references ==="
rg -n -B3 -A3 'server_host' src/zndraw/cli.py || echo "Not found or file missing"

echo -e "\n=== CLI code: binding/0.0.0.0/localhost context ==="
rg -n 'bind|0\.0\.0\.0|localhost' src/zndraw/cli.py || echo "Not found"

Repository: zincware/ZnDraw

Length of output: 1460


🏁 Script executed:

#!/bin/bash
# 3. Check if there are any recent git commits related to this change
echo "=== Check recent commits affecting config.py ==="
git log --oneline -20 -- src/zndraw/config.py 2>/dev/null || echo "Git info unavailable"

echo -e "\n=== Check git diff for current file status ==="
git diff src/zndraw/config.py 2>/dev/null | head -100 || echo "No staged changes"

Repository: zincware/ZnDraw

Length of output: 216


🏁 Script executed:

#!/bin/bash
# 4. Check for test files that might show intended usage
echo "=== Search for config tests ==="
find . -name '*test*config*' -o -name '*config*test*' 2>/dev/null | head -10

echo -e "\n=== Check tests directory for config usage ==="
if [ -d "tests" ] || [ -d "test" ]; then
  rg -n 'server_host\|0\.0\.0\.0' tests/ test/ 2>/dev/null || echo "No matches in tests"
fi

Repository: zincware/ZnDraw

Length of output: 181


🏁 Script executed:

#!/bin/bash
# Check test_config.py for hints
echo "=== test_config.py content ==="
cat tests/test_config.py | head -100

echo -e "\n=== Check for environment-specific config handling ==="
rg -n 'ZNDRAW_|environ|production|development' src/zndraw/config.py | head -20

echo -e "\n=== Check if there's any auth middleware or security defaults ==="
rg -n 'auth|security|protect' src/zndraw/config.py

Repository: zincware/ZnDraw

Length of output: 4518


🏁 Script executed:

#!/bin/bash
# Check the full context of line 188
echo "=== Context around line 188 (server_url handling) ==="
sed -n '175,195p' src/zndraw/config.py

echo -e "\n=== Check for any README or docs about deployment ==="
find . -name 'README*' -o -name '*.md' | head -5 | xargs grep -l 'server_host\|0\.0\.0\.0\|localhost' 2>/dev/null || echo "No matches in docs"

Repository: zincware/ZnDraw

Length of output: 1147


Critical: Default server binding change breaks tests and creates security exposure.

The default server_host is set to "0.0.0.0" (line 120), exposing the server to all network interfaces. However, tests/test_config.py line 46 explicitly asserts config.server_host == "localhost", causing a test failure. Additionally, the CLI help text (line 210) states the default is localhost.

This indicates an incomplete or unintended change with three issues:

  1. Test failure: Line 46 of test_config.py will fail—the test expects "localhost" but the config now provides "0.0.0.0".
  2. Security regression: Binding to 0.0.0.0 exposes the server to the network by default. Since admin credentials are optional (lines 138-139, both default to None), the server may be accessible without authentication.
  3. Inconsistent documentation: CLI help text and all output URLs hardcoded to localhost (lines 210, 297, 401, 423, 430, 452, 456, 553, 556) contradict the actual config default.

The code at line 188 shows awareness of this distinction (self.server_host != "0.0.0.0"localhost for URLs), but the configuration default is misaligned.

Action required: Revert the default to "localhost" (matching the test assertion and documented behavior), allowing users to explicitly opt-in to network exposure via ZNDRAW_SERVER_HOST=0.0.0.0.

🧰 Tools
🪛 Ruff (0.14.8)

120-120: Possible binding to all interfaces

(S104)

🤖 Prompt for AI Agents
In src/zndraw/config.py around line 120, the default server_host should be
reverted from "0.0.0.0" to "localhost" to match tests and docs; change the Field
default to "localhost", ensure environment variable override
(ZNDRAW_SERVER_HOST) still functions so operators can opt into "0.0.0.0"
explicitly, and verify any CLI help text or URL formatting logic remains
consistent with the reverted default.

@PythonFZ PythonFZ merged commit 062a61a into main Dec 17, 2025
6 checks passed
@PythonFZ PythonFZ deleted the fix-cli-env-var-override branch December 17, 2025 14:46
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.

2 participants