Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ python app.py --port 8080 --host 0.0.0.0
python app.py --base-dir /path/to/claude/projects
```

> **Security warning:** Do not use `--host 0.0.0.0` together with `--debug` on untrusted networks.
Comment thread
wpak-ai marked this conversation as resolved.
> That combination exposes Werkzeug's interactive debugger, which allows arbitrary code execution
> from any browser that can reach the server. For typical local browsing, keep the default
> `--host 127.0.0.1` and omit `--debug`.

### CLI Export

```bash
Expand Down
8 changes: 7 additions & 1 deletion app.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ def index():
parser = argparse.ArgumentParser(description="Claude Code Chat Browser")
parser.add_argument("--port", type=int, default=5000)
parser.add_argument("--host", default="127.0.0.1")
parser.add_argument(
"--debug",
action="store_true",
default=False,
help="Enable Flask/Werkzeug debug mode (never use with --host 0.0.0.0 on untrusted networks).",
)
parser.add_argument("--base-dir", default=None, help="Override Claude projects dir")
parser.add_argument(
"--exclude-rules", "-e",
Expand All @@ -56,6 +62,6 @@ def index():
app.run(
host=args.host,
port=args.port,
debug=True,
debug=args.debug,
use_reloader=(sys.platform != "win32"),
Comment thread
wpak-ai marked this conversation as resolved.
Outdated
)
59 changes: 59 additions & 0 deletions tests/test_cli_args.py
Comment thread
wpak-ai marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
pytest tests/test_cli_args.py -v
"""

import ast
import sys
import os
import importlib
Expand All @@ -23,6 +24,43 @@
from scripts.export import build_parser


def _is_app_run_call(node: ast.AST) -> bool:
if not isinstance(node, ast.Call):
return False
func = node.func
return (
isinstance(func, ast.Attribute)
and func.attr == "run"
and isinstance(func.value, ast.Name)
and func.value.id == "app"
)


def _call_passes_hardcoded_debug_true(call: ast.Call) -> bool:
"""True if this Call passes literal True for debug (kwarg or positional)."""
for kw in call.keywords:
if kw.arg == "debug" and isinstance(kw.value, ast.Constant) and kw.value.value is True:
return True
for arg in call.args:
if isinstance(arg, ast.Constant) and arg.value is True:
return True
return False


def _debug_kwarg_uses_args(call: ast.Call) -> bool:
for kw in call.keywords:
if kw.arg != "debug":
continue
val = kw.value
return (
isinstance(val, ast.Attribute)
and isinstance(val.value, ast.Name)
and val.value.id == "args"
and val.attr == "debug"
)
return False


# ---------------------------------------------------------------------------
# export.py argument tests
# ---------------------------------------------------------------------------
Expand Down Expand Up @@ -221,6 +259,7 @@ def _build_parser(self) -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(description="Claude Code Chat Browser")
parser.add_argument("--port", type=int, default=5000)
parser.add_argument("--host", default="127.0.0.1")
parser.add_argument("--debug", action="store_true", default=False)
Comment thread
wpak-ai marked this conversation as resolved.
Outdated
parser.add_argument("--base-dir", default=None)
parser.add_argument("--exclude-rules", "-e", default=None,
metavar="PATH", dest="exclude_rules")
Expand All @@ -237,6 +276,26 @@ def test_host_override(self):
args = parser.parse_args(["--host", "127.0.0.1"])
assert args.host == "127.0.0.1"

def test_debug_default_is_false(self):
parser = self._build_parser()
args = parser.parse_args([])
assert args.debug is False

def test_debug_explicit_true(self):
parser = self._build_parser()
args = parser.parse_args(["--debug"])
assert args.debug is True

def test_app_py_debug_not_hardcoded_true(self):
"""app.run() must wire debug from args, not a literal True."""
app_path = os.path.join(REPO_ROOT, "app.py")
with open(app_path, encoding="utf-8") as f:
tree = ast.parse(f.read(), filename=app_path)
app_run_calls = [n for n in ast.walk(tree) if _is_app_run_call(n)]
assert app_run_calls, "expected at least one app.run() call in app.py"
assert not any(_call_passes_hardcoded_debug_true(c) for c in app_run_calls)
assert any(_debug_kwarg_uses_args(c) for c in app_run_calls)

def test_port_default(self):
parser = self._build_parser()
args = parser.parse_args([])
Expand Down
Loading