Skip to content

Commit e367e1b

Browse files
Fix show_toolbar_with_docker on runtimes with unrelated host address (#2422)
* Fix show_toolbar_with_docker on runtimes with unrelated host address show_toolbar_with_docker derived the Docker host address by resolving host.docker.internal and replacing the last segment with .1. Runtimes such as OrbStack resolve that name to an address outside the container network (0.250.250.254), so the derived address never matches REMOTE_ADDR and the toolbar stays hidden. Fall back to deriving the gateway from the container's own addresses when the host.docker.internal probe does not match. * Reworked show_toolbar_with_docker to support falling through * Add runtimes to spelling words list * Document the host-guess caveat for show_toolbar_with_docker * Add comment in case someone copies this logic --------- Co-authored-by: Tim Schilling <schillingt@better-simple.com>
1 parent 49f4ef3 commit e367e1b

5 files changed

Lines changed: 42 additions & 3 deletions

File tree

debug_toolbar/middleware.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,9 @@ def show_toolbar_with_docker(request: HttpRequest) -> bool:
4444
if not settings.DEBUG:
4545
return False
4646

47-
# Test: settings
4847
if request.META.get("REMOTE_ADDR") in settings.INTERNAL_IPS:
4948
return True
5049

51-
# Test: Docker
5250
try:
5351
# This is a hack for docker installations. It attempts to look
5452
# up the IP address of the docker host.
@@ -64,7 +62,22 @@ def show_toolbar_with_docker(request: HttpRequest) -> bool:
6462
# It's fine if the lookup errored since they may not be using docker
6563
pass
6664

67-
# No test passed
65+
# Some Docker runtimes (for example OrbStack) resolve host.docker.internal
66+
# to an address that is unrelated to the container network, so the check
67+
# above cannot derive the host address from it.
68+
try:
69+
# Make a reasonable guess at the gateway from the container's own
70+
# interface. This assumes the process is running inside a container.
71+
# If this were used outside a container this would grant access to
72+
# anything that appears to come from the network's gateway (router).
73+
container_ips = socket.gethostbyname_ex(socket.gethostname())[2]
74+
gateways = {ip.rsplit(".", 1)[0] + ".1" for ip in container_ips}
75+
if request.META.get("REMOTE_ADDR") in gateways:
76+
return True
77+
except socket.gaierror:
78+
# It's fine if the lookup errored since they may not be using docker
79+
pass
80+
6881
return False
6982

7083

docs/changes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ Pending
99
older versions of Django, the panel explains that upgrading is required.
1010
* Fixed the Django version check in the SQL panel test suite for Django's
1111
boolean parameter handling.
12+
* Fixed ``show_toolbar_with_docker`` on Docker runtimes such as OrbStack that
13+
can resolve ``host.docker.internal`` to an address outside the container
14+
network.
1215
* Restored the select and explain buttons for queries that run without
1316
parameters.
1417
* Fixed the error shown when panel content fails to load, which could not

docs/installation.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,13 @@ option.
163163
Docker gateway IP and treat it as an allowable internal IP so that the
164164
toolbar is shown to you.
165165

166+
When the Docker host lookup fails, the ``show_toolbar_with_docker``
167+
callback guesses the host's address from the container's own network. If
168+
run outside a container that guess can resolve to another machine on your
169+
network, granting it access to the toolbar's data. The
170+
``show_toolbar_with_docker`` callback should only be used inside a
171+
container.
172+
166173
7. Disable the toolbar when running tests (optional)
167174
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
168175

docs/spelling_wordlist.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ refactoring
6262
reinitializing
6363
resizing
6464
runserver
65+
runtimes
6566
spellchecking
6667
sphinxcontrib
6768
spooler

tests/test_integration.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,21 @@ def test_show_toolbar_docker(self, mocked_gethostbyname):
8989
self.assertTrue(show_toolbar_with_docker(self.request))
9090
mocked_gethostbyname.assert_called_once_with("host.docker.internal")
9191

92+
@patch("socket.gethostbyname", return_value="0.250.250.254")
93+
@patch("socket.gethostname", return_value="container")
94+
@patch(
95+
"socket.gethostbyname_ex",
96+
return_value=("container", [], ["192.168.215.7"]),
97+
)
98+
def test_show_toolbar_docker_unrelated_host_address(self, *mocks):
99+
"""Runtimes such as OrbStack resolve host.docker.internal to an
100+
address outside of the container network, so the host address has to
101+
be derived from the container's own address instead."""
102+
self.request.META["REMOTE_ADDR"] = "192.168.215.1"
103+
with self.settings(INTERNAL_IPS=[]):
104+
self.assertFalse(show_toolbar(self.request))
105+
self.assertTrue(show_toolbar_with_docker(self.request))
106+
92107
def test_not_iterating_over_INTERNAL_IPS(self):
93108
"""Verify that the middleware does not iterate over INTERNAL_IPS in some way.
94109

0 commit comments

Comments
 (0)