fix(cloudflared): replace broken --bind-addr at runtime + new migration

Problem: The first migration already ran on the user's server with
--bind-addr (broken). Alembic won't re-run the fixed migration.

Changes:
- _ensure_web_bind_address(): Now detects existing --bind-addr commands
  and replaces them with --host 0.0.0.0 instead of skipping
- New migration 2026_05_29_fix_code_server_bind_addr: Finds code-server
  tool types with --bind-addr in compose_template and replaces with
  --host 0.0.0.0

Quality gates: pytest 42 passed (2 pre-existing unrelated failures)
This commit is contained in:
2026-05-29 17:01:21 +02:00
parent fdfd75790d
commit 021537de56
2 changed files with 86 additions and 15 deletions
@@ -0,0 +1,53 @@
"""fix code-server bind-addr to host in DB template
Revision ID: 2026_05_29_fix_code_server_bind_addr
Revises: 2026_05_29_fix_web_tool_bind_address
Create Date: 2026-05-29 15:00:00.000000
"""
from typing import Sequence
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = "2026_05_29_fix_code_server_bind_addr"
down_revision: str | None = "2026_05_29_fix_web_tool_bind_address"
branch_labels: Sequence[str] | None = None
depends_on: Sequence[str] | None = None
def upgrade() -> None:
conn = op.get_bind()
# Find code-server tool types with broken --bind-addr in compose template
result = conn.execute(
sa.text("""
SELECT id, compose_template
FROM tool_types
WHERE name = 'code-server'
AND compose_template LIKE '%--bind-addr%'
""")
).fetchall()
for tool_id, compose_template in result:
updated = compose_template.replace(
"--bind-addr 0.0.0.0:8443", "--host 0.0.0.0"
).replace(
"--bind-addr", "--host 0.0.0.0"
)
conn.execute(
sa.text("""
UPDATE tool_types
SET compose_template = :compose_template
WHERE id = :id
"""),
{"compose_template": updated, "id": tool_id},
)
print(f"Fixed code-server template ({tool_id}): replaced --bind-addr with --host")
def downgrade() -> None:
pass
+33 -15
View File
@@ -648,28 +648,46 @@ def _ensure_web_bind_address(compose_path: str, tool_type_name: str) -> None:
return
for service_config in compose_data["services"].values():
# Skip if command is already overridden
if "command" in service_config:
return
image = service_config.get("image", "")
if not image:
return
continue
# Check if the image matches a known tool
if tool_type_name == "code-server" and (
is_code_server = tool_type_name == "code-server" and (
"code-server" in image or "coder" in image
):
service_config["command"] = bind_command
break
if tool_type_name == "jupyter-notebook" and (
)
is_jupyter = tool_type_name == "jupyter-notebook" and (
"jupyter" in image or "notebook" in image
):
service_config["command"] = bind_command
break
)
if not is_code_server and not is_jupyter:
continue
compose_file.write_text(yaml.dump(compose_data, default_flow_style=False))
logger.info("Injected bind address for %s: %s", tool_type_name, bind_command)
existing_command = service_config.get("command", "")
if existing_command:
# Fix broken --bind-addr (replaces with --host)
if "--bind-addr" in existing_command:
service_config["command"] = bind_command
compose_file.write_text(
yaml.dump(compose_data, default_flow_style=False)
)
logger.warning(
"Replaced broken bind address for %s: %s%s",
tool_type_name,
existing_command,
bind_command,
)
return
# Already has correct --host, nothing to do
if "--host" in existing_command or "--ip=" in existing_command:
return
# Some other command override exists — don't touch it
return
# No command yet — inject the correct bind address
service_config["command"] = bind_command
compose_file.write_text(yaml.dump(compose_data, default_flow_style=False))
logger.info("Injected bind address for %s: %s", tool_type_name, bind_command)
return
@router.post(