fix: v0.2.9 — review welle 1 (C-1, C-2, M-3)

C-1: __version__ now derived from package metadata via
importlib.metadata.version() so pyproject.toml is the single source of
truth. Previously stuck at "0.1.0" since the initial release.

C-2: Backfill CHANGELOG entries for 0.2.7 and 0.2.8 (both releases had
shipped without changelog updates) and add a 0.2.9 entry covering this
welle.

M-3: Reject project names containing path separators or other unsafe
characters before they reach _find_compose_path. Previously a name like
"../../etc" could traverse out of compose_base_path when the project was
not yet registered with Container Manager. Adds _validate_project_name
(regex ^[a-zA-Z0-9_-]+$, applied in read_compose, update_compose,
update_image_tag, update_env_var) plus parametrized tests for valid and
unsafe names and one rejection test per tool. 236 tests pass.

Also: ruff format autofix on three pre-existing files (cli.py,
config.py, test_config.py) — cosmetic only.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-18 09:07:00 +02:00
parent a1a9388d88
commit 661460bfd9
9 changed files with 246 additions and 8 deletions
+87
View File
@@ -2,6 +2,93 @@
All notable changes to this project will be documented in this file.
## [0.2.9] - 2026-05-18
### Fixed
- `__version__` is now derived from package metadata via
`importlib.metadata.version()`, eliminating the drift between
`pyproject.toml` and `src/mcp_synology_container/__init__.py` (was stuck
at `0.1.0` since the initial release).
- `compose.py`: reject project names that contain path separators or other
unsafe characters before they reach `_find_compose_path`. Previously a
name like `"../../etc"` could traverse out of `compose_base_path` when
the project was not yet registered with Container Manager. The new
`_validate_project_name` helper enforces `^[a-zA-Z0-9_-]+$` and is
applied to `read_compose`, `update_compose`, `update_image_tag`, and
`update_env_var`. Addresses M-3 from the v0.2.8 review.
### Docs
- `CHANGELOG.md` backfilled for releases 0.2.7 and 0.2.8 (entries had been
missed during those releases).
## [0.2.8] - 2026-04-21
### Added
- `tests/test_dsm_client.py` — comprehensive offline test suite for
`DsmClient`:
- `_scrub_url` and `_error_message` pure helpers.
- `request()` happy-path, API-not-cached, `_sid` scrubbing in
`HTTPStatusError`, sensitive-param log masking.
- Session re-auth retry: single-retry semantics, auth-manager-absent
path, re-auth failure path, thundering-herd (login called once under
concurrent 106 responses).
- `trigger_build_stream`: SSE fire-and-forget, JSON error detection,
`ReadTimeout` swallowing, HTTP-error scrubbing.
- `upload_text` and `download_text` happy-path + error-response branches.
- `_ensure_initialized` double-checked locking and negative-cache
cooldown behavior.
### Fixed
- `DsmClient._ensure_initialized`: cache failed init outcomes for 60 s so
that repeated tool calls during a credential outage (wrong password,
IP-blocked 407, DNS failure) do not keep hammering DSM. Each caller
receives the cached exception until the cooldown window expires, after
which a fresh attempt is made. Adds `INIT_ERROR_COOLDOWN` module
constant and `_init_error` / `_init_error_until` state. Addresses M4
from the 0.2.7 review.
## [0.2.7] - 2026-04-21
### Fixed
- `DsmClient`: scrub `_sid` query-parameter values from URLs embedded in
`httpx.HTTPStatusError` messages so the raw DSM session ID never reaches
log output or MCP tool responses (C1).
- `DsmClient`: re-auth lock now snapshots `_sid` before entering the lock
and skips the redundant login if another task has already refreshed the
session, eliminating duplicate logins on concurrent 106/107/119
responses (M3).
- `DsmClient.trigger_build_stream`: re-instates immediate JSON-error
detection (regression from 0.2.6). Inspects the `Content-Type` header
and reads a small capped prefix of the body for `application/json`
responses to surface DSM error codes without forcing the caller into a
multi-minute polling timeout. SSE responses remain fire-and-forget
(C2/M8).
- `compose.update_env_var`: parenthesise the apply-branch match condition
so `(isinstance AND startswith) OR (entry == var_name)` no longer
evaluates the equality branch for non-string entries — aligns the apply
side with the preview-side detection logic (M1).
### Changed
- All 23 `@mcp.tool()` functions: strip `-> str` return annotations and
trim docstrings to a single line (≤100 chars). FastMCP generates an
`outputSchema` entry for every annotated tool, which roughly doubles
the `tools/list` payload size; multi-line docstrings with
`Args:`/`Returns:` sections add further bulk that Claude Desktop must
parse on every connection.
### Chore
- `uv.lock` resynced (was stale at `0.2.2`).
- `.gitignore`: exclude `.claude/` per-user Claude Code settings.
- Mechanical `ruff check --fix` + `ruff format` cleanup (import sorting,
unused-import removal). No functional change.
## [0.2.6] - 2026-04-21
### Fixed