Expands the onboarding setup IP check from 127.0.0.1-only to any loopback or RFC-1918 private address. Docker containers connect via 172.17.x.x — previously blocked with a 403. Public IPs still blocked unless auth enabled. 791 tests pass.
This commit is contained in:
@@ -6,6 +6,10 @@
|
||||
---
|
||||
|
||||
|
||||
## [v0.50.9] Onboarding works from Docker bridge networks (PR #335, fixes #334)
|
||||
|
||||
- **Docker users can now complete onboarding without enabling auth first** (closes #334): The onboarding setup endpoint previously only accepted requests from `127.0.0.1`. Docker containers connect via bridge network IPs (`172.17.x.x`, etc.), so the endpoint returned a 403 mid-wizard with no clear explanation. The check now accepts any loopback or RFC-1918 private address (`127.0.0.0/8`, `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`) using Python's `ipaddress.is_loopback` and `is_private`. Public IPs are still blocked unless auth is enabled.
|
||||
|
||||
## [v0.50.8] Model dropdown deduplication — hyphen vs dot separator fix (PR #332)
|
||||
|
||||
- **Model dropdown no longer shows duplicates for hyphen-format configs** (e.g. `claude-sonnet-4-6` from hermes-agent config): The server-side normalization in `api/config.py` now unifies hyphens and dots when checking whether the default model is already in the dropdown. Previously, `claude-sonnet-4-6` (hermes-agent format) and `claude-sonnet-4.6` (WebUI list format) were treated as different models, causing the same model to appear twice — once as a raw unlabelled entry and once with the correct display name. The raw entry is now suppressed and the labelled one is selected as default.
|
||||
|
||||
@@ -827,10 +827,19 @@ def handle_post(handler, parsed) -> bool:
|
||||
return j(handler, saved)
|
||||
|
||||
if parsed.path == "/api/onboarding/setup":
|
||||
# Writing API keys to disk - restrict to loopback unless auth is active
|
||||
# Writing API keys to disk - restrict to local/private networks unless auth is active.
|
||||
# In Docker, requests arrive from the bridge network (172.x.x.x), not 127.0.0.1,
|
||||
# even when the user accesses via localhost:8787 on the host.
|
||||
from api.auth import is_auth_enabled
|
||||
if not is_auth_enabled() and handler.client_address[0] != "127.0.0.1":
|
||||
return bad(handler, "Onboarding setup is only available from localhost when auth is not enabled.", 403)
|
||||
if not is_auth_enabled():
|
||||
import ipaddress
|
||||
try:
|
||||
addr = ipaddress.ip_address(handler.client_address[0])
|
||||
is_local = addr.is_loopback or addr.is_private
|
||||
except ValueError:
|
||||
is_local = False
|
||||
if not is_local:
|
||||
return bad(handler, "Onboarding setup is only available from local networks when auth is not enabled.", 403)
|
||||
try:
|
||||
return j(handler, apply_onboarding_setup(body))
|
||||
except ValueError as e:
|
||||
|
||||
@@ -526,7 +526,7 @@
|
||||
<div class="settings-section-title">System</div>
|
||||
<div class="settings-section-meta">Instance version and access controls.</div>
|
||||
</div>
|
||||
<span class="settings-version-badge">v0.50.8</span>
|
||||
<span class="settings-version-badge">v0.50.9</span>
|
||||
</div>
|
||||
<div class="settings-field" style="border-top:1px solid var(--border);padding-top:12px;margin-top:8px">
|
||||
<label for="settingsPassword" data-i18n="settings_label_password">Access Password</label>
|
||||
|
||||
Reference in New Issue
Block a user