Skip to content

Commit d7f4701

Browse files
fix: address PR review on debug guard and API docs
- Simplify 127.x.x.x loopback check; reject empty host in format_listen_url - Add malformed 127.* tests; search endpoint stability column - CHANGELOG [0.1.0] footer link; SPA two-release deprecation note - README inline warning on 0.0.0.0 example
1 parent a5b3015 commit d7f4701

6 files changed

Lines changed: 33 additions & 12 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,5 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
2020
### Deprecated
2121

2222
- `export_count` on `GET /api/export/state` (documented only; still returned). Use `last_export_session_count`. Removal planned in a follow-up release per [deprecation policy](docs/deprecation-policy.md).
23+
24+
[0.1.0]: https://github.com/cppalliance/claude-code-chat-browser/releases/tag/v0.1.0

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ python app.py
5858

5959
Options:
6060
```bash
61-
python app.py --port 8080 --host 0.0.0.0
61+
python app.py --port 8080 --host 0.0.0.0 # never add --debug on 0.0.0.0
6262
python app.py --base-dir /path/to/claude/projects
6363
```
6464

app.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def is_loopback_host(host: str) -> bool:
2323
if h.startswith("127.") and h.count(".") == 3:
2424
parts = h.split(".")
2525
try:
26-
return len(parts) == 4 and all(0 <= int(p) <= 255 for p in parts)
26+
return all(0 <= int(p) <= 255 for p in parts)
2727
except ValueError:
2828
return False
2929
return False
@@ -32,6 +32,8 @@ def is_loopback_host(host: str) -> bool:
3232
def format_listen_url(host: str, port: int) -> str:
3333
"""Return a valid ``http://`` URL for the startup banner (IPv6 hosts bracketed)."""
3434
h = (host or "").strip()
35+
if not h:
36+
raise ValueError("host must not be empty")
3537
if h.startswith("[") and h.endswith("]"):
3638
display_host = h
3739
elif ":" in h:
@@ -51,7 +53,7 @@ def validate_startup_cli(args: argparse.Namespace) -> None:
5153
"Werkzeug debugger and session data to other machines.",
5254
file=sys.stderr,
5355
)
54-
raise SystemExit(1)
56+
sys.exit(1)
5557

5658

5759
def create_app(

docs/api-reference.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -292,14 +292,14 @@ Case-insensitive substring search across all non-excluded messages in all projec
292292

293293
`application/json` — array of hit objects:
294294

295-
| Field | Type | Description |
296-
|-------|------|-------------|
297-
| `project` | string | Project `name` |
298-
| `session_id` | string | Session id |
299-
| `title` | string | Session title |
300-
| `role` | string | Message role (`human`, `assistant`, …) |
301-
| `timestamp` | string \| null | Message timestamp |
302-
| `snippet` | string | ~160 chars around match |
295+
| Field | Type | Stability | Description |
296+
|-------|------|-----------|-------------|
297+
| `project` | string | stable | Project `name` |
298+
| `session_id` | string | stable | Session id |
299+
| `title` | string | stable | Session title |
300+
| `role` | string | stable | Message role (`human`, `assistant`, …) |
301+
| `timestamp` | string \| null | stable | Message timestamp |
302+
| `snippet` | string | experimental | ~160 chars around match; length may change |
303303

304304
#### Errors
305305

docs/deprecation-policy.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ A deprecated field may be removed when:
2525
- The bundled SPA no longer reads the field, and
2626
- Tests and CHANGELOG document the removal.
2727

28+
For fields actively read by the bundled SPA (which does not track an external API version), the deprecation period will span **at least two releases** so the SPA and policy can be updated in the same release cycle as the final removal.
29+
2830
## Example (in progress)
2931

3032
| Field | Endpoint | Status | Replacement |

tests/test_cli_args.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,18 @@ def test_debug_explicit_true(self):
325325
def test_is_loopback_host_accepts_loopback(self, host: str) -> None:
326326
assert is_loopback_host(host)
327327

328-
@pytest.mark.parametrize("host", ["0.0.0.0", "192.168.1.1", "", "example.com"])
328+
@pytest.mark.parametrize(
329+
"host",
330+
[
331+
"0.0.0.0",
332+
"192.168.1.1",
333+
"",
334+
"example.com",
335+
"127.0.0.",
336+
"127.256.0.0",
337+
"127.-1.0.0",
338+
],
339+
)
329340
def test_is_loopback_host_rejects_non_loopback(self, host: str) -> None:
330341
assert not is_loopback_host(host)
331342

@@ -357,6 +368,10 @@ def test_validate_startup_cli_rejects_non_loopback_debug(
357368
def test_format_listen_url(self, host: str, port: int, expected: str) -> None:
358369
assert format_listen_url(host, port) == expected
359370

371+
def test_format_listen_url_rejects_empty_host(self) -> None:
372+
with pytest.raises(ValueError, match="host must not be empty"):
373+
format_listen_url("", 5000)
374+
360375
def test_validate_startup_cli_allows_non_loopback_without_debug(self) -> None:
361376
parser = build_cli_parser()
362377
args = parser.parse_args(["--host", "0.0.0.0"])

0 commit comments

Comments
 (0)