Skip to content

Commit 1f5456e

Browse files
fix: address PR review on loopback host, versioning, and docs
1 parent ab1bb2e commit 1f5456e

6 files changed

Lines changed: 31 additions & 15 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ All notable changes to this project are documented in this file.
44

55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
66

7-
## [0.1.0] - 2026-06-02
7+
## [Unreleased]
88

99
### Added
1010

11-
- `__version__` in `app.py` for release tracking
12-
- Startup guard refusing `--debug` with a non-loopback `--host`
11+
- `__version__` in `app.py` for release tracking (`0.1.0.dev0` until the first `v0.1.0` git tag)
12+
- Startup guard refusing `--debug` with a non-loopback `--host` (including bracketed IPv6 loopback such as `[::1]`)
1313
- [Deprecation policy](docs/deprecation-policy.md) for API and JSON field changes
1414
- API field **stability** tables in `docs/api-reference.md` (stable / experimental / deprecated)
1515

@@ -20,5 +20,3 @@ 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

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ Useful flags:
4141
- `--base-dir PATH` — point at a different `projects/` tree (for tests or fixtures)
4242
- `--exclude-rules PATH` — session exclusion rules file
4343
- `--host 0.0.0.0` — listen on all interfaces (use only on trusted networks; never with `--debug`)
44-
- `--debug` — Flask/Werkzeug debug mode (loopback hosts only; enforced when starting via `python app.py`, not `flask run` or WSGI)
44+
- `--debug` — Flask/Werkzeug debug mode (loopback hosts only; enforced when starting via `python app.py`, not `flask run` or WSGI). Extending the guard to `FLASK_DEBUG` / `flask run` is a planned follow-up.
4545

4646
## API and release policy
4747

app.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""Flask app that serves the web GUI for browsing sessions."""
22

3-
__version__ = "0.1.0"
3+
__version__ = "0.1.0.dev0"
44

55
import argparse
66
import os
@@ -15,13 +15,21 @@
1515
from utils.exclusion_rules import resolve_exclusion_rules_path, load_rules
1616

1717

18+
def _normalize_bind_host(host: str) -> str:
19+
"""Lowercase host for checks; strip optional IPv6 brackets (e.g. ``[::1]`` → ``::1``)."""
20+
h = (host or "").strip().lower()
21+
if len(h) >= 2 and h.startswith("[") and h.endswith("]"):
22+
return h[1:-1]
23+
return h
24+
25+
1826
def is_loopback_host(host: str) -> bool:
1927
"""True if ``host`` binds only to the local machine (safe with ``--debug``).
2028
21-
Accepts ``127.0.0.1``, ``localhost``, ``::1``, and other ``127.x.x.x`` addresses.
29+
Accepts ``127.0.0.1``, ``localhost``, ``::1``, ``[::1]``, and other ``127.x.x.x`` addresses.
2230
Rejects all-interfaces forms such as ``0.0.0.0`` and bare ``::`` (not loopback).
2331
"""
24-
h = (host or "").strip().lower()
32+
h = _normalize_bind_host(host)
2533
if h in ("127.0.0.1", "localhost", "::1"):
2634
return True
2735
if h.startswith("127.") and h.count(".") == 3:
@@ -52,7 +60,7 @@ def validate_startup_cli(args: argparse.Namespace) -> None:
5260
if args.debug and not is_loopback_host(args.host):
5361
print(
5462
"error: --debug is only allowed with a loopback --host "
55-
"(127.0.0.1, localhost, ::1, or 127.x.x.x). "
63+
"(127.0.0.1, localhost, ::1, [::1], or 127.x.x.x). "
5664
"Combining --debug with a network-visible --host exposes the "
5765
"Werkzeug debugger and session data to other machines.",
5866
file=sys.stderr,

docs/api-reference.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ HTTP API for **claude-code-chat-browser**. All `/api/*` routes return JSON unles
66

77
**Source of truth for error codes:** [`api/error_codes.py`](../api/error_codes.py)
88

9-
**Field stability:** [`deprecation-policy.md`](deprecation-policy.md)
9+
**Deprecation and removal:** See [`deprecation-policy.md`](deprecation-policy.md) for how stability labels are applied and fields are removed. Field labels are defined in [API field stability](#api-field-stability) below.
1010

1111
---
1212

docs/deprecation-policy.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ 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.
28+
For fields actively read by the bundled SPA (which does not track an external API version), removal happens no earlier than **two tagged releases** after the release that documented the deprecation in CHANGELOG (for example, deprecated in `0.1.0`, removable from `0.3.0` at earliest when versions advance `0.1.0``0.2.0``0.3.0`), and no earlier than **14 calendar days** after that deprecation announcement.
2929

3030
## Example (in progress)
3131

@@ -35,4 +35,12 @@ For fields actively read by the bundled SPA (which does not track an external AP
3535

3636
## Versioning
3737

38-
Release versions follow `MAJOR.MINOR.PATCH` in `app.__version__` and [CHANGELOG](../CHANGELOG.md). This project is pre-1.0; minor releases may add features; patch releases are fixes and documentation.
38+
Release versions follow `MAJOR.MINOR.PATCH` in `app.__version__` and [CHANGELOG](../CHANGELOG.md). Until the first git tag ships, `main` may carry a `.dev0` suffix (for example `0.1.0.dev0`); the CHANGELOG `[Unreleased]` section is the source of truth for what is not yet tagged.
39+
40+
| Bump | Pre-1.0 meaning |
41+
|------|-----------------|
42+
| **Patch** | Bug fixes and documentation; no intentional API removals |
43+
| **Minor** | Additive API/features; deprecations may be announced |
44+
| **Major** | Reserved for the `1.0.0` line and later: signals a stable HTTP JSON contract for external integrators and may include breaking removals that completed their deprecation period |
45+
46+
While the project is pre-1.0, treat **minor** bumps as the usual vehicle for deprecations and **patch** bumps for safe fixes.

tests/test_cli_args.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,9 @@ def test_debug_explicit_true(self):
321321
args = parser.parse_args(["--debug"])
322322
assert args.debug is True
323323

324-
@pytest.mark.parametrize("host", ["127.0.0.1", "localhost", "::1", "127.0.0.2"])
324+
@pytest.mark.parametrize(
325+
"host", ["127.0.0.1", "localhost", "::1", "[::1]", "127.0.0.2"]
326+
)
325327
def test_is_loopback_host_accepts_loopback(self, host: str) -> None:
326328
assert is_loopback_host(host)
327329

@@ -340,7 +342,7 @@ def test_is_loopback_host_accepts_loopback(self, host: str) -> None:
340342
def test_is_loopback_host_rejects_non_loopback(self, host: str) -> None:
341343
assert not is_loopback_host(host)
342344

343-
@pytest.mark.parametrize("host", ["127.0.0.1", "localhost"])
345+
@pytest.mark.parametrize("host", ["127.0.0.1", "localhost", "[::1]"])
344346
def test_validate_startup_cli_allows_loopback_debug(self, host: str) -> None:
345347
parser = build_cli_parser()
346348
args = parser.parse_args(["--host", host, "--debug"])

0 commit comments

Comments
 (0)