From 021537de56d4609f293de4395ebf7f8ddfd796ef Mon Sep 17 00:00:00 2001 From: Alex Blank Date: Fri, 29 May 2026 17:01:21 +0200 Subject: [PATCH] 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) --- .../2026_05_29_fix_code_server_bind_addr.py | 53 +++++++++++++++++++ apps/api/src/api/tool_instances.py | 48 +++++++++++------ 2 files changed, 86 insertions(+), 15 deletions(-) create mode 100644 apps/api/alembic/versions/2026_05_29_fix_code_server_bind_addr.py diff --git a/apps/api/alembic/versions/2026_05_29_fix_code_server_bind_addr.py b/apps/api/alembic/versions/2026_05_29_fix_code_server_bind_addr.py new file mode 100644 index 0000000..a157b26 --- /dev/null +++ b/apps/api/alembic/versions/2026_05_29_fix_code_server_bind_addr.py @@ -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 diff --git a/apps/api/src/api/tool_instances.py b/apps/api/src/api/tool_instances.py index 62eabe1..2dd4853 100644 --- a/apps/api/src/api/tool_instances.py +++ b/apps/api/src/api/tool_instances.py @@ -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(